This page is no longer maintained — Please continue to the home page at www.scala-lang.org

fallbackStringCanBuildFrom used in (Set(1, 2, 3).map(_ * 2)(collection.breakOut)): Seq[Int]

7 replies
ijuma
Joined: 2008-08-20,
User offline. Last seen 22 weeks 2 days ago.

Hey all,

To answer a question on IRC, I executed the following command via scalabot:

scala> (Set(1, 2, 3).map(_ * 2)(collection.breakOut)): Seq[Int]
res0: Seq[Int] = Vector(2, 4, 6)

Kevin Wright pointed out that this was unexpected given the default
builder for Seq. Stefan Zeiger also got involved and with the help of
-Xprint:type it seems that
LowPriorityImplicits.fallbackStringCanBuildFrom is being used in this
scenario:

(scala.this.Predef.Set.apply[Int](1, 2, 3).map[Int, Seq[Int]](((x$1:
Int) => x$1.+(1)))(scala.collection.`package`.breakOut[scala.collection.immutable.Set[Int],
Int, Seq[Int]](scala.this.Predef.fallbackStringCanBuildFrom[Int])):
Seq[Int])

That seems a bit odd, but it's not clear whether it's a bug, so
sending it here for further feedback.

Best,
Ismael

extempore
Joined: 2008-12-17,
User offline. Last seen 35 weeks 3 days ago.
Re: fallbackStringCanBuildFrom used in (Set(1, 2, 3).map(_ * 2)

On 5/22/11 11:50 AM, Ismael Juma wrote:
> scala> (Set(1, 2, 3).map(_ * 2)(collection.breakOut)): Seq[Int]
> res0: Seq[Int] = Vector(2, 4, 6)
>
> (scala.this.Predef.Set.apply[Int](1, 2, 3).map[Int, Seq[Int]](((x$1:
> Int) => x$1.+(1)))(scala.collection.`package`.breakOut[scala.collection.immutable.Set[Int],
> Int, Seq[Int]](scala.this.Predef.fallbackStringCanBuildFrom[Int])):
> Seq[Int])

Not only that, it switched from multiplying by two to adding one! Nice
falsified transcript there ijuma, real believable.

I would say this is definitely a bug in terms of "is this desirable
behavior" but it is probably not a bug in terms of "is the correct
implicit being selected." This is a very unfortunate and heretofore not
known to me consequence of the implicit scope rules, which say
(summarized and simplified) that if we're looking for an implicit T:

* first, check every implicit accessible via simple identifier.
* and if that fails, check the companion of type T.

So it doesn't matter how low priority we go, if something is in predef
it is higher priority than anything in a companion.

ijuma
Joined: 2008-08-20,
User offline. Last seen 22 weeks 2 days ago.
Re: fallbackStringCanBuildFrom used in (Set(1, 2, 3).map(_ * 2)

On Sun, May 22, 2011 at 9:10 PM, Paul Phillips wrote:
> Not only that, it switched from multiplying by two to adding one! Nice
> falsified transcript there ijuma, real believable.

haha, nicely spotted. ;) Seems like I switched the function inside map
when I compiled it with -Xprint:typer (with no consequences to the
issue at hand, of course).

> I would say this is definitely a bug in terms of "is this desirable
> behavior"

Shall I file one?

> * first, check every implicit accessible via simple identifier.
> * and if that fails, check the companion of type T.
>
> So it doesn't matter how low priority we go, if something is in predef
> it is higher priority than anything in a companion.

I see.

Best,
Ismael

extempore
Joined: 2008-12-17,
User offline. Last seen 35 weeks 3 days ago.
Re: fallbackStringCanBuildFrom used in (Set(1, 2, 3).map(_ * 2)

On 5/22/11 1:19 PM, Ismael Juma wrote:
> Shall I file one?

I can't give you any special authorization, but paulp thinks it's a bug.

extempore
Joined: 2008-12-17,
User offline. Last seen 35 weeks 3 days ago.
Re: fallbackStringCanBuildFrom used in (Set(1, 2, 3).map(_ * 2)

This makes it even worse:

scala> import scala.collection.immutable.Seq._
import scala.collection.immutable.Seq._

scala> (Set(1, 2, 3).map(_ * 2)(collection.breakOut)): Seq[Int]
:11: error: ambiguous implicit values:
both method stringCanBuildFrom in object Predef of type => scala.collection.generic.CanBuildFrom[String,Char,String]
and method canBuildFrom in object Seq of type [A]=> scala.collection.generic.CanBuildFrom[collection.immutable.Seq.Coll,A,scala.collection.immutable.Seq[A]]
match expected type scala.collection.generic.CanBuildFrom[Nothing,T,To]
(Set(1, 2, 3).map(_ * 2)(collection.breakOut)): Seq[Int]
^

The CanBuildFrom[String,Char,String] is creating an ambiguity as I attempt to go from Set[Int] to Seq[Int] !? Something is very wrong with that picture.

Jason Zaugg
Joined: 2009-05-18,
User offline. Last seen 38 weeks 5 days ago.
Re: fallbackStringCanBuildFrom used in (Set(1, 2, 3).map(_ * 2)

On Sun, May 22, 2011 at 10:10 PM, Paul Phillips wrote:
> So it doesn't matter how low priority we go, if something is in predef
> it is higher priority than anything in a companion.

Perhaps in this case these
LowPriorityImpicits#fallbackStringCanBuildFrom and
Predef.stringCanBuildFrom could be moved into a (fictional) companion
object for String. Although perhaps that trades one set of undesirable
behaviour for another.

Incidentally, we face a similar problem in Scalaz -- in the implicit
scope of M[A], an implicit defined in a superclass of object M, isn't
of lower priority than an implicit in object A. Driving the priorities
with an annotation (@reluctantImplicit?) might be a solution.

-jason

extempore
Joined: 2008-12-17,
User offline. Last seen 35 weeks 3 days ago.
Re: fallbackStringCanBuildFrom used in (Set(1, 2, 3).map(_ * 2)

On 5/22/11 2:08 PM, Jason Zaugg wrote:
> Driving the priorities
> with an annotation (@reluctantImplicit?) might be a solution.

Keep a @reluctantLanguageDesigner meta-annotation handy.

(He'll like my idea even less: implicit predicate dispatch!)

extempore
Joined: 2008-12-17,
User offline. Last seen 35 weeks 3 days ago.
Re: fallbackStringCanBuildFrom used in (Set(1, 2, 3).map(_ * 2)

On 5/22/11 2:08 PM, Jason Zaugg wrote:
> Perhaps in this case these
> LowPriorityImpicits#fallbackStringCanBuildFrom and
> Predef.stringCanBuildFrom could be moved into a (fictional) companion
> object for String. Although perhaps that trades one set of undesirable
> behaviour for another.

>From my view the ability to do that would be a move toward desirable
behavior. Related:

https://issues.scala-lang.org/browse/SI-4338
java classes with static methods and "object not a value"

Yet another in my carnival of wontfixes! (Anyone who thinks I have it
any better than you guys should count my rejection slips.)

Copyright © 2012 École Polytechnique Fédérale de Lausanne (EPFL), Lausanne, Switzerland