Re: thisExePath purity
On 9/20/16 3:42 PM, crimaniak wrote: On Tuesday, 20 September 2016 at 13:35:27 UTC, Steven Schveighoffer wrote: Note that if you don't import the module that contains the static ctor, it should be trimmed by the linker. Let's imagine linker can trim even imported module with static ctor, if we have something like: immutable string executablePath; @local shared static this() { import std.file : thisExePath; executablePath = thisExePath(); } and there is no references to executablePath. Here it would be useful, I think. Attribute @local (or @module? the name does not matter) mean this block used only to init other symbols in this module so it can be skipped if no references. But if this is all that is in the module, why import the module if you aren't going to use any of it? I would absolutely caution you from putting static this() inside any template. Unfortunately, due to the way D generates these static constructors, any module that uses staticMemoize, or *imports a module that uses it*, will be marked as having a static constructor, and will potentially create cycles. Please be more detail about cycles. Do you mean something like this? https://isocpp.org/wiki/faq/ctors#static-init-order Sort of, I mean this: https://dlang.org/spec/module.html#order_of_static_ctor In other words, because the template has a static ctor in it, just instantiating it in your unrelated module puts static ctor in your module. And then cycles can appear that you wouldn't expect to happen. -Steve
Re: thisExePath purity
On Tuesday, 20 September 2016 at 13:35:27 UTC, Steven Schveighoffer wrote: Yes, but if your code does instantiate it, it is called, even if you don't ever call the function that calls it. Yes, it's not ideal but better then just global variable and static block - it's called in any case, even if variable is not used at all. Ideal solution will be something like attribute for static block leading to make it optional, so module will not be included if no usage of other symbols found. But I don't know way how to make it so template is used. Note that if you don't import the module that contains the static ctor, it should be trimmed by the linker. Let's imagine linker can trim even imported module with static ctor, if we have something like: immutable string executablePath; @local shared static this() { import std.file : thisExePath; executablePath = thisExePath(); } and there is no references to executablePath. Here it would be useful, I think. Attribute @local (or @module? the name does not matter) mean this block used only to init other symbols in this module so it can be skipped if no references. I would absolutely caution you from putting static this() inside any template. Unfortunately, due to the way D generates these static constructors, any module that uses staticMemoize, or *imports a module that uses it*, will be marked as having a static constructor, and will potentially create cycles. Please be more detail about cycles. Do you mean something like this? https://isocpp.org/wiki/faq/ctors#static-init-order
Re: thisExePath purity
On Tuesday, 20 September 2016 at 09:14:39 UTC, Marc Schütz wrote: Have a look at `std.concurrency.initOnce`: https://dlang.org/phobos/std_concurrency.html#.initOnce But you will still need to use assumePure() for calling `thisExePath`, and it might do other things that are impure... Yes, it's near but in this case I try to fix purity, so any variants of lazy initialization is not applicable here.
Re: thisExePath purity
On Tuesday, 20 September 2016 at 04:26:05 UTC, Jonathan M Davis wrote: On Tuesday, September 20, 2016 04:17:21 crimaniak via Digitalmars-d-learn wrote: static shared immutable ReturnType!T value; I would point out that immutable is implicitly shared, so there's no reason to put shared on an immutable variable. However, you _do_ want to put shared on a static constructor that initializes an immutable variable so that it's only run once for the program instead of once per thread (the compiler really should enforce that, but there's a longstanding bug that allows you to reinitialize an immutable variable by not putting shared on the static constructor and starting multiple threads). Ok, I got it. Thanks.
Re: thisExePath purity
On 9/20/16 12:17 AM, crimaniak wrote: Hi and thanks all! On Tuesday, 20 September 2016 at 00:43:10 UTC, Jonathan M Davis wrote: immutable string executablePath; shared static this() { import std.file : thisExePath(); executablePath = thisExePath(); } This code is good for my needs but I start to think about how to call thisExePath only if it is really used and come to this solution: import std.traits: ReturnType, Parameters; string staticMemoize(alias T, Parms = Parameters!T)() pure { struct Holder(alias T) { static shared immutable ReturnType!T value; shared static this(){ value = T(Parms); } } return Holder!T.value; } unittest { import std.file : thisExePath; assert(staticMemoize!thisExePath == thisExePath); } Something like this. Need to refine about input parameters, but I hope, idea is clear. Unlike the function memoize from phobos staticMemoize really pure. And unlike proposed solution with ordinary variable staticMemoize is lazy, because no call - no instantiation. Yes, but if your code does instantiate it, it is called, even if you don't ever call the function that calls it. Note that if you don't import the module that contains the static ctor, it should be trimmed by the linker. I would absolutely caution you from putting static this() inside any template. Unfortunately, due to the way D generates these static constructors, any module that uses staticMemoize, or *imports a module that uses it*, will be marked as having a static constructor, and will potentially create cycles. -Steve
Re: thisExePath purity
On Tuesday, 20 September 2016 at 04:17:21 UTC, crimaniak wrote: Hi and thanks all! On Tuesday, 20 September 2016 at 00:43:10 UTC, Jonathan M Davis wrote: immutable string executablePath; shared static this() { import std.file : thisExePath(); executablePath = thisExePath(); } This code is good for my needs but I start to think about how to call thisExePath only if it is really used and come to this solution: import std.traits: ReturnType, Parameters; string staticMemoize(alias T, Parms = Parameters!T)() pure { struct Holder(alias T) { static shared immutable ReturnType!T value; shared static this(){ value = T(Parms); } } return Holder!T.value; } unittest { import std.file : thisExePath; assert(staticMemoize!thisExePath == thisExePath); } Something like this. Need to refine about input parameters, but I hope, idea is clear. Unlike the function memoize from phobos staticMemoize really pure. And unlike proposed solution with ordinary variable staticMemoize is lazy, because no call - no instantiation. Have a look at `std.concurrency.initOnce`: https://dlang.org/phobos/std_concurrency.html#.initOnce But you will still need to use assumePure() for calling `thisExePath`, and it might do other things that are impure...
Re: thisExePath purity
On Tuesday, September 20, 2016 04:17:21 crimaniak via Digitalmars-d-learn wrote: > static shared immutable ReturnType!T value; I would point out that immutable is implicitly shared, so there's no reason to put shared on an immutable variable. However, you _do_ want to put shared on a static constructor that initializes an immutable variable so that it's only run once for the program instead of once per thread (the compiler really should enforce that, but there's a longstanding bug that allows you to reinitialize an immutable variable by not putting shared on the static constructor and starting multiple threads). - Jonathan M Davis
Re: thisExePath purity
Hi and thanks all! On Tuesday, 20 September 2016 at 00:43:10 UTC, Jonathan M Davis wrote: immutable string executablePath; shared static this() { import std.file : thisExePath(); executablePath = thisExePath(); } This code is good for my needs but I start to think about how to call thisExePath only if it is really used and come to this solution: import std.traits: ReturnType, Parameters; string staticMemoize(alias T, Parms = Parameters!T)() pure { struct Holder(alias T) { static shared immutable ReturnType!T value; shared static this(){ value = T(Parms); } } return Holder!T.value; } unittest { import std.file : thisExePath; assert(staticMemoize!thisExePath == thisExePath); } Something like this. Need to refine about input parameters, but I hope, idea is clear. Unlike the function memoize from phobos staticMemoize really pure. And unlike proposed solution with ordinary variable staticMemoize is lazy, because no call - no instantiation. https://dlang.org/library/std/functional/memoize.html
Re: thisExePath purity
On Tuesday, September 20, 2016 00:37:10 Stefan Koch via Digitalmars-d-learn wrote: > On Tuesday, 20 September 2016 at 00:01:58 UTC, crimaniak wrote: > > Hi! > > > > Is there situations when output of thisExePath() can be > > different during runtime? If yes, what the reason? > > If no, is this possible to mark it as pure in phobos? > > > > https://dlang.org/library/std/file/this_exe_path.html > > No way to do that. > It does I/O. > However you cheat. > look for assumePure in https://dlang.org/phobos/std_traits.html > and then you can create a wrapper for it that is fake pure. Yes, you can cast a function pointer to force purity, but that's almost always a bad idea. It makes far more sense to just grab the value once and reuse it. The only time that I'd suggest using the casting trick for something like this would be when you can't afford to use static constructors, and you can't afford to pass the value around. Casting to pure should be a tool of last resort. It _is_ an option though if you really have no reasonable alternative. Another thing to consider in this case is that casting like that would actually be needlessly expensive if he actually needs to make the call more than once. It would be far cheaper to just save the result and reuse it. And if it's stored in an immutable module-level or static variable, then it can be used in a pure function. - Jonathan M Davis
Re: thisExePath purity
On Tuesday, September 20, 2016 00:01:58 crimaniak via Digitalmars-d-learn wrote: > Hi! > > Is there situations when output of thisExePath() can be different > during runtime? If yes, what the reason? > If no, is this possible to mark it as pure in phobos? > > https://dlang.org/library/std/file/this_exe_path.html In principle, it should be impossible for it to change while the program is running. However, what Phobos has to do to get the information can't be pure. In the best case, it involves calling C functions that we can reasonably assume will be pure but can't technically guarantee will be, but in some cases, it actually involves querying the file system (e.g. on Linux, it reads "/proc/self/exe"), which definitely can't be pure, because it involves I/O. If you really want a pure way to deal with this, then I'd suggest grabbing the value at startup and setting it to an immutable variable. e.g. something like immutable string executablePath; shared static this() { import std.file : thisExePath(); executablePath = thisExePath(); } and then you can use that variable in pure code, because it's guaranteed not to change. - Jonathan M Davis
Re: thisExePath purity
On 9/19/16 8:01 PM, crimaniak wrote: Hi! Is there situations when output of thisExePath() can be different during runtime? If yes, what the reason? If no, is this possible to mark it as pure in phobos? https://dlang.org/library/std/file/this_exe_path.html Not in a way that D can ensure purity. Yes, it will not change. But that guarantee is not communicated via the OS functions required to call to get the information. One thing you can do: immutable string myPath; shared static this() { import std.file: thisExePath; myPath = thisExePath; } // now use myPath as required from pure functions. -Steve
Re: thisExePath purity
On Tuesday, 20 September 2016 at 00:01:58 UTC, crimaniak wrote: Hi! Is there situations when output of thisExePath() can be different during runtime? If yes, what the reason? If no, is this possible to mark it as pure in phobos? https://dlang.org/library/std/file/this_exe_path.html No way to do that. It does I/O. However you cheat. look for assumePure in https://dlang.org/phobos/std_traits.html and then you can create a wrapper for it that is fake pure.