I've been playing around with D, trying to mimic Scala style curryable functions by chaining lambda expressions.
I came up with this:
immutable foo=function(immutable int x)=>(immutable int y)=>(x+y);
struct S
{
static immutable foo=function(immutable int x)=>(immutable int y)=>(x+y);
}
class C static immutable foo=function(immutable int x)=>(immutable int y)=>(x+y);
}
void main()
{
writefln("global\t%s",foo(1)(2));
writefln("struct\t%s",S.foo(1)(2));
writefln("class\t%s",C.foo(1)(2));
}
This is what I get when I run it:
global 3
struct 1528543170
Segmentation fault
As you can see, my method works well for the global function variable, but the struct's static function variable gives junk result, and the class's static function variable fails completely.
If I remove the x
from the return expression - function(immutable int x)=>(immutable int y)=>(y)
- the struct version gives the correct result(2
), but the class version still fails.
If I use a regular method, instead of a function variable:
immutable foo=function(immutable int x)=>(immutable int y)=>(x+y);
struct S
{
static auto foo(immutable int x)
{
return (immutable int y)=>(x+y);
}
}
class C
{
static auto foo(immutable int x)
{
return (immutable int y)=>(x+y);
}
}
void main()
{
writefln("global\t%s",foo(1)(2));
writefln("struct\t%s",S.foo(1)(2));
writefln("class\t%s",C.foo(1)(2));
}
it works just fine:
global 3
struct 3
class 3
And I also get the advantage of using delegates(the compiler won't allow delegates in the first version) - but this style is less elegant.
I am well aware that D has the curry
function in the std.functional
library for currying functions, but sometimes it's more comfortable to make a function curryable by default, and beside - I'm curious to know why my first version doesn't work.
Any ideas?
UPDATE
OK, I've filed a bug. I've done some more digging, and it turns out the argument list of foo
gets shifted, and that's why x
gets junk data.
Lambda-expressions are not allowed in unevaluated expressions, template arguments, alias declarations, typedef declarations, and anywhere in a function (or function template) declaration except the function body and the function's default arguments.
Only variables that are mentioned in the lambda body are captured when a capture-default is used. To use lambda expressions in the body of a class member function, pass the this pointer to the capture clause to provide access to the member functions and data members of the enclosing class.
In order to match a lambda to a single method interface, also called a "functional interface", several conditions need to be met: The functional interface has to have exactly one unimplemented method, and that method (naturally) has to be abstract.
Lambda functions can be divided into two parts: code inside the handler function and the code outside of it. Code outside the handler function only gets executed during the cold start, while the code inside the handler executes per each function call.
Honestly, it looks like you ran into a compiler bug. Please report it. Since the variables in the struct and class are static, their behavior should be identical to that of the module-level variable, and clearly, it's not.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With