Comma inference


#1

Scala has a well known mechanism called “semicolon inference”. I wonder if a similar mechanism may be useful for parameter and argument lists which could then be called “comma inference”.


#2

Could you give an example of where this is useful? Because for the basic case of foo(bar, baz, qux), it’s not obvious that foo(bar baz qux) is clearer (this is ignoring conflicts with infix notation for odd numbers of arguments).


#3

Comma inference should take place at end-of-lines only (modulo end-of-inline comments, infix operators, … like for semicolon inference).

def func(
  a: Int
  b: String
): = ...

func(
  a
  b
)

#4

Regardless of whether this is desirable or not, this can never work in Scala, because it would break existing code.

For example, your example

func(
  a
  b
)

is already valid code and is equivalent to

func(a.b)

We already got trailing commas in 2.12.2. This is what you should use:

def func(
  a: Int,
  b: String,
): = ...

func(
  a,
  b,
)

#5

I know about trailing commas, but find them somewhat unesthetic. Now and then I have to copy sequences of vals into parameters which needs insertion of all these commas.

Yes, you are right “comma inference” would interfere with operation notation where dots can be omitted. For this means “semicolon inference” states some rules when not to infere a semicolon (cited from “Programming Scala”; Odersky et. al):

(1) The line in question ends in a word that would not be legal as the end of a s statement, such as period or an infix operator.

(2) The next line begins with a word that cannot start a statement.

(3) not applicable here

Rules (1) and (2) could also be used for “comma inference”.


#6

Even if your use these rules, your example

does not satisfy either of those rules, as far as I understand. So it makes it not understandable what you want: your first example working or rules that you are proposing? Can you provide an example where “comma inference” working using those two rules works simplifies some expression?


#7

I don’t think Scala (the spec as well as us users) can handle more than one punctuation inference, but there might be some tricks you could try.

You have to get past the parser, so you need a legal “shape” of Scala. For example,

scala> List({
       1
       2
       3
       })
res1: List[Int] = List(3)

The above is still legal Scala. The curly brace gets parsed into Block datatype in the compiler. It might be possible to define a macro that takes vararg Int* as argument, and when Block is passed, expands each statements as an argument.

I haven’t tried it so not sure if it’s going to all work out, but I can see how it might be useful for some DSLs like build.sbt.


#8

Thanks for your comments and proposals. I see that “comma inference” does not hit positive resonance. For me, commas separating parameters or arguments have much in common with semicolons separating statements. Therefore I wondered if commas could be inferred with little mental as well as implementation effort.


#9

In my example a comma would be inferred after the argument “a” because rules (1) and (2) are both not satisfied.


#10

Honestly, I think the comparison is apples-and-oranges. Yes, there are some technical similarities – but in terms of usage, I find them quite different. Semicolon inference is between distinct statements – clear, complete thoughts, that are typically expressed on separate lines. Commas are between parameters – parts of the same statement, which I put on the same line probably 90% of the time.

Personally, I think inferred commas are likely to make code less readable and comprehensible, by and large, not least because they would blur that distinction. So even if it was technically possible, I would probably forbid its use in my company’s codebase…


#11

It seems, you are contradicting youself: rules (1) and (2) are both not satisfied, thus comma cannot be inferred.

Well, to my personal point of view, I feel this idea to be somewhat esthetic, if you like this word. I also don’t like commas when I’m e.g. declaring sequences with something wordy, i.e. in a way I need to put each item on a separate line.

The problem is I don’t see a clear way to have clear non-contradicting way to have this.


#12

I’ve implemented the macro and blogged about it. See removing commas with sbt-nocomma.

import Dependencies._
 
lazy val root = (project in file("."))
  .settings(nocomma {
    ThisBuild / organization := "com.example"
    ThisBuild / scalaVersion := "2.12.4"
    ThisBuild / version      := "0.1.0-SNAPSHOT"
 
    name := "Hello"
 
    // comment works
    libraryDependencies += scalaTest % Test
  })

#13

Oh dear God … :worried:


#14

I like the use case of supplying settings on separate lines without the need for commas! I wonder if a similar approach could handle case class instantiations as well. This would allow to specify configuration information in a succinct way. For example:

case class Something(name: String, size: Int) // still with commas
case class Setup(active: Boolean, something: Something) // still with commas

// but on the usage side:

Setup(
  active = true
  something = Something(
    size = 5
    name = "foo"
  )
)

#15

Well, yes, named parameters assignment seems to not interfere with infix operators syntax and looks pretty reasonable.