[Python-ideas] Extending expressions using ellipsis

Sjoerd Job Postmus sjoerdjob at sjoerdjob.com
Thu Sep 1 07:26:58 EDT 2016


On Thu, Sep 01, 2016 at 01:38:19PM +0300, Joonas Liik wrote:
> On 1 September 2016 at 11:10, Sjoerd Job Postmus
> <sjoerdjob at sjoerdjob.com> wrote:
> > On Thu, Sep 01, 2016 at 10:43:17AM +0300, Joonas Liik wrote:
> >> Not sure if this is a good idea but it might also make some sense to
> >> in stead have an operator at the beginning of the line
> >>
> >> for example some languages have a chainging operator for method calls:
> >>
> >> my_object.m1()
> >>     ..m2()
> >> being equivalent to
> >> my_object.m1()
> >> my_object.m2()
> >>
> >> It could also be possible to have a special
> >> swallow-the-preceding-newline operator or something of that effect.
> >>
> >> side note: the chainging operator does not work on the return value of
> >> the method thus the method no longer has to choose between returning
> >> useful info or `this` for chaining convenience.
> >
> > Not sure if I would appreciate this. Most of the cases where I do
> > chaining method calls, it's the return value that's being chained on. Of
> > course that is logical, because that's what's currently possible. Also,
> > would it be called 'call forking' instead of 'call chaining'...?
> >
> > But also, what does this mean:
> >
> > my_object.value.m1()
> >     ..m2()
> >
> > is that
> >
> > my_object.value.m1()
> > my_object.value.m2()
> >
> > or
> >
> > my_object.value.m1()
> > my_object.m2()
> >
> >
> > I do think the syntax you suggest is readable, I just think the
> > semantics is confusing and ambiguous in non-trivial examples. And the
> > extra '.' to signify it is chaining is not really a syntactical
> > necessity I think.
> >
> > What I think might be a neat idea is to do the following:
> >
> > if:
> > - we have an 'unexpected indent', and
> > - the line starts with a '.'
> >
> > then:
> > - interpret the physical line as continuation of the previous line.
> >
> >
> > In any current Python version this is a syntax error. In a new Python
> > version it could be *the* obvious way to do method chaining.
> >
> > inactive_admins = User.objects
> >                       .filter(is_staff=True)
> >                       .exclude(last_login__gt=three_weeks_ago)
> >
> > In current versions of Python, you have to add a `\` to the end, in a
> > possible future version of Python, you could leave out the `\`.
> >
> > To be fair, I think this only makes sense for when the next line starts
> > with a `.`.
> >
> > In PEP8 we could add a rule about 'aligning the . with the last dot on
> > the previous line' (or an indent of 4 if the previous line has no dot).
> >
> > Even though I think it would make for a good enhancement to the Python
> > language, I can not currently estimate how much of a change to the
> > Python parser this would need to be. Is it a three-hour straight-forward
> > job, or a three-month bug-prone assignment?
> >
> > Regards,
> > Sjoerd Job
> 
> its just some syntax i've come across in some other language (can't
> recall which one unfortunately), the semantics being ..

After doing some research, turns out this is called 'method cascading'
(not to be confused with 'method chaining'). It is found in Dart, which
has exactly this syntax.

> 
> #you have this
> r = a.b()..c()..d()
> 
> #is equivalent to
> t=a
> a.b()
> a.c()
> r=a.d()


After reading up on this, it seems your example is a bit mistaken. It
would be

    t = a.b()
    a.c()
    r = a.d()

(for the other behaviour, you should do `a..b()..c()..d()`)

It turns out that Dart also has assignment cascading:

    r = Address()
        ..street = "East Avenue"
        ..housenumber = 12

> 
> of yourse if you want to maintain readability you want most calls to
> be on separate lines so
> r = a.b()
>     ..c()
>     ..d() # the return value of the last function is the value of the
> entire expression
> 
> with some some names that are actually descriptive this could quite
> nicely represent a sequence of transformations to something for
> example (is this why jQuery has so much method chaining?)

Seeing "transformations" makes me think of method chaining more than the
method cascading as described above. In jQuery (and also Django
querysets), you don't get the same object back, but a new object.

So Django again:

    qs = User.objects.filter(is_staff=True).filter(is_active=True)

is not equal to

    qs = User.objects
    qs.filter(is_staff=True)
    qs.filter(is_active=True)

but

    qs = User.objects
    qs = qs.filter(is_staff=True)
    qs = qs.filter(is_active=True)

> anyway with method chaing you sometimes (often? rarely?) have an issue
> where you have a meaningful return value so you have to chooze if you
> want to return meaningful output or return self/this to enable
> chaining.
> if you need the return value then you obviously need to capture it but
> sometimes you just want the side effect (mutating state of `self`) and
> don't care about what the method returns.
> 
> if you have this you probably want method chaining to be usable in
> expressions tho, having subsets of language usable in different
> contexts rly gets annoying mmighty fast.

Method chaining is already possible in Python, just sometimes you have
to add a bit of extra characters to make it prettily span multiple
lines. Inside an expression it already works.

Method cascading is not yet possible in Python. To be honest, I think it
is off-topic in this thread, but also that it is something that might be
a good idea. It is however already covered in the following thread...
https://mail.python.org/pipermail//python-ideas/2013-November/024124.html
Not to say that the opinions might not have changed since then...


More information about the Python-ideas mailing list