Support upcoming Scala 3 indentation-based syntax in Scala 2.13

Scala 3’s new indentation-based syntax has been in the making for the past half a year. I think it’s an interesting change and I’d like to give it a try in my medium-sized codebases. However, this is not possible today, because to try the new syntax I need to use Scala 3’s Dotty compiler.

I’d like to propose the new syntax (as it is today) is merged in Scala 2.13 —under an experimental flag— so that people with medium-sized and large-sized codebases using Scala 2 today can try it out and give early feedback to better inform the syntax changes in Scala 3.

I think there’s a lot of insights to be gained from using the new syntax in the real world and, given how important stylistic changes are for the end user, the whole community would benefit from this opportunity. I am myself really excited to see how programming with indentation-based syntax feels like.

8 Likes

What would be the difference with compiling their project with Scala 3 instead of Scala 2?

-Ydotty would be the ultimate forking flag.

-Xsource:3.0.0 is already supported, though.

Not having to port your codebase to a new compiler.

Several Scala 2 things do not work as-is in Dotty, most notably scala-reflect macros. So it’s not like you can seamlessly try your Scala 2 code with Dotty.

3 Likes

For example, I might want to try out optional braces without swapping out my ecosystem.

Also, probably all my compiler flags are tuned for 2.13.

Now I really like Jorge’s proposal. I wonder how much is covered by “just syntax”?

3 Likes

Shouldn’t the syntax stabilize first? It might be meant for experimentation and feedback, but you’re going to have an even harder time getting that message across to all users when it’s merged into the mainstream Scala 2.13 compiler.

But the syntax is often the user interface for a language feature. So, supporting Scala 3’s syntax in Scala 2 basically means implementing Scala 3 in Scala 2. Example: type lambdas. What does it mean to support the [A] =>> ... syntax without actually supporting type lambdas?

What could be done though, would be to implement “pre-processors” or compiler plugins that would desugar Scala 3 syntax into Scala 2. In the case of type lambdas, this project already exists and is called kind-projector. I suggest opening an issue in that project to ask for support of Scala 3 [A] =>> ... syntax.

I suggest doing the same for other “syntactic” features (e.g., enums) you want to experiment with: implement your own code pre-processor or compiler plugin, but I’m afraid that the cost of re-implementing Scala 3 in the Scala 2 compiler codebase would be too high for the benefits.

1 Like

My proposal is only concerned with the stylistic changes to the Scala 2 syntax, mostly related to the indentation-based syntax. Other syntax leveraged for new Scala 3 features can be assumed can be dropped.

That’s possible, but it’s not really what this proposal is about. I want an official implementation of the new Scala 3 syntax that I can use by just enabling a flag in the compiler.

I’d like the compiler team to be involved in implementing this feature because there is no official documentation explaining all the changes made in Scala 3’s syntax and I want the implementation to be a blessed, bug-free implementation of the new syntax.

That being said, I wouldn’t mind using a compiler plugin implementing the new syntax so long as it’s a faithful implementation of it. I just think that supporting it directly in the compiler will lower the barrier to trying it out.

1 Like

To add to that, implementing syntax pre-processors in scalac is not possible. kind-projector runs after parser and before namer. You can’t add a phase before the parser, the compiler implementation forbids it. The closest to making parsing “extensible” has been @Duhemm’s work on parser macros which aren’t sufficient either to implement Scala 3 syntax in Scala 2, so it looks like the only path forward is to implement it in the compiler itself behind a flag.

OK, this was not clear in your first post. I agree that this could be useful.

I’m not sure what would be the easiest way to achieve that: either a separate pre-processor tool converting from indentation-based to brace-based, or a compiler flag in Scala 2. We might also need a translation from brace-based to indentation-based, so that existing codebases could be converted and developers could see how the new style looks like on significant pieces of code.

That being said, I’m not sure whether we should first wait for the SIP committee to approve/reject the indentation-based syntax before we invest in creating these tools, or if we should first have this tool so that the SIP committee can decide.

In fact, type lambdas would be a prime candidate for this. The concept already exists, but currently has a horrible syntax. And as @jvican said type-projector cannot change Scala’s syntax.

Scala 3 syntax features that would be straightforward and useful to have with a compiler flag:

  • optional braces

  • enums

  • type lambdas

Anything else? given would be a higher-hanging fruit, but could probably be done too.

2 Likes

given is not just syntax. Its semantics are different as well.

1 Like

It’s been a while I don’t look at enums but IIRC it’s not straightforward to map enums semantics to Scala 2. It if can be done I’m on board. As to given, I would probably leave it out.

1 Like

Maybe because of the Java interop part (or is there something else?). I’d argue it’s a minor part of the feature, and having pure Scala 2 enum syntax without any JVM magic would already be super useful.

I think that should do it:

// dotty
enum Color(val rgb: Int) {
  case Red   extends Color(0xFF0000)
  case Green extends Color(0x00FF00)
  case Blue  extends Color(0x0000FF)
}

// scala 2
trait EnumEntry {
  def name: String
  def ordinal: Int
}

trait Enum[A <: EnumEntry] {
  def values: Seq[A]
  def valueOf(name: String): Option[A] = values.find(_.name == name)
}

sealed abstract class Color(val name: String, val ordinal: Int) extends EnumEntry {
  // using 'def' just to emphasize that there could be methods here too
  def rgb: Int
}

object Color extends Enum[Color] {
  object Red extends Color("Red", 0) { val rgb: Int = 0xFF0000 }
  object Green extends Color("Green", 1) { val rgb: Int = 0x00FF00 }
  object Blue extends Color("Blue", 2) { val rgb: Int = 0x0000FF }
  override val values: Seq[Color] = Seq(Red, Green, Blue)
}

There’s also enumeratum, which might do exactly that using macros.

Is this possible to implement via a compiler plugin or is it too fundamental?

enumeratum does provide this functionality, based on my tinkering the primary difference is that implicits resolve against Scala 2 style enum values, but do not resolve against Scala 3 style enums.

I’m still undecided if this is a good or bad thing, but it is something to be aware of when doing this.

No, it’s not possible:

I think I want to intentionally scope this proposal very well and not include any syntactic changes related to new language features such as enums.

I’m mostly interested in exploring the indentation-based syntax. I see an opportunity here to to build momentum and try out a Python-like way of writing Scala 2.

This effort can be useful to help refine the existing syntax and spot corner cases that would only be found whenever people migrate to Scala 3 for good. I’m certainly most likely to migrate earlier to Scala 3 if my codebase already uses this style.

@odersky @lrytz Do you think this is a good idea?

1 Like

Momentum is good, running afoul of the sunken costs fallacy isn’t. Before large amounts of effort are put into this, it might be a good idea to wait on the discussion about this feature proposal that we’ve been promised.

Just like there is a segment of our community for which doesn’t want Scala to turn into Haskell, there’s a segment of our community that doesn’t want Scala to turn into Python.

2 Likes

This proposal only makes sense if the new syntax is finally merged and blessed in Scala 3. If it isn’t, then you can assume this won’t be implemented.

This thread merely suggests that the impact of the effort is extended to Scala 2.13.x so that the whole community can try it out and give feedback. I don’t intend to start another discussion about the syntax, I believe there are already other threads where that’s happening.

1 Like