for context of discovery, see #6227.
I found that functionPerformList
is defined everywhere as
functionPerformList { arg selector, arglist;
But in IdentityDictionary, it is used as:
^func.functionPerformList(\value, this, args);
// and for forwarding
^func.functionPerformList(\value, this, selector, args);
So because the primitive _ObjectPerformList
is called, this does something that is not really documented and clear:
{ |...args| args }.functionPerformList(\value, 1, 2, 3, [7, 8, 9]) // -> [1, 2, 3, 7, 8, 9]
A shame, because we could have extended the functionality (e.g. adding a dictionary of keywords).
I remember that @rjk complained about the excessive use of ellipsis arguments many years ago.
Now I thought that, object prototyping is broken for higher order functions (Maybe, UnaryOpFunction, BinaryOpFunction and NaryOpFunction). This is (I thought) my mistake long ago, when I reproduced the signature of Function::functionPerformList
for the others.
But it isn’t,
(
q = ();
q.func = { |self, x, y, z| [x, y, z] };
q.unary = { |self, x, y, z| [x, y, z] }.neg;
q.binary = { |self, x, y, z| [x, y, z] } + 2;
q.maybe = Maybe({ |self, x, y, z| [x, y, z] });
)
q.func(1, 2, 3);
q.unary(1, 2, 3);
q.binary(1, 2, 3);
q.maybe(1, 2, 3);
q[\func].functionPerformList(\value, q, 1, 2, 3);
q[\unary].functionPerformList(\value, q, 1, 2, 3);
q[\binary].functionPerformList(\value, q, 1, 2, 3);
q[\maybe].functionPerformList(\value, q, 1, 2, 3);
This works, because:
// this is how BinaryOpFunction defines it:
functionPerformList { arg selector, arglist;
^this.performList(selector, arglist)
}
b = { |x, y, z| [x, y, z] } * 2;
b.functionPerformList(\value, 1, 2, 3); // -> [2, 4, 6]
// I would have expected this to be: [1, nil, nil]
f = { |selector, arglist| arglist };
f.(1, 2, 3); // -> 1, and not [1, 2, 3]
And perhaps, for some very weird reason?
It might be due to an optimization in the compiler, that aliases
BinaryOpFunction::functionPerformList
with
Object::performList
which automatically expands the arguments.
This is how to shoot yourself in the foot by building on implicit features, which make it impossible in this case to extend the interface …
Thoughts?