Scala 3 significant indentation

This is why IMO the timespan from milestone release to RC is way too short.

In most projects, development towards a new release happens in a somewhat linear fashion, and milestones signal that some identifiable portion of that work has been completed and is ready to be tested. Release candidate means that all the work is believed to be done, subject to discovery of release-blocking issues. For example, if a release takes a year, there might be a milestone every few months, and at the end of the year they put out an RC, which will become final if no bugs are discovered, and they usually are, so that cycle repeats a few times until the RC indeed becomes the release.

In this case however, the whole time it seems like everything was being worked on at once, and anything was subject to revision at any time. That’s fine, something like this needs that sort of experimentation. But when everything is in flux, and everyone knows that because there are no proper milestone releases, the percentage of the community that sinks their teeth into it is limited. Certainly in this case it was no small amount. But there are a lot of people who have not even begun porting yet. Some of those are libraries that are upstream of other projects.

I’m glad we’re in the milestone phase already and I know people want Scala 3 to be released already after so many years, but personally I think we need more time until RC. We need to have a longer time where we signal the community “we’re done experimenting, now is the last chance to give feedback before we go into RC and nothing can change except fixing bugs.”

5 Likes

Thanks for your post @nafg, what you wrote is true and makes sense. We ourselves are trying to find the best balance as each step is made, and as you also said, there are a lot of steps at the same time at the moment (feature discussions, tooling and documentation development, updating education, and so forth).

Last and this week it became apparent that community onboarding will take more time than we estimated, so we owe it to all of you to revisit the timeline.

By the end of this week, we should have enough input to propose something sustainable, please stay tuned.

12 Likes

With a long history of writing in other C style languages, and disliking Python due to its indentation based syntax then I would have thought that I would naturally come down on preferring braces style syntax.

However, when I write Scala 2 code I note that I already generally try and leave out braces when I can, e.g. case statements, single lined methods and expressions. I also note that regardless of whether braces are present or not, I want and expect code to be reasonably formatted anyway.

I also note that Python is a very popular language, particularly for beginners, and perhaps the indentation based grammar plays a part in that.

So, I actually expect to try the new quiet syntax in Scala 3 to see how it works in practice, with the knowledge that I can probably just ignore it (in my code) if I don’t like it. I’m not yet sure about the end block marker, and perhaps I will still use braces for classes, traits, objects and longer method definitions. But I am willing to give it a try, with a reasonably possibility that I may end up liking it.

Probably I would have preferred if this feature was marked as being somewhat experimental for 3.0 with a view to running a longer wide community experiment and then deciding in say 3.1 or 3.2 whether this should really become the default syntax, or whether it is an unpopular experiment and should gradually be deprecated.

5 Likes

Amen. Just chiming in to say that I always thought end Foo was ugly and verbose.

I have always needed braces in order to match them in vi.

However, after transitioning to optional braces, now I appreciate end syntax for its intended purpose. Namely, “sorry this method is too long, let me show you where it ends”.

I’ll add that I think tooling support is required given braceless syntax.

2 Likes

When I work on python I usually spend more time on manual formatting because idea do not understand syntax until I format it correctrly, so “significant indentation” is usual less productive for me for writing. I have no problem with reading code, because code is usually formatted in any case.

5 Likes

I think it’s a shame that the topic of significant indentation is always so heated. I sympathize fully with Martin’s reasons for wanting optional braces. When writing code, it’s a pain to fit in braces every time you need to add an extra statement for debugging or other things.

For writing code, I think it’s exclusively a change for the better once tooling (like IntelliJ which currently refuses to indent how I intend all the time) catches up.

For reading, I’m not so sure. I’ve never understood the religious sentiment against having lines with just braces. For long methods or template definitions where it can be hard to find the beginning of the definition, most editors provide some way of navigating to the start of a brace or parenthesis. Providing support for such navigation is much more complicated in the absence of braces.

When I’ve read the Dotty code base, it’s been extremely useful to be able to easily find the beginning and end of a definition using Ctrl+M in Sublime Text.

end markers only solve part of the problem. It tells me what definition just ended, but that doesn’t really help me if I find myself in the middle of a definition and I want to find the beginning. I welcome an example of where it would be useful, but my spontaneous reaction is that it just adds noise where a } would’ve been clearer. It also makes me think of languages with beginend block syntax, which I personally think is very hard to read. The end marker is also not unambiguous, as shown by this example:

class C:
  //Ridiculous amount of code
end C

object C:
  //Ridiculous amount of code
end C

If i now read end C, how can I know if I’m looking at the class C or it’s companion object?

I’m also not sold on using : for starting a block. : already has different meaning depending on whether it’s used in a context bound, or for giving a type to an expression or definition. It could be argued that it’s easy to distinguish the new meaning from the other ones, but I remember seeing arguments (which I can’t find now) against introducing syntax like forall T. T for polymorphic function types, because it would be confusing to introduce new meaning for ‘.’, which is a reasonable objection.

Personally, I would’ve preferred a where marker:

trait A where
  def f: Int

class C(x: Int) extends A where
  def f = x

object O where
  def f = 3

enum Color where
  case Red, Green, Blue

type T = A where
  def f: Int

given [T](using Ord[T]) as Ord[List[T]] where
  def compare(x: List[T], y: List[T]) = ???

extension (xs: List[Int]) where
  def second: Int = xs.tail.head
  def third: Int = xs.tail.tail.head

new A where
  def f = 3

Or simply drop : without replacement.

There are many cases where braces make code more readable and many where the conciseness of leaving them out makes code easier to write and read. Personally I think optional braces would overall be a good addition. I also completely disagree with the opinion that braces must be optional everywhere or nowhere. That said, there are details in the syntax that could be discussed more considering how big change it is and how permanent it is. It will be really hard to change once it’s been established.

7 Likes

The elephant in the room being that if the tooling to make working with significant indentation easy still isn’t there for a language as popular as Python, it’s a bit hubristic to think the folks behind IntelliJ, VSCode, etc will be willing or able to do so for the much smaller Scala community. I’m not saying it’s impossible to get there, just that there’s already sufficient motivation for it to have happened already, so we should temper expectations appropriately.

1 Like

JetBrains did a lot for the Scala community, and the begin/end versus { } problem won’t exist, as IntelliJ already does the fully semantic parsing instead of mechanic { } detection. The rest will be using Metals in some form, so …

3 Likes

Just want to say that I think where is pretty great. Only for lambdas (where -Yindent-colons uses :) it doesn’t really seem to fit.

2 Likes

rcano: There’s always an exact opposite opinion I’m sure. I certainly agree with that. I just have my perspective I was sharing based on my use.

1 Like

That’s fair, it’s far more likely that it’s a case of “not able” than “not willing”, as they’ve done a ton of work with implicits and similar. I just don’t see how they’re suddenly going to be able to smooth over the pain points because we’re asking for it, when the Python community has been dealing with this for literal decades.

3 Likes

Just wanted to add my 2 cents and say that I don’t think there’s anything wrong with braces, and I don’t know what the hurry is to try to get rid of them. They’re a tried and true solution to demarcating scope that’s simple and elegant, IMO.

If Martin and others want to add the ability for braces to be optional, I think that’s fine, as long as people can continue to use braces if they want to.

2 Likes

Interestingly, I had to actively search for the curly braces to identify which snippet was which.

2 Likes

I read your post, looked at the snippets, and still couldn’t see the braces at first :slight_smile:

Unfortunately, I have’t figured out how to show two code snippets side-by-side, which would probably give a better comparison.

Interestingly, that’s one of the things I like about the braces - they’re there when I need them, and remarkably unobtrusive when I don’t :slight_smile:

1 Like

I think the optional braces needs us to be more careful when merging code.

3 Likes

I often use braces in my IDE to view code or collapse it etc. Also there are already too many ways to do too many things in Scala, so many looking at one library compared to another is like viewing two different languages sometimes. I think it is monkey see monkey do, boredom? I think Python doesn’t have braces or something?

I would love to write braces to keep me away from failure in production

I’d really like this meme of “too many ways to do things” to die. It’s such a thought-terminating cliché, which does not apply at all to powerful languages like Scala, where having many options is actually a strength.

Are you telling me it’s a problem that xs.distinct and xs.distinctBy(identity) and xs.toSet.toList and xs.groupBy(identity).map(_._2.head) and

val seen = mutable.Set.empty[T]
xs.filter(x => !seen(x) && {seen += x; true})

all do the same thing is a problem?

More generally, are you saying that languages should be inexpressive enough that you can only do each thing in a single unabstracted way?

Sheesh! Not every language has to be like Python or Go.

That’s a consequence of the fact powerful languages allow domain-specific abstractions to be designed, and again it’s a strength. Humans don’t really think in mutable variables and for loops; they think in high-level and composable concepts.

10 Likes

My concern with academics running the show is not so much having new features. I’m more concerned with how much weight is given to the response of students taking CS 101, or how pretty that recursive Fibonacci calculation looks like.

Or how Scala is trying to compete with Python by becoming more like Python.

6 Likes