Motivation
IterableOnceOps#to is defined as:
def to[C1](factory: Factory[A, C1]): C1
xs.to(List), xs.to(Vector) etc. work today because the companion objects provide implicit conversions such as:
// scala.collection.IterableFactory
implicit def toFactory[A, CC[_]](factory: IterableFactory[CC]): Factory[A, CC[A]]
These are still old-style implicit defs. Once the standard library migrates its conversions to scala.Conversion, every use site of such a conversion will require import scala.language.implicitConversions — otherwise, it emits a feature warning that is scheduled to become an error.
The problem is already visible for user-defined factories written with the (recommended) Conversion:
object MyFactory
trait MyColl[A]
given [T] => Conversion[MyFactory.type, Factory[T, MyColl[T]]] = ???
List(1).to(MyFactory) // warning: Use of implicit conversion ... should be enabled
Requiring a language import for the everyday xs.to(factory) call is clearly unacceptable.
Proposal
Declare Factory and BuildFrom with the into soft modifier:
into trait Factory[-A, +C] extends Any {
...
}
into marks Factory as a valid implicit-conversion target, so a Conversion[X, Factory[…]] is applied at to‘s argument without a language import — at every call site (framework or user), without changing to‘s signature or any other method that takes a Factory. The same applies to BuildFrom if we choose to mark it as well.
This is precisely the scenario the into-as-a-modifier scheme was designed for: a small, fixed set of designated conversion-target types.
Alternative: per-call-site into
The call-site into would also work. It would be more safe, but (probably) requires more code changes at the user code (for all the Factory implicit parameters).
I don’t have a strong opinion which option is better.
import Conversion.into
def to[C1](factory: into[Factory[A, C1]]): C1
Out of scope
Another thing is the migration to Conversion. We cannot just replace the implicit def
implicit def toFactory[K, V, CC[_, _]](factory: MapFactory[CC]): Factory[(K, V), CC[K, V]] = new ToFactory[K, V, CC](factory)
with the Conversion
given toFactory: [K, V, CC[_, _]] => Conversion[MapFactory[CC], Factory[(K, V), CC[K, V]]] = new ToFactory[K, V, CC](_)
due to the binary compatibility. We may drop the implicit modifier and add a new given
def toFactory[K, V, CC[_, _]](factory: MapFactory[CC]): Factory[(K, V), CC[K, V]] = new ToFactory[K, V, CC](factory)
given [K, V, CC[_, _]] => Conversion[MapFactory[CC], Factory[(K, V), CC[K, V]]] = toFactory
but imo, it’s discussion for an another thread.