Re: Understanding Safety of Function Pointers vs. Addresses of Functions

2015-07-15 Thread Laeeth Isharc via Digitalmars-d-learn

On Tuesday, 14 July 2015 at 17:24:41 UTC, anonymous wrote:
This fails with Error: None of the overloads of 'cos' are 
callable using argument types (int[]).


The problem is that template mixins cannot add to existing 
overload sets. The spec says: If the name of a declaration in 
a mixin is the same as a declaration in the surrounding scope, 
the surrounding declaration overrides the mixin one [1]. That 
means, the `cos` from `alias cos = std.math.cos;` completely 
overrides the one from `mixin t!();`. I guess this is a measure 
against function hijacking again.


I'm not sure if it's supposed to work like it does when the 
alias is removed, two implicitly imported/generated symbols 
forming an overload set. But I can't immediately see a problem 
with it either.


[1] http://dlang.org/template-mixin.html - see Mixin Scope




Now - is there a way to rewrite my code without mixins?


Re: Understanding Safety of Function Pointers vs. Addresses of Functions

2015-07-15 Thread jmh530 via Digitalmars-d-learn

On Wednesday, 15 July 2015 at 11:45:00 UTC, Laeeth Isharc wrote:

Now - is there a way to rewrite my code without mixins?


Not sure that is possible. It would be interesting if someone 
could figure it out though.


I'm more focused on making the givemeabettername a bit more 
general. Someone above had sort of asked why bother for the 
simple case. True enough, but if I can write something generic 
enough to work on a wide variety of function types, then I would 
consider it a win. E.g., below.


template givemeabettername(alias fun)
{
static if (arity!fun == 1)
{
T givemeabettername(T)(T x)
if (isDynamicArray!(T))
{
return x.map!fun.array;
}

T givemeabettername(T)(T x)
if (isStaticArray!(T))
{
T result = x.dup;
foreach(ref elem; result)
{
elem = fun(elem);
}
return result;
}
}
}


Re: Understanding Safety of Function Pointers vs. Addresses of Functions

2015-07-14 Thread anonymous via Digitalmars-d-learn

On Tuesday, 14 July 2015 at 01:05:21 UTC, jmh530 wrote:
Note: some of the above seemed to only work when I kept the 
std.math.cos, std.math.sin text in there. When I take it out, I 
get warnings about recursive aliases.


Yeah, you can't do `alias cos = givemeabettername!cos;`. That 
would define the new cos in terms of itself.


But, I can't seem to use a foreach loop. The recursive mixin 
template seems to be required.


You can only use the implicitly static foreach where the normal, 
dynamic foreach is allowed, i.e. in function bodies. This is a 
syntactic restriction. If we had `static foreach` (like we have 
`static if`), that would presumably work everywhere.




So this is the last thing I did (that didn't work). Adding foo 
back to the alias works.


mixin template callThemAll(functions...)
{
   mixin(alias  ~__traits(identifier, functions[0]) ~
		   = givemeabettername!(std.math.~__traits(identifier, 
functions[0]) ~ ););

static if(functions.length 1)
mixin callThemAll!(functions[1..$]);
}

mixin callThemAll!(cos, sin);


Works for me. Please show the complete code and the error message 
you get.


Here's what works for me:

import std.algorithm: map;
import std.math;
import std.array: array;

template givemeabettername(alias fun)
{
T givemeabettername(T : U[], U)(T x)
{
return x.map!fun.array;
}
}

mixin template callThemAll(functions...)
{
mixin(alias  ~__traits(identifier, functions[0]) ~
 = givemeabettername!(std.math.~__traits(identifier, 
functions[0]) ~ ););

static if(functions.length 1)
mixin callThemAll!(functions[1..$]);
}

mixin callThemAll!(cos, sin);

void main()
{
real[] a = [1, 2, 3];
auto c = cos(a);
auto s = sin(a);
}



Re: Understanding Safety of Function Pointers vs. Addresses of Functions

2015-07-14 Thread jmh530 via Digitalmars-d-learn

On Tuesday, 14 July 2015 at 12:12:41 UTC, anonymous wrote:


Works for me. Please show the complete code and the error 
message you get.


Here's what works for me:



Thanks for posting that. I figured out the issue. Before you had 
recommended that I use

alias cos = std.math.cos;
I had kept that text in. When I removed it, everything worked 
just fine. I'm still not sure I grasp the subtleties of alias 
when used with templates.


Re: Understanding Safety of Function Pointers vs. Addresses of Functions

2015-07-14 Thread jmh530 via Digitalmars-d-learn

On Tuesday, 14 July 2015 at 17:24:41 UTC, anonymous wrote:


This fails with Error: None of the overloads of 'cos' are 
callable using argument types (int[]).


The problem is that template mixins cannot add to existing 
overload sets. The spec says: If the name of a declaration in 
a mixin is the same as a declaration in the surrounding scope, 
the surrounding declaration overrides the mixin one [1]. That 
means, the `cos` from `alias cos = std.math.cos;` completely 
overrides the one from `mixin t!();`. I guess this is a measure 
against function hijacking again.


I'm not sure if it's supposed to work like it does when the 
alias is removed, two implicitly imported/generated symbols 
forming an overload set. But I can't immediately see a problem 
with it either.


[1] http://dlang.org/template-mixin.html - see Mixin Scope


That's a great explanation. It doesn't seem like a bug or 
anything. It's just alias and template mixins are two areas of D 
that I'm less familiar with. Combining them together pushes my 
understanding a bit.




Re: Understanding Safety of Function Pointers vs. Addresses of Functions

2015-07-14 Thread anonymous via Digitalmars-d-learn

On Tuesday, 14 July 2015 at 14:02:46 UTC, jmh530 wrote:
Thanks for posting that. I figured out the issue. Before you 
had recommended that I use

alias cos = std.math.cos;
I had kept that text in. When I removed it, everything worked 
just fine. I'm still not sure I grasp the subtleties of alias 
when used with templates.


Oh that's another goodie. So you had a situation like this:

import std.math;

alias cos = std.math.cos;

mixin template t()
{
void cos(real[] arr) {/* ... */}
}

mixin t!();

void main()
{
cos([1, 2, 3]);
}


This fails with Error: None of the overloads of 'cos' are 
callable using argument types (int[]).


The problem is that template mixins cannot add to existing 
overload sets. The spec says: If the name of a declaration in a 
mixin is the same as a declaration in the surrounding scope, the 
surrounding declaration overrides the mixin one [1]. That means, 
the `cos` from `alias cos = std.math.cos;` completely overrides 
the one from `mixin t!();`. I guess this is a measure against 
function hijacking again.


I'm not sure if it's supposed to work like it does when the alias 
is removed, two implicitly imported/generated symbols forming an 
overload set. But I can't immediately see a problem with it 
either.


[1] http://dlang.org/template-mixin.html - see Mixin Scope


Re: Understanding Safety of Function Pointers vs. Addresses of Functions

2015-07-13 Thread jmh530 via Digitalmars-d-learn

On Monday, 13 July 2015 at 02:52:11 UTC, Laeeth Isharc wrote:


I am venturing in territory still new to me, but I think that 
was his point - foreach with tuples looks like it is looping, 
but really it is unpacking them statically at compile time.  
And similarly with the recursive version.  I don't know if you 
can avoid the mixin, but you can make it a little tidier.


import std.math;
import std.stdio;
import std.traits;

mixin template callThemAll(functions...)
{
   	mixin(alias 
foo~__traits(identifier,functions[0])~=~__traits(identifier,functions[0])~;);

static if(functions.length 1)
mixin callThemAll!(functions[1..$]);
}

void main()
{
mixin callThemAll!(sin,cos,tan);
writefln(%s,foosin(1));
writefln(%s,foocos(1));
writefln(%s,footan(1.0));
}

Not sure if you knew this already and still found it too messy.


I had considered mixins as messy, but my original one was way 
messier than this. By comparison, it's not so bad.


Beyond the mixins, what I find most interesting was the 
__traits(identifier,functions[0]). Hadn't seen that before. I was 
only familiar with __FUNCTION__. It definitely simplifies it


Anyway, the downside of the approach so far is that I can't quite 
understand why some versions have worked, but not others. For 
your foo version (with a few modifications to better match what 
I'm doing), I was able to get it working regardless of whether it 
was in main or not. That's good. Further, when I got rid of the 
foo, but kept it in main, it still worked (after changing the 
function names). However, when I moved it back out of main I was 
getting messages about there being no cos/sin available for those 
types.


Note: some of the above seemed to only work when I kept the 
std.math.cos, std.math.sin text in there. When I take it out, I 
get warnings about recursive aliases. But, I can't seem to use a 
foreach loop. The recursive mixin template seems to be required.


So this is the last thing I did (that didn't work). Adding foo 
back to the alias works.


mixin template callThemAll(functions...)
{
   mixin(alias  ~__traits(identifier, functions[0]) ~
		   = givemeabettername!(std.math.~__traits(identifier, 
functions[0]) ~ ););

static if(functions.length 1)
mixin callThemAll!(functions[1..$]);
}

mixin callThemAll!(cos, sin);


Re: Understanding Safety of Function Pointers vs. Addresses of Functions

2015-07-12 Thread Laeeth Isharc via Digitalmars-d-learn
I don't know what exactly you're after, but you can use 
foreach on a whatever-they're-called-now tuple (there's been a 
discussion about the name which I haven't followed; I mean the 
kind you get from a TemplateTupleParameter):


void f1() {}
void f2() {}
void callThemAll(functions ...)()
{
foreach(f; functions) /* The loop is unrolled at compile 
time. */

{
f();
}
}
void main()
{
callThemAll!(f1, f2)();
}


As usual, recursion is an alternative:

void callThemAll(functions ...)()
{
static if(functions.length  0)
{
functions[0]();
callThemAll!(functions[1 .. $])();
}
}



Sorry, I don't think I made myself clear enough. Your code 
allows you to do something like call multiple functions in a 
loop. I'm talking about the fact that


alias cos = givemeabettername!(std.math.cos);
alias sin = givemeabettername!(std.math.sin);

are just two functions of many in std.math. Suppose I wanted to 
write it so that every function in std.math had an array 
version generated by this code. I would be repeating this alias 
line once each time. My point is that I don't see a way to do 
this in a loop. I don't think I can do something like


void callThemAll(functions ...)()
{
foreach(f; functions)
{
alias __Function__ = givemeabettername!(f); //where 
__Function__ is the name of the function for f, not callThemAll

}
}

callThemAll(std.math.cos, std.math.sin);

void main()
{
real[] x = [0, PI];
auto y = cos(x);
auto z = sin(x);
}


I am venturing in territory still new to me, but I think that was 
his point - foreach with tuples looks like it is looping, but 
really it is unpacking them statically at compile time.  And 
similarly with the recursive version.  I don't know if you can 
avoid the mixin, but you can make it a little tidier.


import std.math;
import std.stdio;
import std.traits;

mixin template callThemAll(functions...)
{
   	mixin(alias 
foo~__traits(identifier,functions[0])~=~__traits(identifier,functions[0])~;);

static if(functions.length 1)
mixin callThemAll!(functions[1..$]);
}

void main()
{
mixin callThemAll!(sin,cos,tan);
writefln(%s,foosin(1));
writefln(%s,foocos(1));
writefln(%s,footan(1.0));
}

Not sure if you knew this already and still found it too messy.





Re: Understanding Safety of Function Pointers vs. Addresses of Functions

2015-07-12 Thread jmh530 via Digitalmars-d-learn

On Sunday, 12 July 2015 at 20:31:20 UTC, jmh530 wrote:

On Sunday, 12 July 2015 at 17:11:04 UTC, anonymous wrote:


And personally, I'd probably just type out `x.map!fun.array` 
every time.


[1] http://dlang.org/hijack.html


Thanks for the comments.


After thinking it over, I think you're absolutely right about the 
function pointers. I made a slight change to just this:


private template givemeabettername(alias fun)
{
T givemeabettername(T : U[], U)(T x)
if (isArray!(T))
{
return x.map!(a = fun(a)).array;
}
}

Very cool. I guess I'm still left with the issue that I don't 
know how to loop through a bunch of different functions at 
compile time, but this is so elegant that it doesn't seem like 
that big a deal.


I'll admit, I still don't think I really have a handle on alias 
(i.e., it's not something I immediately think of; I understand 
what it does). It seems like you can do so many things with it. 
It's just not something that I used in other languages much.


Re: Understanding Safety of Function Pointers vs. Addresses of Functions

2015-07-12 Thread jmh530 via Digitalmars-d-learn

On Sunday, 12 July 2015 at 17:11:04 UTC, anonymous wrote:


And personally, I'd probably just type out `x.map!fun.array` 
every time.


[1] http://dlang.org/hijack.html


Thanks for the comments.


Re: Understanding Safety of Function Pointers vs. Addresses of Functions

2015-07-12 Thread jmh530 via Digitalmars-d-learn

On Sunday, 12 July 2015 at 22:26:44 UTC, anonymous wrote:


You don't need the lambda, do you? - return x.map!fun.array;



You're right.



I don't know what exactly you're after, but you can use foreach 
on a whatever-they're-called-now tuple (there's been a 
discussion about the name which I haven't followed; I mean the 
kind you get from a TemplateTupleParameter):


void f1() {}
void f2() {}
void callThemAll(functions ...)()
{
foreach(f; functions) /* The loop is unrolled at compile 
time. */

{
f();
}
}
void main()
{
callThemAll!(f1, f2)();
}


As usual, recursion is an alternative:

void callThemAll(functions ...)()
{
static if(functions.length  0)
{
functions[0]();
callThemAll!(functions[1 .. $])();
}
}



Sorry, I don't think I made myself clear enough. Your code allows 
you to do something like call multiple functions in a loop. I'm 
talking about the fact that


alias cos = givemeabettername!(std.math.cos);
alias sin = givemeabettername!(std.math.sin);

are just two functions of many in std.math. Suppose I wanted to 
write it so that every function in std.math had an array version 
generated by this code. I would be repeating this alias line once 
each time. My point is that I don't see a way to do this in a 
loop. I don't think I can do something like


void callThemAll(functions ...)()
{
foreach(f; functions)
{
alias __Function__ = givemeabettername!(f); //where 
__Function__ is the name of the function for f, not callThemAll

}
}

callThemAll(std.math.cos, std.math.sin);

void main()
{
real[] x = [0, PI];
auto y = cos(x);
auto z = sin(x);
}


Re: Understanding Safety of Function Pointers vs. Addresses of Functions

2015-07-12 Thread anonymous via Digitalmars-d-learn

On Sunday, 12 July 2015 at 21:07:34 UTC, jmh530 wrote:

private template givemeabettername(alias fun)
{
T givemeabettername(T : U[], U)(T x)
if (isArray!(T))
{
return x.map!(a = fun(a)).array;


You don't need the lambda, do you? - return x.map!fun.array;


}
}

Very cool. I guess I'm still left with the issue that I don't 
know how to loop through a bunch of different functions at 
compile time, but this is so elegant that it doesn't seem like 
that big a deal.


I don't know what exactly you're after, but you can use foreach 
on a whatever-they're-called-now tuple (there's been a discussion 
about the name which I haven't followed; I mean the kind you get 
from a TemplateTupleParameter):


void f1() {}
void f2() {}
void callThemAll(functions ...)()
{
foreach(f; functions) /* The loop is unrolled at compile 
time. */

{
f();
}
}
void main()
{
callThemAll!(f1, f2)();
}


As usual, recursion is an alternative:

void callThemAll(functions ...)()
{
static if(functions.length  0)
{
functions[0]();
callThemAll!(functions[1 .. $])();
}
}



Re: Understanding Safety of Function Pointers vs. Addresses of Functions

2015-07-12 Thread anonymous via Digitalmars-d-learn

On Sunday, 12 July 2015 at 16:34:17 UTC, jmh530 wrote:
I've been playing around with this a little more. I wrote this 
function to encapsulate a simple operation on arrays.


U array_fun(T, U)(T fp, U x)
if (isFunctionPointer!(T)  isArray!(U))
{
return x.map!(a = fp(a)).array;
}

Then I wrote a cos function that calls it on using a function 
pointer.


T cos(T : U[], U)(T x)
if (isArray!(T))
{
auto fp = (U a) = cos(a);
return array_fun(fp, x);
}

This seems to work just fine, but for some reason this only 
seems to work when I import std.math : cos. It doesn't work 
when I just do import std.math. Bug?


Your function is called cos, too. So you need your local cos and 
std.math.cos to form an overload set. This isn't automatically 
done with implicitly imported functions to avoid hijacking [1] 
(accidentally calling the wrong function). Selectively imported 
functions are added to the overload set, as you (the programmer) 
are obviously aware of them and want them in the overload set. An 
alternative would be to use an alias:


import std.math;
alias cos = std.math.cos;


Nevertheless, if I want to implement it for another function, 
then I have to write it all over again. So I wrote a mixin that 
would encapsulate that idea (I put in the \n, \t for formatting 
purposes because I like to be able to writeln it out and see 
that it matches the original).


template mixin_builder(string function_name)
{
const char[] mixin_builder =
T  ~ function_name ~ (T : U[], U)(T x)\n ~
\tif (isArray!(T))\n ~
{\n ~
\tauto fp = (U a) =  ~ function_name ~ (a);\n ~
\treturn array_fun(fp, x);\n ~
};
}

Then I can just call
mixin(mixin_builder!(cos));
mixin(mixin_builder!(sin));

While it works, it feels a bit hackish. I'm not sure I can 
think of a generic way to do this without mixins.


Take the function via an alias parameter:

template givemeabettername(alias fun)
{
T givemeabettername(T : U[], U)(T x)
if (isArray!(T))
{
auto fp = (U a) = fun(a);
return array_fun(fp, x);
}
}
alias cos = givemeabettername!(std.math.cos);
alias sin = givemeabettername!(std.math.sin);


But turning a statically known function to a function pointer 
only to pass it to `map` seems pointless to me. So:


template givemeabettername(alias fun)
{
T givemeabettername(T : U[], U)(T x)
if (isArray!(T)) /* With the specialization above, this 
is redundant, isn't it?  */

{
return x.map!fun.array;
}
}


And personally, I'd probably just type out `x.map!fun.array` 
every time.


[1] http://dlang.org/hijack.html


Re: Understanding Safety of Function Pointers vs. Addresses of Functions

2015-07-12 Thread jmh530 via Digitalmars-d-learn
On Wednesday, 8 July 2015 at 18:31:00 UTC, Steven Schveighoffer 
wrote:


You can use a function lambda:

auto fp = (real a) = cos(a);

Note, I had to put (real a) even though I would have expected 
a = cos(a) to work.


-Steve


I've been playing around with this a little more. I wrote this 
function to encapsulate a simple operation on arrays.


U array_fun(T, U)(T fp, U x)
if (isFunctionPointer!(T)  isArray!(U))
{
return x.map!(a = fp(a)).array;
}

Then I wrote a cos function that calls it on using a function 
pointer.


T cos(T : U[], U)(T x)
if (isArray!(T))
{
auto fp = (U a) = cos(a);
return array_fun(fp, x);
}

This seems to work just fine, but for some reason this only seems 
to work when I import std.math : cos. It doesn't work when I just 
do import std.math. Bug?


Nevertheless, if I want to implement it for another function, 
then I have to write it all over again. So I wrote a mixin that 
would encapsulate that idea (I put in the \n, \t for formatting 
purposes because I like to be able to writeln it out and see that 
it matches the original).


template mixin_builder(string function_name)
{
const char[] mixin_builder =
T  ~ function_name ~ (T : U[], U)(T x)\n ~
\tif (isArray!(T))\n ~
{\n ~
\tauto fp = (U a) =  ~ function_name ~ (a);\n ~
\treturn array_fun(fp, x);\n ~
};
}

Then I can just call
mixin(mixin_builder!(cos));
mixin(mixin_builder!(sin));

While it works, it feels a bit hackish. I'm not sure I can think 
of a generic way to do this without mixins.


Re: Understanding Safety of Function Pointers vs. Addresses of Functions

2015-07-09 Thread via Digitalmars-d-learn

On Wednesday, 8 July 2015 at 21:04:27 UTC, jmh530 wrote:
On Wednesday, 8 July 2015 at 18:31:00 UTC, Steven Schveighoffer 
wrote:

You can use a function lambda:

auto fp = (real a) = cos(a);

Note, I had to put (real a) even though I would have expected 
a = cos(a) to work.


-Steve


Interesting. You have to put real because there is also a float 
and double version of cos.


Even if there are no overloads, you'd still need to specify the 
type. That's because `a = cos(a)` is not a function, but a 
function template, and therefore can't be store in a variable.


Re: Understanding Safety of Function Pointers vs. Addresses of Functions

2015-07-09 Thread Steven Schveighoffer via Digitalmars-d-learn

On 7/9/15 4:44 AM, Marc =?UTF-8?B?U2Now7x0eiI=?= schue...@gmx.net wrote:

On Wednesday, 8 July 2015 at 21:04:27 UTC, jmh530 wrote:

On Wednesday, 8 July 2015 at 18:31:00 UTC, Steven Schveighoffer wrote:

You can use a function lambda:

auto fp = (real a) = cos(a);

Note, I had to put (real a) even though I would have expected a =
cos(a) to work.



Interesting. You have to put real because there is also a float and
double version of cos.


Even if there are no overloads, you'd still need to specify the type.
That's because `a = cos(a)` is not a function, but a function template,
and therefore can't be store in a variable.


I didn't know this! I thought it would infer the type if there wasn't 
any overloads (or in this case, I thought there was a weird issue with 
the fact that cos is intrinsic).


This is good to know.

-Steve


Re: Understanding Safety of Function Pointers vs. Addresses of Functions

2015-07-08 Thread via Digitalmars-d-learn

On Wednesday, 8 July 2015 at 03:31:43 UTC, jmh530 wrote:
I'm still not sure why I'm getting the error I mention in the 
original post. For instance, the code below is giving that 
Error 42 Symbol Undefined error. Seems very mystifying...


import std.math : cos;

real foo(T)(T fp, real x)
{
return fp(x);
}

void main()
{
real x = 0;
real y = foo(cos, x);
}


It seems std.math.cos is an intrinsic function (i.e. one that the 
compiler implements when needed, or generates the appropriate asm 
for):

https://github.com/D-Programming-Language/phobos/blob/master/std/math.d#L630

The compiler should probably refuse to take the address of such a 
function. I've found this bug report:

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


Re: Understanding Safety of Function Pointers vs. Addresses of Functions

2015-07-08 Thread jmh530 via Digitalmars-d-learn

On Wednesday, 8 July 2015 at 11:15:12 UTC, Marc Schütz wrote:


It seems std.math.cos is an intrinsic function (i.e. one that 
the compiler implements when needed, or generates the 
appropriate asm for):

https://github.com/D-Programming-Language/phobos/blob/master/std/math.d#L630

The compiler should probably refuse to take the address of such 
a function. I've found this bug report:

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


Thanks. I was worried I was doing something wrong.




Re: Understanding Safety of Function Pointers vs. Addresses of Functions

2015-07-08 Thread jmh530 via Digitalmars-d-learn

On Wednesday, 8 July 2015 at 14:37:23 UTC, jmh530 wrote:

Thanks. I was worried I was doing something wrong.


It seems like if you wrap the intrinsic function in another 
function than it works fine (below). Easy enough work-around, I 
suppose.


If there is no intention to fix the pointer to assembly function 
issue (I have zero clue how to go about it, maybe there is a good 
reason it can't be fixed), this work-around could be implemented 
in the std.math library for those functions. I.e., put the 
assembly code in separate functions and then have the existing 
intrinsic functions act as wrappers to those.


import std.math : cos;

real cos_wrap(real x) pure nothrow @nogc @safe
{
return cos(x);
}

void main()
{
auto fp = cos_wrap;
real x = 0;
real y = fp(x);
}




Re: Understanding Safety of Function Pointers vs. Addresses of Functions

2015-07-08 Thread Steven Schveighoffer via Digitalmars-d-learn

On 7/8/15 11:49 AM, jmh530 wrote:

On Wednesday, 8 July 2015 at 14:37:23 UTC, jmh530 wrote:

Thanks. I was worried I was doing something wrong.


It seems like if you wrap the intrinsic function in another function
than it works fine (below). Easy enough work-around, I suppose.

If there is no intention to fix the pointer to assembly function issue
(I have zero clue how to go about it, maybe there is a good reason it
can't be fixed), this work-around could be implemented in the std.math
library for those functions. I.e., put the assembly code in separate
functions and then have the existing intrinsic functions act as wrappers
to those.

import std.math : cos;

real cos_wrap(real x) pure nothrow @nogc @safe
{
 return cos(x);
}

void main()
{
 auto fp = cos_wrap;
 real x = 0;
 real y = fp(x);
}


You can use a function lambda:

auto fp = (real a) = cos(a);

Note, I had to put (real a) even though I would have expected a = 
cos(a) to work.


-Steve



Re: Understanding Safety of Function Pointers vs. Addresses of Functions

2015-07-08 Thread jmh530 via Digitalmars-d-learn
On Wednesday, 8 July 2015 at 18:31:00 UTC, Steven Schveighoffer 
wrote:

You can use a function lambda:

auto fp = (real a) = cos(a);

Note, I had to put (real a) even though I would have expected 
a = cos(a) to work.


-Steve


Interesting. You have to put real because there is also a float 
and double version of cos.


Re: Understanding Safety of Function Pointers vs. Addresses of Functions

2015-07-07 Thread anonymous via Digitalmars-d-learn

On Tuesday, 7 July 2015 at 19:54:19 UTC, jmh530 wrote:
I'm not sure I understand the safety of function pointers vs. 
the addresses of functions. The code below illustrates the 
issue.


I was under the impression that pointers are not allowed in 
safe code.


No, pointers are fine. It's pointer arithmetic that's considered 
unsafe.


Naturally, I took that to also mean that function pointers are 
not allowed in safe code. Indeed, I haven't been able to pass a 
function pointer to a safe function. However, I am able to take 
the address of a function and pass that as a parameter. It 
seems to work fine for taking the address of functions and 
templates (so long as I !)


So long as you exclamation mark? Huh?


import std.stdio : writeln;
import std.traits;
import std.math;

void function_safety(T)(T fp)
{
if (functionAttributes!fp  FunctionAttribute.safe)
writeln(fp is safe);
else if (functionAttributes!fp  FunctionAttribute.trusted)
writeln(fp is trusted);
else if (functionAttributes!fp  FunctionAttribute.system)
writeln(fp is system);
else
writeln(fp is neither safe nor trusted nor system);
}

void main()
{
function_safety(cbrt);  //prints fp is trusted
real function(real) fp = cbrt;


You're explicitly typing that as `real function(real)` which is 
not an @safe type. Add @safe and you're good to go:


real function(real) @safe fp = cbrt;
function_safety(fp); /* prints fp is safe */

Or let the compiler infer things:

auto fp = cbrt;
function_safety(fp); /* prints fp is trusted */


function_safety(fp); //prints fp is system
}


Re: Understanding Safety of Function Pointers vs. Addresses of Functions

2015-07-07 Thread H. S. Teoh via Digitalmars-d-learn
On Tue, Jul 07, 2015 at 07:54:18PM +, jmh530 via Digitalmars-d-learn wrote:
 I'm not sure I understand the safety of function pointers vs. the addresses
 of functions. The code below illustrates the issue.

Function pointers and addresses of functions are the same thing. There
is no difference between them.


 I was under the impression that pointers are not allowed in safe code.

This is incorrect. Pointers are allowed in safe code as long as they are
not manipulated in unsafe ways (e.g., assigning a literal value to them,
pointer arithmetic, casting to a pointer to an incompatible type, using
a pointer to call an un-@safe function from @safe code, etc.).


 Naturally, I took that to also mean that function pointers are not
 allowed in safe code. Indeed, I haven't been able to pass a function
 pointer to a safe function. However, I am able to take the address of
 a function and pass that as a parameter. It seems to work fine for
 taking the address of functions and templates (so long as I !)

The reason for this is that function pointers have attributes associated
with them, as part of the type system. The address of a @safe function
is a @safe function pointer, meaning that it's legal to call the
function through this pointer in @safe code. The address of a @system
function is a @system function pointer, which *cannot* be used to call
the function from @safe code.

However, while it is not allowed to assign a @system function pointer to
a @safe function pointer (since that could be used to bypass the @safe
restriction on calling @system functions), it is OK to assign a @safe
function pointer to a @system function pointer (this is called
covariance). This is allowed because a @system function pointer can only
be dereferenced in @system code, and @system code can freely call any
function with no restrictions. Where this might become a problem,
though, is when you inadvertently assign a @safe function pointer to a
@system function pointer, and then attempt to call it from @safe code --
the compiler will reject that. This is what happened with your sample
code:


[...]
 void main()
 {
   function_safety(cbrt);  //prints fp is trusted
   real function(real) fp = cbrt;

Here, fp is a @system function pointer. While cbrt is a @safe function
pointer, it is covariant with a @system function pointer, so the
assignment is allowed.


   function_safety(fp); //prints fp is system
[...]

The result, however, is now @system, so you can no longer call cbrt from
@safe code through this particular function pointer (though you can
obviously call it through a @safe function pointer).

The correct syntax for declaring a @safe function pointer would be:

real function(real) @safe fp = ...;

Either that, or use `auto` to let the compiler figure out the correct
function pointer attributes for you:

auto fp = cbrt;
pragma(msg, typeof(fp).stringof);

The compiler prints:

real function(real x) nothrow @nogc @trusted

So you see here that two other attributes, nothrow and @nogc, are also
inferred by the compiler, which is a good thing because otherwise your
function pointer wouldn't be usable from nothrow or @nogc code,
respectively.


T

-- 
Music critic: That's an imitation fugue!


Re: Understanding Safety of Function Pointers vs. Addresses of Functions

2015-07-07 Thread jmh530 via Digitalmars-d-learn

On Tuesday, 7 July 2015 at 20:13:08 UTC, anonymous wrote:


So long as you exclamation mark? Huh?



Thanks for the detailed answer. All I meant here is that if I 
have some
T foo(T)(T x), then to take the address, sometimes I've needed to 
foo!int or foo!real, etc.


Re: Understanding Safety of Function Pointers vs. Addresses of Functions

2015-07-07 Thread anonymous via Digitalmars-d-learn

On Tuesday, 7 July 2015 at 20:32:49 UTC, jmh530 wrote:
Thanks for the detailed answer. All I meant here is that if I 
have some
T foo(T)(T x), then to take the address, sometimes I've needed 
to foo!int or foo!real, etc.


Ah, sure. Templates don't have addresses. Function templates are 
not exempt from that. I think you always have to instantiate them 
in order take an address, not just sometimes.


Re: Understanding Safety of Function Pointers vs. Addresses of Functions

2015-07-07 Thread jmh530 via Digitalmars-d-learn

On Tuesday, 7 July 2015 at 20:23:08 UTC, H. S. Teoh wrote:


The reason for this is that function pointers have attributes 
associated with them, as part of the type system. The address 
of a @safe function is a @safe function pointer, meaning that 
it's legal to call the function through this pointer in @safe 
code. The address of a @system function is a @system function 
pointer, which *cannot* be used to call the function from @safe 
code.


However, while it is not allowed to assign a @system function 
pointer to a @safe function pointer (since that could be used 
to bypass the @safe restriction on calling @system functions), 
it is OK to assign a @safe function pointer to a @system 
function pointer (this is called covariance). This is allowed 
because a @system function pointer can only be dereferenced in 
@system code, and @system code can freely call any function 
with no restrictions. Where this might become a problem, 
though, is when you inadvertently assign a @safe function 
pointer to a @system function pointer, and then attempt to call 
it from @safe code -- the compiler will reject that. This is 
what happened with your sample code:




This, and the rest, does such a good job explaining why I have 
been so confused.


Either that, or use `auto` to let the compiler figure out the 
correct function pointer attributes for you:


auto fp = cbrt;
pragma(msg, typeof(fp).stringof);



I've tried using auto, but I get errors when I use auto with a 
function that has been overloaded. For instance,

creal function(creal) pure nothrow @nogc @safe fp = conj;
compiles, but
auto fp = conj;
does not.


Re: Understanding Safety of Function Pointers vs. Addresses of Functions

2015-07-07 Thread jmh530 via Digitalmars-d-learn
I'm still not sure why I'm getting the error I mention in the 
original post. For instance, the code below is giving that Error 
42 Symbol Undefined error. Seems very mystifying...


import std.math : cos;

real foo(T)(T fp, real x)
{
return fp(x);
}

void main()
{
real x = 0;
real y = foo(cos, x);
}