Why is autotupling not behind a SIP-18 import

504 views
Skip to first unread message

Rüdiger Klaehn

unread,
Nov 28, 2013, 11:48:31 AM11/28/13
to scala-debate
Hi all,

IMHO one of the most confusing features of scala is autotupling. See this SO question. http://stackoverflow.com/questions/20224728/scala-traversableonce-and-toset

If you have to explain something like this to a beginner, you might as well give up.

Now there exists this facility called SIP-18 to hide difficult to use and complex language features from beginners. I would love to have a way to disable autotupling. I can not think of a single situation where I used it intentionally.

Would it be a good idea to add a language.autoTupling option?

best regards,

Rüdiger

Simon Ochsenreither

unread,
Nov 28, 2013, 12:47:06 PM11/28/13
to scala-...@googlegroups.com

Would it be a good idea to add a language.autoTupling option?

The question is whether we shouldn't get rid of it altogether, if it is true that you have never encountered a situation where it was used intentionally (I have the same experience).

I brought it up on scala-internals a few months ago¹ and I think the answer was that as soon as dbuild would be running, we would be able to assess how much code in the wild would be impacted by killing ()-insertion.
Not sure what's the status on dbuild currently.


¹ https://groups.google.com/d/topic/scala-internals/4RMEZGObPm4/discussion

Simon Ochsenreither

unread,
Nov 28, 2013, 12:56:18 PM11/28/13
to scala-...@googlegroups.com
And in the same turn, I wonder why we didn't manage to make parameter lists work in a less painful way if we decided to mass with tupling in the first place.

Imho, one of Scala's biggest warts is still this:

scala> val m = Map(1 -> 2)
m: scala.collection.immutable.Map[Int,Int] = Map(1 -> 2)

scala> m.map((key, value) => (key+1, value+1))
<console>:9: error: missing parameter type
              m.map((key, value) => (key+1, value+1))
                     ^
<console>:9: error: missing parameter type
              m.map((key, value) => (key+1, value+1))
                          ^

scala> m.map(((key, value)) => (key+1, value+1))
<console>:1: error: not a legal formal parameter
       m.map(((key, value)) => (key+1, value+1))
              ^

scala> m.map({case (key, value) => (key+1, value+1)})
res1: scala.collection.immutable.Map[Int,Int] = Map(2 -> 3)


I mean ... what the hell?! We know it's type exactly ... why do we force people to use pattern matching/partial functions for something this simple?

Haoyi Li

unread,
Nov 28, 2013, 1:11:28 PM11/28/13
to Simon Ochsenreither, scala-...@googlegroups.com
I mean ... what the hell?! We know it's type exactly ... why do we force people to use pattern matching/partial functions for something this simple?

+1. Partial functions also force us to use:

- multi-statement blocks "{}"
- the possibility of multiple `case` clauses
- the possibility of MatchErrors, since the partial func doesn't need to be total

When in the vast majority of cases, you want a single expression, with one, total function, and I just want to destructure the damn thing.


--
You received this message because you are subscribed to the Google Groups "scala-debate" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-debate...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Jason Zaugg

unread,
Nov 28, 2013, 1:49:48 PM11/28/13
to Simon Ochsenreither, scala-debate
On Thu, Nov 28, 2013 at 6:56 PM, Simon Ochsenreither <simon.och...@gmail.com> wrote:
scala> m.map({case (key, value) => (key+1, value+1)})
res1: scala.collection.immutable.Map[Int,Int] = Map(2 -> 3)


I mean ... what the hell?! We know it's type exactly ... why do we force people to use pattern matching/partial functions for something this simple?

Slightly pedantic, I know, but this isn't a partial function, its a pattern matching anonymous function.

-jason

martin odersky

unread,
Nov 28, 2013, 2:31:08 PM11/28/13
to Simon Ochsenreither, scala-debate
On Thu, Nov 28, 2013 at 6:56 PM, Simon Ochsenreither <simon.och...@gmail.com> wrote:
And in the same turn, I wonder why we didn't manage to make parameter lists work in a less painful way if we decided to mass with tupling in the first place.

Imho, one of Scala's biggest warts is still this:

scala> val m = Map(1 -> 2)
m: scala.collection.immutable.Map[Int,Int] = Map(1 -> 2)

scala> m.map((key, value) => (key+1, value+1))
<console>:9: error: missing parameter type
              m.map((key, value) => (key+1, value+1))
                     ^
<console>:9: error: missing parameter type
              m.map((key, value) => (key+1, value+1))
                          ^

scala> m.map(((key, value)) => (key+1, value+1))
<console>:1: error: not a legal formal parameter
       m.map(((key, value)) => (key+1, value+1))
              ^

Yes, I am with you. We should at a minimum give a more helpful error message. The automatic tupling conversion was an attempt to get there eventually, so that you would not need to distinguish between case pattern and tuples. But it got stuck halfway in no-man's land (and gave us an appreciation that doing it right is not so easy, after all). 

Cheers

 - Martin
 
scala> m.map({case (key, value) => (key+1, value+1)})
res1: scala.collection.immutable.Map[Int,Int] = Map(2 -> 3)


I mean ... what the hell?! We know it's type exactly ... why do we force people to use pattern matching/partial functions for something this simple?

--
You received this message because you are subscribed to the Google Groups "scala-debate" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-debate...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.



--
Prof. Martin Odersky
LAMP/IC, EPFL
Station 14, 1015 Lausanne, Switzerland
Tel: +41 21 693 6863

Jason Zaugg

unread,
Nov 28, 2013, 2:35:57 PM11/28/13
to martin odersky, Simon Ochsenreither, scala-debate
On Thu, Nov 28, 2013 at 8:31 PM, martin odersky <martin....@epfl.ch> wrote:

On Thu, Nov 28, 2013 at 6:56 PM, Simon Ochsenreither <simon.och...@gmail.com> wrote:
And in the same turn, I wonder why we didn't manage to make parameter lists work in a less painful way if we decided to mass with tupling in the first place.

Imho, one of Scala's biggest warts is still this:

scala> val m = Map(1 -> 2)
m: scala.collection.immutable.Map[Int,Int] = Map(1 -> 2)

scala> m.map((key, value) => (key+1, value+1))
<console>:9: error: missing parameter type
              m.map((key, value) => (key+1, value+1))
                     ^
<console>:9: error: missing parameter type
              m.map((key, value) => (key+1, value+1))
                          ^

scala> m.map(((key, value)) => (key+1, value+1))
<console>:1: error: not a legal formal parameter
       m.map(((key, value)) => (key+1, value+1))
              ^

Yes, I am with you. We should at a minimum give a more helpful error message. The automatic tupling conversion was an attempt to get there eventually, so that you would not need to distinguish between case pattern and tuples. But it got stuck halfway in no-man's land (and gave us an appreciation that doing it right is not so easy, after all). 

Jason Zaugg

unread,
Nov 28, 2013, 2:58:23 PM11/28/13
to martin odersky, Simon Ochsenreither, scala-debate

Yes, I am with you. We should at a minimum give a more helpful error message. The automatic tupling conversion was an attempt to get there eventually, so that you would not need to distinguish between case pattern and tuples. But it got stuck halfway in no-man's land (and gave us an appreciation that doing it right is not so easy, after all). 

Here's a better error message for the first case:


I threw in a better message for the second case, too:


Simon: could you please review the new error messages? 

-jason

Jason Zaugg

unread,
Nov 28, 2013, 3:07:16 PM11/28/13
to Rüdiger Klaehn, scala-debate
I agree we should try to make this less dangerous.

Right now, you can compile with -Yno-adapted-args which gives you what you're after (but not newcomers who compile with standard options.) Alternatively, there is -Ywarn-adapted-args just warns, rather than errors.

The most common gotcha I've seen is with JodaTime: get one constructor parameter wrong, as in `new LocalDate(1, 2, "3")`, and you'll end up calling the overload that accepts Object (!).

I think we ought to warn-by-default then deprecate this if the target method is Java defined. We could also warn by default if it is overloaded; or if the alternative accepts a supertype of Tuple, rather than a Tuple directly.

IIRC, the problem with turning it off altogether is with infix calls:

  val x: Buffer[(Int, Int)] = ...
  x += (1, 2)

This is initially typechecked as `x.+=(1, 2)`, and then tupled to match the one-argument method `+=`.

-jason

Simon Schäfer

unread,
Nov 28, 2013, 3:35:52 PM11/28/13
to scala-debate

On 11/28/2013 09:07 PM, Jason Zaugg wrote:
> IIRC, the problem with turning it off altogether is with infix calls:
>
> val x: Buffer[(Int, Int)] = ...
> x += (1, 2)
>
> This is initially typechecked as `x.+=(1, 2)`, and then tupled to
> match the one-argument method `+=`.
I thought that this notation is removed somewhere in the last months. At
least I can't remember the day when the compiler didn't fall apart with
this one.
>
> -jason

Jason Zaugg

unread,
Nov 28, 2013, 3:35:36 PM11/28/13
to Rüdiger Klaehn, scala-debate
On Thu, Nov 28, 2013 at 9:07 PM, Jason Zaugg <jza...@gmail.com> wrote:


IIRC, the problem with turning it off altogether is with infix calls:

  val x: Buffer[(Int, Int)] = ...
  x += (1, 2)

This is initially typechecked as `x.+=(1, 2)`, and then tupled to match the one-argument method `+=`.

Apparently, IDRC:

scala> val x = collection.mutable.Buffer[(Int, Int)]()
x: scala.collection.mutable.Buffer[(Int, Int)] = ArrayBuffer()

scala> x += (1, 2)
<console>:9: error: type mismatch;
 found   : Int(1)
 required: (Int, Int)
              x += (1, 2)
                    ^ 

I can't quite put my finger on the example I was looking for..

-jason

Simon Ochsenreither

unread,
Nov 28, 2013, 3:38:33 PM11/28/13
to scala-...@googlegroups.com, Rüdiger Klaehn

IIRC, the problem with turning it off altogether is with infix calls:

  val x: Buffer[(Int, Int)] = ...
  x += (1, 2)

This is initially typechecked as `x.+=(1, 2)`, and then tupled to match the one-argument method `+=`.

But here, solely the overloaded method signature of

def +=(elem1: A, elem2: A, elems: A*): ArrayBuffer.this.type

is to blame, which is an utter disaster and completely incoherent with the reasoning about += vs. ++=.
If I use +=, I want to add a single argument, not multiple ones.

I'm pretty sure I wrote something about that some while ago, too. I'm actually surprised that it hasn't been deprecated yet.

Simon Ochsenreither

unread,
Nov 28, 2013, 3:42:16 PM11/28/13
to scala-...@googlegroups.com, martin odersky, Simon Ochsenreither

I threw in a better message for the second case, too:


Simon: could you please review the new error messages?

The PR looks good as a stop-gap measure, but I really hope we can fix this issue so that we can stop recommending such ugly and unnecessary workarounds to people.

Jason Zaugg

unread,
Nov 28, 2013, 3:43:09 PM11/28/13
to Simon Ochsenreither, Rex Kerr, scala-debate, Rüdiger Klaehn
You are right, that should be reviewed. I'm cc-ing Rex, who is doing some great janitorial work in collections at the moment.

The example I was searching for was:

scala> val x = Set[(Int, Int)]()
x: scala.collection.immutable.Set[(Int, Int)] = Set()

scala> x contains (1, 2)
res10: Boolean = false 

I'm not sure that we can require an opt-in for this particular case.

-jason

martin odersky

unread,
Nov 28, 2013, 3:51:42 PM11/28/13
to Simon Ochsenreither, scala-debate, Rüdiger Klaehn
On Thu, Nov 28, 2013 at 9:38 PM, Simon Ochsenreither <simon.och...@gmail.com> wrote:

IIRC, the problem with turning it off altogether is with infix calls:

  val x: Buffer[(Int, Int)] = ...
  x += (1, 2)

This is initially typechecked as `x.+=(1, 2)`, and then tupled to match the one-argument method `+=`.

But here, solely the overloaded method signature of

def +=(elem1: A, elem2: A, elems: A*): ArrayBuffer.this.type

is to blame, which is an utter disaster and completely incoherent with the reasoning about += vs. ++=.
If I use +=, I want to add a single argument, not multiple ones.

No, += adds as many single elements as you give. You cannot add multiple elements with ++=, because ++= flattens the argument. So you cannot use ++= to add multiple lists to buffer of lists, say.

There sure is a clash between vararg syntax here and auto-tupling. I believe the answer is to get rid of auto-tupling. 

Cheers

 - Martin


 
I'm pretty sure I wrote something about that some while ago, too. I'm actually surprised that it hasn't been deprecated yet.

--
You received this message because you are subscribed to the Google Groups "scala-debate" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-debate...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Simon Ochsenreither

unread,
Nov 28, 2013, 3:54:52 PM11/28/13
to scala-...@googlegroups.com, Simon Ochsenreither, Rex Kerr, Rüdiger Klaehn
The example I was searching for was:

scala> val x = Set[(Int, Int)]()
x: scala.collection.immutable.Set[(Int, Int)] = Set()

scala> x contains (1, 2)
res10: Boolean = false 

I'm not sure that we can require an opt-in for this particular case.

Agree. Requiring people to add another pairs of parentheses for clarity wouldn't hurt, but ideally we should be able to close the gap between tuples and parameter lists, not widen it.
What I'd like to see killed though (in absence of an example like the above one) is the case of “0-tuples”. Maybe Adriaan can comment on dbuild's status.

Som Snytt

unread,
Nov 28, 2013, 5:30:25 PM11/28/13
to Jason Zaugg, Rüdiger Klaehn, scala-debate

On a few occasions, I have thought that a "beginner's configuration" would be useful, either as -Xnoob or as a dedicated script in the distro, though I wouldn't know what to call it.  How about "scalino"?

Then scalino would definitely be -Yno-adapted-args -Xlint plus messages that are more tutorial. Possibly the -feature message, "see the docs for a discussion" falls in that category.


Rex Kerr

unread,
Nov 29, 2013, 1:56:11 AM11/29/13
to Jason Zaugg, Simon Ochsenreither, scala-debate, Rüdiger Klaehn
I wouldn't interpret this as a failure of the collections library.  Instead, I would view it as a mismatch between the compiler's interpretation of such commands and intuition.

To me,

  x contains (1, 2)
  x += (1, 2)

both look like

  instance method tuple

not

  instance method (arg1, arg2)

On the other hand,

  x.contains(1, 2)
  x.+=(1, 2)

both look like

  instance.method(arg1, arg2)

Unfortunately, the compiler doesn't agree with me.

Rather than auto-tupling, I would say that the first two should be considered _explicit_ tupling; tupling has higher precedence than function argument lists when a single tuple argument is expected, at least in point-free notation.

At least that's my sense of what the intuition is, and is a suggestion of how to keep the desired behavior while still avoiding at least some of the confusions.

  --Rex



Jason Zaugg

unread,
Nov 29, 2013, 2:58:42 AM11/29/13
to Rex Kerr, Simon Ochsenreither, scala-debate, Rüdiger Klaehn
On Fri, Nov 29, 2013 at 7:56 AM, Rex Kerr <ich...@gmail.com> wrote:
I wouldn't interpret this as a failure of the collections library.  Instead, I would view it as a mismatch between the compiler's interpretation of such commands and intuition.

To me,

  x contains (1, 2)
  x += (1, 2)

both look like

  instance method tuple

not

  instance method (arg1, arg2)

Is that intuition because you're mentally type checking and parsing simultaneously? What about the following?

  "abcd" slice (1, 2)
  res1: String = b 

Right now, the parser erases the knowledge of whether infix of dotted method call syntax was used. It also is unable to know anything about the type of the method being called.

So somehow I think we're a bit stuck. In your example, we'd need to introduce auto-detupling for the call to `slice`.

But I do think we could phase out auto-tupling for cases when the expected type is a Any, rather than specifically TupleN. Not sure how easy it will be to implement that situational deprecation, but I'll give it a shot.

-jason

Naftoli Gugenheim

unread,
Nov 29, 2013, 4:40:42 AM11/29/13
to Jason Zaugg, Rex Kerr, Simon Ochsenreither, scala-debate, Rüdiger Klaehn
I agree with Rex. Infix notation usually has one operand on the right. If it opens with a parenthesis then it's a tuple.

I don't mind badly if the compiler auto-detuples though. So the slice case would work, not because you passed two operands, but because being that slice does not take a Tuple2 the compiler would reinterpret it as separate method arguments. After all, that is how it intuitively appears to work. But I don't see much advantage to allowing it.




--

Jason Zaugg

unread,
Nov 29, 2013, 4:48:04 AM11/29/13
to Naftoli Gugenheim, Rex Kerr, Simon Ochsenreither, scala-debate, Rüdiger Klaehn
On Fri, Nov 29, 2013 at 10:40 AM, Naftoli Gugenheim <nafto...@gmail.com> wrote:
I agree with Rex. Infix notation usually has one operand on the right. If it opens with a parenthesis then it's a tuple.

I don't mind badly if the compiler auto-detuples though. So the slice case would work, not because you passed two operands, but because being that slice does not take a Tuple2 the compiler would reinterpret it as separate method arguments. After all, that is how it intuitively appears to work. But I don't see much advantage to allowing it.

You have to be careful here:

scala> object OL { def apply(a: Int, b: Int) = 0; def apply(as: Any) = 0 }
defined object OL

scala> OL apply (1, 2)
res0: Int = 0

scala> OL.apply(1, 2)
res1: Int = 0

You've just changed the outcome of that program.

To get there, we would need to first deprecated then remove infix for arity > 1. I don't think this is a realistic change to make. I believe that we are better off improving the safety measure around the existing auto-tupling.

-jason

Rex Kerr

unread,
Nov 29, 2013, 11:14:07 AM11/29/13
to Jason Zaugg, Simon Ochsenreither, scala-debate, Rüdiger Klaehn
On Thu, Nov 28, 2013 at 11:58 PM, Jason Zaugg <jza...@gmail.com> wrote:
On Fri, Nov 29, 2013 at 7:56 AM, Rex Kerr <ich...@gmail.com> wrote:
I wouldn't interpret this as a failure of the collections library.  Instead, I would view it as a mismatch between the compiler's interpretation of such commands and intuition.

To me,

  x contains (1, 2)
  x += (1, 2)

both look like

  instance method tuple

not

  instance method (arg1, arg2)

Is that intuition because you're mentally type checking and parsing simultaneously? What about the following?

  "abcd" slice (1, 2)
  res1: String = b 

If I saw "abcd" slice (1, 2) my first thought would indeed be "takes a Tuple2[Int,Int]".  My second thought would be, "takes two Int arguments".
 

Right now, the parser erases the knowledge of whether infix of dotted method call syntax was used.

I'm assuming that not only does it erase this knowledge, but that altering this behavior would be a nontrivial amount of work and/or yield undesirable difficulties into the code.
 
It also is unable to know anything about the type of the method being called.

But the parser isn't where the tuple-vs-not decision is ultimately made, so all that matters is that it captures a convertible representation (so it doesn't really matter what it thinks it is).
 
So somehow I think we're a bit stuck. In your example, we'd need to introduce auto-detupling for the call to `slice`.

The problems with map += (1, 2) would be solved if auto-tupling would be invoked not only if there was no method of the right arity, but also if the method with the right arity fails to typecheck.

The toSet() problem would not.
 

But I do think we could phase out auto-tupling for cases when the expected type is a Any, rather than specifically TupleN. Not sure how easy it will be to implement that situational deprecation, but I'll give it a shot.

I think we'd want to catch AnyVal as well as Any.  Not sure about AnyRef.

  --Rex
 

HamsterofDeath

unread,
Nov 29, 2013, 12:47:14 PM11/29/13
to scala-...@googlegroups.com
i suggest this:
in case of a possible ambiguity, force the user to write
((a,b,c)) to make clear that you are passing one parameter that is a tuple
if the case is clear and cannot be confused, allow a simple (a,b,c)

i can't define in the spot what "the case is clear" means, but .... i am in a hurry^^
personally, i would love tuples and parameter lists to be treated 100% equally, meaning one can be applied to the other and vice versa

Dennis Haupt

unread,
Nov 29, 2013, 12:48:57 PM11/29/13
to scala-...@googlegroups.com
or use another syntax for tuples :D
t(a,b,c)
->(a,c,d)
[a,b,c]
<a,b,c>
so many symbols to choose from!
--

Simon Ochsenreither

unread,
Dec 5, 2013, 8:58:39 AM12/5/13
to scala-...@googlegroups.com

Antoine Gourlay

unread,
Dec 5, 2013, 9:10:22 AM12/5/13
to Simon Ochsenreither, scala-...@googlegroups.com
> WAT? Scala
>
> http://dan.bodar.com/2013/12/04/wat-scala/

That's just beautiful. SI-7743 strikes again.

https://issues.scala-lang.org/browse/SI-7743

Emre Sevinc

unread,
Dec 5, 2013, 9:18:47 AM12/5/13
to Antoine Gourlay, Simon Ochsenreither, scala-...@googlegroups.com
Especially confusing when:

$ scala
Welcome to Scala version 2.10.3 (Java HotSpot(TM) Server VM, Java 1.7.0_25).
Type in expressions to have them evaluated.
Type :help for more information.

scala> List("ab").toSet
res0: scala.collection.immutable.Set[String] = Set(ab)

scala> Set("ab")
res1: scala.collection.immutable.Set[String] = Set(ab)

scala> List("ab").toSet.head
res2: String = ab

scala> Set("ab").head
res3: String = ab

scala> List("ab").toSet.head.head
<console>:8: error: value head is not a member of type parameter B
              List("ab").toSet.head.head
                                    ^

scala> Set("ab").head.head
res5: Char = a



--
Emre



martin odersky

unread,
Dec 5, 2013, 9:47:50 AM12/5/13
to Simon Ochsenreither, scala-debate
On Thu, Dec 5, 2013 at 2:58 PM, Simon Ochsenreither <simon.och...@gmail.com> wrote:

That's indeed a classic. 

I think we are all in agreement that auto-tupling was a bad idea, but to how to get rid of it? I believe the best thing to do would be a automatic program rewrite, which inserts the tupling explicitly. I.e. 

    List(1, 2, 3).toSet()

would be rewritten to

   List(1, 2, 3).toSet(())

Once we have a program like this, we could add more rules. E.g. put all XML literals in triple quotes. Rewrite procedure syntax, and so on. 

What do you think? 

Cheers

 - Martin

Simon Ochsenreither

unread,
Dec 5, 2013, 10:55:41 AM12/5/13
to scala-...@googlegroups.com, Simon Ochsenreither

    List(1, 2, 3).toSet()

would be rewritten to

   List(1, 2, 3).toSet(())

I don't think that code was ever intended this way. Most of the usages are probably erroneous.
As mentioned in the other thread in internals, I think it makes sense to just remove automatic () insertion completely and think about a better approach to auto-tupling for Scala 2.12.

 
Once we have a program like this, we could add more rules. E.g. put all XML literals in triple quotes. Rewrite procedure syntax, and so on.

I think something along the lines of “go fix” would be really helpful, especially because much of the code for migrating/fixing code snippets could be extracted out of IDEs and provided by an additional compiler component instead. This way, one wouldn't have to write quick fixes for each IDE separately.

But for 2.11 I'm completely happy if we let the IDE deal with it. Some progress in 2.11 is better than none.


Someone linked me your comment regarding tuples, union/intersection types on HN ...

Just wanted to say that I think union and intersection types are very interesting and powerful. Also agreed on the fact that Tuple22 and friends are not ideal. We are looking for ways to avoid that in a future version of Scala. I am certainly very interested in what you and the Ceylon community do in terms of language design and hope we can learn from each other.

... and I think it would make a lot of sense to look into reevaluating/simplifying the whole Tuple story with all the lessons we have learned since then. Fixing auto-tupling and improving Tuples should imho happen in the same step, so that we don't have to touch very similar code twice.

As far as I see, Slick is adopting HLists in its next version, so 2.12 could maybe really be the right time and place to do revisit Tuples with all that experience gained.

Rüdiger Klaehn

unread,
Dec 5, 2013, 11:32:09 AM12/5/13
to Simon Ochsenreither, scala-debate
Is anybody aware of code that uses auto-tupling intentionally in the wild?


--

martin odersky

unread,
Dec 5, 2013, 11:33:50 AM12/5/13
to Rüdiger Klaehn, Simon Ochsenreither, scala-debate
Stefan told me it's used in Slick. Another idiom I have come across is:

Some(1, 2)

or 

case Some(1, 2) => ...

Cheers

 - Martin

Simon Ochsenreither

unread,
Dec 5, 2013, 11:52:15 AM12/5/13
to scala-...@googlegroups.com, Rüdiger Klaehn, Simon Ochsenreither
Imho, we should really treat () insertion and auto-tupling separately. There might be non-erroneous code using auto-tupling, but I haven't seen non-erroneous code using () insertion. Additionally, the occurrences of () insertion seem to be a lot less frequent than even auto-tupling.

I did a few commits some time ago making the compiler warning/lint/feature clean, and I think I didn't found a single case of () insertion:

https://github.com/scala/scala/commit/0459db43728e1dc38c3a1db6b7b1920810d0f858
https://github.com/scala/scala/commit/f2de2c4ec43180351ef1f306bcc5f24643ba5477
https://github.com/scala/scala/commit/f670e28d4da648511063c6825905c4960ee94445
https://github.com/scala/scala/commit/7943084a2d06e21f112b4efd0ab70ec6e38ce510

I suggest just moving forward on this. Compared to other things we fixed in the past and never got any complaint, this should be a low-impact change.

martin odersky

unread,
Dec 5, 2013, 12:04:06 PM12/5/13
to Simon Ochsenreither, scala-debate, Rüdiger Klaehn
On Thu, Dec 5, 2013 at 5:52 PM, Simon Ochsenreither <simon.och...@gmail.com> wrote:
Imho, we should really treat () insertion and auto-tupling separately. There might be non-erroneous code using auto-tupling, but I haven't seen non-erroneous code using () insertion. Additionally, the occurrences of () insertion seem to be a lot less frequent than even auto-tupling.

Yes, agreed. I'd be for deprecating ()-insertion now. And offer a tool to rewrite auto-tupling occurrences.

Cheers

 - Martin
 
I did a few commits some time ago making the compiler warning/lint/feature clean, and I think I didn't found a single case of () insertion:

https://github.com/scala/scala/commit/0459db43728e1dc38c3a1db6b7b1920810d0f858
https://github.com/scala/scala/commit/f2de2c4ec43180351ef1f306bcc5f24643ba5477
https://github.com/scala/scala/commit/f670e28d4da648511063c6825905c4960ee94445
https://github.com/scala/scala/commit/7943084a2d06e21f112b4efd0ab70ec6e38ce510

I suggest just moving forward on this. Compared to other things we fixed in the past and never got any complaint, this should be a low-impact change.

--
You received this message because you are subscribed to the Google Groups "scala-debate" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-debate...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Jason Zaugg

unread,
Dec 5, 2013, 12:04:31 PM12/5/13
to Rüdiger Klaehn, Simon Ochsenreither, scala-debate
On Thu, Dec 5, 2013 at 5:32 PM, Rüdiger Klaehn <rkl...@gmail.com> wrote:
Is anybody aware of code that uses auto-tupling intentionally in the wild?

This is pretty common, and requires auto-tupling

scala> List((1, 2)) contains (1, 2)
res0: Boolean = true

-jason

Matthew Pocock

unread,
Dec 5, 2013, 12:26:04 PM12/5/13
to Jason Zaugg, scala-debate, Simon Ochsenreither, Rüdiger Klaehn

This use is slightly different form as it is not using dot method invocation. When I first found infix notation I was supprised to find it working for anything other than arity-1 methods.

Matthew

Sent from my android - may contain predictive text entertainment.

--

Simon Ochsenreither

unread,
Dec 5, 2013, 1:14:44 PM12/5/13
to scala-...@googlegroups.com, Simon Ochsenreither, Rüdiger Klaehn

Yes, agreed. I'd be for deprecating ()-insertion now.

Simon Ochsenreither

unread,
Dec 7, 2013, 4:51:22 PM12/7/13
to scala-...@googlegroups.com, Jason Zaugg, Simon Ochsenreither, Rüdiger Klaehn
I think this is a very nice summary of all the weird behavior around ()-insertion: https://gist.github.com/Poita79/7803974
Might make sense to compare proposed improvements against this and see whether things get more consistent or confusing.

c cygil

unread,
Dec 9, 2013, 4:33:57 PM12/9/13
to scala-...@googlegroups.com
I agree that the non-unity of tuples and function arguments is a major annoyance in Scala (why, Martin, why?)
but I've found a superior alternative to pattern matching on function arguments for this use case. 

Function.tupled transforms an n-argument function into a 1-argument function where that argument is a tuple
with the n arguments as members:

import Function._
val m = Map(1 -> 2)
m.map( tupled{ (key, value) => (key +1, value + 1) } )

<output>: res1: scala.collection.immutable.Map[Int,Int] = Map(2 -> 3)

For some reason, Function.tupled is not widely known, so I post it here for reference.

Of course, this is how functions should work in Scala by default, as in Haskell.

On Friday, November 29, 2013 4:56:18 AM UTC+11, Simon Ochsenreither wrote:

Imho, one of Scala's biggest warts is still this:

scala> val m = Map(1 -> 2)
m: scala.collection.immutable.Map[Int,Int] = Map(1 -> 2)

scala> m.map((key, value) => (key+1, value+1))
<console>:9: error: missing parameter type
              m.map((key, value) => (key+1, value+1))
                     ^
<console>:9: error: missing parameter type
              m.map((key, value) => (key+1, value+1))
                          ^

scala> m.map(((key, value)) => (key+1, value+1))
<console>:1: error: not a legal formal parameter
       m.map(((key, value)) => (key+1, value+1))
              ^

scala> m.map({case (key, value) => (key+1, value+1)})
res1: scala.collection.immutable.Map[Int,Int] = Map(2 -> 3)


I mean ... what the hell?! We know it's type exactly ... why do we force people to use pattern matching/partial functions for something this simple?

 

Haoyi Li

unread,
Dec 9, 2013, 5:03:25 PM12/9/13
to c cygil, scala-...@googlegroups.com
I agree that the non-unity of tuples and function arguments is a major annoyance in Scala (why, Martin, why?)

To be fair, it's a hard problem. It's pretty simple to reflect turn argument lists into tuples if you're willing to give up a lot of "modern" conveniences that Scala gives you, like named arguments, or default arguments, which are *really* nice to use! 

Haskell does away with them, and most other languages have no similar concept of reified argument lists. Of those I've used, I think Python comes the closest. Each argument list is just a list of *args and a dict of **kwargs. It's not so straightforward to do in a statically typed language though.


--

Simon Ochsenreither

unread,
Dec 9, 2013, 7:01:53 PM12/9/13
to scala-...@googlegroups.com

Function.tupled transforms an n-argument function into a 1-argument function where that argument is a tuple
with the n arguments as members:

Wow, nice! I think I name this something more specific for precisely this use-case and put it in my default imports somewhere.

Naftoli Gugenheim

unread,
Dec 11, 2013, 3:27:15 PM12/11/13
to Haoyi Li, scala-debate, c cygil

Named and default arguments exist for methods, not functions. So you could still replace FunctionN with Function[TupleN, _], and update method-to-function conversion accordingly...

Reply all
Reply to author
Forward
0 new messages