-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Possible syntax for infix operators #5937
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
Comments
When it comes to operators, current Scala has two simple rules:
Simple as these rules are, they give a lot of flexibility. The problem is that syntactic flexibility like that can lead to choice paralysis and disagreement what style to use. Concretely, there are two problems:
A rule to combat (1) is that every symbolic operator should be an alias of an alphanumeric method, which can be googled more easily. It's a good rule, but it is tedious to write two methods instead of one, so one might be tempted to cut corners. As to (2), the problem is that it's hard to come up with a hard rule that works for everyone.
Some would also write
I have even seen
I admit this made my eyes pop. The problem is that there's no clear guidance what to use. I have recently started to never write alphanumeric methods directly as infix operators. Mostly I use method syntax, and if that feels too unnatural I resort to put the operator in backticks. I.e.
instead of
But that's also just a convention, which is enforced by nothing. |
The choice paralysis problem probably has to be solved by delegating the choice to someone else, typically (but not necessarily) the library author. During the discussions on extension methods, I postulated (somewhere) a slightly radical idea that it should only be possible to define infix and/or symbolic methods as extension methods, something like:
If we were to force method definitions to be alphanumeric (non-symbolic) only, then using symbolic operators (those not in So if you really wanted to use methods like |
A rule to combat (1) is that every symbolic operator should be an alias
of an alphanumeric method, which can be googled more easily. It's a good
rule, but it is tedious to write two methods instead of one, so one might
be tempted to cut corners.
If it were an enforced rule, how could one cut corners (other than by
omitting the symbolic alias)?
…On Sun, Feb 17, 2019 at 1:43 PM Jon Pretty ***@***.***> wrote:
The choice paralysis problem probably has to be solved by delegating the
choice to someone else, typically (but not necessarily) the library author.
During the discussions on extension methods, I postulated (somewhere) a
slightly radical idea that it should only be possible to define infix
and/or symbolic methods as extension methods, something like:
def (m1: Matrix) + (m2: Matrix) = m.add(m2)
If we were to force method definitions to be alphanumeric (non-symbolic)
only, then using symbolic operators (those not in Predef) would require
an explicit import to indicate where they come from.
So if you really wanted to use methods like flatMap and map in infix
style, then you still could, but you would have to want to do it enough to
define them as extension methods. And methods like eq could be infix
extension methods defined in Predef.
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#5937 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAGAUFYBNAKcjZgGH_grQ4MJTAjAhQrFks5vOaLBgaJpZM4a_sWC>
.
|
One possibility to solve (1) and (2) together would be to introduce an
and with argument:
The simple form can be understood to be an abbreviation of the parameterized form where the method name is repeated. I.e. the
Some possible rules would be:
Rules (1-3) introduce a convenient syntax to define an operator name with a normal method. Rules (4-5) are normative; they rule out existing possibilities. Adopting rule (5) has the advantage that then all fields and methods could be represented in alphanumeric form. Since the operator name is used purely internally, it needs not be translated to bytecode. This is also great for interoperability with other languages. Similar rules could be introduced for types. I.e. all type definitions must be alphanumeric but they can have Another question is what is the best syntax for infix declarations. I have used
Other possibilities would be:
Not sure what's best. Annotations look probably most familiar, but this might be considered to overstretch annotation usage to influence typing and name resolution like this. |
Two more rules, which are left out so far, could be:
Without (6) and (7), it is still possible to define symbolic nouns. E.g. use
It's admittedly a mis-use of notation since there is nothing |
It looks very strange to put the infix operator inside quotes, especially if the decision is taken to introduce a new |
This would be quite painful on the browser side, for the same reason Sébastien recently cited: |
@jducoeur In fact |
Recap'ing my opinion on the matter from the offline meeting: I think the proposal stated above tries to address the initial problem with solutions that are too complicated. And in doing so, it will pose non-trivial compatibility and migration issues. Here is a different proposal that addresses the core problems with a different solution with minimum impact. Let me start with the problem of variations in style, which is also presented as choice paralysis. As was mentioned by @propensive, we can make sure the choice is enforced to the library author, rather than every call site. For that, I propose an annotation @infix
def +=(that: A): Unit = ... The presence or absence of the annotation dictates the style to use at call site. If I call Note that About the overuse of symbolic names, the proposal suggests that we use alphanumeric aliases (whether "by hand" or with dedicated syntax). I think this is a mistake---and I had already said that about aliases in the 2.13 collections---because that very solution leads to choice paralysis itself: am I supposed to use If we come back to the initial problem that aliases wanted to address, they were twofold:
The two problems can be solved in a way that does not affect typechecking in Scala and does not lead to choice paralysis either: use another annotation, whose name I am yet unsure of but I'll use @infix @name("append")
def +=(elem: A): Unit = ... The string in the annotation is used by IDEs and other tools as help text. It could even come up in auto-completion. But the only valid name in Scala source code remains A warning/error could also be emitted if a method with a symbolic name does not have For compatibility with Scala 2, we can very easily define the annotations in the 2.14 library. They might not be checked by Scala 2, but they will be good enough for cross-compilation purposes. The checks are also simple enough that they could be backported to Scala 2 without too much effort, I believe. |
@sjrd I like that proposal! One potential abbreviation would be to merge @infix and @name. I.e. @infix("append")
def +=(elem: A): Unit = ... Being shorter, it will encourage stating alphanumeric aliases. We could retain |
If symbolic operators will have an annotation specifying the JVM name of
the method, would the whole $bang$plus encoding scheme become unnecessary?
…On Mon, Feb 18, 2019 at 12:14 PM odersky ***@***.***> wrote:
@sjrd <https://github.com/sjrd> I like that proposal! One potential
abbreviation would be to merge @infix <https://github.com/infix> and @name
<https://github.com/name>. I.e.
@infix("append")
def +=(elem: A): Unit = ...
Being shorter, it will encourage stating alphanumeric aliases. We could
retain @name as an annotation that can be used stand-alone, in case we
want to have a symbolic thing that is not an infix operator. But maybe it
should be @externalName or something like that, then.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#5937 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAGAUNdruuj2k2p3E69O-bMwfnWflSaYks5vOt9ngaJpZM4a_sWC>
.
|
@odersky The merge is shorter, but its meaning is very misleading IMO.
A warning when omitting @nafg In theory, yes. In practice, dropping it right away would expose us to regressions in mixed Scala/Java codebases where Java already calls some |
@sjrd I see your argument. Maybe |
Yes, |
I agree that this doesn't make sense, but I thought that this is already handled elsewhere. I don't really agree that all the other problems stated here are actually problems that require solving. Or that the extra rules and handholding are strictly better than the problems they are solving. Perhaps an optional |
Personally I think consistency is worth more than avoiding some boilerplate. I really like working with Scala, but I think one of the biggest problems we face in using it professionally is that there is too much room for personal style. Now you can use linters and formatters, but I think it would be nice if Scala itself became a bit more opinionated. This proposal goes in that direction and I am favor, regardless if it becomes a keyword or annotation, or something else that achieves the same thing. |
In some sense I couldn't agree more. It's what I like about the way it is now: all operators are just methods, every call is a method call, all methods are treated equally. |
Consistency, like simplicity, is always relative. Often consistency and simplicity on the level of a programming language is in direct conflict with consistency and simplicity of the programs written in that language. |
#5975 now defines a doc page that gives an elaboration of the proposed rules for |
alpha as an annotation looks good. Should we have infix as a modifier like override? |
No description provided.
The text was updated successfully, but these errors were encountered: