-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Use := for Assignment #7598
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
Could you clarify if |
I believe it should be written |
This change does not play well with the desugaring of i += 1 now desugars into i := i + 1 while xs +:= 5 desugars into xs := xs.+:(5) |
Poking at this, it sounds like you're suggesting Most obviously, what does a
or
Either way, it winds up feeling rather asymmetrical against:
And @sjrd beat me to talking about While I'm not dead-set against this one, I think I'm against trying to rush it into 3.0 this late in the process. This would have to happen slowly, over several releases, anyway, so I don't think it qualifies for the "rewrite all the textbooks" argument. I'd recommend putting this one off and giving it sufficient time for thought and experiment... |
I believe a var x := 1 One can argue either way, but ultimately, that's the safe choice. The fact that it's different from Operators: I don't see the problem. |
What would you suggest to user-land code that made use of |
Yes, there's a ton of DSLs that heavily use |
@dwijnand That is addressed by
|
Hum but then how do you actually assign something to a var whose type has a |
Another thing: this will not work well with setters defined as def x: Int = ...
def x_=(v: Int): Unit = ... How do you explain that foo.x := 5 desugars into foo.x_=(5) and not foo.x_:=(5) |
Yes, setters are an issue. For compatibility we probably have to leave them as |
You mean a |
Or maybe you're forced to backtick-escape: var foo = SettingKey[String]("foo", "")
foo := SettingKey[String]("foo", "Use foo to foo")
foo `:=` "bob" |
Yes, maybe we can add a special rule that backtick-escape always means straight assignment. But I'd like to see some actual use cases first. |
I don't think any special rule is necessary - wrapping the LHS in parenthesis (i.e. |
What about extension methods (currently via implicit classes) that use |
No, since the priority goes the other way: if the variable's type has an applicable method |
It's exactly the same rules as for assignment operators. So, extension methods are supported. |
FWIW, I develop a DSL that uses |
Just want to add that Scala already achieves this: initialization/definition and mutation can be distinguished in syntax easily. Given any code snippet, it's easy to find all mutations on the first sight. This is not true in Java, where an immutable final field can be initialized via assignment. For language ergonomics, when there is no syntactic ambiguity and semantic ambiguity for the compiler and for programmers, reuse of the same symbol may be beneficial. For example, in natural languages:
In each sentence, the meaning of |
I don't mind this change either way, as long as things like Scalatags or Scala-Js-React do not break, but this line sticks out:
Does that mean a Maybe |
Can we not change things unless there is a really, really strrong reason?
def incr = x = x + 1
This is terribly wrong on several levels. It's hard to parse and uses
equals for two fundamentally different things. By itself, x = x + 1 makes
no sense either, and requires embarrassing explanations for everyone new to
programming.
I don't buy this argument.
1. It's not hard to parse, and if it is you can break it up onto another
line. How common is this anyway?
2. The two uses of equals are close enough and unambiguous enough that
there's nothing wrong with using the same symbol for both.
3. I don't see how x := x + 1 makes any more sense than x = x + 1. Maybe
what's confusing is that the idea of a var is confusing. So let people
program more functionally and this issue is irrelevant. Maybe
reassignment is an advanced feature that shouldn't be taught too early. In
any case one can always write x_=(x + 1)...
(Technically, IIUC := is more appropriate for a definition than for
reassignment, but of course it would be even worse to change definition
syntax.)
…On Thu, Nov 21, 2019 at 10:28 PM Li Haoyi ***@***.***> wrote:
I don't mind this change either way, as long as things like Scalatags or
Scala-Js-React do not break, but this line sticks out:
That is, in a := b, if the left hand side has an applicable method named
:= the assignment is rewritten to a.:=(b).
Does that mean a var thing: {def := } could never be mutated? That
doesn't seem like a particularly good outcome. In particular, the way
update is de-sugared isn't comparable at all because it is ambiguous: foo(x)
= y cannot be anything else other than an .update call.
Maybe var thing: {def := } is an uncommon scenario to be in, but we
shouldn't make uncommon scenarios impossible
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#7598>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAAYAUEMFC3PYOOIXJUDYFTQU5GWJANCNFSM4JQA26SA>
.
|
We had a discussion about this above, but for clarity let me add the full types: class Ref[X] { def := (x: X): Unit = ??? }
var x, y: Ref[Int] = new Ref[Int]
x := 1 // calls the method
y := x // is a primitive assignment, since the method is not applicable We would make assignments impossible if we defined class Ref[X] { def := (x: Any): Unit = ??? } Maybe we need an escape hatch for these situations such as putting |
I like this proposal. In Haskell, the use of One small thought: Scala excels at DSLs, and It'd be nice if This would open the playing field to alternate versions of val ref = new AtomicRef[Int](0)
ref := 1 // ref.:=(1)
ref := 2 // ref.:=(2)
ref += 4 // ref.update(_ + 4) |
In my opinion the cost of introducing this change (code, corner cases, making people like it and use it) is bigger than the gains from this change. |
This was once implemented in the Virtualized Scala fork. |
Will the return type of new assignment operator still be |
@lbialy I think this pattern is an ugly hack for imperative languages to make up for the fact that they don't have an expression-based syntax. In Scala, you'd just write: while ({ c := inputStream.read(buf); c != -1 }) { ... } And with the new control syntax it would become the more elegant: while { c := inputStream.read(buf); c != -1 } do { ... } |
Another option is to use |
I think we need an escape hatch. "oh you cannot ever assign We shouldn't be willing to take shortcuts for common cases at the expense of making uncommon cases literally impossible. |
I've been thinking about this proposal for a few days now and the more I think about it the more I like it. It improves clarity by distinguishing definition and assignment (the At a glance, I don't like the new proposal by @lihaoyi directly above this comment because it seems to only address the It's unfortunate that a good amount of the discussion in this thread (and in other channels) has been rather reactionary and not really about the merits or demerits of the proposal. Regardless of whether or not this proposal is accepted, I find it difficult to imagine that the success of scala 3 is contingent on this minor (though still quite beneficial in my view) syntactic change. I also find the notion that new and existing developers will struggle with learning The points that Heather Miller made in her scale by the bay keynote are relevant to the current scala 3 hysteria. The software development field is growing so quickly that newcomers will outnumber the old heads in the blink of an eye. If 70% of scala 2 users abandoned scala due to the scala 3 changes, scala 3 could still be an enormous success if it spurred growth in new areas. The growth trends for scala 2 do not seem great so it seems foolish to bend over backwards to accommodate all of the legacy use cases. For all the handwringing about the python 2/3 split, last time I checked it was both one of the most popular languages and fastest growing. Right now, scala can't really make either claim. |
What would you propose as an alternative to the dotty status quo for getting feedback on new language syntax? I have read a number of blog posts about experimenting with dotty which imply that a number of non-epfl people (including people working in industry as well as hobbyists) have been tinkering with dotty. It would certainly be foolish to disregard feedback from anyone out of hand -- and I doubt that @odersky literally meant that you need to use dotty for months to offer feedback even if the stockholm syndrome comment was a bit alienating -- but he has a point that often you do have to try something for a while to properly evaluate it. I've learned this is the case with restaurants just as much as programming. I fear that if progress in scala is dictated by industry and reddit threads, it will pander to the lowest common denominator. |
Respect for people's experience, history of contributions, demonstrated competence, and knowing what they want is a reasonable alternative. People here have years-to-decades long careers working in dozens of different languages and environments, many of which have syntax similar to that being proposed. We're not a class of 1st year undergraduates. Imagine if you were a salesperson trying to hawk some SAAS software, and your sales pitch was "you have to try it for months, we promise you that you'll grow to like it". They'd think you're crazy, and for good reason, because you probably are. The whole point of a design document/proposal/discussion process is to build consensus without everyone having to spend large amounts of time becoming invested in something. If the document is "here it is, ready or not" and the discussion is "try it for a few weeks/months, I think you'll like it", the entire process has failed. Such a design document/proposal would never pass muster in any professional environment. |
Wow. That was a very respectful response! Thank you. |
Ethan, he wasn't talking about you! https://www.dictionary.com/browse/you
I agree with Li Haoyi. Furthermore, even if 5 or 20 or 100 people do feel
more productive after using it for 3 months, that doesn't mean there can't
be valid reasons not to ship something in 3.0. (1) Feeling more productive
can be subjective. So disregarding people's input is never valid. (That
doesn't mean everyone has veto power, but every argument has to be
considered.) It might make other people less productive. (2) Even if it
only makes people more productive, you also have to take into account the
PR effect changes have. If the result is going to be a spate of rants on
dzone and reddit about how scala has gone off the rails, it's not going to
help with scala's adoption and perception issues.
…On Sun, Nov 24, 2019 at 8:25 PM Ethan Atkins ***@***.***> wrote:
Respect for people's experience, history of contributions, demonstrated
competence, and knowing what they want is a reasonable alternative. People
here have years-to-decades long careers working in dozens of different
languages and environments, many of which have syntax similar to that being
proposed. We're not a class of 1st year undergraduates.
Imagine if you were a salesperson trying to hawk some SAAS software, and
your sales pitch was "you have to try it for months, we promise you that
you'll grow to like it". They'd think you're crazy, and for good reason,
because you probably are.
Wow. That was a very respectful response! Thank you.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#7598>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAAYAUF2IJZNI57A34FYAUTQVMSQFANCNFSM4JQA26SA>
.
|
I am sorry if the remark about Stockholm syndrome irked people - it was meant as a figure of speech. I believe my history of interactions has shown that I do value and take into account feedback everywhere. Otherwise I would not spend considerable time engaging in this discussions! And, yes, there are a number of dimensions that need to be brought up, some of them technical, the others issues of perception. On the technical and UX issues I tend to give more weight to the opinions of people who have actually tried the stuff. What I tried to convey in my comment that seemingly went over badly is my enthusiasm for what a great language we have achieved! It's a really pleasing experience to write serious code in Scala 3. I would never have thought that the combination of small syntax changes would have such a dramatic effect on usability. And in my opinion that aspect has to be experienced, you can't give it justice if you have not tried it. |
While I can see the value in making mutation stand out more and be set apart from definition, on a syntactical level, I fear that the overal cost/benefit ratio of the proposed change is negative. Consider these two definitions: val x = 1
var y = 1 While from a more higher-level, functional perspective these two things might be two entirely different things they compile down to very same byte code: Writing a value into to a "named" memory location. To people coming to Scala from more imperative Languages the difference between This, however, appears less principled: val x = 1
var y := 1 The difference between I fear that this would confuse people coming to Scala from imperative languages, while the first snippet is perfectly clear. Is this disadvantage then overcompensated by benefits reaped later when people have more experience and work in more idiomatic Scala codebases? Therefore we are faced with a proposal that has a high risk of being unhelpful to newcomers while at the same time provides little benefit to the already large, existing user base. Especially when viewed under the principle that changes to the language must present a relatively large improvement over the status quo in order to offset the considerable cost of the change itself, I'd say that the best way forward would be to leave things as is. |
IMO forcing brackets is much more acceptable than replacing def incr = { x = x + 1 } looks okay to me. This is also the case for forcing indentation. |
Agreed. Even if assignment syntax is changed for some reason to :=, a var
should still be defined with =. There is a very elegant symmetry in val,
var, and def having the same syntax, after all they're the same thing,
assigning a name to an expression, except for different semantics about the
specifics of that, and because of def's semantics it can also have
parameters.
If you like, call := the *re*assignment operator.
(I still don't think the change is motivated enough to justify it, but if
it is, I would still argue the above.)
…On Mon, Nov 25, 2019 at 5:53 AM Mathias ***@***.***> wrote:
While I can see the value in making mutation stand out more and be set
apart from definition, on a syntactical level, I fear that the overal
cost/benefit ratio of the proposed change is negative.
Consider these two definitions:
val x = 1var y = 1
While from a more higher-level, functional perspective these two things
might be two entirely different things they compile down to very same byte
code: Writing a value into to a "named" memory location. To people coming
to Scala from more imperative Languages the difference between x and y
only manifests itself in the things that can be done to x and y,
specifically that y can be "changed".
The *initialization* of x and y however is exactly the same operation,
down to the machine level.
Therefore, from in imperative viewpoint, I'd say the snippet above
captures the essence of the two definitions perfectly.
This, however, appears less principled:
val x = 1var y := 1
The difference between x and y is already expressed via the val vs. var
keywords. The initialization operation itself is identical but now requires
two different syntaxes. When seen on a low level there is only *one*
difference between x and y, namely that y can receive a different value
later vs. x can't, and this difference doesn't even manifest itself on
these lines themselves but only on the lines *using* these definitions.
Yet, we now have to change val x = 1 in *two* places to turn it into a
true "variable" and it now looks as if the initialization code were somehow
different between the two lines.
I fear that this would confuse people coming to Scala from imperative
languages, while the first snippet is perfectly clear.
So, the benefit to new Scala users could be negative, especially at the
very beginning.
Is this disadvantage then overcompensated by benefits reaped later when
people have more experience and work in more idiomatic Scala codebases?
I'd say no.
This change would affect an area of the language that, while I'd consider
it a crucially important part, is rightfully used less and less the more
experience one gains with the language. Many idiomatic Scala codebases
hardly use any vars at all.
So any improvements to their syntax won't really make any difference to
them.
vars are simply too rare.
Therefore we are faced with a proposal that has a high risk of being
unhelpful to newcomers while at the same time provides little benefit to
the already large, existing user base. Especially when viewed under the
principle that changes to the language must present a relatively large
improvement over the status quo in order to offset the considerable cost of
the change itself, I'd say that the best way forward would be to leave
things as is.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#7598>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAAYAUE3G3YN7P4H56OPTT3QVOVBLANCNFSM4JQA26SA>
.
|
I have now read lines similar to this one in many proposals. Regardless of the proposal, every time I read a line like that it scares me a little bit more. I realize that it's necessary to be able to compile as much Scala2 code with Scala3 as possible. But by the time Scala 3.0 gets released it will contain so many new things—and still support all the old things they are supposed to replace—that all the permutations of ways to write the same piece of code will have exploded exponentially. Am I the only one who fears that this might cause Scala 3 to be viewed by some as a huge pile of unrelated syntax and features, while the goal was actually to make things simpler and reduce the amount of ways to do the same thing? Even if everyone was disciplined enough (then why is the simplification even necessary?) to only write new code with the new syntax, you'd still get codebases that are a mix of new things and old things, and new developers would still need to learn all the old stuff too, including how all the old stuff interacts with the new stuff. |
If you need a graceful migration, then you need a period in which both are supported. Otherwise, you can't change things. |
Most of us have tried the various features in other contexts though; we're not only writing Scala!
There's also the flip side: that many are experiencing things that someone full time working on Dotty and teaching undergraduates using Scala might not be experiencing:
it's entirely possible that a change massively benefits someone writing Scala compilers and teaching undergraduates, and still have the change do great harm to someone running the upgrade treadmill on an old project, or selling Scala to a non-language-enthusiast team. It's entirely possible that a change makes Scala look great to a Python enthusiast, while making it look horrible to a Python un-enthusiast. There is no contradiction here. Which is why I keep arguing against "try it, maybe you'll like it". It's a useless piece of information. Even if I quit my job tomorrow and spent the next 3 months and spent 40 hours a week using a new feature on some project, it would tell me exactly nothing about how well that feature plays in a large professional codebase. It would tell me nothing about how the feature will play in the maintenance of my suite of open source libraries. In many of these contexts, I can already predict how a change would play out; after all, one role of a software developer is to help predict the effect of a change before investing days/weeks/years in executing on it. It's literally our job! And that's the purpose of of a proper design proposal/document/review: to get everyone's input, from all their different backgrounds, their predictions on how a change might impact them, without having to perform expensive (and ultimately unhelpful) experiments and investments. If you prioritize feedback from hands-on Dotty experience, you are prioritizing feedback from people teaching undergraduates, writing Scala compilers, write toy side projects, since those are the only use cases for Dotty right now. It wouldn't be surprising at all if you then end up creating a Scala language optimized for teaching undergraduates, writing Scala compilers, and writing toy projects, at the expense of everything and everyone else. After all, nobody's going to come to you next week and tell you their experience porting their million-line hundred-developer enterprise codebase to Dotty. |
Sure but my fear was that there comes a point where the resulting language is no longer graceful. |
Maybe it looks ugly, but no identifier will ever clash with var x = 0
while x < 100 do
x _= x + 1 or perhaps ugly is precisely what we need :) |
It's not a valid identifier: trait Ref {
def _= (value: Any): Unit
}
<console>:2: error: identifier expected but '_' found.
def _= (value: Any): Unit
^ You would at least need to use two underscores, like |
It's a valid fear. In fact, he Dotty repo is a way to combat that: instead of just evaluating language features in a vacuum, it's implemented a number of features, to test how graceful the resulting language functions. |
@lihaoyi Just to put some facts straight:
All I wrote was that in my experience Scala 3 is shaping up to be a great language. You may believe that or not. But there's no need to denigrate the messenger. |
Sorry, I do not mean to denigrate anyone. Just explaining that I think “try
it out” is neither necessary nor sufficient to get a good read of things in
many scenarios, and prioritizing trying it out may overfit on use-cases
where trying out experimental tools and changes is easier
…On Mon, 25 Nov 2019 at 9:18 AM, odersky ***@***.***> wrote:
@lihaoyi <https://github.com/lihaoyi> Just to put some facts straight:
-
I do a bit more than teaching undergraduates. Through my books and
MOOCs I have taught several hundreds of thousands of programmers (total
inscriptions have reached 1 Million by now). According to our statistics,
85% of them were professionals (had a first degree).
-
We also do a bit more than writing compilers. It's also the standard
library, and the IDE, and the doc tool, and porting stuff to the Dotty
community build (you will see your own libraries in that build shortly).
It's true that this is still a fairly special slice of the whole ecosystem;
for instance one particularity is that we are sitting at the bottom of the
food chain with almost no dependencies. So, yes, other people have other
problems which might make them have other priorities.
All I wrote was that in my experience Scala 3 is shaping up to be a great
language. You may believe that or not. But there's no need to denigrate the
messenger.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#7598>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAHEB7FTJKPXIEJV4QP7KO3QVQCFRANCNFSM4JQA26SA>
.
|
Guido Van Rossum retired over
I have not shied away in the past from proposing to change language features that have a migration cost. But in this case, in the end, the change just does not seem important enough. Maybe syntax highlighting could render assignment equals different from definition equals. That would be a tooling solution to some of the problems. |
I feel like you are taking this the wrong way. I do think these changes are going to make the language better, but better language doesn't mean better adoption or acceptance. If you look at the top language list, they are all horrible languages. But still people use them widely. Currently Scala is used more than just a teaching or toy language. People use it in the industry, so any change will introduce cost and we are talking real money, and being comfortable to use isn't gonna justify that. |
Right but it's an argument in favor of staggering changes over several
releases
…On Mon, Nov 25, 2019, 10:26 AM Dale Wijnand ***@***.***> wrote:
If you need a graceful migration, then you need a period in which both are
supported. Otherwise, you can't change things.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#7598>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAAYAUDBXBWO5KWY6XFLSATQVPVA7ANCNFSM4JQA26SA>
.
|
@dwijnand reminded quite an important issue
If this new syntax for assignment would be introduced gracefully,
the pushback and concerns a specially from library authors could be addressed by giving a clear deprecation period. I very much like this proposal, but also am a bit concerned about the negative impact. So big 👍 for @odersky and everyone else who participates in such important discussions |
The amount of issues and conflicts that have arisen with def incr = x = x + 1 makes @lihaoyi's suggested solution of forcing curly braces much more appealing than a walrus operator. I know it's been said before, but not only are you saving a reserved operator, you don't have to teach anything new to anyone who already knows what I very rarely use |
As I understand it, this proposal does not prevent using |
Speaking of IDEs:
|
@pavelfatin I like it! |
I've used it for years in a language called, Simple Build Tool, I didn't like it when I first came across it and I don't like it now. Such a change would only make sense if the ==, was being changed to = for equality. |
I had liked this proposal very much, but only until I read that Yes, I treat
So, from a newbie perspective, (In other words, IMHO the aforementioned reference problem prevents us not only from introducing Sorry for a necrocomment. |
Since we are close to feature freeze, I'd like to discuss the last remaining point that remains open for me. Should we use
:=
instead of=
for assignments? I left it lying for a long time since I hesitated to wake up a sleeping dog. Almost everybody else uses=
for assignment. So the path of least resistance is to continue using=
in Scala. However, now that I am actually very happy about the syntax we have achieved, using=
for assignments sticks out like a sore thumb. So before accepting the status quo, I wanted to at least make the argument why one would want to switch.Consider:
This is terribly wrong on several levels. It's hard to parse and uses equals for two fundamentally different things. By itself,
x = x + 1
makes no sense either, and requires embarrassing explanations for everyone new to programming.Other languages don't have the problem to the same degree, since they don't use
=
for definitions. For instance, in Java or Python, you could read=
as always meaning assignment. Theincr
example looks like this in these languages:But in Scala, we do use
=
for definitions, which makes the abuse of the operator in assignments so much worse.:=
is a natural alternative. It's used in every serious treatment of imperative programming logics and is also used in quite a few languages, including Algol, Pascal, OCaml, F#, Go. Using:=
instead of=
makes imperative operations visually more distinct from functional ones, which is a good thing.:=
can be treated by the same rules as operator assignments. That is, ina := b
, if the left hand side has an applicable method named:=
the assignment is rewritten toa.:=(b)
. I believe we can roll the existing syntactic expansion of=
toupdate
calls into the same logic, which would simplify the desugaring rules.Migration: Scala 3.0 should allow
=
and:=
.=
would be deprecated at some later version. This will probably take some time.The text was updated successfully, but these errors were encountered: