dart-lang / sdk

The Dart SDK, including the VM, dart2js, core libraries, and more.
https://dart.dev
BSD 3-Clause "New" or "Revised" License
9.85k stars 1.52k forks source link

Meta-issue for discussion of the proposal to make semicolons after statements optional #30347

Closed leafpetersen closed 3 years ago

leafpetersen commented 6 years ago

This issue is to provide a forum for community discussion and feedback related to the proposal to make semicolons optional after statements.

This entry will be updated when a proposal is available.

cc @munificent @eernstg @floitschG @lrhn

cc @Hixie

brianegan commented 6 years ago

Just my 2 cents, but coming from a JS / Android background, I'd love either "Semicolons - YES" or "Semicolons - NO".

I do not think OPTIONAL semicolons are healthy for a development community for two reasons:

  1. It will lead to needless bikeshedding. Just witness / read up on the endless debate in the JS community over whether or not to use them. So many hours wasted over something purely stylistic. These debates do not help us solve actual problems.
  2. Additionally, it will make reading code harder for beginners, because it will introduce a stylistic distinction that might not be as easily understood by newcomers.

To keep an open mind, I'd love to hear more about the reasoning in support of optional semicolons. Do folks feel it will help adoption? Is it a stepping-stone toward a Dart v3 w/o semicolons?

Hixie commented 6 years ago

The bikeshedding in the JS community isn't over something purely stylistic. Semicolon insertion in JS (and some other "optional semicolon" languages like Kotlin) can have very dramatic effects on the semantics of the code. For example, consider:

// Javascript
function test() {
    return 1 + 1
             + 2
             + 3
}

console.log('Hello, world! ' + test());
// Kotlin
fun test(): kotlin.Int {
    return 1 + 1
             + 2
             + 3
}

fun main(args: Array<String>) {
    println("Hello, world! ${test()}")
}

What do you think they print?

Hixie commented 6 years ago

(I am reserving judgement on the issue when it comes to Dart until there's a concrete proposal.)

sethladd commented 6 years ago

Make it an error to have statement continuations after the return line. Also, I'm curious if there's actually a problem here, given what go, kotlin, and swift have been doing. Do they report this as a static warning or error?

I am not worried about "two ways to do it", there are infinite ways to do most formatting and conventions. I am confident that the combination of automatic formatters and style guides (both global and local per-team) will create cultural norms here.

brianegan commented 6 years ago

@sethladd Before we talk about all the tools that could be built to support this, could you maybe just elaborate a bit about what you see as the user benefit? How will this help us write better programs as a community? What "user need" is it targeting / solving?

To be clear: I prefer languages without semi-colons, but I just don't quite see what this will add to the Dart community or how it will help the ecosystem overall, and that's what I'm trying to understand a bit.

I'll await the proposal to see if it answers those Qs :)

sethladd commented 6 years ago

Modern languages are generally believed to be less boilerplate, more terse, and including language features working for you. For example, type inferencing is the language working for you. We could force you to right type annotations everywhere, or we can say "in many cases, we can infer it for you". Auto-inserting punctuation is another way the language can work for you. Also, there's an element of being seen as a light-weight, modern language and staying competitive. The trend in languages was to go to var, to go for closures, to go for => functions, and now to go for implicit semicolons (done right, of course).

Hixie commented 6 years ago

The code above is valid in Javascript and Kotlin respectively. (But the important question to me is, can you guess what they print?)

I think "make it an error to have statement continuations after the return line" is a perfectly valid part of a complete proposal, but I'd need to see the complete proposal before I could really say how valid it is.

BTW, omitting punctuation isn't new. Perl, Fortran, even COBOL all had stuff like this. Lisp didn't even have semicolons. I would hardly say it's a sign of a modern language.

sethladd commented 6 years ago

I would hardly say it's a sign of a modern language.

Re-modernizing? But yes, good point, plenty of languages pioneered here.

Hixie commented 6 years ago

In fact, Perl went even further and allowed you to omit the (/) around function arguments, if you want to really have the language "work for you". You can write entire programs in Perl using nothing but a-z and whitespace. I'm not sure I would take that as a point in favour of the language, though. The work Perl does for you when writing the code is work you have to pay back in spades when reading the code, to the point that Perl has often been referred to as a write-only language. Readability is infinitely more important than writeability.

ds84182 commented 6 years ago

So there are several problems that arise if Dart removes the semicolon requirement:

With semicolons:

print("hello");
() { print("goodbye"); };

Without semicolons:

print("hello")
() { print("goodbye") }

The first example would just print "hello", the second example could either print "hello" or throw an error, depending on how it's interpreted by the parser.

This can become worse if someone does this:

returningPrint() => print
() { print("goodbye") }

Now, instead of the function returning print the function tries to return the result of print(), which isn't a valid function call.

There would be a lot of ambiguity introduced by closure syntax... who says it's a call + block or a closure?

sethladd commented 6 years ago

How do swift, go, and kotlin handle these cases?

Hixie commented 6 years ago

Go has a crazy syntax for lambdas which is whitespace-sensitive (you can't put a line break after the arguments before the return type, or some such). They also have a reserved word before the lambda which disambiguates between closures and calls.

Swift and Kotlin use braces for closures. I haven't quite figured out the syntax exactly. Kotlin, as previously mentioned, makes choices that make its semicolon-insertion confusing and bug-prone.

zoechi commented 6 years ago

If there is a simple way to get rid of all ambiguities, then getting rid of semicolons would be great of course. If getting rid of ; hurts for example autocompletion, I'd rather keep ;. Making ; optional only for most cases seems more like an approach to appeal to JS developers to me, like Dart tried at the beginning with it's optional types, to then later move to strong mode because the original approach limits language development and most developers prefer good feedback from the tools anyway, which in the end could mean optional ; might hurt more than it helps (as already hinted to by @brianegan)

munificent commented 6 years ago

Just my 2 cents, but coming from a JS / Android background, I'd love either "Semicolons - YES" or "Semicolons - NO".

We would make semicolons optional mainly to support:

  1. Migrating existing Dart code that contains them.
  2. Code that is mechanically generated by tools.
  3. As an input to an automated formatter which would then remove them and replace them with whitespace as appropriate.

Idiomatic Dart code would not contain semicolons, "Effective Dart" would tell you to omit them, and dartfmt would probably strip them. Note that Ruby, Scala, Go, Lua, and Python all allow semicolons and yet semicolons have not infested their ecosystems. :)

JoseRFJuniorLLMs commented 6 years ago

yes god

{ usePushEach: true },

Kirrrr commented 6 years ago

Excuse me my freshman impertinence but I want to place some biased yet sincere questions here.

Isn't semicolons at the end of statements a part of solid complex language syntax? Doesn't omitting of semicolons lead to need of serious changes in language syntax to keep it ok? Isn't semicolons a mean to achieve sturdy and transparent code structure? Is that syntax overhead really hard to bear? Isn't it pretty strangely to draw parallels between Dart and other languages with significantly different syntax? Is current Dart syntax really ready for omitting the semicolons without any damage to whole project? What is the real positive impact of omitting of the semicolons besides of somebodie's attitude? Guys, lets take a good experiense from Assembler language and shorten all keyword to 3-4 letters, hm? Or lets declare war to colons and points because there are so many of them in code.

(sorry for clumsy English)

zoechi commented 6 years ago

@Kirrrr I also don't mind writing them, but if the Dart team sees a good way to get rid of them without causing serious downsides, I don't see why they shouldn't make an attempt.

I think non-nullable-, union-, immutable- types and extension methods have much higher priority, but that doesn't mean I'm against getting rid of ;.

munificent commented 6 years ago

Good faith questions are always welcome. :)

Isn't semicolons at the end of statements a part of solid complex language syntax?

Nope. It's an arbitrary choice. Some languages have nice, clean, solid syntax but no semicolons (Lisp, Smalltalk, Python). Perl does require semicolons but is notoriously tricky. Complexity is never a goal, it's a cost we pay to attain other goals. Simplicity is the goal.

Doesn't omitting of semicolons lead to need of serious changes in language syntax to keep it ok?

It depends on the language and the rules you use to treat newlines as significant. If we do it well, no. We wouldn't make them optional if it caused significant changes to the way people write their Dart code.

Isn't semicolons a mean to achieve sturdy and transparent code structure?

Not really. It's just a character. There's nothing magical about ";" compared to "\n", ".", etc.

Isn't it pretty strangely to draw parallels between Dart and other languages with significantly different syntax?

Some of the languages with optional semicolons are pretty similar to Dart syntactically — Swift, Kotlin, and Scala in particular.

Is current Dart syntax really ready for omitting the semicolons without any damage to whole project?

Yes. It's a pretty small change. Go made semicolons optional after the language was in wide use without any major problems.

What is the real positive impact of omitting of the semicolons besides of somebodie's attitude?

Users choose products for both technical and emotional reasons. Programming languages are visual products (for most users) and the visuals matter. If most of our users find that Dart looks nicer and is less error-prone without requiring explicit semicolons, it's a win.

Stargator commented 6 years ago

We would make semicolons optional mainly to support:

I would recommend either Semicolons must be used or no semi-colons. If we are going to take the effort to change the language regarding this, it needs to be clear and not a patch intermediate step.

Optional semi-colons serves no practical matter nor resolves a problem. It would only exist as a migration path and, if so, thus should be avoided as it easily could be left in the SDK for years due to debate.

The Dart language isn't against introducing breaking changes (see: Dart 2.0). So again, the decision should be either with semi-colons or no semi-colons.

In my opinion, I say leave the semi-colons in. It fits Dart's intention of not being surprising to developers.

daveob commented 6 years ago

Coming from hobbyist languages like BASIC and Lua, I would love to see Dart get rid of (or at least make optional) the ending semi-colon. For me, it makes the language appear less fussy and more readable.

munificent commented 6 years ago

I would recommend either Semicolons must be used or no semi-colons. If we are going to take the effort to change the language regarding this, it needs to be clear and not a patch intermediate step.

Optional semi-colons serves no practical matter nor resolves a problem. It would only exist as a migration path and, if so, thus should be avoided as it easily could be left in the SDK for years due to debate.

Well, migration is a problem. :) Also, allowing semicolons makes things easier for tools like code generators that produce Dart source code and don't want to have to fuss with newlines.

Python, Ruby, Kotlin, Scala, and Swift all allow semicolons. Despite that, they all have consistent clean ecosystems where semicolons rarely appear in user code.

Stargator commented 6 years ago

Well, migration is a problem

Migration is always a problem (see Dart 2.0). But should mean making it optional. Does the language really need to make semicolons optional? No, it doesn't.

The language is best when designed for the developer's use as a consumer of the API. Whether tools like semicolons is irrelevant.

I think the semicolons should stay and not be optional. It makes the language easier to understand especially when different examples of the code are given. And that is Dart's best feature, not being surprising to the developer and using tried and true concepts.

Optional semicolons causes more confusion for new users as well as teams trying to come to a standard. The Dart Style Guide would have to choose a side and that'll decide how most users go.

brianegan commented 6 years ago

I was on the fence about optional semi-colons, but have been persuaded the arguments made above: If the Dart Style Guide recommends no semicolons and dartfmt could automatically remove them, I'd be a happy camper. Once you get used to writing code without semicolons, it's hard to go back. Making them optional seems to have legit use cases.

Overall, I think it's a good thing if peeps go with the Dart Style Guide out of the box! The fewer style discussions we have the more time we have to write our apps. As a bonus, it makes it easier is to read through other code bases as well :)

Hixie commented 6 years ago

I think it's impossible to have an informed opinion without knowing what the concrete proposal is. If it's like more like JavaScript or Kotlin, where you can't tell at a glance what the code does, and where in some common cases you can write code that actively looks different than what it does, then it's probably a mistake. If it's more like Lisp, where there's no ambiguity, then it's probably fine. In between these poles are languages like Pascal, where semicolons are optional in certain cases and must be omitted in certain cases and required in others, but that doesn't gain you much (maybe slightly cleaner lambda block syntax though the => syntax in Dart makes that moot).

kuashe commented 6 years ago

Making ; optional only for most cases seems more like an approach to appeal to JS developers to me

@zoechi I think it would be regrettable not to appeal to JS developers , especially for those looking for an alternative to Node. Has pointed out by @brianegan , after not using semicolons for a while it's really hard to go back to a language using them . Go doesn't use them and it makes the code incredibly simple to read , it seems like the community really enjoy it.

Using ; everywhere makes Dart feel very much like Java, which is regrettable because Dart is in general less verbose than Java.

Stargator commented 6 years ago

Using ; everywhere makes Dart feel very much like Java, which is regrettable because Dart is in general less verbose than Java.

I like that feeling, though :thinking:

agrosner commented 6 years ago

Semicolons are really just noise. If you need to write something like:

print("hello");
() { print("goodbye") }

then there is something else wrong than just needing semicolons.

IDE can warn you in instances where you might get tripped up, but overall, removing semicolons is much cleaner. Coming from Kotlin, swift, JS, I keep forgetting to put in ; which is annoying and requires a little bit more of thought.

I mean the examples listed above are valid, however given a strong direction on what it prints just requires a little more learning.

function test() {
    return 1 + 1
             + 2
             + 3
}

if an operator is listed on the next line of a return statement, dart should just collect them or just make it an error to place an operator on the next line as first statement.

tedhenry100 commented 5 years ago

An explicit statement terminator (e.g. a semicolon) is a great thing to enhance code readability and to help the compiler catch mistakes. I don't see the need to spend any effort on making semicolons optional. There are far more important things to do.

charafau commented 5 years ago

I think non-nullable-, union-, immutable- types and extension methods have much higher priority, but that doesn't mean I'm against getting rid of ;.

This, so much this plus case / data classes and Scala like collection library... (And pattern matching)

idrougge commented 5 years ago

A semicolon does not improve readability unless your syntax is ambiguous. A semicolon can just as well be used as an obfuscation mechanism and can only be used to terminate already terminated statements; it is not possible to terminate a parenthesis or brace-delimited statement using a semicolon, so in effect it becomes only a new kind of whitespace.

I think the main reason Dart has mandated semicolons is exaggerated reliance on tradition and a fear of repeating ASI mistakes of notoriously ambiguous languages like Javascript. A clean-room design made today would never include semicolons, as demonstrated by Swift, Kotlin, Scala and even such a conservative language as Go.

agrosner commented 5 years ago

Semicolons once you remove them and try to use them again just appear as "code noise", just as the new or const operator already removed. this cleans up times when forgetting a semicolon is considered a compiler error. Swift, Scala, Kotlin, TypeScript, JS, and other modern languages don't require it and it works just fine. having to type an extra ; to terminate statements becomes boilerplate coming back from writing those languages.

Hixie commented 5 years ago

Swift, Scala, Kotlin, TypeScript, JS, and other modern languages don't require it

Please don't make this argument. There have been languages without semicolons since the 1950s. Several of the earliest languages didn't have them. There are also plenty of modern languages with semicolons. Rust, for instance, is a new language with semicolons. Dart, obviously, is another (it was developed in the same year as Kotlin). Ceylon, P, Hack, Perl 6, they all have semicolons.

If we want to remove semicolons, then we should do so because that makes Dart a better language. We should not do it because it's the current fashion. That's the worst reason to make a change to a programming language.

and it works just fine

Optional semicolons in JavaScript absolutely don't "work just fine". It's a huge source of bugs and is the main reason I am concerned that if we remove semicolons from Dart that we should do it with the utmost care. I already discussed this in the third comment on this very issue.

haltcase commented 5 years ago

@Hixie the problems with skipping semicolons are often exaggerated and are easy enough to dodge in JavaScript (basically don't start a line with one of something like six characters), but regardless they arise because newlines are not interpreted as terminators like they are in languages explicitly designed without semicolons like Swift, Kotlin, Nim, etc.

I agree that if Dart were to remove semicolons it has to be done with care. When JS is pointed at as the bad egg, it's mostly because it doesn't consider line terminators as part of the equation and its ASI (automatic semicolon insertion) is an implicit thing done at runtime. These are both simple problems that Dart can very easily avoid.

Hixie commented 5 years ago

Kotlin didn't avoid them either (again, see comment 3 in this issue).

I agree that some languages (e.g. some of the languages from the 1950s) have shown that it's possible to design a language without semicolons where the lack of semicolons isn't an issue. I have yet to see a proposal for doing this in Dart, so it's hard to say which way it would go for Dart.

Stargator commented 5 years ago

@Hixie I agree.

juanmendez commented 5 years ago

I think if others are so used to write semicolons let them do so. In contrast, many other developers are now using Kotlin, such as my case, and would love to continue writing code without semicolons. Please make it an option.

hooluupog commented 5 years ago

To maximize the benefits(less typing and less syntax noises) of getting rid of semi-colon, no semi-colon is the best choice. Optional is not compelling(losing code consistency).
+1 for Semi-colon or no semi-colons.

lukepighetti commented 5 years ago

Javascript gets along just fine with optional semicolons. People like to talk about it, but I have yet to see optional semicolons actually break anything?

I would like optional semicolons in Dart.

CorayThan commented 5 years ago

Coming from Kotlin, Typescript (sans semi-colons), and Java I would certainly like to see them optional. It's a pain remembering to put them in, and any code that would make you think "how does this work?" without semi colons shouldn't have been committed, and shouldn't have passed code review.

lrhn commented 5 years ago

Just to up the game a little, I'll argue that semicolons should be unnecessary (and block braces too).

The purpose of code is two-fold: To be read by computers and to be read by humans, in such a way that the computer actually does what the human thinks it will do. Basically, it must not be misleading to humans, and must be unambiguous to computers. Adding extra punctuation is a simple way to achieve this, at the cost of ... well, extra punctuation.

Semicolons adds nothing to this if the code is not otherwise ambiguous. Humans mostly don't see them, which is why omitting a semicolon, or adding too many, are hard bugs to track down.

Same for block braces - humans really use indentation to understand structure, so:

if (test) 
  doSomething();
  doSomethingElse();

is easily misread as doing two things guarded by the test. Automatic formatting fixes the whitespace, it doesn't insert the braces, because we think that "what the computer does" is the easy thing to figure out, and so we fix the layout so that humans will read the same meaning. The computer always win, so whatever it thinks code means, that's what it means.

So, effectively, the braces are unnecessary because they are redundant. In a correctly indented program, we are specifying block structure both using braces and using indentation, and that's redundant - and potentially misleading if the two are not in sync.

Languages with significant whitespace are readable because of this. They work without redundancy, they only specify things in one way, and that's the way that humans would read it (as long as the computer can figure out what that is).

Semicolons are the same - they provide no separate meaning, they are only there to make it easy for the computer to figure out what the human already knows (likely from looking at indentation), and again the two can get out of sync:

for (var x = arglebargle; x < glopglyf; x += flimflamflopper);
  print("...");

Whoops. Computer always win.

So, the goal of removing semicolons is valid when it reduces the unnecessary punctuation. Any time a human will read something differently than the computer, the punctuation was not unnecessary, and we might need to also change the syntax in other ways to make it still work out.

I personally doubt we can make all semicolons unnecessary without taking indentation into account.

And we probably don't want to make existing valid code change behavior, unless we make optional/no-semicolons an opt-in feature on a per library basis (like any other breaking language change should be).

(Don't get me started on commas! :smile:)

Hixie commented 5 years ago

Parentheses around arguments are also unnecessary, as shown by Perl. And commas in lists too, as shown by Lisp. Fortran even showed that spaces were unnecessary.

On the other hand, Python has shown that making whitespace significant is a horrible mistake when refactoring code, JavaScript and Kotlin have shown that making semicolons optional results in confusing code and prevents certain desirable patterns, the Dart analyzer and the Dart formatter have shown that it's trivial to catch mistakes where the indentation gets out of sync with the syntax, Lisp has shown that using only one style of nesting punctuation leads to impenetrable code, Fortran has shown that making whitespace optional can come close to destroying space probes, and Perl has shown that in general while you can certainly make a language in which it's possible to not use any punctuation at all, that doesn't mean anyone will be able to understand a word of your program.

Our focus here should be on how we can make Dart a better language. Are semicolons a problem in Dart? Or are they a feature? I would argue that they are a valuable feature, currently, that allow the language to be more expressible than it would be if something else served the purpose of statement separator.

There are certainly some changes we could make that would be clear improvements. For example, Algol and Pascal have shown that using semicolons as separators instead of terminators can help make one-line blocks clearer. This would be useful in Dart when dealing with short closures.

As I wrote above, it's hard to make clear judgments here without a concrete proposal.

Stargator commented 5 years ago

As I wrote above, it's hard to make clear judgments here without a concrete proposal. Agreed completely.

Our focus here should be on how we can make Dart a better language. Are semicolons a problem in Dart? Or are they a feature?

I would argue they are not a problem. With the dart analyzer, missing a semi-colon is trivial and easy to catch. Making them optional would just mean the analyzer would ignore them (I assume, there's no proposal) and would limit the usefulness of the analyzer.

Dart's mission is not to surprise the developer and not having semi-colons or making them optional would be surprising and confusing.

The bottom line, do semi-colons in Dart break anything? I don't see anything in Dart or any proposed changes to Dart that are be blocked by the use of semi-colons in the code.

I would argue that they are a valuable feature, currently, that allow the language to be more expressible than it would be if something else served the purpose of statement separator.

Agreed.

lukepighetti commented 5 years ago

The only thing I want to add to this is that if semi-colons are to remain required, dartfmt should add them in for us. (This probably for another topic, but I also strongly believe we need a more opinionated, yet dynamic formatter like Prettier for JS. Run pub packages through dartfmt if you must, I don't care.)

lrhn commented 5 years ago

The only thing I want to add to this is that if semi-colons are to remain required, dartfmt should add them in for us.

But where?

The good thing about semicolons is that they tell you explicitly where statements end. To insert semicolons, you have to figure out where statements end, and if you can always do that, you've proven that semicolons really aren't necessary. So, for dartfmt to have this feature, it means it has to be able to parse invalid Dart programs (also known as "not actually Dart programs"), deduce a statement structure that isn't explicit in the code using some set of heuristics, correct the code by inserting semicolons, then check that the result is valid Dart code, and finally format the code.

lukepighetti commented 5 years ago

I don't have a good answer for you, but I know that Prettier does it with seemingly perfect success. And if what you say is true, and Prettier is still able to achieve this, then that seems like enough of a reason why we don't need semicolons at all. 😄

munificent commented 5 years ago

Prettier does it with seemingly perfect success

That's because semicolons are optional in JavaScript.

lukepighetti commented 5 years ago

@munificent Prettier inserts semi-colons as if they were necessary and does so with accuracy. I'm not sure what more you would ask for from a formatter that adds semi-colons.

lukepighetti commented 5 years ago

This brings up another question though. If the debugger can tell me that there's a semicolon missing, and show me where, why can't a formatter add it in that location?

matanlurey commented 5 years ago

@lukepighetti I think if you have specific questions about how Dartfmt could change behavior, a new issue thread is more appropriate than this one. This is specifically about if semi-colons should become optional (right now they are required, so the formatter can't choose to omit them or parse precisely without them).

Stargator commented 5 years ago

As this topic came up in the past (2012), this is the statement they made at the time. So any pro- optional semi-colons (or just plain pro-remove semi-colons) would do well to address the deciding factor from back then:

Here's what Lars said (in http://code.google.com/p/dart/issues/detail?id=34#c60) in response:

We have decided not to support optional semicolons for the following reasons:

  • White space should not have semantic impact. In JavaScript the worst problem related to this is around return. return 1 This will return undefined which is completely broken.
  • Dart programs will be become more consistent and therefore easier to read.