It makes a Func which calls the given Func if a predicate is true. The problem is it assumes f arity is 0. Is there any way to write similar method which takes f arguments into account properly? Something like this:
static Func decorate(Func f) {
|The same params f takes| {
if (pred()) f(params)
}
}
I searched a bit and found nothing besides good old copy-pasting:
static Func decorate(Func f) {
Func? ret := null
switch (f.params.size) {
case 0:
ret = |->| { if (pred()) f() }
case 1:
ret = |Obj? p0| { if (pred()) f(p0) }
case 2:
ret = |Obj? p0, Obj? p1| { if (pred()) f(p0, p1) }
case 3:
ret = |Obj? p0, Obj? p1, Obj? p2| { if (pred()) f(p0, p1, p2) }
case 4:
ret = |Obj? p0, Obj? p1, Obj? p2, Obj? p3| { if (pred()) f(p0, p1, p2, p3) }
default:
throw ArgErr("Too many arguments")
}
return ret
}
But I really don't like this...
brianThu 31 Mar 2011
There actually isn't really a nice way to do that right now. So probably need to design something new. The idea of new factory method on Func seems to make sense:
I think of this as a symptom for the lack of varargs in Fantom. However I prefer the way ActionScript3 (i.e. Flash/Flex) does it over Java-style varargs.
In Java, varargs are just compiler sugar for the final argument being an array. You even have the option of calling the method with an array instead of the separate values, to keep backward compatibility.
In AS3, varargs are treated as just an implementation detail of the function. At the call site, it just looks like any other function with those extra arguments.
This has ramifications when you call the method reflectively.
public static function foo(a:String, b:String, ...rest):void {
...
}
...
foo("a", "b", "c", "d", "e");
var func:Function = foo;
func.apply(null, ["a", "b", "c", "d", "e"]);
Notice how in AS3, the elements "c", "d" and "e" did not have to be wrapped in another array for the reflective call.
At first this screwed me up because I expected varargs to work the same way as Java. Once I got used to it though, I found I preferred it because the usage is more consistent. That is, regular calls and reflective calls look the same, argument-wise.
brianThu 31 Mar 2011
I think of this as a symptom for the lack of varargs in Fantom. However I prefer the way ActionScript3 (i.e. Flash/Flex) does it over Java-style varargs.
I don't really like the way Java does it either, but I think on the JVM we sort of have to do it that way. In the end we have to generate an actual Java method with a static signature. Did you have some thoughts how else it could work?
qualidafialFri 1 Apr 2011
Fantom signature:
static Void foo(Int a, Int b, Int... args)
Equivalent Java signature:
static void foo(long a, long b, fan.sys.List<Long> args)
Pretty similar to how Java does it, except that in Fantom:
foo(1, 2) // is valid
foo(1, 2, [,]) // is invalid
foo(1, 2, 3, 4) // is valid
foo(1, 2, [3, 4]) // is invalid
Internally, the valid expressions above are actually compiled down to the corresponding invalid expressions--but this is an implementation detail that we bury in the fcode to bytecode translator.
As far as reflection goes, the Func we get from #foo.func would have to transparently handle varargs before parlaying the method call to the object, e.g.
class FooMethodFunc : Func
{
Obj? callList(Obj?[]? args)
{
Int a := args[0]
Int b := args[1]
Int[] c := Int[,].addAll(args[2..-1]).ro
foo(a, b, c) // what the generated bytecode might look like
}
}
One big win we get with varargs is the ability to easily wrap a Func as the original post on this thread suggests:
|Int a, Str b, Float c| foo := ...
wrapperFunc := |Obj?... args->Obj?|
{
// do something interesting before, after or around call to wrapped Func e.g.
return isValid(args)
? foo.callList(args)
: null
}
Now wrapperFunc has effectively the same signature as the wrapped Func, without having to know anything about it.
For what it's worth, I found myself adding classes into my data binding library design precisely because of the lack of varargs in anonymous functions.
This change would obviously require rolling a new fcode version. I think if we decide to do this, it's worth making varargs a first-class construct in fcode, and to not clutter the fcode with the JVM implementation details discussed above. Those should be implicit in the fcode to bytecode translation.
I hope this all makes sense!
brianMon 4 Apr 2011
I do think the varargs discussion is sort of orthogonal to the initial problem reported. Varargs might be a potential solution, but in the end in JVM land we still have to box into a list.
I personally don't really see a great need for varargs precisely because it is so trivial to create inline lists:
foo(a, b, [c, b, d])
A bit of noise, but it seems acceptable to me to keep complexity down.
Another perspective is that I'd much rather have named arguments in additional to positional parameters. And I think that any work we did for varargs would interact with named parameters very poorly. So I'd like to keep that option open in the future.
dsav Thu 31 Mar 2011
Please consider the following code:
It makes a Func which calls the given Func if a predicate is true. The problem is it assumes f arity is 0. Is there any way to write similar method which takes f arguments into account properly? Something like this:
I searched a bit and found nothing besides good old copy-pasting:
But I really don't like this...
brian Thu 31 Mar 2011
There actually isn't really a nice way to do that right now. So probably need to design something new. The idea of new factory method on Func seems to make sense:
Does everybody like that?
qualidafial Thu 31 Mar 2011
I think of this as a symptom for the lack of varargs in Fantom. However I prefer the way ActionScript3 (i.e. Flash/Flex) does it over Java-style varargs.
In Java, varargs are just compiler sugar for the final argument being an array. You even have the option of calling the method with an array instead of the separate values, to keep backward compatibility.
In AS3, varargs are treated as just an implementation detail of the function. At the call site, it just looks like any other function with those extra arguments.
This has ramifications when you call the method reflectively.
Java:
ActionScript3:
Notice how in AS3, the elements "c", "d" and "e" did not have to be wrapped in another array for the reflective call.
At first this screwed me up because I expected varargs to work the same way as Java. Once I got used to it though, I found I preferred it because the usage is more consistent. That is, regular calls and reflective calls look the same, argument-wise.
brian Thu 31 Mar 2011
I don't really like the way Java does it either, but I think on the JVM we sort of have to do it that way. In the end we have to generate an actual Java method with a static signature. Did you have some thoughts how else it could work?
qualidafial Fri 1 Apr 2011
Fantom signature:
Equivalent Java signature:
Pretty similar to how Java does it, except that in Fantom:
Internally, the valid expressions above are actually compiled down to the corresponding invalid expressions--but this is an implementation detail that we bury in the fcode to bytecode translator.
As far as reflection goes, the
Func
we get from#foo.func
would have to transparently handle varargs before parlaying the method call to the object, e.g.Likewise for anonymous functions:
One big win we get with varargs is the ability to easily wrap a
Func
as the original post on this thread suggests:Now
wrapperFunc
has effectively the same signature as the wrappedFunc
, without having to know anything about it.For what it's worth, I found myself adding classes into my data binding library design precisely because of the lack of varargs in anonymous functions.
This change would obviously require rolling a new fcode version. I think if we decide to do this, it's worth making varargs a first-class construct in fcode, and to not clutter the fcode with the JVM implementation details discussed above. Those should be implicit in the fcode to bytecode translation.
I hope this all makes sense!
brian Mon 4 Apr 2011
I do think the varargs discussion is sort of orthogonal to the initial problem reported. Varargs might be a potential solution, but in the end in JVM land we still have to box into a list.
I personally don't really see a great need for varargs precisely because it is so trivial to create inline lists:
A bit of noise, but it seems acceptable to me to keep complexity down.
Another perspective is that I'd much rather have named arguments in additional to positional parameters. And I think that any work we did for varargs would interact with named parameters very poorly. So I'd like to keep that option open in the future.