Re: trusted purity?

2013-08-19 Thread monarch_dodra

On Monday, 19 August 2013 at 12:55:54 UTC, bearophile wrote:
For the function array() this is not enough, because instead of 
"= void" you have a function that returns some void-initialized 
data. To help the D type system a bit perhaps an annotations 
like @void_init is useful, to be attached to functions like 
uninitializedArray and minimallyInitializedArray.


Bye,
bearophile


After re-reading "pure" documentation, I think I can solve the 
problem by marking uninitialized/minimallyInitialized as "weakly 
pure". From there using it in a pure context is trivial.


This is in line with what GC.malloc does.


Re: trusted purity?

2013-08-19 Thread monarch_dodra

On Monday, 19 August 2013 at 12:55:54 UTC, bearophile wrote:
The problem is that while writing down the proof of the purity 
of foo3 is probably not too much hard, later the D compiler is 
not able to verify such proof.


Bye,
bearophile


Right, that is pretty much it. EG:

//
import core.stdc.stdlib;

int* myPureFun(int i) pure
{
auto p = cast(int*) malloc(int.sizeof);
if (!p) assert(0);
*p = i;
return p;
}
//

I can solve this the same way (kind of) as with safety, by 
marking the function as I can mark a function as trusted, by 
casting the function as pure:


//
int* myPureFun(int i) pure
{
alias extern (C) void* function(size_t) pure PureF_t;
auto p = cast(int*) (cast(PureF_t)&malloc)(int.sizeof);
if (!p) assert(0);
*p = i;
return p;
}
//

A basic "I know what I'm doing compiler" kind of assertion.

My only issue with doing this is I'm afraid it might be wrong: A 
"trusted" function means nothing to the compiler.


However, in the above example, I *marked* malloc as pure, and 
even though "myPureFun" is conceptually pure, *malloc* remains 
impure, and I don't know how the compiler deals with being told 
it is pure.


Is that code snippet wrong?


Re: trusted purity?

2013-08-19 Thread bearophile

monarch_dodra:


FYI, the problem I'm trying to fix is this one:
* "uninitializedArray" returns an array with un-initialized 
elements. This, by definition, is not pure, since the value 
returned is garbage. I'm fixing the function so that it becomes 
*impure*.
* "array" is implemented in terms of "uninitializedArray": 
Allocate an array, and then fill it. "array" is pure, since its 
return is defined. array also works with ctfe.


Here are some examples of what I think you are talking about. 
foo1 is pure, foo2 is pure (but currently the type system doesn't 
complain), foo3 is pure again because all array items are 
deterministically initialized using only pure/immutable data:



// Pure:
int[3] foo1(in int x) pure {
int[3] arr;
return arr;
}

// Not pure:
int[3] foo2(in int x) pure {
int[3] arr = void;
return arr;
}

// Pure:
int[3] foo3(in int x) pure {
int[3] arr = void;
arr[] = x;
return arr;
}

void main() {}


I presume foo2 should be refused as not pure. The array() 
function is like foo3, it creates data that is not pure, not 
deterministic, but then overwrites it all with referentially 
transparent information. So on the whole foo3 is pure and array() 
is often pure.


The problem is that while writing down the proof of the purity of 
foo3 is probably not too much hard, later the D compiler is not 
able to verify such proof. So some alternative solution is 
needed. The trusted pure you talk about is a solution, it means 
saying to the compiler, "trust me I have a proof of purity of 
this function". But programmers should be trusted as little as 
possible if you want a reliable language and reliable programs. 
So perhaps some mid-way solution is preferable.


Andrei used the idea of cooked and uncooked variables, it's 
probably used here:


class Bar1 {
immutable int[2] x;
this() {
}
}

Bar1 gives the error:
Error: constructor test.Bar1.this missing initializer for 
immutable field x



While this gives no errors:

class Bar2 {
immutable int[2] x;
this() {
x[0] = 1;
}
}


Perhaps using a similar strategy you can accept a function like 
this:


int[3] foo3(in int x) pure {
int[3] arr = void;
arr[] = x;
return arr;
}


Because now arr is not uncooked, it was overwritten by 
referentially transparent data...


For the function array() this is not enough, because instead of 
"= void" you have a function that returns some void-initialized 
data. To help the D type system a bit perhaps an annotations like 
@void_init is useful, to be attached to functions like 
uninitializedArray and minimallyInitializedArray.


Bye,
bearophile


Re: trusted purity?

2013-08-19 Thread monarch_dodra

I've been struggling with this, so here are my observations:

On Monday, 29 April 2013 at 18:31:15 UTC, Walter Bright wrote:

On 4/29/2013 3:58 AM, monarch_dodra wrote:
Is there *any* way to make a call to a non-pure function in a 
pure context, if

you know you won't violate your own purity?
2. put the impure code in a separate function, take its 
address, and cast its address to being a pointer to a pure 
function. (Of course, such a cast should be rejected by @safe 
code.)


This doesn't work with CTFE. I'm currently not seeing how I could 
make a function that needs to make a "trusted pure" call work at 
compile time: The function pointer cast will fail during CTFE, 
and if I add a "if (__ctfe)" block without it, then the function 
will be impure, due to the code inside the "if (__ctfe)" block.


I've yet to solve this problem.

3. Put the code in an extern(C) function, compiled separately 
as impure, but declared as pure in the client. C functions 
don't get name mangling, so the compiler won't know it's impure.
Unfortunately, this doesn't work with templates. You have to 
force instantiation by inserting a straight up (dummy) call to 
the function, but that immediately makes the caller impure...


I feel it's a good thing that you'll need to jump through some 
hoops to do this, otherwise 'pure' would not be very useful.


I agree, but these aren't hoops, they're pole vaults.

FYI, the problem I'm trying to fix is this one:
* "uninitializedArray" returns an array with un-initialized 
elements. This, by definition, is not pure, since the value 
returned is garbage. I'm fixing the function so that it becomes 
*impure*.
* "array" is implemented in terms of "uninitializedArray": 
Allocate an array, and then fill it. "array" is pure, since its 
return is defined. array also works with ctfe.


I'm at a deadlock on this one.


Re: trusted purity?

2013-04-30 Thread monarch_dodra

On Tuesday, 30 April 2013 at 17:06:00 UTC, Walter Bright wrote:

On 4/29/2013 10:42 PM, monarch_dodra wrote:
Thanks. That (kinda) worked. I just had to add an alias, 
because the
compiler was complaining about: "Error: fp_pure_t is used as a 
type"


Yeah, I should have tested it before posting!


Oh, no problem, you gave me the right answer anyways, that's what
counts. Thanks.


Re: trusted purity?

2013-04-30 Thread Walter Bright

On 4/29/2013 10:42 PM, monarch_dodra wrote:

Thanks. That (kinda) worked. I just had to add an alias, because the
compiler was complaining about: "Error: fp_pure_t is used as a type"


Yeah, I should have tested it before posting!



Re: trusted purity?

2013-04-29 Thread monarch_dodra

On Monday, 29 April 2013 at 20:51:50 UTC, Walter Bright wrote:

On 4/29/2013 1:03 PM, monarch_dodra wrote:

On Monday, 29 April 2013 at 18:34:46 UTC, Walter Bright wrote:

On 4/29/2013 10:19 AM, monarch_dodra wrote:
I'm getting strange behavior trying to cast to pure. This is 
my

test program:


You're casting a C function to a D function. This will cause 
crashes.


OK, so say I have a documented pure C function, how do I call 
it from a pure
scope? You say, take the address and cast it, but not if it's 
C...


extern (C) {
int foo(int);
}

extern (C) {
pure int function(int) fp_pure_t;
}

...
cast(fp_pure_t)(&foo)


Thanks. That (kinda) worked. I just had to add an alias, because 
the compiler was complaining about: "Error: fp_pure_t is used as 
a type"


This works though:

//
extern (C) {
int foo(int);
}
extern (C) {
alias pure int function(int) fp_pure_t;
}
...
cast(fp_pure_t)(&foo)
//

That works.


Re: trusted purity?

2013-04-29 Thread Kenji Hara
Hmm. Interesting approach. I tried to utilize the "trusted pure" concept .

template TrustedPure(alias func)
{
import std.traits, std.algorithm;

alias F1 = FunctionTypeOf!(func);
static if (functionAttributes!F1 & FunctionAttribute.pure_)
{
alias TrustedPure = func;
}
else
{
alias F2 = SetFunctionAttributes!(
F1,
functionLinkage!F1,
functionAttributes!F1 | FunctionAttribute.pure_);

auto ref TrustedPure(A...)(auto ref A args)
pure// mark as expected
@system // represent 'unsafe' operation.
{
// forward!args does not work, because
// std.algorithm.move is not pure...
return (cast(F2*)&func)(/*forward!*/args);
}
}
}
void main() pure
// cannot add @safe, because TrustedPure functions are always @system
{
import core.stdc.stdlib;
alias pmalloc = TrustedPure!(core.stdc.stdlib.malloc);
alias pfree = TrustedPure!(core.stdc.stdlib.free);

auto p = cast(int*)pmalloc(int.sizeof);
*p = 100;
pfree(p);
}

Kenji Hara


2013/4/30 monarch_dodra 

> I'm getting strange behavior trying to cast to pure. This is my
> test program:
>
> //
> import std.stdio;
> import core.stdc.stdlib;
>
> void main()
> {
>  auto p1 = &core.stdc.stdlib.free;
>  auto p2 = cast(void function(void*))&core.stdc.**stdlib.free;
>  auto p3 = cast(void function(void*)
> pure)&core.stdc.stdlib.free;
>  auto pp1 = core.stdc.stdlib.malloc(5);
>  auto pp2 = core.stdc.stdlib.malloc(5);
>  auto pp3 = core.stdc.stdlib.malloc(5);
>  writeln(p1);
>  p1(pp1);
>  writeln(p2);
>  p2(pp2); //This hangs
>  writeln(p3); //Never reaches here
>  p3(pp3);
> }
> //
>
> Am I doing something wrong? Could somebody else test this? I'm on
> win32.
>
> I've also been getting some object violations trying to use this
> cast...
>


Re: trusted purity?

2013-04-29 Thread Walter Bright

On 4/29/2013 1:03 PM, monarch_dodra wrote:

On Monday, 29 April 2013 at 18:34:46 UTC, Walter Bright wrote:

On 4/29/2013 10:19 AM, monarch_dodra wrote:

I'm getting strange behavior trying to cast to pure. This is my
test program:


You're casting a C function to a D function. This will cause crashes.


OK, so say I have a documented pure C function, how do I call it from a pure
scope? You say, take the address and cast it, but not if it's C...


extern (C) {
int foo(int);
}

extern (C) {
pure int function(int) fp_pure_t;
}

...
cast(fp_pure_t)(&foo)




Re: trusted purity?

2013-04-29 Thread monarch_dodra

On Monday, 29 April 2013 at 18:34:46 UTC, Walter Bright wrote:

On 4/29/2013 10:19 AM, monarch_dodra wrote:

I'm getting strange behavior trying to cast to pure. This is my
test program:


You're casting a C function to a D function. This will cause 
crashes.


OK, so say I have a documented pure C function, how do I call it 
from a pure scope? You say, take the address and cast it, but not 
if it's C...


Re: trusted purity?

2013-04-29 Thread Jonathan M Davis
On Monday, April 29, 2013 12:58:44 monarch_dodra wrote:
> Is there *any* way to make a call to a non-pure function in a
> pure context, if you know you won't violate your own purity?
> 
> This is something you can do with @safe (@trusted), but what
> about pure?
> 
> For example, "free" is not pure, because you can't call it twice
> on the same pointer. But if you manage the pointer yourself
> inside a struct, you can guarantee the purity of your own
> functions. But the language won't allow you to do that.

You can cast a pointer to the function. std.datetime does that for the 
LocalTime and UTC singletons. Take a look at the semi-recently added 
std.traits.SetFunctionAttributes.

> Related question:
> Can a function that "sometimes throws" be considered as pure?

Throwing has nothing to do with purity. pure is purely a question of whether 
the function accesses module-level or static variables which can possibly be 
mutated after they're initialized. Strong purity (which is required for 
most/all optimizations) is then places additional requirements on the function 
parameters, but purity itself is simply a question of whether the function 
accesses module-level or static variables. So, throwing has nothing to do with 
it.

- Jonathan M Davis


Re: trusted purity?

2013-04-29 Thread Walter Bright

On 4/29/2013 10:19 AM, monarch_dodra wrote:

I'm getting strange behavior trying to cast to pure. This is my
test program:


You're casting a C function to a D function. This will cause crashes.



Re: trusted purity?

2013-04-29 Thread Walter Bright

On 4/29/2013 5:08 AM, monarch_dodra wrote:

I've hit this issue before: In D, if the *managed* memory runs out, then it is
an error (since then *everything* crumbles: arrays, GC. etc). The reason it is
an error is that since the memory is managed by the language, there is nothing
the user can do anyway, so throwing is pointless.

for unmanaged memory, on the otherhand, the user *can* do something about it, so
throwing is better.


You cannot call a function pure if it sometimes throws a recoverable exception 
and sometimes does not, and this is not based on the supplied arguments.




Re: trusted purity?

2013-04-29 Thread Walter Bright

On 4/29/2013 3:58 AM, monarch_dodra wrote:

Is there *any* way to make a call to a non-pure function in a pure context, if
you know you won't violate your own purity?


Vee haf veys:

1. put "debug" before the impure code (but you'll have to compile with -debug)

2. put the impure code in a separate function, take its address, and cast its 
address to being a pointer to a pure function. (Of course, such a cast should be 
rejected by @safe code.)


3. Put the code in an extern(C) function, compiled separately as impure, but 
declared as pure in the client. C functions don't get name mangling, so the 
compiler won't know it's impure.



I feel it's a good thing that you'll need to jump through some hoops to do this, 
otherwise 'pure' would not be very useful.





Related question:
Can a function that "sometimes throws" be considered as pure?


deadalnix's answer is correct.



Re: trusted purity?

2013-04-29 Thread deadalnix

On Monday, 29 April 2013 at 10:58:45 UTC, monarch_dodra wrote:
Is there *any* way to make a call to a non-pure function in a 
pure context, if you know you won't violate your own purity?


This is something you can do with @safe (@trusted), but what 
about pure?




This raise the case once again for trusted as a statement and not 
as a qualifier. Tis would solve the purity issue.



Related question:
Can a function that "sometimes throws" be considered as pure?


Yes as long at its behavior depends only on parameters.


Re: trusted purity?

2013-04-29 Thread monarch_dodra

I'm getting strange behavior trying to cast to pure. This is my
test program:

//
import std.stdio;
import core.stdc.stdlib;

void main()
{
 auto p1 = &core.stdc.stdlib.free;
 auto p2 = cast(void function(void*))&core.stdc.stdlib.free;
 auto p3 = cast(void function(void*)
pure)&core.stdc.stdlib.free;
 auto pp1 = core.stdc.stdlib.malloc(5);
 auto pp2 = core.stdc.stdlib.malloc(5);
 auto pp3 = core.stdc.stdlib.malloc(5);
 writeln(p1);
 p1(pp1);
 writeln(p2);
 p2(pp2); //This hangs
 writeln(p3); //Never reaches here
 p3(pp3);
}
//

Am I doing something wrong? Could somebody else test this? I'm on
win32.

I've also been getting some object violations trying to use this
cast...


Re: trusted purity?

2013-04-29 Thread Henning Pohl

On Monday, 29 April 2013 at 12:08:58 UTC, monarch_dodra wrote:
I've hit this issue before: In D, if the *managed* memory runs 
out, then it is an error (since then *everything* crumbles: 
arrays, GC. etc). The reason it is an error is that since the 
memory is managed by the language, there is nothing the user 
can do anyway, so throwing is pointless.


for unmanaged memory, on the otherhand, the user *can* do 
something about it, so throwing is better.


I myself am not sure I 100% agree with this, but that was the 
conclusion last time I tried to transform an malloc=>Exception 
into a malloc=>Error+Nothrow


What about using allocators the user can specify? The default one 
would be malloc + Error + nothrow. All the signatures of 
RefCounted have to change depending on the allocator's ones, 
though. This is where attribute inference is rather needed.


Re: trusted purity?

2013-04-29 Thread monarch_dodra

On Monday, 29 April 2013 at 11:50:11 UTC, Henning Pohl wrote:

On Monday, 29 April 2013 at 11:32:33 UTC, monarch_dodra wrote:
I'm still worried about what it means for a pure function to 
throw... (I'm thinking about the  "enforce(malloc)" scheme)


If malloc returns null, we are out of memory. In D this is not 
an exception, it is an error. So I guess we just need to check 
the pointer returned by malloc and throw an OutOfMemoryError on 
failure. Thus if the ctor called is nothrow, it can be marked 
as nothrow, too.


So in this case, there should be no problem making it pure.


I've hit this issue before: In D, if the *managed* memory runs 
out, then it is an error (since then *everything* crumbles: 
arrays, GC. etc). The reason it is an error is that since the 
memory is managed by the language, there is nothing the user can 
do anyway, so throwing is pointless.


for unmanaged memory, on the otherhand, the user *can* do 
something about it, so throwing is better.


I myself am not sure I 100% agree with this, but that was the 
conclusion last time I tried to transform an malloc=>Exception 
into a malloc=>Error+Nothrow


Re: trusted purity?

2013-04-29 Thread Henning Pohl

On Monday, 29 April 2013 at 11:32:33 UTC, monarch_dodra wrote:
I'm still worried about what it means for a pure function to 
throw... (I'm thinking about the  "enforce(malloc)" scheme)


If malloc returns null, we are out of memory. In D this is not an 
exception, it is an error. So I guess we just need to check the 
pointer returned by malloc and throw an OutOfMemoryError on 
failure. Thus if the ctor called is nothrow, it can be marked as 
nothrow, too.


So in this case, there should be no problem making it pure.


Re: trusted purity?

2013-04-29 Thread monarch_dodra

On Monday, 29 April 2013 at 11:15:20 UTC, Henning Pohl wrote:
I've been working on a pull request and came up with something 
like this:


private void initialize(A...)(auto ref A args)
{
auto m = cast(void* function(size_t size) pure)&malloc;
_store = cast(Impl*) enforce(m(Impl.sizeof));
auto r = cast(void function(in void* p, size_t sz) nothrow 
pure)&GC.addRange;

static if (hasIndirections!T)
r(&_store._payload, T.sizeof);
emplace(&_store._payload, args);
_store._count = 1;
}


I always forget you can cast the type of a function...

The purity of "emplace" depends on the purity of the ctor 
called. I'm not sure how to fix that.


I'm not sure there's anything to fix there: If the CTor is not 
pure, then how could emplace be pure?


I did some work on emplace that is awaiting to be pulled, which 
should improve its purity.


On Monday, 29 April 2013 at 11:19:33 UTC, Henning Pohl wrote:
By the way, my post is related to the impurity of RefCounted: 
http://d.puremagic.com/issues/show_bug.cgi?id=9998


Yes, that is also what I am investigating. The cast is would 
indeed be a fix for malloc/free. RefCounted's 
isInitialized/refCount still need to be marked as pure though.


I'm still worried about what it means for a pure function to 
throw... (I'm thinking about the  "enforce(malloc)" scheme)


Re: trusted purity?

2013-04-29 Thread Henning Pohl
By the way, my post is related to the impurity of RefCounted: 
http://d.puremagic.com/issues/show_bug.cgi?id=9998


Re: trusted purity?

2013-04-29 Thread Henning Pohl
I've been working on a pull request and came up with something 
like this:


private void initialize(A...)(auto ref A args)
{
auto m = cast(void* function(size_t size) pure)&malloc;
_store = cast(Impl*) enforce(m(Impl.sizeof));
auto r = cast(void function(in void* p, size_t sz) nothrow 
pure)&GC.addRange;

static if (hasIndirections!T)
r(&_store._payload, T.sizeof);
emplace(&_store._payload, args);
_store._count = 1;
}

The purity of "emplace" depends on the purity of the ctor called. 
I'm not sure how to fix that.