Feedback sought: Optional Braces

Can someone explain to me what the value is in having a keyword or any other symbol to essentially be some kind of sugar for {}? It seems completely backwards to me. If I’m supposed to read code and then mentally insert { and } everywhere before I can begin to understand it, why not just use {} and be done with it?

The same question also regarding using some small inconspicuous symbol with no meaning. Why not go full YAML and just use indentation all the way instead of small symbols that just gets lost in everything else?

The same goes for end. Why does the end of a block get a keyword but the beginning gets a short almost invisible symbol? It doesn’t make any sense to me whatsoever.

5 Likes

I agree, of course! Re-reading my post, I see how I can sound l like a condescending brat, so I apologise for that.

Not only h/v spacing mind you: line endings and beginnings matter too. I am definitely biased in having as little syntactic devices as possible and let coding style do the rest, but it only works if the syntax is used consistently, so if I see a line ending with : I expect the next line to be a type, not an expression. Whereas, if it ends with =, the opposite is true.

3 Likes

I am sorry for offtopic, but it is really very hard construction for such simple and common thing.
For example in swift:

  if let value = myOption {
    val x = value + 1
    x * x
 }else{
     val x = defaultValue
     x + 1
 }

I would be very glad to have somthing like:

 val result = myOption.ifNone{
  val x = defaultValue
  x + 1
} else { value =>
  val x = value + 1
  x * x
}

fold is good too, but as you have sad it is less readable.

I am not a fan of multiple {...} blocks in a row. I believe it tends to lead to obscure code and is overused. So, maybe not having a convenient brace-less syntax for it is OK.

Are you saying we should not have methods that take multiple functions as arguments?

This looks pretty cool, but it’s flying pretty close to the sun in terms of ambiguity and parse-ability by both computers and humans. Coffeescript does exactly this, e.g. see the -> lambda in the example below:

$ 'body'
.click (e) ->
  $ '.box'
  .fadeIn 'fast'
  .addClass 'show'
.css 'background', 'white'

But Coffeescript is also well known for going too far in the direction of optional syntax.

If we could pull it off that would be great, but it would demand the greatest scrutiny to make sure it behaves properly and looks reasonable in all sorts of scenarios and edge cases, and doesn’t fall into the same human-readability pitfalls that Coffeescript finds itself in.

5 Likes

Ughh, I find ( ) for multi-lines much more annoying than { }. Please not. In fact I prefer to use curly braces for lambdas on single lines as well. They are only bad if you use a German keyboard layout (but who does when writing in a curly braces language?)

1 Like

I’m a bit curious why you prefer them even for single line lambdas as well. I mean, I do it too, but mostly out of habit because it’s annoying having to switch the whole time when you add a line, or when you want to make it a pattern matching function (*). Not because there’s any kind of advantage to it.

And then there are these methods such as Either.fold that have 2 function parameters in 1 parameter list and suddenly replacing ( ) with { } doesn’t work anymore.

If I’m not mistaken foo{ ... } is actually just short notation for foo({ ... }). So once you start inferring the curly braces it makes sense to only write the parentheses.

(*) Another one of those confusing syntax gotchas by the way. When a beginner asks me why they have to surround a PartialFunction / pattern matching function in curly braces the only possible answer seems to be “because that’s just the way it is”.

3 Likes

To this point, I think it may help to define a Scala 3 Style Guide, like Python’s PEP 8. The use of whitespace seems to be more important in an indentation style.

(This would be part of an update to the current Scala 2 Style Guide.)

3 Likes

Same thing here. What really surprised me is that some people actually like it! I would be personally sad to have to use this syntax in Scala. I’d rather use any of the rest :, do, with/where, etc…

7 Likes

I guess I like to clearly see the block boundaries, and curly braces are
visually more distinct, plus I prefer to have an extra space between
and after the opening brace:

xs.map { x =>
  val tmp = foo(x)
  tmp * tmp
}

I try to avoid methods like Either.fold with two function parameters
in the same argument block, in my API, I would always use currying if I
needed more than one function parameter. In the case of Option.fold,
I’d use that if I can put the zero case very short in parens, like
opt.fold(z) { x => ... }, and tend do use pattern matching if I need
more space for the None case. I almost never write ({ ... }).

2 Likes

And take a look at Unison

“def zero ? x do true end”

:scream_cat:

1 Like

I really want to like the optional braces syntax. I haven’t used it ever, but I have been using Scala professionally since about 2012.

The examples Martin supplied in the OP are subjectively very difficult to visually parse, at least in the github UI. Maybe it will just take more time, but I’m doubting it.

I think it would be easier if the indentations were four spaces instead of two. The use of four spaces in Python, or at least the official Python source, makes it subjectively much easier to parse. Here are the first two random examples I found.

6 Likes

The nothing idea has some merit, but I think it only works when we allow single-line lambdas. Otherwise it’s too restrictive.

Also, even if we allow single-line lambdas, it’s not the most compact syntax:

xs.foreach(println)
xs.map(_ + 1)

beat

xs.foreach x => println(x)
xs.map x => x + 1

in size, though maybe not in clarity.

Anyway, I think “nothing” is acceptable. I mildly prefer .. because it’s more flexible but perhaps it’s better not to introduce too many concepts.

scala> try 42 catch case _: NullPointerException => 27
val res0: Int = 42

scala> try 42 catch case _: NullPointerException => 27 case _: RuntimeException => 17
1 |try 42 catch case _: NullPointerException => 27 case _: RuntimeException => 17
  |                                                ^^^^
  |                                            eof expected, but 'case' found

scala> 42 match case 27 => false
1 |42 match case 27 => false
  |         ^^^^
  |         '{' expected, but 'case' found
1 |42 match case 27 => false
  |                         ^
  |                         'case' expected, but eof found

So I’d also like

scala> List(42).map case x => x + 1
1 |List(42).map case x => x + 1
  |             ^^^^
  |             eof expected, but 'case' found

Some are opposed to one-line run-on cases using braces, omitting a semi-colon.

1 Like

Sounds inventive, but it kind of a stretch.
What has not been mentioned (that I saw) is that : feels natural because it is the natural and historic way to start an enumeration in many natural languages. e.g: “I went to the shop to buy the following: fruits, milk…”.

So being able to place : to open a block or put several sub-items sounds great to me. The problem perhaps is that : has a previous meaning defining return types (which I would rather change instead if I would to ignore compatibility completely). Having both is not ideal, but less terrible to me than some other alternatives like “with”, “where”, “let”, “#”, etc.

2 Likes

I must say I’m genuinely surprised at how much I like the nothing-at-all syntax. To me, if there was a way of somehow extending this syntax to get rid of problems that @sjrd mentioned, it’d be a clear winner.

Though as things currently stand, I’d actually be more in favour of @LPTK’s proposal of using @ to begin blocks. I find it useful to have a consistent visual indicator whenever a block of code begins, and in this regard, that syntax works very well.

This is actually where I feel that the current syntax is somewhat lacking: indented blocks of code sometimes begin with a :, but not always. I find it somewhat jarring every time a line ends with match and the block of cases begins, as though I need to switch gears to understand that I’m not actually looking at another line of code. I needed to write some Python recently and it feels like the way it consistently uses : actually helps make it pleasant to read.

2 Likes

This code is not really comparable to the Dotty code base. In Python, people tend to write blocks with short imperative statements, which makes them easy to read. The fact is that Scala programs usually have much, much more elaborate expressions, so they’re almost surely going to be harder to read no matter what.

3 Likes

:thumbsup:

In any braceless scheme, what is the way to apply a multi-line argument:

def foo(a: Int, b : Int) : Unit = ???

foo(1, {
  //Do Something
  //Do Some More
})
2 Likes