-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Alternative Syntax for Control Expressions #7024
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hello, and thank you for opening this PR! 🎉
All contributors have signed the CLA, thank you! ❤️
Commit Messages
We want to keep history, but for that to actually be useful we have
some rules on how to format our commit messages (relevant xkcd).
Please stick to these guidelines for commit messages:
- Separate subject from body with a blank line
- When fixing an issue, start your commit message with
Fix #<ISSUE-NBR>:
- Limit the subject line to 72 characters
- Capitalize the subject line
- Do not end the subject line with a period
- Use the imperative mood in the subject line ("Add" instead of "Added")
- Wrap the body at 80 characters
- Use the body to explain what and why vs. how
adapted from https://chris.beams.io/posts/git-commit
Have an awesome day! ☀️
Pure opinion: I really dislike this sort of syntax -- I find it significantly harder to scan code and understand the control flow in keyword-centric languages like this. It's the sort of thing that would actively nudge me away from Scala. I get that it's just being presented as an option, and that's fine in principle, but I gotta say: it seems contrary to the general bent of the Scala 3 project, of being a bit more opinionated about style. I would probably forbid it in any codebase I'm leading... |
df88fac
to
6d6180d
Compare
I am very concerned about this. I grew up with Pascal/Delphi, so I'm not against the new syntax per se. I am concerned about the change. The issue is that it will inevitably lead to a fracture of the ecosystem. A lot of code will use the old syntax, including all the existing material in books and on the Web. And supposedly a lot of new code will use the new syntax. We'll have zillions of people wondering how to read other people's code, or if the two things are the same, or which one they should use, etc. We've seen this problem before for other things, for example The low ratio is not helped by the fact that I see little in the way of motivation for this change. With a historical record of everything that's been discussed the past few years, I can see this being motivated in the context of indentation-based syntax, which is a radically different syntax aspect. With such a change, there are objective reasons to switch to In the context of brace-based syntax, I could see a much more restrictive version of this proposal: allow braces instead of parens for the condition of while {
val c = str.charAt(i)
c >= '0' && c <= '9'
} {
i += 1
} Aside: Speaking of indentation-based syntax, using it would basically require treating newlines in conditions as statement separators, so that I could for example write the following: while
val c = str.charAt(i)
c >= '0' && c <= '9'
do
... If we don't treat them as newlines now, then treating them as newlines with indentation syntax would be an even more problematic change. For that reason, at least newlines should be treated as statement separators now (and hence systematically fail to parse, since we are not in a block under non-indentation-based syntax), if there is still any ounce of desire to have indentation-based syntax in the future. |
@jducoeur @sjrd This is not intended to stay an alternative for long. My current thinking is that we should standardize on the new syntax, and rewrite all old syntax automatically (this PR proves that this is feasible). Using indentation or not is a separate aspect. I am ready to argue that the new syntax is vastly superior even if we stick with braces. |
What's changed since last time?
This is a nice tweak, and I'd hope it could make it in. Notably, it doesn't require rewriting existing code, nor would such a rewrite rule be widely applicable. I do like the |
I'm cautiously, hesitantly willing to accept this new style once I remind myself that it's only syntax. I've no doubt we'll all get used to it. However, one minor benefit of the current brace-based syntax is that text editors and IDEs can very easily match an opening to a closing brace, and indicate this to the user. |
I for one really like the added symmetry and welcome the change |
I don't think rewrite tools solves all problems, there are people generating Scala code automately, or projects uses modified Scala syntax (https://github.com/lihaoyi/Scalatex), also all the code snippets written in various blog posts, forums on the web. It will just be a lot of pain. I wonder if instead we can do a structural editor with configurable syntax presentation (I am interested in experiment with this). |
Rebased on top of #7031 |
Allow drop drop parens or braces in control expressions Use for-do, for-yield, while-do, if-then-else instead.
Squashed to a single commit on top of #7031 |
Very beautiful improvement to the syntax of Scala. 👍 This streamlined syntax emphasizes the expression-oriented nature of Scala (reminiscent of the change in method syntax, I do think rewriting and deprecation of the old syntax are both important for any change of this magnitude: rewriting to ease migration, deprecation to enforce a single style in large code bases. Now I know some will object to this change, on grounds it makes Scala a worse Better Java. There is a kernel of truth here; those who love curly braces will find more streamlined syntax yet another reason to stick with Java or Kotlin. But I would suggest that this change makes Scala a better Scala, and that the Better Java market is not a growth market for Scala. Python has also shown, with its tremendous success, that the lack of parentheses, curly braces or the presence of indentation-sensitive syntax are no impediments to adoption or tooling (indeed, most languages would be lucky to have a fraction of Python's success in these areas). In summary, this change is a great example of Scala "doubling-down" on Scala—a change courageously opinionated enough to (yes) give some another reason to stay with Java, but also bold enough to galvanize those who love the conciseness and expressive power of Scala, and who would love to see a change this impactful to end-user ergonomics and aesthetics. |
If one believes in "Make each program do one thing well", one would avoid adding any code rewrite features to a compiler and let a separate tool, like |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
@odersky might we support golang-style control flow syntax, which is omission of conditional parentheses but still braces around the block? (I have limited interest in significant indentation syntax and will most likely keep using curly braces. But I find your exploration of "radical" changes to be inspiring and will give it a try, especially given the excellent tool support to convert sources :-) Golang style might look like def hello(x: Int): Unit = if x > 5 {
println(x)
println(x*2)
} |
I love this change. It's like those mornings I remember to clean my eyeglasses. The rest of the day is better and clearer. However, for a very long time, I've been accustomed to vi getting confused by stray braces in comments and then failing to match braces correctly, so I'll have to get used to not dealing with that issue. |
IFF we go full indentation-crazy, how about allowing the user to skip the new keywords and instead literally double down on indentation: use an extra indentation to denote what's inside the missing parenthesis: if x < 0 &&
y > 1 // <-- extra indent means it's "inside the ()"
-x
else
x
while x >= 0 &&
y > 1 // <-- extra indent means it's "inside the ()"
x = f(x)
for x <- xs
if x > 0 // <-- extra indent means it's "inside the ()"
yield
x * x
for x <- xs
y <- ys // <-- extra indent means it's "inside the ()"
println(x + y) Maybe it's a little better if the "inside the ()" part lines up with the keyword+space: if x < 0 &&
y > 1 // <-- extra indent means it's "inside the ()"
-x
else
x
while x >= 0 &&
y > 1 // <-- extra indent means it's "inside the ()"
x = f(x)
for x <- xs
if x > 0 // <-- extra indent means it's "inside the ()"
yield
x * x
for x <- xs
y <- ys // <-- extra indent means it's "inside the ()"
println(x + y) Maybe too subtle for the if x < 0 &&
y > 1 // <-- extra indent means it's "inside the ()"
-x
else
x Not sure I like it, but wanted to put it out there as it's not going to get much lighter than this, and I hadn't seen this in any of the significant indentation discussions. |
This got me thinking - I feel like we are heading to the wrong direction. To get Scala more widely used, is changing syntax the correct way? Scala needs a killer use like other popular languages (Rails for Ruby, ReactNative for JS, Android Dev for Kotlin, etc.), and, to me, syntax is not the road blocker for getting people to use it. |
@texasbruce
Yes, this is an important question. There may be a better place to discuss this, but let's start here. In my opinion the main blocker to Scala's adoption (besides a reputation for brutal compile times) is the pervasive conventions that define idiomatic Scala usage. I wrote about this https://contributors.scala-lang.org/t/principles-for-implicits-in-scala-3/3072/51
I think "Step 1a" to improving mass adoption of Scala is to merge cats into the standard library. EDIT: I started a reddit thread. |
To me the question is, since cannot predict but only speculate on the future, what is the potential gain, and what is the potential risk. For example, there could be a scenario where due to changed syntax scala becomes X% more popular, but there could be another conceivable scenario where it results in a total of Y% less popularity. What are values for X and Y that we should think about? |
Looking from the outside in, the Scala community is--to put it as politely as I can--a dumpster fire. Fixing that will have a much better effect than any syntax changes. |
@jackmaney I'd just like to offer a counter perspective in that, being relatively new to Scala, I've been pleasantly delighted by the language, standard library, 3rd party libraries, helpful Q&A on reddit, community members with whom I've interacted, etc. I am particularly impressed by the thoughtfulness and execution so far on the transition to Scala 3. The talks from Scala Days 2019 were great. The communication around Dotty is great. The Dotty website is great. |
Having the indentation part of the syntax is a terrible idea. Code style and code meaning should be two distinct things. Also, I like my curly to eye ball where is the start and end of blocks. Have you even copy paste Python code from one place to another ? It is a nightmare. |
I may be a Scala newbie, but this new-style of syntax would cause me to not migrate willingly to Scala 3 as a hobbyist. It's my belief that using keywords and implied grouping, over explicit parenthesis and braces, really hurts readability. The only saving grace, is that it encourages simpler branches and loops, and breaking the conditions onto a previous line, as it gets unreadable so quickly. People practicing python have embraced that as 'pythonic'. In addition, the extra keypresses / screen realestate of the keyword 'then' is irritating. |
As a former Perl developer I think this serves no purpose other than to create more syntax to learn before you can be proficient in Scala and both slows you down and knocks your confidence as you read other people's code. |
This PR implements a new "quiet" syntax for control expressions that does not rely in
enclosing the condition in parentheses, and also allows to drop parentheses or braces
around the generators of a
for
-expression. Examples:The rules in detail are:
if
-expression can be written without enclosing parentheses if it is followed by athen
.while
-loop can be written without enclosing parentheses if it is followed by ado
.for
-expression can be written without enclosing parentheses or braces if they are followed by ayield
ordo
.do
in afor
-expression expresses afor
-loop.if
or awhile
.So the meaning of newlines is the same no matter whether parentheses are present
or absent.
for
-expression. This turns out to be not a problem because Allow infix operators at start of line #7031 basically removed the need to put expressions in parentheses to get nice operator formatting.Rewrites
The Dotty compiler can rewrite source code from old syntax and new syntax and back.
When invoked with options
-rewrite -new-syntax
it will rewrite from old to new syntax, dropping parentheses and braces in conditions and enumerators. When invoked with with options-rewrite -old-syntax
it will rewrite in the reverse direction, inserting parentheses and braces as needed.