On Sat, Feb 22, 2014 at 9:31 AM, Masklinn <masklinn@masklinn.net> wrote:
On 2014-02-21, at 18:30 , Chris Angelico <rosuav@gmail.com> wrote:
So here's the proposal. Introduce a new operator to Python, just like the dot operator but behaving differently when it returns a bound method. We can possibly use ->, or maybe create a new operator that currently makes no sense, like .. or .> or something. Its semantics would be:
As Yuri noted the concept exists, AFAIK it was introduced by smalltalk as "message cascading". Basically, the ability to send a sequence of messages to the same subject without having to repeatedly specify the subject. I believe Dart is the first language to have resurrected this feature so far.
Cascading is what I'm looking for here, yes. As noted in the Wiki page Yuri linked to, chaining-with-return-self enables cascading. Consider this to be a proposal to add method cascading to Python. Also, since Dart uses .., that's a good reason to use .. here too.
1) Look up the attribute following it on the object, exactly as per the current . operator 2) If the result is not a function, return it, exactly as per current. 3) If it is a function, though, return a wrapper which, when called, calls the inner function and then returns self.
I could be wrong, but I'm pretty sure this is an over-complication when you look at it at the bytecode level: you can load the subject as many times as you've got attr accesses to do on it, or you could have an alternate attr access which puts TOS back. No need for a wrapper.
That would be a job for the peephole optimizer. What happens if you do this: func = x..y # more code func().z It can't just leave x on the stack, but it has to have the same semantics. But I agree, the DUP_TOP form would be excellent for the common case:
No need for a wrapper. Where `a.b` compiles to
LOAD_FAST a LOAD_ATTR b POP_TOP
`a->b` would compile to
LOAD_FAST a DUP_TOP LOAD_ATTR b POP_TOP
at this point you've got an a left on the stack and can reuse it:
`a->b()->c()->d()` would be
LOAD_FAST a
DUP_TOP LOAD_ATTR b CALL_FUNCTION POP_TOP
DUP_TOP LOAD_ATTR c CALL_FUNCTION POP_TOP
DUP_TOP LOAD_ATTR d CALL_FUNCTION POP_TOP
Or maybe it would do nothing special and the cascade would yield (or pop) the subject unless closed by an attribute access or regular method call. That would avoid the requirement of a `yourself`-type method when initialising mutables, although the final irregularity may lack visibility.
Yes, it would do that. If you use .. everywhere, then the end result of the whole expression should be the original object. In Pike GTK, where most methods return themselves, I can do this: object window = GTK2.Window(0) ->set_title("Title!") ->add(some_object) ->show_all(); The return value from show_all() is the original window. With explicit method cascading, I could either capture the return value of the last function call by choosing _not_ to use cascading there, or I could capture the original object by continuing the cascade. (In the case of GUI work like this, I'd default to cascading, if I were not using the result of the expression. It'd mean that adding or deleting lines of code wouldn't risk changing anything - it's like permitting a trailing comma in a tuple/list.) ChrisA