This is a proposal based on #682 to remove the & operator, in favor of just using closures.
Current & operator and its closure equivalents:
&foo => |,| { foo }
&foo(a) => |,| { foo(a, b) }
&foo(a, b) => |,| { foo(a, b) }
&foo(a, b) => |c,d| { foo(a, b, c, d) }
A bit more chars to express the same concept, but I find that after two years I use this operator very little. I think this is a case where we can remove a feature and save some of our complexity budget.
If you care, please give me a yeah or nay.
tcolarWed 29 Jul 2009
yeah.
can the & be used for field access then ? (don't like the *)
tompalmerWed 29 Jul 2009
Although & is still already a binary operator.
tcolarWed 29 Jul 2009
Right kinda forgot that (binary and).
Though i don't think continuing a binary operation after a new line is nearly as commonly done at all.
But yeah i guess it still needs smarts as far as a parse goes.
Note though, there where a few other grammar items that required to be "smart" with newlines anyway. Examples:
indexExpression: if [] is after a newline it's not an index expr.
I think mostly I'm okay with this, the only thing is there's a pretty common use case -- using curry to pass a callback function to an event handler -- that's convenient and familiar to probably a lot of people coming to Fan.
On the + side, with both curry and closures, there's the confusion over when to use which and whether there's a difference.
Overall I think I'm in favor of removing curry; then all the places where it's currently used in the Fan distro, will provide an intro to closure usage for those (like me) that haven't spent a lot of time in languages that use it.
qualidafialWed 29 Jul 2009
+1
jodastephenWed 29 Jul 2009
I think this change suits Fan, although the FP lovers will hate the change no doubt.
I also think that this is related to Bound methods/Properties which tackles issues that more commonly crop up in coding.
brianWed 29 Jul 2009
I think this change suits Fan, although the FP lovers will hate the change no doubt.
True, but I don't think FP lovers like Fan to begin with
And it frees up & for a prefix operator. True it is also a binary operator, but it was one that was never used when not on the RHS of an assignment or as argument to a method because it wasn't a complete statement otherwise.
jodastephenWed 29 Jul 2009
Oh, I'm in favour of the change, but have a feeling that something very similar will return with proper properties/bound methods.
brianWed 29 Jul 2009
Oh, I'm in favour of the change, but have a feeling that something very similar will return with proper properties/bound methods.
I agree, but now we will be free to develop that feature without worrying about how it interacts with curry operator.
Any other yeahs or nays?
heliumWed 29 Jul 2009
yeah
alexlamslWed 29 Jul 2009
Oh Yeah.
Edit: May I ask humbly what is FP in the conversation above?
brianWed 29 Jul 2009
Functional Programmers (at least that was what I thought we were talking about)
freddy33Thu 30 Jul 2009
+1 The & is quite confusing and the closure syntax very clear. I just modified our parser for the * operator for field access. Conclusion: I don't like it, and & will feel/look a lot better.
brianSun 9 Aug 2009
Promoted to ticket #697 and assigned to brian
brianSun 9 Aug 2009
OK, here is the major problem with removing the curry operator today...
Today there is a subtle (and one might say confusing) difference between how a closure and curry binds its scope. A closure binds local variables as true variables, but curry binds strictly by reference at the time the curry is created.
Consider this program:
x := "alpha"
closure := |,| { echo(x) }
curry := &echo(x)
closure()
curry()
x = "beta"
closure()
curry()
This will print:
alpha // closure
alpha // curry
beta // closure now uses new value of x
alpha // curry bound to what x was originally
The reason this is important is because it determines the immutability of the function. In the code above closure is mutable, but curry is immutable.
This problem must be solved in order to allow closures to replace curry everywhere they are used.
The most obvious solution is to duplicate Java's use of final keyword on local variables. But I'd like to hear other ideas.
KevinKelleySun 9 Aug 2009
I was wishing for final the other day, trying to figure some way to pass a closure to an actor so it could do tick callbacks to a window, and I kept getting not immutable errors.
Ended up figuring out I could get a curry to work -- without quite understanding that this is why.
So:
final w := (Widget)this
Ticker(20ms).send(|,| { w.repaint })
where ticker calls the func then uses sendLater(delay) to send it back to itself.
andySun 9 Aug 2009
A keyword modifier seems natural here (I assume you will use const here vs final). Its a bit more verbose potentially, but given how little this use case has popped up, seems fine. Plus its useful beyond the curry/closure case.
JohnDGSun 9 Aug 2009
const means the object pointed to by the reference is immutable and cannot change. final means the reference is immutable and cannot be reassigned to a different instance. Each refers to a different thing, and const final has a meaning unique from either const or final alone.
andySun 9 Aug 2009
You can make that distinction, but Fan does not already. A const field implies both. So I would assume we would extend the same to local variables. I think its much simpler to use one term, even if its not 100% technically correct.
KevinKelleySun 9 Aug 2009
In Fan terms once might be appropriate for this.
Or, is there a way to avoid adding to the keyword load by letting closures be immutable if they don't do anything stupid? I don't know exactly what that would mean though.
brianMon 10 Aug 2009
Well both final or const would solve this particular problem. Final (or once) locals with semantics of Java would mean the reference cannot be reassigned - that would allow me to optimize heap local variables similar to how inner classes work today in Java (although Fan seems to be running pretty darn fast even with heap based locals).
Const would be a stronger guarantee than final, but has the ugly problem that it leaks into the signature:
Void m(const Str[] m)
If we ever did support const params/locals, then I would expect that signature leaked into the call site as:
m(list.toImmutable)
But after some more thought I think we can avoid all this ugliness and complexity and follow the same convention as I already use in List and Map by just having a Func.toImmutable method.
In fact, I am actually going to rework things a bit and put this as a method on Obj:
class Obj
{
This toImmutable()
}
It will continue to work as is for List and Map, and closures will do something similar by calling toImmutable on all their bound arguments. This actually will plug up a hole I've been meaning to fix in the const type system when working with const Obj fields.
tcolarMon 10 Aug 2009
Nice ! I actually was thinking about how it would be cool to have toImmutable available globally few days ago.
KevinKelleyMon 10 Aug 2009
Perfect. Hg pull.
brianWed 4 Nov 2009
Ticket resolved in 1.0.47
The compiler code for the deprecated & operator has been fully removed.
Method? method()
Return the associated method if this function implements a
method slot. If this function a is curried method using
the "&" operator method call syntax, it will return the
associated method. Otherwise return null.
brian Tue 28 Jul 2009
This is a proposal based on #682 to remove the
&
operator, in favor of just using closures.Current
&
operator and its closure equivalents:A bit more chars to express the same concept, but I find that after two years I use this operator very little. I think this is a case where we can remove a feature and save some of our complexity budget.
If you care, please give me a yeah or nay.
tcolar Wed 29 Jul 2009
yeah.
can the
&
be used for field access then ? (don't like the*
)tompalmer Wed 29 Jul 2009
Although
&
is still already a binary operator.tcolar Wed 29 Jul 2009
Right kinda forgot that (binary and).
Though i don't think continuing a binary operation after a new line is nearly as commonly done at all.
But yeah i guess it still needs smarts as far as a parse goes.
Note though, there where a few other grammar items that required to be "smart" with newlines anyway. Examples:
indexExpression: if [] is after a newline it's not an index expr.
callParams: () as to be on same line.
typeLitteral: # need to be on same line
and so on
That's what the notAfterEol() stuff is for in my ant grammar (a bit ugly) http://svn.colar.net/Fan/src/net/colar/netbeans/fan/antlr/Fan.g
KevinKelley Wed 29 Jul 2009
I think mostly I'm okay with this, the only thing is there's a pretty common use case -- using curry to pass a callback function to an event handler -- that's convenient and familiar to probably a lot of people coming to Fan.
On the + side, with both curry and closures, there's the confusion over when to use which and whether there's a difference.
Overall I think I'm in favor of removing curry; then all the places where it's currently used in the Fan distro, will provide an intro to closure usage for those (like me) that haven't spent a lot of time in languages that use it.
qualidafial Wed 29 Jul 2009
+1
jodastephen Wed 29 Jul 2009
I think this change suits Fan, although the FP lovers will hate the change no doubt.
I also think that this is related to Bound methods/Properties which tackles issues that more commonly crop up in coding.
brian Wed 29 Jul 2009
True, but I don't think FP lovers like Fan to begin with
And it frees up
&
for a prefix operator. True it is also a binary operator, but it was one that was never used when not on the RHS of an assignment or as argument to a method because it wasn't a complete statement otherwise.jodastephen Wed 29 Jul 2009
Oh, I'm in favour of the change, but have a feeling that something very similar will return with proper properties/bound methods.
brian Wed 29 Jul 2009
I agree, but now we will be free to develop that feature without worrying about how it interacts with curry operator.
Any other yeahs or nays?
helium Wed 29 Jul 2009
yeah
alexlamsl Wed 29 Jul 2009
Oh Yeah.
Edit: May I ask humbly what is
FP
in the conversation above?brian Wed 29 Jul 2009
Functional Programmers (at least that was what I thought we were talking about)
freddy33 Thu 30 Jul 2009
+1 The & is quite confusing and the closure syntax very clear. I just modified our parser for the * operator for field access. Conclusion: I don't like it, and & will feel/look a lot better.
brian Sun 9 Aug 2009
Promoted to ticket #697 and assigned to brian
brian Sun 9 Aug 2009
OK, here is the major problem with removing the curry operator today...
Today there is a subtle (and one might say confusing) difference between how a closure and curry binds its scope. A closure binds local variables as true variables, but curry binds strictly by reference at the time the curry is created.
Consider this program:
This will print:
The reason this is important is because it determines the immutability of the function. In the code above closure is mutable, but curry is immutable.
This problem must be solved in order to allow closures to replace curry everywhere they are used.
The most obvious solution is to duplicate Java's use of
final
keyword on local variables. But I'd like to hear other ideas.KevinKelley Sun 9 Aug 2009
I was wishing for
final
the other day, trying to figure some way to pass a closure to an actor so it could dotick
callbacks to a window, and I kept getting not immutable errors.Ended up figuring out I could get a curry to work -- without quite understanding that this is why.
So:
where ticker calls the func then uses sendLater(delay) to send it back to itself.
andy Sun 9 Aug 2009
A keyword modifier seems natural here (I assume you will use
const
here vsfinal
). Its a bit more verbose potentially, but given how little this use case has popped up, seems fine. Plus its useful beyond the curry/closure case.JohnDG Sun 9 Aug 2009
const
means the object pointed to by the reference is immutable and cannot change.final
means the reference is immutable and cannot be reassigned to a different instance. Each refers to a different thing, andconst final
has a meaning unique from eitherconst
orfinal
alone.andy Sun 9 Aug 2009
You can make that distinction, but Fan does not already. A
const
field implies both. So I would assume we would extend the same to local variables. I think its much simpler to use one term, even if its not 100% technically correct.KevinKelley Sun 9 Aug 2009
In Fan terms
once
might be appropriate for this.Or, is there a way to avoid adding to the keyword load by letting closures be immutable if they don't do anything stupid? I don't know exactly what that would mean though.
brian Mon 10 Aug 2009
Well both
final
orconst
would solve this particular problem. Final (or once) locals with semantics of Java would mean the reference cannot be reassigned - that would allow me to optimize heap local variables similar to how inner classes work today in Java (although Fan seems to be running pretty darn fast even with heap based locals).Const would be a stronger guarantee than final, but has the ugly problem that it leaks into the signature:
If we ever did support const params/locals, then I would expect that signature leaked into the call site as:
But after some more thought I think we can avoid all this ugliness and complexity and follow the same convention as I already use in
List
andMap
by just having aFunc.toImmutable
method.In fact, I am actually going to rework things a bit and put this as a method on Obj:
It will continue to work as is for
List
andMap
, and closures will do something similar by callingtoImmutable
on all their bound arguments. This actually will plug up a hole I've been meaning to fix in the const type system when working withconst Obj
fields.tcolar Mon 10 Aug 2009
Nice ! I actually was thinking about how it would be cool to have toImmutable available globally few days ago.
KevinKelley Mon 10 Aug 2009
Perfect. Hg pull.
brian Wed 4 Nov 2009
Ticket resolved in 1.0.47
The compiler code for the deprecated
&
operator has been fully removed.tactics Tue 15 Dec 2009
Found some doc that needs fixing in http://fantom.org/doc/sys/Func.html#method