Should we gather usage statistics about SIP-44 (fewer braces)?

This thread already lost focus (as they always do). Why are we talking about individual preferences and our carefully crafted arguments on why we prefer what we prefer on a post about gathering statistics again?

We should start other threads on “my brand of scala is better than yours! - enter the flamewars” to keep every one happy, as it is very clear that people do love the topic of their individual affinities.
It would be a fun read.

2 Likes

If you don’t have a pretty good idea of the possible spectrum of preferences, it’s pretty hard to get statistics via survey. So while the “my preference is x” stuff might be over-done, it’s not irrelevant.

What is your favorite flavor of ice cream?

  1. Tomato
  2. Chocolate
  3. Holiday Spumoni with Sprinkles, Chex Mix, and Chili Flakes
  4. Other

Otherwise, the most effective way to keep things on target is to suggest actions, so we’re talking about what might be done.

3 Likes

I’ve mostly been keeping out of this, but seriously: readability is relative and subjective.

I’m super-experienced: I have 45 years of professional experience in about 30 languages of every sort, including 17 years in Scala. I find many Scala 3 examples staggeringly unreadable. I care about readability profoundly, and have for several decades – IMO, Scala 3 is a major step backwards in that respect.

Seriously, that’s my personal primary objection here. There are lots of problems with the new syntax IMO, including the refactoring challenges mentioned upthread, but for me there is a huge, huge problem with readability.

Again – this is subjective, and I’m happy to agree with that. But statements implying that Scala 3 is objectively more readable are just plain wrong, and I am profoundly disappointed in the number of members of this community who keep leaning into trying to say otherwise.

So long as the new syntax is optional, I’m okay with it. I’m in the process of experimentally starting to move my team towards Scala 3, so this syntax is extremely top of mind for me. I suspect we’re going to lean towards a mostly-but-not-entirely-braceful style so that the legacy services and the new ones aren’t jarringly different and folks can use the same mental muscles. That’s all fine. But I don’t expect us to ever move towards fully-braceless – I hate it myself, and AFAICT so do all the other experienced Scala devs on the team.

6 Likes

Me too, and I find Scala 3 to be the most readable language ever–which would suggest that “readability is relative and subjective” is the right call. But a lot of the percepts out of which readability are built are generally quite a bit less variable than you would expect given the difference in opinion (aside from things like space-blindness, dyslexia, and so on–ideally a language will be usable for people with atypical perceptual capacities).

So this makes me wonder whether actually the examples you find staggeringly unreadable are actually the same ones most people find less readable (comparatively), but it bothers you more. If we were going to ask people anything in depth, it would be good to have examples of this sort, so we could judge to what extent the same constructs are viewed as ultra-clear by some and staggeringly unreadable by others, or whether relative clarity ranking is more or less agreed upon, but the bottom ends are viewed with much more distaste by one group than the other. (For instance, with temperature preference, you can find lots of people who agree with “too hot” and “too cold”, but some people find the cold viscerally unpleasant and the hot is tolerable, while others find the opposite–even though they all agree that the too cold is too cold, and the too hot is too hot. Happily, a lot of people are all fairly comfortable in an intermediate temperature range, if you can find it.)

So, can you share some examples that you think are unreadable?

I find almost all of the ones with end markers extra-unreadable, personally. They’re big and intrusive; and if the block is short they’re pointless because you can see the start, and if the block is long they’re pointless because they don’t contain enough context to be useful anyway (and probably you don’t even see the end marker because you’re in the middle).

I don’t know what we’d do with such information, even if we gathered it. But if we were going to make any sort of better-informed decisions going forward (even if only informing what style to promote), I think it would have to be built out of things like this.

Here are some short examples.

(1) Conditional statements

// (A)
if x.name == "J. Smith" then
  db.add(x)

// (B)
if x.name == "J. Smith" then
  db.add(x)
end if

// (C)
if (x.name == "J. Smith") {
  db.add(x)
}

(2) Conditional expressions (multi-line)

// (A)
val entry =
  if x.name == "J. Smith" then db.get(x.name)
  else db.get("J. Doe")

// (B)
val entry =
  if x.name == "J. Smith" then
    db.get(x.name)
  else
    db.get("J. Doe")
  end if

// (C)
val entry = {
  if (x.name == "J. Smith") {
    db.get(x.name)
  }
  else {
    db.get("J. Doe")
  }

(3) While loops

// (A)
while i < xs.length do
  val y = foo(x(i))
  baz += bar(y)
  i += 1

// (B)
while i < xs.length do
  val y = foo(x(i))
  baz += bar(y)
  i += 1
end while

// (C)
while (i < xs.length) {
  val y = foo(x(i))
  baz += bar(y)
  i += 1
}

(4) Block assignments

// (A)
val complex =
  val simple = 2
  val easy = "eel"
  foo(simple, bar(easy, simple)) + easy

// (B)
val complex =
  val simple = 2
  val easy = "eel"
  foo(simple, bar(easy, simple)) + easy
end complex

// (C)
val complex = {
  val simple = 2
  val easy = "eel"
  foo(simple, bar(easy, simple)) + easy
}

(5) Function definitions

// (A)
def catconcap(a: String, b: String): String =
  val c = b + a
  c.toUpperCase

// (B)
def catconcap(a: String, b: String): String =
  val c = b + a
  c.toUpperCase
end catconcap

// (C)
def catconcap(a: String, b: String): String = {
  val c = b + a
  c.toUpperCase
}

(6) Function invocation, static value with block

def foo(i: Int): Int = ???

// (A)
foo:
  val ii = i*i
  ii + bar(ii)

// (B)
/* There is no end marker for function invocation */

// (C)
foo{
  val ii = i*i
  ii + bar(ii)
}

(7) Function invocation, context-block-like

// (A)
boundary:
  if foo(x) then break(bar(x))
  x + 2*x*x + baz(x)

// (B)
/* There is no end marker for function invocation */

// (C)
boundary {
  if foo(x) then break(bar(x))
  x + 2*x*x + baz(x)
}

(8) Function invocation, simple lambda argument

def foo(op: Int => String): Int = ???

// (A)
foo: i =>
  val eel = db.readEel().getOrElse("eel")
  eel.take(i).sum

// (B)
/* There is no end marker for function invocation */

// (C)
foo{ i =>
  val eel = db.readEel().getOrElse("eel")
  eel.take(i).sum
}

(9) Function invocation, multi-parameter, complex lambda

// (A)
xs.fold(0): (acc, x) =>
  val y = foo(x)
  acc + bar(y, baz(y))

// (B)
/* There is no end marker for function invocation */

// (C)
xs.fold(0){ (acc, x) =>
  val y = foo(x)
  acc + bar(y, baz(y))
}

(10) Function invocation, multi-lambda

// (A)
sumtype.fold(
  left =>
    val x = foo(left)
    bar(x, baz(x))
)(
  right =>
    val y = quux(right)
    bippy(y, y.x)
)

// (B)
/* There is no end marker for function invocation */

// (C)
sumType.fold{ left =>
  val x = foo(left)
  bar(x, baz(x))
}{ right =>
  val y = quux(right)
  bippy(y, y.x)
}

(11) Varargs/lists

// (A)
List(
  locally:
    val x = foo()
    bar(x, baz(x))
  ,
  locally:
    val y = quux()
    bippy(y, y.x)
)

// (B)
/* There is no end marker for function invocation */

// (C)
List(
  {
    val x = foo()
    bar(x, baz(x))
  },
  {
    val y = quux()
    bippy(y, y.x)
  }
)

(12) Match statements

// (A)
fish match
  case "eel" =>
    val x = foo()
    bar(x, baz(x))
  case _ =>
    quux()

// (B)
fish match
  case "eel" =>
    val x = foo()
    bar(x, baz(x))
  case _ =>
    quux()
end fish

// (B')
fish match
case "eel" =>
  val x = foo()
  bar(x, baz(x))
case _ =>
  quux()
end fish   // Technically you can omit the end

// (C)
fish match {
  case "eel" =>
    val x = foo()
    bar(x, baz(x))
  case _ => quux()
}

(13) Chaining

// (A)
xs
  .map: x =>
    val y = x*x + 2*x + 1
    foo(y, bar(y))
  .filter: x =>
    val z = x > 0 && x < 10
    quux(z, bippy(z), x)
  .sum()

// (B)
/* There is no end marker for function invocation */

// (C)
xs.
  map{ x =>
    val y = x*x + 2*x + 1
    foo(y, bar(y))
  }.
  filter{ x =>
    val z = x > 0 && x < 10
    quux(z, bippy(z), x)
  }.
  sum()

(14) Traits (simple)

// (A)
trait Foo[A]:
  def foo(a: A, i: Int): A

// (B)
trait Foo[A]:
  def foo(a: A, i: Int): A
end Foo

// (C)
trait Foo[A] {
  def foo(a: A, i: Int): A
}

(15) Classes (non-simple)

// (A)
class Foo[A](a: A, i: Int, s: String, c: Char)
extends Bar[A], Baz[Int], Quux[String], Bippy[Char]:
  def apply(): Boolean

// (B)
class Foo[A](a: A, i: Int, s: String, c: Char)
extends Bar[A], Baz[Int],
        Quux[String], Bippy[Char]:  // You had better indent here!
  def apply(): Boolean
end Foo

// (C)
class Foo[A](a: A, i: Int, s: String, c: Char)
extends Bar[A] with Baz[Int]
with Quux[String] with Bippy[Char] {
  def apply(): Boolean
}

(16) Objects

// (A)
object Foo:
  def bar: Bar = ???

// (B)
object Foo:
  def bar: Bar = ???
end Foo

// (C)
object Foo {
  def bar: Bar = ???
}

(17) extension methods

// (A)
extension (s: String)
  def four: String = s.take(4)
  def six: String = s.take(6)

// (B)
extension (s: String)
  def four: String = s.take(4)
  def six: String = s.take(6)
end extension

// (C)
extension (s: String) {
  def four: String = s.take(4)
  def six: String = s.take(6)
}

(18) Nesting

// (A)
def foo(x: Baz, ys: List[String) = boundary:
  ys.flatMap: y =>
    dbContext("eel"):
      foo(y) match
        case The(z) =>
          if quux(z) then boundary.break(Bar(x))
          Bar(z)
        case _ =>
           Bar(x)
// (B)
def foo(x: Baz, ys: List[String) = boundary:
  ys.flatMap: y =>
    dbContext("eel"):
      foo(y) match
        case The(z) =>
          if quux(z) then
            boundary.break(Bar(x))
          end if
          Bar(z)
        case _ =>
           Bar(x)
      end match
end foo
// (C)
def foo(x: Baz, ys: List[String) = {
  boundary {
    ys.flatMap{ y =>
      dbContext("eel") {
        foo(y) match {
          case The(z) =>
            if (quux(z)) boundary.break(Bar(x))
            Bar(z)
          case _ =>
             Bar(x)
         }
      }
    }
  }
}

With a test set like this–which isn’t necessarily a good one to reveal the problems with significant indentation–to my eye, for short examples like these, (B) is always the worst option, in addition to not being able to be consistently applied (end isn’t always available).

But, to my eye, more often than not (A) beats (C), with multi-lambda and nontrivial classes being very clearly the other way ((C) much better than (A)).

So if we were going to do something like this, do we have more examples where it’s really clear one way or the other, or feels very much one way or the other to someone who isn’t me?

I just found an example in the docs of something that seems to me pretty unreadable in the OOP docs.

trait SubjectObserver:

  type S <: Subject
  type O <: Observer

  trait Subject:
    self: S =>
      private var observers: List[O] = List()
      def subscribe(obs: O): Unit =
        observers = obs :: observers
      def publish() =
        for obs <- observers do obs.notify(this)

  trait Observer:
    def notify(sub: S): Unit

Here we have Subject and Observer at the exact same nesting depth, but because Subject has a self type, everything is indented an extra level. It makes it feel like notify and subscribe are at different depths (but they’re not!).

And if you try to fix it by putting self: S => at the same depth as the function definitions–which is valid–then it kind of gets lost amidst the functions.

Is this the kind of thing you mean, @jducoeur?

2 Likes

These don’t contradict. There are people who disagree on what is more readable, and there are people who don’t care that much about what is more readable. Most people are both, even if you aren’t.

It’s the same story with the symbols and mathy Greek letters in code debate. There are people who:

  • find it pleasant to read
  • find it unpleasant to read
  • think that ‘pleasant to read’ is not at all relevant to the duties of a software engineer, and the slightest inconvenience is enough to shut them off from the idea, even if they did find it pleasant.

My C++ friend agrees with me that reads better than sqrt, but he would never choose to use it in his code, and not because of the practicality of typing it out, but because the idea just strikes him as ridiculous, for reasons he can’t explain beyond vibes, his cultural upbringing in C – his fundamental aesthetic towards programming is low-level and instrumental, he sees coding as primarily a way to make physical computers do stuff; the point is the machine, not the human mind or formulas themselves. “I’m an ‘Engineer, not an artist!” - which is certainly the common sense perception of what programming is all about. But if you view ‘making computers do stuff’ as only a coincidental outcome of programming, and the real task as something closer to creative writing + philosophy + mathematics, and view yourself as a sort of author wanting to cultivate a rich reading experience for yourself and others who care as much as you do, then symbols and meaningful whitespace can feel very attractive and reasonable.

1 Like

I would like to see some of these examples. I wager that if they are unreadable, it’s because they are also in a style of coding that I wouldn’t do (like writing long functions or heavily imperative)

I feel like part of the discussion is becoming unproductive.

It seems there is little desire to gather data about how this new syntax has impacted the community, in part because some people already feel certain that the new syntax is carrying its weight.

That’s probably fine, but a replacement for that data is not that people post anecdotes about how much they like the new syntax, and it’s not useful for a few people to start making “alternative hypotheses” for why not everyone has seen the light.

We might as well be debating tabs vs. spaces. These syntax preferences are a matter of personal taste, and I don’t see how someone could argue otherwise without gathering that usage data. And just like with tabs vs. spaces, it’s unlikely that someone will be convinced that their taste is wrong.

If I understand correctly, there are no plans to force people onto the new syntax, nor is removing the new syntax on the table.

So both syntaxes will stay and people can pick the one they like better for their projects.

Shouldn’t that be the end of the discussion about preferences?

It would probably be better to focus on the original question: If we wanted data showing that this new syntax is valuable (enough), what would that data look like, and how might it be gathered. If the decision is to not do any such data gathering, I feel like all that’s left is tabs vs. spaces discussion, and that doesn’t seem likely to lead anywhere?

That’s fairly simple: I am an existence proof that it’s more than a matter of personal taste. I cannot read non-trivial braceless code because I cannot distinguish the indentation (and I know it’s not age, as I gave Python a try multiple times when I was younger).

That’s what they keep saying, but the official docs are in braceless style, as are the docs for libraries like specs2 (which I find particularly unreadable). If I were coming fresh to Scala, that would be enough to turn me off even if the codebase I would be working in were braceful, because I would have been stopped at the door by unreadable documentation.

That’s a pretty heavy finger on the scales for Scala 3 to eventually become braceless by default, because the ramps to onboard new devs are going to filter out anyone who can’t read braceless code.

Part of the reason these conversations keep getting derailed in that those of us who either can’t read braceless code, simply find it less readable, or just dislike it keep having to repeatedly assert that we do exist.

5 Likes

That’s fairly simple: I am an existence proof that it’s more than a matter of personal taste. I cannot read non-trivial braceless code because I cannot distinguish the indentation (and I know it’s not age, as I gave Python a try multiple times when I was younger).

Sorry, what I wanted to get across is that clearly there is no consensus about which style is better, and different people feel differently about the two styles. What I meant by a “matter of taste” is just that it’s subjective, and we don’t have access to statistics about what the broader community thinks, because the data gathering proposed in the OP hasn’t been done. So all we have to go off is anecdotes by people in this forum who feel strongly either way.

So if there is no desire to gather data about how the new style has been received, the discussion is naturally going to veer into people posting about their personal feelings on the two styles, but that doesn’t really seem like it’s going anywhere.

I don’t think either side can convince the other about the merits of their preferred style. If they could, this feature wouldn’t (still) be so controversial. So it seems like wheel-spinning to continue trying to convince the other side that the new style is actually good/bad, which I feel is what a number of posts above have been trying to do.

That’s what they keep saying

I’m going to trust that the intention is being honestly portrayed, and that Scala simply has two styles permanently now. I mainly care about the ability to opt out of the braceless style. As long as that stays, I can just disable braceless style and act as if it doesn’t exist.

I would be very unhappy about losing that opt out though, and I would consider it a nudge to migrate off the language.

2 Likes

I remember all those endless debates around infix method calls. Some people liked it, some people hated it, some used occasionally. But over years the conclusion was to restrict usage of infix calls to specific cases that have to be framed out explicitly.


On the contrary, there’s Java language and there’s google-java-formatter library that has a very profound feature: it doesn’t allow any configuration whatsoever. The intent was to stop any debates about formatting preferences right now. And guess what? Many Java projects go for it, because:

  1. It really stops the nonsensical debates and lets teams to focus on important things.
  2. It also helps developers overcome the urge to format code manually.

Debates about code styles are bad – they distract teams and sometimes lead to conflicts.

Manual formatting is bad – if developers on some project still do it, they waste their valuable time and company resources. No real business is going to pay for that.

In modern software development whatever can be automated – it has to be automated. Code formatting is one of such things. Exact coding style is not important. In practice, everyone can get used to any style even if they didn’t like it in the beginning.

But what’s really important is to have as few different coding styles as possible. And it would be perfect if it could be enforced on the language level itself – i.e. either braces-only or no-braces. But not both, please. Otherwise these kind of debates will never end.

1 Like

I don’t disagree, but to me that’s an argument for not introducing an alternative syntax in the first place.

But since that particular ship has sailed, I think it minimizes the harm to existing projects to leave the old syntax available.

Otherwise, it forces all projects to do full-project reformatting, and even if that can be automated, it’s a huge waste of time for everyone, especially if you want eyes on all changes at your company. It’s a lot of friction for very little value.

2 Likes

Concrete examples – not to hand, precisely because I haven’t had enough opportunities yet to use Scala 3 in anger.

But by and large, the examples I see that leave me needing to mentally decipher them tend to be methods that are (a) more than ten lines long and/or (b) nested more than three levels deep. A lot of people here seem to respond to those with “well, you shouldn’t be writing that way”, which I find infuriating. I’m not doing this with my own little projects, I’m running a fairly sizeable team of engineers with varying levels of experience, and a huge legacy codebase, and ideals don’t get the features out the door. I’m doing what I can to train folks, but code quality will vary, and I find that harder to deal with in braceless style. (And ideals aside, I do sometimes run across those big methods in real code that people are posting online.)

I also find the paren-less style for method calls absolutely mystifying, period, full stop. I at least grok why people like the braceless style, but I truly hate the paren-less one – it’s so different from pretty much any other language I’ve ever seen, with no benefit that I can see. I basically wind up scratching my head at every single example in that style, groaning at every colon I stumble across, and have little desire to waste time getting used to it.

All of this is very top-of-mind for me – I’m in the middle of bootstrapping our Scala 3 experiments, and am going to be primarily responsible for establishing our coding style in it, so I’m going to be talking with our engineers (both the senior and junior ones) to figure out the right balance for us. We absolutely can’t go whole-hog in the braceless style – the team is going to be dealing with both Scala 2.13 and 3 in parallel, probably for a long time, and I’m not going to burden them with mental shifts going back and forth, so it’s all about finding the places where braceless really is beneficial (mainly small methods, I suspect) but otherwise keeping a largely 2.13 look-and-feel.

5 Likes

You are also an outlier. There also exists people who struggle with indentation sizes > 1 due to eye disabilities, and so on.

I came fresh to Scala a couple years ago and the braceless style was something that turned me on.

Just an idea, maybe an extension could be made in IDEs and web browsers to render braces visually around expressions even when there are none, to help accommodate people who seriously cannot read braceless code. Sort of like inlay hints. Funny, I actually did the inverse in VSCode when I had to use C# - I find curly braces so intolerable that I used the prettify symbols mode extension to turn all braces into invisible whitespace so I would not have to see them.

Because it’s Java, that is their culture - limiting what’s allowed at the higher end of the skill curve so that the community stays streamlined to the lowest common denominator of developer talent, maximizing the mass production of mediocre code for business profits.

Java exists for those who want that. Does every language need to be like Java? Can we not have one production language that is home to programmers who want more than that? A language that gives teams the liberty to express themselves exactly how they find most productive.

There is not another language like Scala. If you like it’s feature set, you have no other options. So, I am glad that the language allows both braces and braceless, because it makes the language more inclusive to everyone. And individual teams can set up formatters to settle debates, it does not need to be at the language level.

1 Like

Really? There are many fp languages that don’t use parens for function calls… Are you talking about the : x => notation for passing lamdas into a higher order function, or something else?

You are also an outlier

Because it’s Java, that is their culture - limiting what’s allowed at the higher end of the skill curve so that the community stays streamlined to the lowest common denominator of developer talent, maximizing the mass production of mediocre code for business profits.

But not all programmers value readability to the same extent, and some programmers find it totally bizarre how much others care about it. [ … ] This difference in mindset and values is certainly a large factor underlying the whitespace debate even if there are other objective friction points.

Many senior programmers prefer the syntax. Languages which select for high skill programmers like Haskell, OCaml, F# use this syntax.

But if you view ‘making computers do stuff’ as only a coincidental outcome of programming, and the real task as something closer to creative writing + philosophy + mathematics, and view yourself as a sort of author wanting to cultivate a rich reading experience for yourself and others who care as much as you do, then symbols and meaningful whitespace can feel very attractive and reasonable.

Please stop posting like this.

These statements come across as stroking your own ego while inventing reasons to denigrate people who do not share your preferences. They are reminiscent of how people talked about gaming consoles 20 years ago.

The idea that Google or other Java users preempt formatting debates by enforcing a style because they want to “limit what’s allowed at the higher end of the skill curve” is a ridiculous thing to say.

5 Likes

like what? My tone, or my content? If I can improve the way I come across I would like to. But something tells me there is no tone or phrasing I could possibly use that would make you not find what I’m saying pretentious. My ideas themselves seem to be what you find obnoxious. So, your request really is just for me to be quiet and not give my opinion here.

I don’t want to share these opinions here, I know it’s not going to be well received. But I feel obligated to respond to public comments attacking preferences I hold, on the contributors forum where there is a suggestion of restricting those preferences.

If everyone else is allowed to say “style isn’t that deep bro, who cares”, of course it’s only fair for me to make a case why is that deep, and give some hypotheses for why I think other programmers are missing it. And it’s strange for you to accuse me of inventing reasons, when I am usually quoting their own statements, and if any I asked of them here to confirm, they (and you) would likely admit to my speculations about mindset, “Yeah, I don’t think of programming in that way at all, what you are saying sounds very bizarre and pretentious" which is halfway what you have already said to me now.

… This is a fact that he admits. It is a minority of people who seriously struggle with whitespace beyond a matter of taste. If he has tried and tried and still cannot cope with it, he is an outlier. It’s no insult.

This was in response to someone suggesting that my preference is only appealing to beginners and isn’t suited for real programming. You didn’t think that was condescending, but me mentioning the existence of Haskell programmers was too much?

It’s really simple. They limit what’s allowed at the higher end of the skill curve because it is also limits what’s allowed at the lower end, they are drawing towards the middle of the bell curve, ‘stabilizing selection’. Java demonstrably has this culture by their refusal to add lots of things like operator overloading (“I left out operator overloading because I had seen too many people abuse it in C++”). See also the creator of F# explaining that he wont support typeclasses in part because he doesn’t want the language to overempower programmers who have advanced knowledge in abstract math and theory - that would make the median programmers feel less comfortable. Programming cultures do this all the time.

About formatters - if you let high skill programmers who are all on the same page decide how they format their code, it enhances their productivity. If you let a huge team containing many mediocre or less passionate programmers decide how they each format their code, you get dumpster fires. The ‘enterprise’ compromise is to mandate a style that can be followed by the median programmer, not impressively beautiful but also not atrociously ugly.

Sure there is also a good point about avoiding spending time debating, and I do agree that a team should agree on a consistent coding style even if some members dislike it. But clearly the wild variance in coding quality amongst developers at those companies is also a motivator (like @jducoeur already mentioned about his company), and more what I was referring to.

edit: Actually never mind, discussing this is just adding extra noise to the thread.

It’s interesting how readability is matter of preference. Personally, I believe well-written Scala 3 code provides a huge leap in readability over Scala 2 and most other languages. Many people are not seeing it yet, since they are stuck in old codebases or old habits. But I believe when you make the switch it’s quite amazing. Everybody has their own tastes, of course, but if you want to experience what I mean with “huge leap”, here are some guidelines I follow in my daily coding

  1. Use indentation syntax.
  2. Never use Java style control, it’s always if-then or for-do
  3. Write applications that represent a control structure with : + indent.
  4. If operator expressions span multiple lines, always write the operator at the start of the following line rather than at the end of the preceding line (that’s a very important one!).
  5. Use end markers sparingly. My rule is that an end marker is appropriate if the section of code it closes contains blank lines.

Together these rules lead to a consistent and in my view eminentently readable style, You might disagree and find that the leap is sidewards or even backwards. But at least there are no half measures.

Thank you for bringing that up. We should try to address any warts that remain. Self types is on the list of todos already. I think the current syntax is too opaque anyway.

3 Likes