Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

permit a<space>.b syntax, if possible #17305

Open
xitology opened this issue Jul 6, 2016 · 15 comments
Open

permit a<space>.b syntax, if possible #17305

xitology opened this issue Jul 6, 2016 · 15 comments
Assignees
Labels
parser Language parsing and surface syntax

Comments

@xitology
Copy link
Contributor

xitology commented Jul 6, 2016

Julia 0.4 deprecated and Julia 0.5-dev made an error the a<space>.b syntax:

julia> a .b
ERROR: syntax: space before "." not allowed in "a ."

It prevents me from using a "method-chaining" pattern, which is common in some languages and frameworks:

(obj.meth1(...)
    .meth2(...)
    .meth3(...))

Admittedly, it is less common in Julia as it lacks special method syntax, but I happen to use it in my experimental Julia-based query DSL:

@query(
    table
    .filter(predicate)
    .group(attribute)
    .select(...))

It is possible to un-deprecate this syntax? I found the original commit 28e7bd4, but it has no justification for deprecating it in the first place.

@tkelman
Copy link
Contributor

tkelman commented Jul 6, 2016

If you're making a macro dsl, you should probably use an infix operator.

@xitology
Copy link
Contributor Author

xitology commented Jul 6, 2016

@tkelman From my perspective, . is an infix operator since (a+b).(c+d) is well-formed Julia syntax.

@JeffBezanson
Copy link
Member

This was discussed extensively in #11891 and #7232.

Since julia doesn't require semicolons at the ends of statements, the pattern

(obj.meth1(...)
    .meth2(...)
    .meth3(...))

doesn't work well because after obj.meth1(...) we don't know to expect any further expressions.
However putting the dot at the end of the line solves this. The following parses fine:

@query(
    table.
    filter(predicate).
    group(attribute).
    select(...))

@gabrielgellner
Copy link
Contributor

@xitology but an infix operator that doesn't allow spaces ;) Is there any reason not to use |> instead? feels like it would read better. I like that dot is forced to be written tightly. We have so many uses of . now with the broadcast notation, I think it is important to keep the use of it constrained so that code is written in a more consistent manner.

@xitology
Copy link
Contributor Author

xitology commented Jul 6, 2016

My (ab)use of Julia syntax is certainly unorthodox and I'm sure will be frowned upon by Julia developers. The . is used as a monadic composition operation (like >=>), while for |> I use :. You can see real examples here and here. As you can see, . is being used to mimic attribute access and using any other operator in place of . will make the syntax much more heavyweight.

That said, I don't want to make it a discussion of my stylistic choices in DSL design. This is hardly a great argument for changing language parser. I just used it as one example where one might prefer method-chaining.

As opposed to f<space>(, which is, arguably, poor style, and shouldn't appear in real code, it's not unreasonable to see a<space>.b in code like this:

somefunc(
    big_expr
    .attr)

Indeed, you could write

somefunc(
    big_expr.
    attr)

but I think the former is more stylistically appropriate and would be the first choice for most programmers.
I understand that you cannot use it without wrapping in parentheses, but that's also the case in Python.

I don't know if it interferes with other language features (like @macro<space>()), but if not, I just don't see why it must be prohibited.

@xitology
Copy link
Contributor Author

xitology commented Jul 6, 2016

I'm sorry for spamming this issue, but here's another argument. Even though currently method-chaining APIs for Julia do not exist, it looks like you are going to enable overriding the attribute access operator (see #1974). If so, I'm sure method-chaining APIs will appear even without macros, so this issue will probably be raised again.

@KristofferC
Copy link
Member

There doesn't seem to be anything actionable here.

@clarkevans
Copy link
Member

@JeffBezanson Is it that it would be inconvenient in the parser to support this, or that it's just plain impossible to support? This is a particularly important case for us for code ergonomics reasons.

@JeffBezanson
Copy link
Member

It's certainly possible; indeed we allowed it prior to v0.4. We decided to remove it in #11891, but it seems to me the argument there wasn't overwhelming, and indeed a couple people said we might want to revisit this if we added dot overloading, which we did.

Could you give an example of the specific syntax you'd like to use? One thing we probably cannot support is

obj.method1(x)
   .method2(y)
   .method3(y)

However it already works if you put the dots at the end of lines:

obj.method1(x).
    method2(y).
    method3(y)

Some people seem to consider that completely unacceptable, but that seems overly fussy to me.

@StefanKarpinski
Copy link
Member

Would it be possible to at least allow parsing the former syntax inside of parens? In either case, it would be a nonbreaking change.

@JeffBezanson
Copy link
Member

If we removed the rule about spaces before dots, yes, I think that would just work. People will surely then try it in statement position though.

@clarkevans
Copy link
Member

clarkevans commented Mar 20, 2018

First, thank you for looking again at this ticket. As Kyrylo noted above, our primary use case is "abusing" the @macro syntax parser in order to construct a familiar "fluent interface". As such, I don't think using leading periods "in statement position" would be particularly common. Currently, we have single line queries, such as below.

@query(department.filter(count(employee)>2).count())

As the queries get much longer and involved, we'd like a way to make them multi-line. Of course, we could ask users to use the period at the end of each line, as Jeff noted. I don't think it is particularly nice to read or customary. Further, as you append new operators to the end, you have to modify the previous line for the trailing period, and hence it shows up as 2 lines changed in source code control rather than a single insertion. Here's how we'd prefer to line-break the previous query for readability.

# doesn't work
@query(
  department
 .filter(count(employee)>2)
 .count()
)

One potential alternative is the begin/end variant. However, I can't collapse it all into a single line without adding periods; this is an odd rule to explain to casual users. That said, adding another query in the chain doesn't involve modifying previous lines. So, this is probably the alternative we'd promote if leading-periods is not permitted.

@query begin
    department
    filter(count(employee)>2)
    count()
end

We have tried to use |> at the beginning of each line, and that works, however, |> is a visually large indicator and gets to be quite ugly in single-line forms with involved compositions. The period (.) is really the best "non-distracting" indicator for expression composition. Of course, long term, we may need to implement our own parser. That said, our desire to create a "fluent" interface for a complex library will not be uncommon.

@JeffBezanson
Copy link
Member

Ok, we can make the parenthesized @query( ) case work just by removing the error. Beyond that, the "fluent" syntax comes from languages that require semicolon statement delimiters, so we're probably stuck there.

@clarkevans
Copy link
Member

clarkevans commented Mar 20, 2018

Kyrylo also mentioned it's usefulness in regular function calls.

somefunc(
    big_expr
    .attr)

Is this the same production? Also, I think Kyrylo noted that
having parenthesis required is the case for Python as well.

@JeffBezanson
Copy link
Member

Yes.

@JeffBezanson JeffBezanson added the parser Language parsing and surface syntax label Mar 20, 2018
@JeffBezanson JeffBezanson added this to the 1.x milestone Mar 21, 2018
@JeffBezanson JeffBezanson reopened this Mar 21, 2018
@JeffBezanson JeffBezanson self-assigned this Apr 4, 2018
@DilumAluthge DilumAluthge removed this from the 1.x milestone Mar 13, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
parser Language parsing and surface syntax
Projects
None yet
Development

No branches or pull requests

8 participants