Re: purity question

2017-05-30 Thread H. S. Teoh via Digitalmars-d-learn
On Tue, May 30, 2017 at 11:10:19AM -0700, Jonathan M Davis via 
Digitalmars-d-learn wrote:
[...]
> Yeah, basically, D's pure was originally what is now sometimes called
> "strongly pure," which is quite close to functionally pure in that the
> same input results in the same output (it still allows alocating
> memory and returning it though, so you can have equal but different
> objects if the same function is called multiple times with the same
> arguments in different contexts where the compiler doesn't memoize
> it). However, pure was so restrictive as to be borderline useless,
> because it could only pass types that were immutable or implicitly
> convertible to immutable. So, it was expanded to include any function
> which could not access global, mutable state, because such functions
> can be called from a "strongly" pure function without violating the
> strongly pure function's guarantees - and thus "weakly" pure functions
> were born, making it so that D's pure is really more like @noglobal
> than functionally pure. It's a critical building block in functional
> purity, and strongly pure functions still get all of the benefits that
> they got before (and now they can actually be useful, because they can
> call many more functions), but _most_ pure functions are weakly pure
> and thus don't get the full benefits of functional purity - and that's
> why some folks like Ketmar tend to get annoyed with D's pure. But the
> way it is is actually quite useful even if it's initially confusing.
> And even when there are no strongly pure functions in your program,
> knowing that a function cannot access global variables except through
> its arguments means a lot in and of itself.
[...]

In retrospect, we could have named "weakly pure" something like
@noglobal, and "strongly pure" as pure.

But be that as it may, I think D's pure system is actually extremely
ingenious.  Look at it this way: in the classical sense of functional
purity, which is what you get in (pure) functional languages, it can get
quite difficult to implement the functionality you want, because the
language enforces that every primitive you use in your implementation
must be pure.  The reasoning is that if you're only allowed to use pure
primitives, then the resulting function is guaranteed to be pure.  It's
nice and simple. However, it's also rather cumbersome, especially in the
context of an imperative language like D.

For example, in a functional language you cannot assign new values to
variables, and you cannot write for-loops, because the loop index is not
allowed to mutate. You cannot mutate anything, because mutation makes
the code impure. So instead of straightforward loops, you need to resort
to things like tail recursion; instead of mutation, you need to use
monads, and so on.  I'm not saying this is a bad thing, but it's just
cumbersome because you, the programmer, cannot simply implement a
function with a straightforward algorithm, but you have to work harder
to express the algorithm in functional terms using recursion and other
functional (pure) constructs.

The first insight in D's purity system is the observation that, given
some function f(), from the caller's POV all they care about is that (1)
the function always returns the same value given the same arguments, and
(2) there are no visible side-effects.  Point (2) is where the insight
lies: in a sense, it *doesn't matter* if f() does all kinds of impure
stuff in order to compute its return value, as long as the outside world
cannot see it.  It may be internally impure, but externally, as far as
the outside world is concerned, it's pure, because the caller can't tell
the difference.  So D allows things like variables, mutation, for-loops,
and all kinds of stuff inside (strongly) pure functions -- as long as
no global state is touched, and as long as the function arguments aren't
modified (from the caller's POV), f() is pure.  In other words, as long
as f() keeps its dirty laundry to itself and leaves the outside world
untouched, it is externally pure, even if it's internally impure.

The next insight is this: suppose f() calls g(), and g() is impure.  In
the traditional functional language purity system, this is outright
illegal, because a pure function, by definition, cannot call an impure
function, otherwise it is itself impure.  However, suppose g() does not
modify any global state.  It *may* modify stuff through its arguments --
which makes it impure.  But if f() is not allowed to modify its
arguments and has no global state, then at worst, it can only pass its
internal, non-global state to g(). Therefore, it is impossible for g()
to reach global state through its arguments. Thus, f()'s (external)
purity is preserved.

Note the fine distinction here, that g()'s external purity is keyed on
being called from inside a strongly-pure function f(). If f() is impure,
then there is no guarantee that g() may modify global state (because f()
may pass a reference to a global 

Re: purity question

2017-05-30 Thread Jonathan M Davis via Digitalmars-d-learn
On Tuesday, May 30, 2017 16:54:13 ag0aep6g via Digitalmars-d-learn wrote:
> On 05/30/2017 11:12 AM, Rene Zwanenburg wrote:
> > If malloc were marked as pure, wouldn't that mean it must return the
> > same pointer every time you call it with the same size?
>
> D's `pure` mostly means: "does not access mutable state, and does not do
> input/output".
>
> There is never a requirement that a function must return the same value
> for the same input. But a compiler is allowed to memoize the result of a
> `pure` function when it has no mutable indirections in its parameter and
> return types. Such a function is "strongly pure".
>
> When there are mutable indirections, the function is "weakly pure".
> Weakly pure functions are not assumed to be memoizable, but "weakly
> pure" still has meaning:
>
> * Can call weakly pure functions from strongly pure ones.
>
> * When a weakly pure function has mutable indirections in the return
> type but not in the parameters (like malloc), then it must be returning
> freshly allocated memory. That means, the result cannot be referenced
> from anywhere else. So it can be converted to const/immutable/shared
> implicitly. The spec calls that a "pure factory function".
>
> Repeating Biotronic's links, the spec and David Nadlinger's article are
> the go-to resources for D's take on purity:
>
> https://dlang.org/spec/function.html#pure-functions
> http://klickverbot.at/blog/2012/05/purity-in-d/

Yeah, basically, D's pure was originally what is now sometimes called
"strongly pure," which is quite close to functionally pure in that the same
input results in the same output (it still allows alocating memory and
returning it though, so you can have equal but different objects if the same
function is called multiple times with the same arguments in different
contexts where the compiler doesn't memoize it). However, pure was so
restrictive as to be borderline useless, because it could only pass types
that were immutable or implicitly convertible to immutable. So, it was
expanded to include any function which could not access global, mutable
state, because such functions can be called from a "strongly" pure function
without violating the strongly pure function's guarantees - and thus
"weakly" pure functions were born, making it so that D's pure is really more
like @noglobal than functionally pure. It's a critical building block in
functional purity, and strongly pure functions still get all of the benefits
that they got before (and now they can actually be useful, because they can
call many more functions), but _most_ pure functions are weakly pure and
thus don't get the full benefits of functional purity - and that's why some
folks like Ketmar tend to get annoyed with D's pure. But the way it is is
actually quite useful even if it's initially confusing. And even when there
are no strongly pure functions in your program, knowing that a function
cannot access global variables except through its arguments means a lot in
and of itself.

- Jonathan M Davis



Re: purity question

2017-05-30 Thread ag0aep6g via Digitalmars-d-learn

On 05/30/2017 11:12 AM, Rene Zwanenburg wrote:
If malloc were marked as pure, wouldn't that mean it must return the 
same pointer every time you call it with the same size?


D's `pure` mostly means: "does not access mutable state, and does not do 
input/output".


There is never a requirement that a function must return the same value 
for the same input. But a compiler is allowed to memoize the result of a 
`pure` function when it has no mutable indirections in its parameter and 
return types. Such a function is "strongly pure".


When there are mutable indirections, the function is "weakly pure". 
Weakly pure functions are not assumed to be memoizable, but "weakly 
pure" still has meaning:


* Can call weakly pure functions from strongly pure ones.

* When a weakly pure function has mutable indirections in the return 
type but not in the parameters (like malloc), then it must be returning 
freshly allocated memory. That means, the result cannot be referenced 
from anywhere else. So it can be converted to const/immutable/shared 
implicitly. The spec calls that a "pure factory function".


Repeating Biotronic's links, the spec and David Nadlinger's article are 
the go-to resources for D's take on purity:


https://dlang.org/spec/function.html#pure-functions
http://klickverbot.at/blog/2012/05/purity-in-d/


Re: purity question

2017-05-30 Thread Biotronic via Digitalmars-d-learn

On Tuesday, 30 May 2017 at 13:45:07 UTC, Rene Zwanenburg wrote:

On Tuesday, 30 May 2017 at 11:34:52 UTC, ketmar wrote:
If malloc were marked as pure, wouldn't that mean it must 
return the same pointer every time you call it with the same 
size?


of course. but D "pure" is not what other world knows as 
"pure". we love to mess with words.


Well, there's the ability to modify non-const reference 
parameters from a pure function, but that's not applicable to 
malloc. Are there any other special rules?


The rules[0] are:

0) Can't call functions not marked pure.
1) Can't touch anything mutable that's not explicitly passed to 
the pure function.
1b) Except GC internal state - i.e. memory can be allocated via 
the GC.

1c) And floating-point exception flags and modes.
2) Can't do I/O (can be seen as a special case of 1 and 0).

There's a few more details, but that's the important stuff.

For a good article on the subject, I recommend David Nadlinger's 
Purity in D:


http://klickverbot.at/blog/2012/05/purity-in-d/

[0]: https://dlang.org/spec/function.html#pure-functions


Re: purity question

2017-05-30 Thread ketmar via Digitalmars-d-learn

Rene Zwanenburg wrote:


On Tuesday, 30 May 2017 at 11:34:52 UTC, ketmar wrote:
If malloc were marked as pure, wouldn't that mean it must return the 
same pointer every time you call it with the same size?


of course. but D "pure" is not what other world knows as "pure". we love 
to mess with words.


Well, there's the ability to modify non-const reference parameters from a 
pure function, but that's not applicable to malloc. Are there any other 
special rules?


"pure" methods can mutate object state.


Re: purity question

2017-05-30 Thread Rene Zwanenburg via Digitalmars-d-learn

On Tuesday, 30 May 2017 at 11:34:52 UTC, ketmar wrote:
If malloc were marked as pure, wouldn't that mean it must 
return the same pointer every time you call it with the same 
size?


of course. but D "pure" is not what other world knows as 
"pure". we love to mess with words.


Well, there's the ability to modify non-const reference 
parameters from a pure function, but that's not applicable to 
malloc. Are there any other special rules?


Re: purity question

2017-05-30 Thread ketmar via Digitalmars-d-learn

Rene Zwanenburg wrote:


On Monday, 29 May 2017 at 01:36:24 UTC, Jonathan M Davis wrote:

A simple example: anything that has a malloc/free pair.


Yeah, if you do it right, you should be fine, but you have to do it 
right, and it's very easy to miss some detail that makes it wrong to 
insist to the compiler that what you're doing is pure.


If malloc were marked as pure, wouldn't that mean it must return the same 
pointer every time you call it with the same size?


of course. but D "pure" is not what other world knows as "pure". we love to 
mess with words.


Re: purity question

2017-05-30 Thread Rene Zwanenburg via Digitalmars-d-learn

On Monday, 29 May 2017 at 01:36:24 UTC, Jonathan M Davis wrote:

A simple example: anything that has a malloc/free pair.


Yeah, if you do it right, you should be fine, but you have to 
do it right, and it's very easy to miss some detail that makes 
it wrong to insist to the compiler that what you're doing is 
pure.


If malloc were marked as pure, wouldn't that mean it must return 
the same pointer every time you call it with the same size?


Re: purity question

2017-05-29 Thread Seb via Digitalmars-d-learn

On Monday, 29 May 2017 at 08:49:07 UTC, ketmar wrote:

Brad Roberts wrote:

libraries that themselves aren't marked pure, there's a real 
need for escape hatches.  A simple example: anything that has 
a malloc/free pair.


they aren't pure. it is a sad misconception about purity, which 
D makes even more complex by allowing to mark, for example, 
*setters* as pure. but still, `malloc()` and `free()` aren't 
pure. and while various functions in std.math, for example, are 
marked `pure`, they aren't too.


There is pureMalloc since 2.074.0 (it was never announced):

https://github.com/dlang/druntime/pull/1746

However, without a pureFree it's rather limited in usefulness and 
needs to be workaround in real life:


https://github.com/dlang/druntime/pull/1718


Re: purity question

2017-05-29 Thread Ola Fosheim Grøstad via Digitalmars-d-learn

On Monday, 29 May 2017 at 11:25:06 UTC, ketmar wrote:
almost all of them, 'cause they depends on FPU rounding 
settings.


Well, yeah. IIRC contemporary floating point machine language 
instructions allow embedding of rounding mode into the 
instruction.


A pity languages are lagging behind, stuck in the 1980s...

WebAssembly is locking it to the default IEEE754-2008 
round-to-even. Which is reasonable as they aim for max 
portability, albeit a bit limiting.





Re: purity question

2017-05-29 Thread ketmar via Digitalmars-d-learn

Ola Fosheim Grøstad wrote:


On Monday, 29 May 2017 at 08:49:07 UTC, ketmar wrote:
pure. and while various functions in std.math, for example, are marked 
`pure`, they aren't too.


Out of curiosity, which functions in std.math aren't "pure" in the D 
sense?


almost all of them, 'cause they depends on FPU rounding settings.


Re: purity question

2017-05-29 Thread Ola Fosheim Grøstad via Digitalmars-d-learn

On Monday, 29 May 2017 at 08:49:07 UTC, ketmar wrote:
pure. and while various functions in std.math, for example, are 
marked `pure`, they aren't too.


Out of curiosity, which functions in std.math aren't "pure" in 
the D sense?




Re: purity question

2017-05-29 Thread ketmar via Digitalmars-d-learn

Brad Roberts wrote:

libraries that themselves aren't marked pure, there's a real need for 
escape hatches.  A simple example: anything that has a malloc/free pair.


they aren't pure. it is a sad misconception about purity, which D makes 
even more complex by allowing to mark, for example, *setters* as pure. but 
still, `malloc()` and `free()` aren't pure. and while various functions in 
std.math, for example, are marked `pure`, they aren't too.


Re: purity question

2017-05-28 Thread Seb via Digitalmars-d-learn

On Sunday, 28 May 2017 at 23:49:16 UTC, Brad Roberts wrote:
Is there a mechanism for declaring something pure when it's 
built from parts which individually aren't?


string foo(string s)
{
// do something arbitrarily complex with s that doesn't 
touch globals or change global state except possibly state of 
the heap or gc

return s;
}


Ali has answered this two years ago:

http://www.digitalmars.com/d/archives/digitalmars/D/learn/using_memset_withing_a_pure_function_74629.html#N74631

Copying for convenience:


If you want to live dangerously, you can use assumePure, which is 
found

in one of the unittest blocks of std.traits:

import std.traits;

auto assumePure(T)(T t)
if (isFunctionPointer!T || isDelegate!T)
{
 enum attrs = functionAttributes!T | FunctionAttribute.pure_;
 return cast(SetFunctionAttributes!(T, functionLinkage!T, 
attrs)) t;

}

int i = 0;

void foo()
{
 ++i;// foo accesses mutable module-level data
}

void bar() pure
{
 auto pureFoo = assumePure();
 pureFoo();// <-- pure function is calling impure function
}

void main()
{
 assert(i == 0);
 bar();
 assert(i == 1);// mutation through a pure function
}

It also came up in other discussions (the keyword is 
`assumePure`), e.g.

- http://forum.dlang.org/post/hpxxghbiomtitrmwe...@forum.dlang.org
- http://forum.dlang.org/post/nfhqvffqtkfsxjewg...@forum.dlang.org


Re: purity question

2017-05-28 Thread Jonathan M Davis via Digitalmars-d-learn
On Sunday, May 28, 2017 18:46:22 Brad Roberts via Digitalmars-d-learn wrote:
> Again, of course it's possible to do it wrong.  Escape hatches are like
> that.  And of course things are being worked on and improved, I'm one of
> the ones that's done a good bit of that at various points in time.  I'm
> really not seeking a lesson or lecture in why it's dangerous.

Sorry, if I'm coming across like I'm lecturing you. I'm not trying to. I'm
trying to be clear about the situation, and because this is on D.Learn, with
something like this, I don't want to show how to get around the issue
without clearly warning about the risks, because even if you know exactly
what you're doing when casting to get around purity problems, many others
reading this list will not.

- Jonathan M Davis



Re: purity question

2017-05-28 Thread Brad Roberts via Digitalmars-d-learn

On 5/28/2017 6:46 PM, Brad Roberts via Digitalmars-d-learn wrote:


Here's the bug that I'm digging into today, a clear example of an api 
that _should_ be pure, but based on the implementation is rather 
difficult for the compiler to infer.


https://issues.dlang.org/show_bug.cgi?id=17442


Re: purity question

2017-05-28 Thread Brad Roberts via Digitalmars-d-learn

On 5/28/2017 6:36 PM, Jonathan M Davis via Digitalmars-d-learn wrote:

On Sunday, May 28, 2017 17:53:25 Brad Roberts via Digitalmars-d-learn wrote:

On 5/28/2017 5:34 PM, Jonathan M Davis via Digitalmars-d-learn wrote:

On Sunday, May 28, 2017 16:49:16 Brad Roberts via Digitalmars-d-learn

wrote:

Is there a mechanism for declaring something pure when it's built from
parts which individually aren't?

string foo(string s)
{

   // do something arbitrarily complex with s that doesn't touch

globals or change global state except possibly state of the heap or gc

   return s;

}

 you can cast 

Ok, so there essentially isn't.  I'm well aware of the risks of lying to
the compiler, but it's also not sufficiently smart to unravel complex
code.  Combined with there being interesting parts of the standard
libraries that themselves aren't marked pure, there's a real need for
escape hatches.

Well, the big thing is that there are a number of functions in Phobos that
need to have someone go over them and fix them so that they are inferred to
be pure when they should be. Some work has been done in that area, and the
situation is certainly better than it once was, but not enough work has been
done to make it so that we can at all reasonably that everything in Phobos
that should be pure is and what isn't shouldn't be.


A simple example: anything that has a malloc/free pair.

Yeah, if you do it right, you should be fine, but you have to do it right,
and it's very easy to miss some detail that makes it wrong to insist to the
compiler that what you're doing is pure. So, arguably, having anything more
user-friendly than a cast is pretty dangerous. Having folks slap something
like @assume_pure on things (if there were such an attribute) could be
pretty risky. We already have enough trouble with @trusted on that front.
Ultimately, we want to be in a position where needing to get around pure is
very rare, and in most cases, I'd just tell folks to give up on pure on that
piece of code rather than trying to hack it into working.

- Jonathan M Davis


Again, of course it's possible to do it wrong.  Escape hatches are like 
that.  And of course things are being worked on and improved, I'm one of 
the ones that's done a good bit of that at various points in time.  I'm 
really not seeking a lesson or lecture in why it's dangerous.


Here's the bug that I'm digging into today, a clear example of an api 
that _should_ be pure, but based on the implementation is rather 
difficult for the compiler to infer.


Re: purity question

2017-05-28 Thread Jonathan M Davis via Digitalmars-d-learn
On Sunday, May 28, 2017 18:39:02 Brad Roberts via Digitalmars-d-learn wrote:
> On 5/28/2017 6:27 PM, Jonathan M Davis via Digitalmars-d-learn wrote:
> > There was a whole discussion or 3 is PRs about making malloc pure, and
> > IIRC, it was done and then decided that it wasn't safe to do some for
> > one reason or another (IIRC, it had to do with what would happen when
> > calls were elided, because the caller was strongly pure, but I'm not
> > sure). So, I'd be _very_ careful about deciding that it was safe to
> > call malloc in pure code. I expect that it's just fine in some
> > contexts, but it's easy enough to screw up and mark something as pure
> > when it really shouldn't be because of some detail you missed that you
> > should be _really_ careful about decided to cast to pure.
>
> That's one reason I explicitly referenced malloc/free pairs.  It's a lot
> easier to be sure that those together aren't violating purity.

Agreed. But it's the intricacies like that which make having a clean
backdoor for pure a bit dangerous, much as it would be nice when you
actually need to do it and know what you're doing well enough to get it
right.

- Jonathan M Davis



Re: purity question

2017-05-28 Thread Brad Roberts via Digitalmars-d-learn

On 5/28/2017 6:27 PM, Jonathan M Davis via Digitalmars-d-learn wrote:

On Monday, May 29, 2017 01:01:46 Stefan Koch via Digitalmars-d-learn wrote:

On Monday, 29 May 2017 at 00:53:25 UTC, Brad Roberts wrote:

On 5/28/2017 5:34 PM, Jonathan M Davis via Digitalmars-d-learn

wrote:

On Sunday, May 28, 2017 16:49:16 Brad Roberts via

Digitalmars-d-learn wrote:

Is there a mechanism for declaring something pure when it's
built from
parts which individually aren't?

string foo(string s)
{

   // do something arbitrarily complex with s that doesn't

touch
globals or change global state except possibly state of the
heap or gc

   return s;

}

 you can cast 

Ok, so there essentially isn't.  I'm well aware of the risks of
lying to the compiler, but it's also not sufficiently smart to
unravel complex code.  Combined with there being interesting
parts of the standard libraries that themselves aren't marked
pure, there's a real need for escape hatches.  A simple
example: anything that has a malloc/free pair.

There is

void[] myPureMalloc(uint size) pure @trusted nothrow @nogc
{
 alias pure_malloc_t = pure nothrow void* function(size_t size);
 return (cast(pure_malloc_t)malloc)(size)[0 .. size];
}

There was a whole discussion or 3 is PRs about making malloc pure, and IIRC,
it was done and then decided that it wasn't safe to do some for one reason
or another (IIRC, it had to do with what would happen when calls were
elided, because the caller was strongly pure, but I'm not sure). So, I'd be
_very_ careful about deciding that it was safe to call malloc in pure code.
I expect that it's just fine in some contexts, but it's easy enough to screw
up and mark something as pure when it really shouldn't be because of some
detail you missed that you should be _really_ careful about decided to cast
to pure.

- Jonathan M Davis


That's one reason I explicitly referenced malloc/free pairs.  It's a lot 
easier to be sure that those together aren't violating purity.


Re: purity question

2017-05-28 Thread Jonathan M Davis via Digitalmars-d-learn
On Sunday, May 28, 2017 17:53:25 Brad Roberts via Digitalmars-d-learn wrote:
> On 5/28/2017 5:34 PM, Jonathan M Davis via Digitalmars-d-learn wrote:
> > On Sunday, May 28, 2017 16:49:16 Brad Roberts via Digitalmars-d-learn 
wrote:
> >> Is there a mechanism for declaring something pure when it's built from
> >> parts which individually aren't?
> >>
> >> string foo(string s)
> >> {
> >>
> >>   // do something arbitrarily complex with s that doesn't touch
> >>
> >> globals or change global state except possibly state of the heap or gc
> >>
> >>   return s;
> >>
> >> }
> >
> >  you can cast 
>
> Ok, so there essentially isn't.  I'm well aware of the risks of lying to
> the compiler, but it's also not sufficiently smart to unravel complex
> code.  Combined with there being interesting parts of the standard
> libraries that themselves aren't marked pure, there's a real need for
> escape hatches.

Well, the big thing is that there are a number of functions in Phobos that
need to have someone go over them and fix them so that they are inferred to
be pure when they should be. Some work has been done in that area, and the
situation is certainly better than it once was, but not enough work has been
done to make it so that we can at all reasonably that everything in Phobos
that should be pure is and what isn't shouldn't be.

> A simple example: anything that has a malloc/free pair.

Yeah, if you do it right, you should be fine, but you have to do it right,
and it's very easy to miss some detail that makes it wrong to insist to the
compiler that what you're doing is pure. So, arguably, having anything more
user-friendly than a cast is pretty dangerous. Having folks slap something
like @assume_pure on things (if there were such an attribute) could be
pretty risky. We already have enough trouble with @trusted on that front.
Ultimately, we want to be in a position where needing to get around pure is
very rare, and in most cases, I'd just tell folks to give up on pure on that
piece of code rather than trying to hack it into working.

- Jonathan M Davis



Re: purity question

2017-05-28 Thread Jonathan M Davis via Digitalmars-d-learn
On Monday, May 29, 2017 01:01:46 Stefan Koch via Digitalmars-d-learn wrote:
> On Monday, 29 May 2017 at 00:53:25 UTC, Brad Roberts wrote:
> > On 5/28/2017 5:34 PM, Jonathan M Davis via Digitalmars-d-learn
> >
> > wrote:
> >> On Sunday, May 28, 2017 16:49:16 Brad Roberts via
> >>
> >> Digitalmars-d-learn wrote:
> >>> Is there a mechanism for declaring something pure when it's
> >>> built from
> >>> parts which individually aren't?
> >>>
> >>> string foo(string s)
> >>> {
> >>>
> >>>   // do something arbitrarily complex with s that doesn't
> >>>
> >>> touch
> >>> globals or change global state except possibly state of the
> >>> heap or gc
> >>>
> >>>   return s;
> >>>
> >>> }
> >>
> >>  you can cast 
> >
> > Ok, so there essentially isn't.  I'm well aware of the risks of
> > lying to the compiler, but it's also not sufficiently smart to
> > unravel complex code.  Combined with there being interesting
> > parts of the standard libraries that themselves aren't marked
> > pure, there's a real need for escape hatches.  A simple
> > example: anything that has a malloc/free pair.
>
> There is
>
> void[] myPureMalloc(uint size) pure @trusted nothrow @nogc
> {
> alias pure_malloc_t = pure nothrow void* function(size_t size);
> return (cast(pure_malloc_t)malloc)(size)[0 .. size];
> }

There was a whole discussion or 3 is PRs about making malloc pure, and IIRC,
it was done and then decided that it wasn't safe to do some for one reason
or another (IIRC, it had to do with what would happen when calls were
elided, because the caller was strongly pure, but I'm not sure). So, I'd be
_very_ careful about deciding that it was safe to call malloc in pure code.
I expect that it's just fine in some contexts, but it's easy enough to screw
up and mark something as pure when it really shouldn't be because of some
detail you missed that you should be _really_ careful about decided to cast
to pure.

- Jonathan M Davis



Re: purity question

2017-05-28 Thread Era Scarecrow via Digitalmars-d-learn

On Monday, 29 May 2017 at 01:12:53 UTC, Era Scarecrow wrote:

...


 Hmm didn't notice the post had split. Otherwise i wouldn't have 
replied... That and thinking about the GC state (outside of 
allocating memory)...


Re: purity question

2017-05-28 Thread Era Scarecrow via Digitalmars-d-learn

On Sunday, 28 May 2017 at 23:49:16 UTC, Brad Roberts wrote:
// do something arbitrarily complex with s that doesn't 
touch globals or change global state except possibly state of 
the heap or gc


 Sounds like the basic definition of pure to me; At least in 
regards to D. Memory allocation which is a system call, doesn't 
actually break purity. Then again if you were worried about not 
using the gc, there's the newer nogc property.


[quote]
 TDPL pg. 165: 5.11.1 Pure functions

 In D, a function is considered pure if returning a result is 
it's only effect and the result depends only on the function's 
arguments.

[/quote]


Re: purity question

2017-05-28 Thread Stefan Koch via Digitalmars-d-learn

On Monday, 29 May 2017 at 01:01:46 UTC, Stefan Koch wrote:


There is


void[] myPureMalloc(uint size) pure @trusted nothrow @nogc
{
   import core.stdc.stdlib : malloc;
   alias pure_malloc_t = @nogc pure nothrow void* function(size_t 
size);

   return (cast(pure_malloc_t))(size)[0 .. size];
}

This is the fixed version.


Re: purity question

2017-05-28 Thread Brad Roberts via Digitalmars-d-learn

On 5/28/2017 6:01 PM, Stefan Koch via Digitalmars-d-learn wrote:

On Monday, 29 May 2017 at 00:53:25 UTC, Brad Roberts wrote:

On 5/28/2017 5:34 PM, Jonathan M Davis via Digitalmars-d-learn wrote:
On Sunday, May 28, 2017 16:49:16 Brad Roberts via 
Digitalmars-d-learn wrote:

Is there a mechanism for declaring something pure when it's built from
parts which individually aren't?

string foo(string s)
{
  // do something arbitrarily complex with s that doesn't touch
globals or change global state except possibly state of the heap or gc
  return s;
}

 you can cast 



Ok, so there essentially isn't.  I'm well aware of the risks of lying 
to the compiler, but it's also not sufficiently smart to unravel 
complex code.  Combined with there being interesting parts of the 
standard libraries that themselves aren't marked pure, there's a real 
need for escape hatches.  A simple example: anything that has a 
malloc/free pair.


There is

void[] myPureMalloc(uint size) pure @trusted nothrow @nogc
{
   alias pure_malloc_t = pure nothrow void* function(size_t size);
   return (cast(pure_malloc_t)malloc)(size)[0 .. size];
}


That's still a cast.  It's a nice way to isolate the cast, but it's 
clearly still there.  And as I said, that's just one simple example.


Re: purity question

2017-05-28 Thread Stefan Koch via Digitalmars-d-learn

On Monday, 29 May 2017 at 00:53:25 UTC, Brad Roberts wrote:
On 5/28/2017 5:34 PM, Jonathan M Davis via Digitalmars-d-learn 
wrote:
On Sunday, May 28, 2017 16:49:16 Brad Roberts via 
Digitalmars-d-learn wrote:
Is there a mechanism for declaring something pure when it's 
built from

parts which individually aren't?

string foo(string s)
{
  // do something arbitrarily complex with s that doesn't 
touch
globals or change global state except possibly state of the 
heap or gc

  return s;
}

 you can cast 



Ok, so there essentially isn't.  I'm well aware of the risks of 
lying to the compiler, but it's also not sufficiently smart to 
unravel complex code.  Combined with there being interesting 
parts of the standard libraries that themselves aren't marked 
pure, there's a real need for escape hatches.  A simple 
example: anything that has a malloc/free pair.


There is

void[] myPureMalloc(uint size) pure @trusted nothrow @nogc
{
   alias pure_malloc_t = pure nothrow void* function(size_t size);
   return (cast(pure_malloc_t)malloc)(size)[0 .. size];
}


Re: purity question

2017-05-28 Thread Brad Roberts via Digitalmars-d-learn

On 5/28/2017 5:34 PM, Jonathan M Davis via Digitalmars-d-learn wrote:

On Sunday, May 28, 2017 16:49:16 Brad Roberts via Digitalmars-d-learn wrote:

Is there a mechanism for declaring something pure when it's built from
parts which individually aren't?

string foo(string s)
{
  // do something arbitrarily complex with s that doesn't touch
globals or change global state except possibly state of the heap or gc
  return s;
}

 you can cast 



Ok, so there essentially isn't.  I'm well aware of the risks of lying to 
the compiler, but it's also not sufficiently smart to unravel complex 
code.  Combined with there being interesting parts of the standard 
libraries that themselves aren't marked pure, there's a real need for 
escape hatches.  A simple example: anything that has a malloc/free pair.


Re: purity question

2017-05-28 Thread Jonathan M Davis via Digitalmars-d-learn
On Sunday, May 28, 2017 16:49:16 Brad Roberts via Digitalmars-d-learn wrote:
> Is there a mechanism for declaring something pure when it's built from
> parts which individually aren't?
>
> string foo(string s)
> {
>  // do something arbitrarily complex with s that doesn't touch
> globals or change global state except possibly state of the heap or gc
>  return s;
> }

Either everything the function is doing is pure, or it can't be pure without
cheating, and cheating is usually a bad idea. There is no @trusted
equivalent for pure. Now, if you're absolutely sure that the function
doesn't do anything that's actually going to run afoul of pure and what the
compiler will assume about pure functions, but it's using stuff that wasn't
properly marked as pure, or does something that can't be marked as pure for
some reason but in this context would actually be fine, you can cast.

For instance, std.datetime's LocalTime is a singleton which gets the
timezone conversion from the system. Its operations can't be pure, but it
can be constructed as pure, and because it's a singleton, it will return the
same instance every time. Originally, a static constructor was used to
initialize the singleton (which therefore worked great with pure), but
because of circular dependency pain with static constructors, we had to get
rid of the static constructors in std.datetime. The solution was to move the
initialization into another function which was not pure, and then when we
call it from theh singleton function, we cast it to pure:

static immutable(LocalTime) opCall() @trusted pure nothrow
{
alias FuncType = @safe pure nothrow immutable(LocalTime) function();
return (cast(FuncType))();
}

static immutable(LocalTime) singleton() @trusted
{
import core.stdc.time : tzset;
import std.concurrency : initOnce;
static instance = new immutable(LocalTime)();
static shared bool guard;
initOnce!guard({tzset(); return true;}());
return instance;
}

Now, in the vast majority of cases, I would strongly advise against cheating
in this manner, because you need to be absolutely sure that you're not
actually violating pure (particularly what the compiler will assume about
pure) by what you're doing, and usually what it comes down to is that
something that your function is calling needs to be fixed so that it can be
inferred as pure, or it simply needs to be marked as pure. Casting is a
horrible hack that should only be used as a last resort and only when you're
100% sure that it's fine. However, you _can_ use casting as a backdoor if
you really have to.

- Jonathan M Davis