Feedback sought: Optional Braces

M4 should be out in the first week of February. We will have the with syntax in the nightlies starting tomorrow.

3 Likes

Can with be made optional in the future after the ambiguity issue is no longer a concern?

1 Like

Is optional braces defined in Scala 3 Syntax Summary?

BlockExpr         ::=  ‘{’ (CaseClauses | Block) ‘}’

I can not see any definition…
Are the rules difficult to describe in formal grammar?

Great! Trying out scalaVersion := dottyLatestNightlyBuild.get now!
Would the recent proposals by @smarter on simpler syntax in lamdas including

List(1, "a").collect(case x: Int => x)
Map(1 -> 2).map(case (k,v) => v)

be possible to include in M4 | RC1?

This often trips my students; it seems as having to sometimes change () to {} hinders them in their first steps towards being comfortable with anonymous functions and higher-order functions in combination. It does not seem uncommon that students with some experience of an imperative language seem to think that “ouch! it did not work with (case …) then I make a while-loop instead”…

Link to the post by @smarter Feedback sought: Optional Braces

2 Likes

Note that for this particular example you can already write:

Map(1 -> 2).map((k,v) => v)

Thanks to parameter untupling.

2 Likes

As long as it’s a single case, this looks like an easy generalization. For more than one cases, it looks more complicated / less regular to allow them in parnentheses.

1 Like

Is it too “irregular” to allow () for single cases specifically?

1 Like

It looks like I’m a contrarian here, but I prefer : over with.

Part of what I’m thinking is that if I was teaching Scala and had to introduce the following class, I would say, “Book is a class that has two constructor parameters, title and authors, and it has a var field named copiesSold and a public method named price”:

class Book(val title: String, val authors: ArrayBuffer[String]) {
  var copiesSold = 0
  def price = ???
}

So when I speak I don’t use the word “with” when talking about a class, instead I say that it “has these attributes and behaviors,” or maybe that it “contains” these. Since I don’t use with when talking about the class, it seems a little wonky (for lack of a better term) to use it in the code. (Though “has” is arguably a synonym for “with”.) Conversely, I like that a : can symbolize any phrase such as “has these attributes and behaviors.”

Aesthetically, IMHO, I also find that the word with looks like it’s dangling out there by itself for small class declarations:

class Book(val title: String, val authors: ArrayBuffer[String]) with
   var copiesSold = 0
   def price = ???

That makes me actually prefer with::

class Book(val title: String, val authors: ArrayBuffer[String]) with:
   var copiesSold = 0
   def price = ???

But I wouldn’t want that, so if we go with with, I think I’d always use end to make it feel more complete:

class Book(val title: String, val authors: ArrayBuffer[String]) with
   var copiesSold = 0
   def price = ???
end Book

As a result of all of that, I prefer just the :, which is more concise, and doesn’t have that dangling feeling:

class Book(val title: String, val authors: ArrayBuffer[String]):
   var copiesSold = 0
   def price = ???

Also, using a : feels just like you’re writing text, like Markdown:

A Book:
  - takes the parameters `title` and `authors`
  - has `copiesSold`
  - has `price`

In my own experience with Scala 3, : works really well for small classes, so I don’t use end to close the class. Then when a class starts getting longer, I do use end, and I still like it.

Also, I don’t feel any confusion with the type ascription issue that I’ve seen other people mention. In this context I think of the : as a container for what follows. It’s like we use => to mean “transformer” with HOFs and arguably with case statements inside match, but I don’t confuse that with using => for self-types.

Again, that’s just my preference. If nothing else, I thought I’d share an opposing viewpoint and the rationale behind it. :slight_smile:

1 Like

Optional brace can be done without change any language syntax, actually. Just use a font with transparent brace glyph. And then we could stop hearing things like Wait, isn't three space indentation a joke ?, and keep focus on things everyone cares, lsp server and compiler performance e.g.

3 Likes

You actually don’t need to use a special font if your editor supports changing the color of the braces to have the same color as the background. I have been using such a setting in IntelliJ IDEA for years. I like to call it “Hidden Braces”.

6 Likes

I agree with the wonkyness and I have the same feeling that speaking “class C has members …” is more natural. Therefore I’m considering to, if with finally wins because of the regularity argument, instead speak “class C declared with members …” and the the English feels right again.

BTW: Just reading the pre-print of the fantastic PINS-ed5 and I’m trying to imagine with instead of : and hoping the itch with with would go away after eating a lot of pages :wink:

Which is why optional braces should be just that: optional. There should be no “with”, no “:”, there should be nothing at all but identation. I am not sure why this has been entirely dismissed as an option. All of this debate about strange keywords or symbols would be over should we just agree on the real purpose of optional braces, I.e., that braces are optional (rather than replaceable by a keyword and an optional “end” tag).

1 Like

It has to do with ambiguity and risks of mistyping white space, but I have not seen the detailed explanations with examples of this. Perhaps someone here can summarize the problems of having no token just indentation? @nafg Also raised the question if we later can drop the extra cruft if ambiguity issues are settled. But I guess the problems are perhaps not going away?

There is certainly something to keeping it that simple (although I suspect it is not possible due to possible ambiguity in some situations, even though I can’t think of any right now). I believe Odersky suggested a no-marker variant earlier in this thread, but some issues where found with it which made him reject it.

The optional end-marker could perhaps be added anyway (even if the braces where simply made optional without requiring a start-marker) to improve readability of larger code blocks.

1 Like

See:

2 Likes

I am not sure I understand the argument. Aren’t there many other examples, also under the status quo with “with” or “:”, where an incorrect indentation may change the meaning of the code? Why would a class definition be more error-prone than

if condition then
   conditional_expression
misindented_expression

Where misindented_expression would incorrectly execute outside of the if statement because “a single stray space changes the meaning of the program” (quoting Odersky)?

As for the “harder to see visually” I subjectively don’t agree. If we accept the idea of significant indentation, well one must accept the concept that adding spaces changes the meaning. I’m not sure a “:” makes a difference. It is a question of habit, and IDEs will soon enough add visual clues about whether something is the class body or not.

2 Likes

I think the argument is that

if condition then
conditional_expression

is unambiguous, whereas

class A
object B

is.

I understand the argument but why would we arbitrarily limit acceptable versus nonacceptable ambiguities to such use cases? My example above with the if statement is another example of an indentation-related visual ambiguity; and arguably it may have more disastrous consequences.

I guess my argument is: why would we protect the developer against erroneous idents (i.e. enforcing the use of “with” or “then” or “:” or other) but tolerate the risk of erroneously missing indents (i.e. see my example above with if-else where second statement is incorrectly out of the if statement). To me, both are dangers related to the optional braces syntax; therefore if we accept the idea of coding braceless, we should not stop half way under some vague and arbitrary fear about specific use cases.

1 Like

class tends to have larger bodies of code, so for short definition you don’t tend to have end markers but for long definition you could.

One thing I find confusing myself with optional braces is the non consistent begin markers :, with, = or nothing

1 Like

In the if example you need to miss several spaces, whereas in the class example, just one space changes the meaning (= accidental).