Re: thisExePath purity

2016-09-21 Thread Steven Schveighoffer via Digitalmars-d-learn

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

2016-09-20 Thread crimaniak via Digitalmars-d-learn
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

2016-09-20 Thread crimaniak via Digitalmars-d-learn

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

2016-09-20 Thread crimaniak via Digitalmars-d-learn
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

2016-09-20 Thread Steven Schveighoffer via Digitalmars-d-learn

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

2016-09-20 Thread Marc Schütz via Digitalmars-d-learn

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

2016-09-19 Thread Jonathan M Davis via Digitalmars-d-learn
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

2016-09-19 Thread crimaniak via Digitalmars-d-learn

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

2016-09-19 Thread Jonathan M Davis via Digitalmars-d-learn
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

2016-09-19 Thread Jonathan M Davis via Digitalmars-d-learn
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

2016-09-19 Thread Steven Schveighoffer via Digitalmars-d-learn

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

2016-09-19 Thread Stefan Koch via Digitalmars-d-learn

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.