Scala 3 tuple methods shadowing extensions

Following code gives different result with Scala 2 and Scala 3:

type V = (Double, Double)

implicit class TupleOps(v: V) {
  def size: Double = math.sqrt(v._1 * v._1 + v._2 * v._2)
}

(1.0, 0.0).size

This is from code which uses tuples as poor man’s vectors. Now in Scala 3 all vectors have size 2 or 3 depending on their dimensionality, which causes subtle yet substantial havoc.

I am not aware of being warned of this in any migration guide, certainly not at Incompatibility Table | Scala 3 Migration Guide | Scala Documentation, nor there was any warning by the compiler the size extension is now made useless. There are other methods, like map and probably other, which are now implemented by tuples themselves. I had extension map for tuples as well, making them behave like a lightweight collection. Fortunatelly in case of map the signature was very different, therefore attempting to use Scala 3 map as my map resulted in compiler error.

Is there or could there be some warning for this?

Maybe this is signal of a bigger problem, but if i understood you correctly you get into trouble in this case because in the transition from Scala 2 to Scala 3 the method size was added to Tuple which supersedes your implementation without a issuing warning. In fact any new method that has been added to one of the basic types could cause such (or a comparable) issue right?

In this case you could probably escape it by calling your method length (which somehow would feel more to the point, but i am no native speaker), but in general the problem could be broader. A warning would certainly help.

1 Like

Yes, I can solve this case, what I am concerned is there might perhaps be other cases I am not aware of. Looking back, when I hit the conflict with tuple map, I should pay more attention and check what other functions were added at the same time, but it is not quite obvious where to look for them. The methods are not visible in IDE - eventually I found them in scala.runtime.Tuples, but how should I know this?

Actually, I think at this point the problem is most likely solved for me, I posted this more to help other people not to fall in this trap when porting to Scala 3.

2 Likes

There is a warning for extension methods, for just this purpose.

I commented at a previous discussion and created a couple of tickets to improve its usefulness.

But the use case is as you describe: I had an extension method for a 3rd party class (such as in the JDK) and then they added API with the name I used, and now my extension is no longer useful.

Scala 2 just got a couple of lints for useless or unintended conversions; it occurred to me to lint also implicit classes, but I’m not sure a forward port would be worth the trouble, as I assume it’s not a permanent language feature.

2 Likes

Ok. So there is warning implemented by Warn if extension receiver already has member by som-snytt · Pull Request #17543 · scala/scala3 · GitHub - that is great. Now how do I enable that warning, or why did not it warn me?

Maybe the problem is for tuples it is not the receiver type itself who has the member, it is only an extension method which somehow has higher priority tham the one I have created?

The warning is not behind a flag, but it’s too conservative, to avoid false positives. I created tickets.

I’ll look at “shadowed” extension methods; I have noted (in the linked discussion and elsewhere) that the “ideal” warning would be at the use site, where it would look at available extensions. (“Available” means checking extensions that are accessible from the use site.)

I didn’t create a ticket for that because it looks expensive for a compiler warning. (That would make sense as an IDE feature.) (Maybe it’s expensive for all call sites but OK just for when an extension has already been found.)

2 Likes