Scala 3 quiet syntax

I think this specific syntax is more about removing the enclosing parenthesis rather then omitting curly braces; this is why I asked if it would be possible to mix curly braces with the then syntax.

I would much rather see

xs.map { x =>
  val y = x - 1
  y * y
}

than

xs.map:
  x =>
      val y = x - 1
      y * y

Besides, this entire feature (optional braces) is still quite controversial.

4 Likes

Slightly besides the point, but I’ve proposed @ for this use case before. I think it looks nice, and it is backward-compatible (won’t break any code):

xs.map @ x =>
  val y = x - 1
  y * y

The rule would be: Anything that comes after @ (including indented blocks) is considered wrapped into a set of curly braces. Also, @ has least precedence and associates to the left.

So

xs.foldLeft @ init @ (a, x) =>
  val res = a + x
  res

means

xs.foldLeft { init } { (a, x) =>
  val res = a + x
  res
}

As for if/then/else, I think it’s perfect as it is.

3 Likes

Looks like the @ sometimes closes a previous place and sometimes it does not. What if I want to open a second curly brace without closing one?

2 Likes

That’s because it is left-associative. As with any operators, you can’t have it sometimes associate right and sometimes associate left.

Perhaps it would be more useful as a right-associative operator (like Haskell’s $), but I am not sure.

It’s almost like you’d want two paired operators. We could bikeshed that a bit, and I’m willing to kick it off by suggesting {} - there’s plenty of prior art, and it wouldn’t break any code :wink:

1 Like

No, I do not. The entire point is to avoid them.

The problem of paired operators is that they accumulate in annoying ways, making it harder to see which closing brace closes which opening one.
For example, compare f(a)(g(b)(h(c)(d))) with f(a) @ g(b) @ h(c)(d) (assuming right-associativity).
This is not to mention the fact that we’d like to avoid having to terminate functions passed as arguments with an extraneous } line, leveraging indentation syntax instead,

There’s also plenty of prior art with $ in Haskell.

2 Likes

Maybe we can have an IDE plugin that makes curly braces look like something else.

1 Like

The issue I have with these sorts of examples is they don’t reflect the sort of code I tend to run into. Convert that example into something that’s a bit more realistic, and the braces cease to be an issue (particularly with something like the Rainbow Brackets plugin):

input.fold(inputIsEmptyError) { 
  _.entries.fold(entriesAreEmptyError) {
    validateEntries(allowFoo)(_)
  }
}
2 Likes

I’m finally getting around to playing with Dotty as I look at book revisions for the third edition that will use Dotty and I ran into an error that really worries me. I’m putting it here because it relates to the quiet syntax and meaningful whitespace. Previously I have voiced the opinion that I’m not a fan of meaningful whitespace, but I was always under the impression that if one was using the “noisy” syntax nothing would change and this wouldn’t cause a disruption to those who don’t want to move over. Then I got the following error message:

[error] 7 |		val v = new Vect2D(3,4) {}
[error]   |		^
[error]   |		Incompatible combinations of tabs and spaces in indentation prefixes.
[error]   |		Previous indent : 4 spaces
[error]   |		Latest indent   : 2 tabs

I get this by adding a line, using vim, to existing code. The existing code uses spaces, vim, by default, puts in tabs. As an experienced programmer who happens to use the tab key for indentation, I find this behavior a bit annoying because code that is copied and pasted will almost always have spaces for indentation. I can change some setting and get around this though. As an educator who tries to teach novice programmers, I see this an an absolute nightmare. Any time default configurations for tools produce the wrong behavior it means a bunch of headaches for both students and teachers. Yes, the error message is very clear, but this means we either have to have every student change the behavior of vim or stop using vim. I will note that if I edit the file in VS Code everything is fine as it convert my tabs to spaces by default.

What isn’t obvious from this error message is that this code is in curly braces. There is no reason for the compiler to enforce indentation rules because other syntax elements are making it clear where the block begins and ends. The decision to enforce the rules of meaningful whitespace in situations where they aren’t needed as the default behavior seems to me to be very problematic from the education standpoint even if it is only mildly annoying for experienced developers. Is there any way to make it so this rule is not enforced by default for blocks inside of curly braces or has this ship already sailed?

I will note that this project is using 0.25.0-RC2 in case that matters.

4 Likes

There is -noindent, but I was going to say maybe this is just a bug, which is mistaken.

The forum tells me I already pasted the link which says the indentation prefixes must be comparable. “To avoid such errors, it is a good idea not to mix spaces and tabs in the same source file.”

This is why it doesn’t just ignore what is between braces:

In a brace-delimited region, no statement is allowed to start to the left of the first statement after the opening brace that starts a new line.

This rule is helpful for finding missing closing braces.

Maybe that means it should only enforce the rule when there are missing braces to find.

It looks like the flags are intended to be ergonomical. I don’t understand all the dimensions of use cases, but probably you’re not supposed to be unpleasantly surprised. So maybe it is an ergonomics bug.

val rewriteNoIndent = ctx.settings.noindent.value && rewrite

val noindentSyntax =
  ctx.settings.noindent.value
  || ctx.settings.oldSyntax.value
  || (migrateTo3 && !ctx.settings.indent.value)
val indentSyntax =
  ((if (Config.defaultIndent) !noindentSyntax else ctx.settings.indent.value)
   || rewriteNoIndent)
2 Likes

I think that this is just a matter of ensuring vim is setup sensibly.

I actually like the fact that Scala is enforcing that the indentation to be consistent, and given that the mapping from tabs to space indents vary, forcing one or the other to be used consistently generally seems helpful.

Thanks for pointing me to that page. Unfortunately, providing the -noindent flag isn’t a nice option the way we have historically started off using the Scala script environment. These days the preferred tool for Scala scripts seems to be Ammonite. I will have to play with that some, though there is a certain simplicity is the command for both the REPL and running scripts being scala. We have changed things some so that we move to sbt projects about halfway through CS1. Once we get there, we can set up whatever flags we want, but it really is the first part of the class where we want them to also learn to work on the command line and with a basic editor like vim that I’m most worried about.

1 Like

I can talk to our system admins, but I don’t think I can get that changed. Other tools, like make require tabs and we need one configuration to work for everything. So I expect that vim is going to use tabs. However, cut and paste code uses spaces. So this effectively precludes using vim nicely for Scala for any curriculum that also includes tools like make that need tabs.

1 Like

I’m pretty sure you can setup vim to have different indentation settings per language.

1 Like

Google plus StackOverflow tells me that you are indeed correct. Now I get to talk to the admins about getting everyone a Scala specific setup. That should be quite feasible. I guess the first thing to do though is test it some on my own machine while I’m playing with Dotty and converting stuff over.

(In case anyone might mention that I could use the rewrite tools, I agree that I could, but when the code is for a textbook you don’t want to. I feel that I need to make the changes by hand so that I know what they were so I can pay close attention to associated changes that might be needed in the text.)

Although the recent question was about the specific tool vim, it could be generalized to “will you be able to edit any Scala code/file with any text editor without having to convert spaces into tabs or vice versa in order to have it compile”.

On a subjective note, having to set up a tool in a specific way to make it work with a new programming language I was learning would disencourage me pretty quickly, especially if said tool was something as plain as a text editor. (This is not an argument against the “quiet syntax” per se, I like that, but I also like that things “just work”.)

3 Likes

Which editors make tabs vs spaces easier to see? (I’m sympathizing with students and their teachers.)

Geoff Knauth (mobile)

1 Like

Many editors have an option to show whitespace, either natively or as a plugin. I know for a fact sublime and vscode do, I suspect many others as well.

1 Like

I was about to say that leaving these on all the time makes the display noisy, then I popped up VS Code and decided to look into it. It turns out that I already had it set to display whitespace, but in the default color settings, it is dim enough that not only is it not noisy, I hadn’t even noticed it was there. This is also partly because I tend to use a rather small font on my 4K monitor. There is a nice menu option for turning it on and off as well.

This has been a productive discussion for me. Thank you all for your input. While I’m not converted to liking meaningful whitespace, I do think this has convinced me that I can get our tools to work with it well enough that it won’t cause too many headaches for our students.

2 Likes

Probably kicking in an open door, but in doubt, when using vim, set the vi list option and you will actually see the tab chars displayed as ^I
(: set list)

1 Like