Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Lint or deprecate auto-tupling (like Scala 2's -Xlint:adapted-args) #19255

yawaramin started this conversation in Feature Requests
Discussion options

Equivalent of Scala 2. E.g. Some(1,2) should warn about adapted args.

You must be logged in to vote

Replies: 8 comments 8 replies

Comment options

This would fit in well with the effort being made in Scala 3.4 to begin phasing out legacy language features.

One past discussion in this area: https://contributors.scala-lang.org/t/lets-drop-auto-tupling/1799

Another: #4311

The Scala 2 ticket is scala/bug#3583 , where I suggested that we deprecate instead of merely offering a lint. If Scala 3 deprecates, I believe we would follow suit and deprecate in Scala 2 as well under -Xsource:3.

You must be logged in to vote
3 replies
Comment options

Note https://contributors.scala-lang.org/t/lets-drop-auto-tupling/1799/9

[It] would be a shame to lose what is effectively our only tool for safe mixed-typed variadics. It seems like if autotupling is going to mostly go away, it’d be nice to get some way to get it back via a request at the definition site.

The trio of generics, autotupling, and typeclasses allow you to actually write safe arity-generic methods (within any relevant tuple size limits).

It would be nice to make autotupling an opt-in behavior for some intentional functions, unless this is already possible in Scala 3 otherwise. In the thread I'm calling the opt-in as

def foo[A: ParamList](params: A): Unit = ???
Comment options

If it was a warning, it could be opted in to with @nowarn, I think?

Comment options

If it was a warning, it could be opted in to with @nowarn, I think?

As long as it can be done at the definition and not the call-sites, as that'd be a lot of noise. Mayyybe with Wconf.

Comment options

@nicolasstucki Did this come up at all when you were doing your inventory recently?

You must be logged in to vote
1 reply
Comment options

No. I will add it to the list in https://github.com/orgs/lampepfl/projects/2/views/11

Comment options

It's more tricky than just dropping auto-tupling. We'll have to start with this:

 val buf: ListBuffer[Int] = ???
 val buf += (1, 2)

This needs to be declared illegal first. The general rule will be that infix operators no longer take vararg arguments.
Why? Because auto-tupling is necessary to make this work in the current rules:

val xs: List[(Int, Int)] = ???
(1, 2) :: xs
xs :+ (1, 2)

If we drop auto-tupling, this would no longer work, which would be upsetting. So we have to start with the infix varargs. buf += (1, 2) needs to be illegal. Right now it's a deprecation warning:

sc ../new/test.scala -deprecation
-- Deprecation Warning: ../new/test.scala:15:12 --------------------------------
15 |val _ = buf += (1, 2)
 | ^^^^^^
 |method += in trait Growable is deprecated since 2.13.0: Use `++=` aka `addAll` instead of varargs `+=`; infix operations with an operand of multiple args will be deprecated

What we need to do:

  1. Warn on the compiler side that (1) infix operator definitions cannot take vararg parameters, (2) infix operator calls cannot take vararg arguments. These should give deprecation warnings in the next version.
  2. Make these things illegal in a version after that, which would mean that a tuple passed to such an infix operator is treated as a tuple.
  3. Drop auto-tupling.

It's a long road. We better start quickly. Who can do the first step (deprecation)?

You must be logged in to vote
0 replies
Comment options

I also want to clearly state that we should not waste our time linting this, like we did in Scala 2. Doing a lint here is a half-baked solution that creates language dialects.

EDIT: Sorry, we do already have a lint in place. It's a language import: import language.noAutoTupling. Here's the doc comment:

 /** Where imported, auto-tupling is disabled.
 *
 * '''Why control the feature?''' Auto-tupling can lead to confusing and
 * brittle code in presence of overloads. In particular, surprising overloads
 * can be selected, and adding new overloads can change which overload is selected
 * in suprising ways.
 *
 * '''Why allow it?''' Not allowing auto-tupling is difficult to reconcile with
 * operators accepting tuples.
 */
 @compileTimeOnly("`noAutoTupling` can only be used at compile time in import statements")
 object noAutoTupling

So, yes, to make progress, and make the import redundant, we have to follow the steps I outlined above.

You must be logged in to vote
0 replies
Comment options

The discussion about "will they or won't they?" goes back to 2018 when the API was deprecated: "Scala 3.0 will probably drop support for infix operators with multiple parameters." (szeiger) So it's already been a long road trip.

Scala 2's best effort is to lint both, -Xlint:multiarg-infix. The "warts" are close siblings.

The advantage of a lint is that you get to hear feedback about how it messes with someone's DSL.

which would be upsetting

... for some definition of "liberating".

You must be logged in to vote
0 replies
Comment options

OK, thanks to @odersky for pointing out import language.noAutoTupling which is effectively the same lint as in Scala 2. Does anyone know how to import it for a whole project? I don't recall having to do that in a Scala project before.

You must be logged in to vote
3 replies
Comment options

➜ ~ scala -language:noAutoTupling
Welcome to Scala 3.3.1 (21, Java OpenJDK 64-Bit Server VM).
Type in expressions for evaluation. Or try :help.
scala> Some(42,27)
-- Error: --------------------------------------------------------------------------------------------------------------
1 |Some(42,27)
 | ^^
 | too many arguments for method apply in object Some: (value: A): Some[A]
1 error found

Another trick for the feature implicits is just to stick your own implicit definition somewhere, such as a package or a custom predef for -Yimports.

Comment options

Except that it has no feature trait and:

scala> { given scala.language.noAutoTupling.type = scala.language.noAutoTupling; Some(42,27) }
-- Error: --------------------------------------------------------------------------------------------------------------
1 |{ given scala.language.noAutoTupling.type = scala.language.noAutoTupling; Some(42,27) }
 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 | `noAutoTupling` can only be used at compile time in import statements
1 error found

export also doesn't work...

Comment options

Awesome, thank you. Looks like we already have effectively the Scala 2 lint for project-wide use.

Comment options

At scala/scala#10857 (comment) I noticed the lint doesn't warn for infix tupling:

➜ ~ scala -Xlint:adapted-args
Welcome to Scala 2.13.15 (OpenJDK 64-Bit Server VM, Java 23).
Type in expressions for evaluation. Or try :help.
scala> def f[A](x: A) = x
def f[A](x: A): A
scala> f(1,2,3)
 ^
 warning: adapted the argument list to the expected 3-tuple: add additional parens instead
 signature: f[A](x: A): A
 given arguments: 1, 2, 3
 after adaptation: f((1, 2, 3): (Int, Int, Int)) [quickfixable]
val res0: (Int, Int, Int) = (1,2,3)
scala> object X { def f[A](x: A) = x.getClass }
object X
scala> X f (1,2,3)
val res1: Class[_ <: (Int, Int, Int)] = class scala.Tuple3
scala>

I was reviewing the behavior because I wondered why I had a nowarn on a tuple:

importInfos(ctx.unit) ::= (info, keyword, ctx.owner) : @nowarn

So in that PR, I demote -Xlint:multiarg-infix to -Wmultiarg-infix.

Not only am I reconciled to the current behavior, I hope it does not change. I don't use "multiarg infix", but somebody does.

I would propose that the desired feature is not auto-tupling but auto-untupling: if applying infix tuple doesn't work, only then consider multiarg infix. (The opposite of current priority.) That is in the spirit of parameter untupling: "don't hassle me with arity boilerplate".

You must be logged in to vote
0 replies
Comment options

Just wanted to point out that autotupling is currently essential for libraries like @armanbilge's Calico - I guess it'd still be fine if autotupling were to be made illegal, but it'd surely become less convenient. Mayybe the DSL can be reworked to still work without autotupling too...

You must be logged in to vote
1 reply
Comment options

Thanks for the ping. It looks like #19255 (reply in thread) captures the Calico usecase.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

AltStyle によって変換されたページ (->オリジナル) /