Re: Store any callable in an array

2018-05-07 Thread wjoe via Digitalmars-d-learn

On Monday, 7 May 2018 at 10:20:22 UTC, ag0aep6g wrote:

On 05/07/2018 04:41 AM, wjoe wrote:

Could you elaborate on the unsafe destructor please?


If TFunc has an unsafe destructor, asDelegate is also not safe 
and can't be @trusted.


An example of how that can break safety:


auto asDelegate(TFunc)(TFunc func) @trusted
{
 import std.functional : toDelegate;
 return toDelegate(func);
}

int* ptr;
size_t length;

struct S
{
void opCall() {}
~this() @system
{
ptr[length - 1] = 13;
}
}

void main() @safe
{
ptr = new int;
length = 5; /* Whoops, got the length wrong. */
immutable int* imm = new int(42);
auto dg = asDelegate(S.init);
assert(*imm == 42); /* Fails. Immutability has been broken. 
*/

}


The program has undefined behavior, which means it's invalid. 
And it's the fault of the wrong @trusted.



Are there any other gotchas ?


The postblit function `this(this)` is also commonly overlooked 
with regards to @trusted. It might not be a problem here, 
though, because toDelegate has a `ref` parameter.


An unsafe `alias this` would be another problem. Example:

/* ... asDelegate, ptr, length, main as above ... */
struct S
{
@property T t() @system
{
ptr[length - 1] = 13;
return T.init;
}
alias t this;
}
struct T
{
void opCall() {}
}


Those are the things I can see happening in asDelegate.

Additionally, you'd have to check what the toDelegate call does 
exactly before trusting it. And if it turns out that the call 
can be trusted, then you can probably just mark toDelegate 
itself as @trusted. And then there would be no need for 
asDelegate anymore.


Thank you for taking the time to write up this reply and widen my 
horizon. Very much appreciated.


After further investigation I found a post where someone asked 
about the differences of function/delegate and one of the replies 
explained that functions converted to a delegate occur a 
considerable performance impact.


This and since toDelegate has a bug with @safe functions, and 
slapping a @trusted on to it sounds like more headache than it's 
worth, I will handle these cases separately.


Thanks everybody for all the replies.


Re: Store any callable in an array

2018-05-07 Thread ag0aep6g via Digitalmars-d-learn

On 05/07/2018 04:41 AM, wjoe wrote:

Could you elaborate on the unsafe destructor please?


If TFunc has an unsafe destructor, asDelegate is also not safe and can't 
be @trusted.


An example of how that can break safety:


auto asDelegate(TFunc)(TFunc func) @trusted
{
 import std.functional : toDelegate;
 return toDelegate(func);
}

int* ptr;
size_t length;

struct S
{
void opCall() {}
~this() @system
{
ptr[length - 1] = 13;
}
}

void main() @safe
{
ptr = new int;
length = 5; /* Whoops, got the length wrong. */
immutable int* imm = new int(42);
auto dg = asDelegate(S.init);
assert(*imm == 42); /* Fails. Immutability has been broken. */
}


The program has undefined behavior, which means it's invalid. And it's 
the fault of the wrong @trusted.



Are there any other gotchas ?


The postblit function `this(this)` is also commonly overlooked with 
regards to @trusted. It might not be a problem here, though, because 
toDelegate has a `ref` parameter.


An unsafe `alias this` would be another problem. Example:

/* ... asDelegate, ptr, length, main as above ... */
struct S
{
@property T t() @system
{
ptr[length - 1] = 13;
return T.init;
}
alias t this;
}
struct T
{
void opCall() {}
}


Those are the things I can see happening in asDelegate.

Additionally, you'd have to check what the toDelegate call does exactly 
before trusting it. And if it turns out that the call can be trusted, 
then you can probably just mark toDelegate itself as @trusted. And then 
there would be no need for asDelegate anymore.


Re: Store any callable in an array

2018-05-06 Thread wjoe via Digitalmars-d-learn

Thanks for replying.

On Friday, 4 May 2018 at 19:12:16 UTC, ag0aep6g wrote:

On 05/04/2018 06:33 PM, Neia Neutuladh wrote:

auto asDelegate(TFunc)(TFunc func) @trusted
{
     import std.functional : toDelegate;
     return toDelegate(func);
}

The "@trusted" means that you promise this thing is safe, even 
if the compiler can't be certain.


If toDelegate isn't (always) @safe, how can you be sure that 
your wrapper is? Also, TFunc may have an unsafe destructor.


That's not good use of `@trusted`.


Could you elaborate on the unsafe destructor please? Are there 
any other gotchas ?


Re: Store any callable in an array

2018-05-06 Thread wjoe via Digitalmars-d-learn

Thanks for replying.

On Saturday, 5 May 2018 at 00:30:35 UTC, Neia Neutuladh wrote:

On Friday, 4 May 2018 at 19:12:16 UTC, ag0aep6g wrote:
[...] If it's a user-defined type with opCall, that's something 
to pay attention to, but it's beyond the scope of the original 
question.


Actually it's not. Callable structs/classes are use cases I'm 
asking about as well.




Re: Store any callable in an array

2018-05-05 Thread ag0aep6g via Digitalmars-d-learn

On 05/05/2018 02:30 AM, Neia Neutuladh wrote:

On Friday, 4 May 2018 at 19:12:16 UTC, ag0aep6g wrote:
If toDelegate isn't (always) @safe, how can you be sure that your 
wrapper is?

[...]
Looking at the code, I believe there are several casts that the compiler 
can't verify but are used safely.


If you're right and the casts are used safely, and if that's the one 
thing that makes toDelegate @system, then toDelegate should be marked as 
@trusted. Or the casts should be @trusted, if they can be isolated like 
that.


But belief isn't strong enough for that. You should be certain when 
applying @trusted. And thinking of all the ways that code might be 
unsafe is tricky, especially when you're dealing with arbitrary types in 
a template.



Also, TFunc may have an unsafe destructor.



[...]> If it's a user-defined type with
opCall, that's something to pay attention to, but it's beyond the scope 
of the original question.


That's the one. The scope of the original question doesn't matter if you 
don't restrain your function in the same way. Your function accepts 
structs, so you have to take them into account. Also, the thread is 
about "anything" callable. That includes structs with opCall.


Re: Store any callable in an array

2018-05-04 Thread Neia Neutuladh via Digitalmars-d-learn

On Friday, 4 May 2018 at 19:12:16 UTC, ag0aep6g wrote:
If toDelegate isn't (always) @safe, how can you be sure that 
your wrapper is?


If it were @safe, the compiler would accept it.

Looking at the code, I believe there are several casts that the 
compiler can't verify but are used safely.



Also, TFunc may have an unsafe destructor.


If it's a delegate with an un-@safe destructor (how would that 
work? a captured context variable?), then it's already not @safe. 
If it's a function, it doesn't have a destructor. If it's a 
user-defined type with opCall, that's something to pay attention 
to, but it's beyond the scope of the original question.


Re: Store any callable in an array

2018-05-04 Thread ag0aep6g via Digitalmars-d-learn

On 05/04/2018 06:33 PM, Neia Neutuladh wrote:

auto asDelegate(TFunc)(TFunc func) @trusted
{
     import std.functional : toDelegate;
     return toDelegate(func);
}

The "@trusted" means that you promise this thing is safe, even if the 
compiler can't be certain.


If toDelegate isn't (always) @safe, how can you be sure that your 
wrapper is? Also, TFunc may have an unsafe destructor.


That's not good use of `@trusted`.


Re: Store any callable in an array

2018-05-04 Thread Neia Neutuladh via Digitalmars-d-learn

On Friday, 4 May 2018 at 15:36:29 UTC, wjoe wrote:
I have a class that I want to be able to register callbacks and 
I'd like to be able to register any callable - functions, 
delegates, lambdas, anything.


Is there another way to do it besides converting those 
toDelegate, which states a bug with @safe functions?


Or better store each type in their own array ?

Cheers!


auto asDelegate(TFunc)(TFunc func) @trusted
{
import std.functional : toDelegate;
return toDelegate(func);
}

The "@trusted" means that you promise this thing is safe, even if 
the compiler can't be certain.


Store any callable in an array

2018-05-04 Thread wjoe via Digitalmars-d-learn
I have a class that I want to be able to register callbacks and 
I'd like to be able to register any callable - functions, 
delegates, lambdas, anything.


Is there another way to do it besides converting those 
toDelegate, which states a bug with @safe functions?


Or better store each type in their own array ?

Cheers!