Feedback sought: Optional Braces

Requiring end-markers for any scope that has blank lines would be really good! It puts all of my legibility concerts to rest. Why not add this as a compiler warning the same way as “Line is indented too far to the left” does now?

1 Like

Let me clarify. We used to have this which was fine:

    class Zip(home: Path) extends Three(home) with Archived { 
      private[this] def zip = this
      type S = Record.Three.Zip[this.type]

      val creator = new InPlateSlot[S, zip.type]:
        val owner = zip

        protected def uncheckedCreate(home: Path, sd: SpannerDir): S = 
          new Record.Three.Zip[zip.type](zip, home, sd)
      }
    }

Now we got this, which is potentially confusing:

    class Zip(home: Path) extends Three(home) with Archived { 
      private[this] def zip = this
      type S = Record.Three.Zip[this.type]

      val creator = new InPlateSlot[S, zip.type]:
        val owner = zip

        protected def uncheckedCreate(home: Path, sd: SpannerDir): S = 
          new Record.Three.Zip[zip.type](zip, home, sd)

Say we have stricter end-tags requiring everything with blank lines to have end-markers (say we introduce -Ystrict-endtags). Then we get something like this:

    class Zip(home: Path) extends Three(home) with Archived:
      private[this] def zip = this  // Is there a better way?
      type S = Record.Three.Zip[this.type]

      val creator = new InPlateSlot[S, zip.type]:
        val owner = zip

        protected def uncheckedCreate(home: Path, sd: SpannerDir): S = 
          new Record.Three.Zip[zip.type](zip, home, sd)

      end InPlateSlot
    end Zip

I think that’s much better then braces ever where.
Why not make it required?

The thing is, either you use : everywhere including method by-name arguments, or you use an alternate scheme like the proposed <| operator, and with in class/object/trait etc. These come together.

If we require it, it should be part of a style checker, as any other layout issue. But yes, I think style checkers should require it.

It’s a separate question whether the Scala 3 compiler should come with a standard style checker. This thread is already too long to discuss that one.

I think minimal style checking should definitely come with the compiler! It would put many of these hotbed issues to rest. @odersky why don’t you start that thread?

Lot’s of people seeing to be suggesting recommending end Foo statements in cases where there have been blank lines in the block defining Foo. I’d like to point two things in your Zip and InPlateSlot example.

  1. You’ve ended up with an extra line when compared to the braced example (12 vs 11). This deeply ironic. E: This is because of an extra blank line I realise, you haven’t reduced the number of lines though

  2. It’s 100% harder for me (yes, this is personal) to pair the start/ends up. There is an objective reason for this though. In the braced example braces always come at the end of lines; I can trivially scan only the last character of a line to see if it is the start/end. In your example I have to read the whole line looking for Zip and InPlateSlot. That’s bad enough but also block of text can be anywhere on the line: for classes/traits at the start; for values/methods at the end.

So in summary we’ve added a line and made the location of the start/end characters less consistent and harder to find.

E2: I’ve scanned the docs and I think the first end should have been end creator in this case (not end InPlateSlot) That doesn’t change the point that the line has to be read and the location moves. The End Statement section of the docs (I can’t link right now, they seem to be down) details the complexity of the rules.

4 Likes

Can you try to scan for the token ‘end’ in general or is it harder? Here’s a version with slightly better colors:

1 Like

The colours don’t really help me. Braces just naturally pair up in my head as they are the last characters of the line and are also distinctive (the characters e, n, and d are everywhere in code and there’s no “start” marker to pair them with). I suppose if we were to move to braceless as the de-facto standard I’d have to get used to it though. I’d probably have to work off indentation alone.

1 Like

It is hard to read for two reasons: First, as has been said, you have to scan the whole line for Zip/InPlaceSlot. Second, the position where the relevant identifier appears is not the point where the block starts.

So, you have:


<Stuff> <the id matching the end marker> <more stuff> <the actual beginning of the block>
<stuff>
<end marker>

3 Likes

It’s not just “stuff”, it’s a brief description (2, 3 words at most) in keywords of what you’re about to see (a class etc)

I found it easy to see what “end Zip” lines up with (because “class zip” is near the start of a line), but I found “end InPlateSlot” hard to line up. I was naturally looking for a method and I had to visually scan the code a couple of times to see what it was closing. I believe that if this had been a pair of braces then I would have spotted the closing scope very easily in this case. Suitable code colouring also helps make it easier.

However, when you have lots of levels of braces then it isn’t always so easy to see what they are closing. In these scenarios an end marker is better, although I’m not sure whether it is necessarily more readable than closing the block with } // InPlateSlot

4 Likes

Sure, let me correct that:


<brief explanation of up to three words> <the id matching the end marker> <more stuff> <the actual beginning of the block>
<stuff>
<end marker>

1 Like

That’s because it is wrong. The example as given does not compile, it gives you a “misaligned end marker” for “end InPlateSlot”. You have to write

end creator

then it’s OK.

3 Likes

I totally don’t get why the end marker should be end creator, since creator has nothing to do with the reason we started a block. The beginning of the line could be anything. We could replace val creator = with creators += or cout << or whatever.

6 Likes

After all, I am sure there should be a flag that can provide ability to choose the style for a project:

  • significant indentation
  • insignificant identation
  • mixed

I am very glad for those who prefer new styles until it harms my projects.

  • insignificant indentation

    it is just less dsl oriented and too complicated for me. At least I do not understand why : end is better than {}, but I know when it is worse in my case

  • significant identation

    I think I understand where it is better, but it seems it is not my case.

  • mixed

    Ok, let it be the best case in long future, but please let me wait that future calmly without hollywars at my company.

Interesting. So your position is that optional braces is such a big downside that it tilts the overall balance of the language from “adopt” to “don’t adopt”.

Having used languages with and without braces, I have a slight preference towards no braces, but I can live with braces as well.

And I believe most programmers have a similar attitude: they won’t reject or accept a language solely based on the presence or absence of braces.

In any case, in my book braces fall in the category of “subjective aesthetic preference”, and thus it’s harder to extrapolate or prescribe from my own preference to the preference of other (potentially newer) user of the language,

3 Likes

I’m in the same position, furthermore I will be describing Scala3 to Scala2 pretty much like Raku to Perl, or Typescript to Javascript. One is clearly the evolution of the other but if you know the original, you don’t know or understand the newer version. Knowing Scala2 will not let you understand a codebase written in scala3, knowing Scala 2 will not let you write any Scala 3.

Edit: although my primary objection is not optional braces, just the overall redesign of the language.

4 Likes

If there was a simple consistent brace-less grammar for Scala that supported all features, then it would be purely a subjective aesthetic preference.

If, however, the new grammar is complex and inconsistent and does not support all features, then it is different.

5 Likes

That’s a pretty fair summation of the problem, for my particular case.

Unfortunately, as described previously described (extensively), for me this isn’t a subjective aesthetic preference, it’s closer to an accessibility issue. The closest analog I could think of is if someone decided to take the Red/Blue Function thought experiment and implement it with red and green, then told everyone with red/green colorblindness that, if they’d just try it a bit more, they’d get used to it.

I don’t know how common my difficulty parsing this syntax is in the general community. I doubt it’s really common, but I also have no reason to think I’m unique. So until the tooling is in place to work past the readability issue, optional braces act as a gatekeeper for the rest of the functionality (at least in my case), and I cannot recommend upgrading.

4 Likes

Funny…I find the end markers make it even worse. (The reason it is funny is this is my code that I posted as an example. Different people have different preferences!)

2 Likes