Feedback sought: Optional Braces

I also don’t think a consensus was reached in the number of spaces for indentation. IIUC, the current implementation is 3 spaces, but this is highly irregular although it has other nice properties.

2 Likes

Yes, I agree. We will not be able to mandate that, nor do we want to. Number of spaces is not defined in the language and is orthogonal to everything else. If there is a standard it’s formed organically.

1 Like

True, although official examples, books, style guides and formatters do matter in this regard, so I personally try to be conservative there.

1 Like

Thank you for continuing to iterate on this and seek input.

I’m definitely in favour of ‘with’ over ‘:’. Keeping ‘:’ for type ascriptions makes the language cleaner and more regular.

For consistency, I do think that it would be good for the language to also allow brackets or ‘with’ to be used when collective extension statements are defined. Although perhaps that is already allowed in the latest version?

But for most class/object definitions I still think that the best symbols are probably ‘{’ and ‘}’. I guess the one benefit of ‘with’ is being able to name the end of the class, but a decent editor should be able to provide that information anyway.

For short method bodies and control statements I can easily see the benefit of being able of being able to elide the brackets to make the code shorter and cleaner. But for much bigger/longer constructs the appeal isn’t so obvious to me. Once Scala 3.0 is out (and fastparse is available) I will move my code to Scala 3 and try out the different choices, and pick the syntax that I prefer.

I do strongly think that we should keep this experimental for a release or two - but I don’t think that means that it needs to be under an experimental language flag. This would mean that the updated Scala books might not get written until 3.1, but on the plus side it is possible to get real feedback about how Scala 3 is being received and used by the wider community before the syntax ends up being fixed in stone for the next 10 years.

It would be nice to do this in one release, but I still think that it is more important to be absolutely confident that all of the right choices are being made here.

2 Likes

Just as a call-back: Back when the discussion between : and with was in full swing further upthread, .. seemed to break the stalemate for many people (though not all). It’s short, unobtrusive and scores perhaps more points than either : or with.

1 Like

About collective extension methods, the situation is somewhat different.

  • collective extension methods do not define a local scope, where as with + <indent> means “local scope” everywhere else.

  • we certainly do want to allow a single extension method without needing with. I.e.

    extension (x: T) def append (y: T): T = ...
    
    extension (x: T)
      def prepend (y: T): T = ...
    

    should both be accepted. So then when we combine the two to a single collective extension, would we require a with or allow one? Requiring it is just as bad as braces in that I have to add something to the other scope if I have more than one thing in the inner scope. Allowing it just gives two ways to do the same thing.

That’s why I think it’s better not to use with. But there can be a nice error message that explains the matter if somebody writes it.

1 Like

My impression was that opinions of .. were much more polarized than for the other alternatives. Some people liked it, but the people who didn’t like it really didn’t like it.

I welcome the change to with, i find anywhere where we have class parameters the colon starts to look very sketchy.

-enum Tagged[T](val cls: Class[?]):
+enum Tagged[T](val cls: Class[?]) with
   case IntTag  extends Tagged[Int](classOf[Int])
   case UnitTag extends Tagged[Unit](classOf[Unit])
4 Likes

For clarity. are collective extensions allowed to use braces?

The current documentation suggests that they are:
https://dotty.epfl.ch/docs/reference/contextual/extension-methods.html

So, I was coming more from the angle that “with” is allowed instead of a pair of braces rather than it introducing a “local scope”.

Yes. So in that analogy, with makes sense. Or rather, braces don’t really make sense here since they pretend to introduce a local scope where there is none. But it’s the only thing we have if we do not want to rely on indentation. I think it’s OK. Code using extension methods is always new code, so people will tend to rely on indentation, even if they don’t use braces elsewhere.

I guess that if you don’t allow ‘with’ now for collective extension statements, then it doesn’t close the door to allowing it in future if, after more experience and feedback, that was deemed to make the language more regular.

For what it’s worth, having followed this conversation for a long time, my personal preference is definitely with.
And, for consistency, I think it should be required for multi-line enstensions.

Keep in mind that IDEs can choose how to display keywords, so for those who find it cumbersome/distracting to watch, I think there’ll be ample opportunity for IDE configuration.

10 Likes

Is it possible to have the language be non-regular :, with, etc., while applying auto-fixes in IDEs for common mistakes (like text editors can automatically capitalize the first character after a period)?
For example, if someone writes while true: then it will be automatically converted to while true do. With such a feature I think the irregularity problems are mitigated significantly.

3 Likes

Stylistically, I think single-method extensions should be in one line (at least the definition and = operator, if not the actual implementation), and think that’s enough of a visual cue to warrant mandating with for collective extensions.

The use of the with keyword is a good visual cue that multiple methods are expected:

extension (x: T) with
  def prepend (y: T): T = ...

Indeed, IDEs will probably reformat and delete with as a suggestion, if you use collective extensions with a single method; and certainly I would like such matters of syntactic consistency to be handled by scalafmt at some later date.

8 Likes

The purpose of : (and now with) in class/object/trait is to disambiguate in case of stray whitespaces. In extensions you don’t have the problem, so… against with in extensions.

It would be possibly auto-fixable but a pain to learn and use.

I really prefer to just have a more regular language.

1 Like

The compiler might not need it, but if it helps to make the language more regular (and thus predictable for the user) I’m all for it.

I want to be able to simply write code without having to think about specific syntax intricacies.

4 Likes

People who liked : generally didn’t like ... But although I was an early proponent of it, I think other changes have made it unnecessary. I do like .. better than :, but I think the most important consideration is this one:

Hence, with wins, because it’s consistent with the pre-existing idea of with. .. could be self-consistent, but it’s an entirely new thing: a “begin significant indentation mark”, as opposed to “optional braces”. The logic is “add this new thing to get a new syntax” rather than merely “you can leave off braces when they’re superfluous”.

So :+1: from me for with.

5 Likes

For completeness,

class C[A](x: A) extends T w/
  def f = ???

w/ means with. If it is a soft token at EOL, then the slash looks line-continuing.

2 Likes

There’s also the question whether with and braces together is supported:

class C[A](x: A) extends T with {
  def f = ???
}

It can be seen as optional with in addition to optional braces. Then there’s the question of given:

given C with {}
given C {} //  `with` elided
given c: C {} // named
given c: C & {} // abstract with refinement

Of course you cannot omit both.