digitalmars.D.learn - thisExePath purity
- crimaniak (5/5) Sep 19 2016 Hi!
- Stefan Koch (6/11) Sep 19 2016 No way to do that.
- Jonathan M Davis via Digitalmars-d-learn (15/28) Sep 19 2016 Yes, you can cast a function pointer to force purity, but that's almost
- Steven Schveighoffer (13/18) Sep 19 2016 Not in a way that D can ensure purity. Yes, it will not change. But that...
- Jonathan M Davis via Digitalmars-d-learn (21/26) Sep 19 2016 In principle, it should be impossible for it to change while the program...
- crimaniak (27/33) Sep 19 2016 Hi and thanks all!
- Jonathan M Davis via Digitalmars-d-learn (10/11) Sep 19 2016 I would point out that immutable is implicitly shared, so there's no rea...
- crimaniak (3/14) Sep 20 2016 Ok, I got it. Thanks.
- Marc =?UTF-8?B?U2Now7x0eg==?= (5/38) Sep 20 2016 Have a look at `std.concurrency.initOnce`:
- crimaniak (3/7) Sep 20 2016 Yes, it's near but in this case I try to fix purity, so any
- Steven Schveighoffer (11/42) Sep 20 2016 Yes, but if your code does instantiate it, it is called, even if you
- crimaniak (23/32) Sep 20 2016 Yes, it's not ideal but better then just global variable and
- Steven Schveighoffer (9/31) Sep 21 2016 But if this is all that is in the module, why import the module if you
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
Sep 19 2016
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.htmlNo 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.
Sep 19 2016
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: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 DavisHi! 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.htmlNo 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.
Sep 19 2016
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.htmlNot 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
Sep 19 2016
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.htmlIn 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
Sep 19 2016
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
Sep 19 2016
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
Sep 19 2016
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:Ok, I got it. Thanks.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).
Sep 20 2016
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: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...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.
Sep 20 2016
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.
Sep 20 2016
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: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. -Steveimmutable 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.
Sep 20 2016
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
Sep 20 2016
On 9/20/16 3:42 PM, crimaniak wrote:On Tuesday, 20 September 2016 at 13:35:27 UTC, Steven Schveighoffer wrote:But if this is all that is in the module, why import the module if you aren't going to use any of it?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.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. -SteveI 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
Sep 21 2016