April 29, 2013
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.

April 29, 2013
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.

April 29, 2013
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
April 29, 2013
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...
April 29, 2013
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)


April 30, 2013
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 <monarchdodra@gmail.com>

> 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...
>


April 30, 2013
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.
April 30, 2013
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!

April 30, 2013
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.
August 19, 2013
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.