Can implicits be used to disambiguate overloaded definition? - scala

Consider the following overloaded definition of method mean:
def mean[T](data: Iterable[T])(implicit number: Fractional[T]): T = {
import number._
val sum = data.foldLeft(zero)(plus)
div(sum, fromInt(data.size))
}
def mean[T](data: Iterable[T])(implicit number: Integral[T]): Double = {
import number._
val sum = data.foldLeft(zero)(plus)
sum.toDouble / data.size
}
I would like second definition which returns Double only to be used in the case of Integral types, however
mean(List(1,2,3,4))
results in compiler error
Error: ambiguous reference to overloaded definition,
both method mean in class A$A16 of type [T](data: Iterable[T])(implicit number: Integral[T])Double
and method mean in class A$A16 of type [T](data: Iterable[T])(implicit number: Fractional[T])T
match argument types (List[Int])
mean(List(1,2,3,4))
^
Is there any way to use the fact that Fractional[Int] implicit is not available in order to disambiguate the two overloads?

Scala only considers the first argument list for the overload resolution, according to the specification. Both mean methods are deemed equally specific and ambiguous.
But for implicit resolution the implicits in scope are also considered, so a workaround could be to use a magnet pattern or a type class. Here is an example using the magnet pattern, which I believe is simpler:
def mean[T](data: MeanMagnet[T]): data.Out = data.mean
sealed trait MeanMagnet[T] {
type Out
def mean: Out
}
object MeanMagnet {
import language.implicitConversions
type Aux[T, O] = MeanMagnet[T] { type Out = O }
implicit def fromFractional[T](
data: Iterable[T]
)(
implicit number: Fractional[T]
): MeanMagnet.Aux[T, T] = new MeanMagnet[T] {
override type Out = T
override def mean: Out = {
import number._
val sum = data.foldLeft(zero)(plus)
div(sum, fromInt(data.size))
}
}
implicit def fromIntegral[T](
data: Iterable[T]
)(
implicit number: Integral[T]
): MeanMagnet.Aux[T, Double] = new MeanMagnet[T] {
override type Out = Double
override def mean: Out = {
import number._
val sum = data.foldLeft(zero)(plus)
sum.toDouble / data.size
}
}
}
With this definition it works normally:
scala> mean(List(1,2,3,4))
res0: Double = 2.5
scala> mean(List(1.0, 2.0, 3.0, 4.0))
res1: Double = 2.5
scala> mean(List(1.0f, 2.0f, 3.0f, 4.0f))
res2: Float = 2.5

Here is my attempt at typeclass solution as suggested by others
trait Mean[In, Out] {
def apply(xs: Iterable[In]): Out
}
object Mean {
def mean[In, Out](xs: Iterable[In])(implicit ev: Mean[In, Out]): Out = ev(xs)
private def meanFractional[T](data: Iterable[T])(implicit number: Fractional[T]): T = {
import number._
val sum = data.foldLeft(zero)(plus)
div(sum, fromInt(data.size))
}
private def meanIntegral[T](data: Iterable[T])(implicit number: Integral[T]): Double = {
import number._
val sum = data.foldLeft(zero)(plus)
sum.toDouble / data.size
}
implicit val meanBigInt: Mean[BigInt, Double] = meanIntegral _
implicit val meanInt: Mean[Int, Double] = meanIntegral _
implicit val meanShort: Mean[Short, Double] = meanIntegral _
implicit val meanByte: Mean[Byte, Double] = meanIntegral _
implicit val meanChar: Mean[Char, Double] = meanIntegral _
implicit val meanLong: Mean[Long, Double] = meanIntegral _
implicit val meanFloat: Mean[Float, Float] = meanFractional _
implicit val meanDouble: Mean[Double, Double] = meanFractional _
import scala.math.BigDecimal
implicit val meanBigDecimal: Mean[BigDecimal, BigDecimal] = meanFractional _
}
object MeanTypeclassExample extends App {
import Mean._
println(mean(List(1,2,3,4)))
println(mean(List(1d,2d,3d,4d)))
println(mean(List(1f,2f,3f,4f)))
}
which outputs
2.5
2.5
2.5

Related

Scala Method on Generic Data Type

I am trying to create a generic class that only accepts java.math.BigDecimal or Long. Here is the code:
class myClass[T]()
{
def display( x : T) = {
println(x.doubleValue())
}
}
val input = new java.math.BigDecimal(100)
// val input = 100L
val x = new myClass[java.math.BigDecimal]()
x.display(input)
Clearly I will have this error: ScalaFiddle.scala:22: error: value doubleValue is not a member of type parameter T.
I tried playing with implicit conversion, view bound, and context bound for hours. No result so far. Is there any way I can force Scala to believe me that T has method .doubleValue()? (java.big.Decimal and Long both has .doubleValue() method, but they don't share same super-class)
Try structural type bound
class myClass[T <: {def doubleValue(): Double}]
or type class
trait HasDoubleValue[T] {
def doubleValue(t: T): Double
}
object HasDoubleValue {
implicit val long: HasDoubleValue[Long] = t => t.doubleValue
implicit val bigDecimal: HasDoubleValue[BigDecimal] = t => t.doubleValue
}
implicit class DoubleValueOps[T: HasDoubleValue](x: T) {
def doubleValue(): Double = implicitly[HasDoubleValue[T]].doubleValue(x)
}
class myClass[T: HasDoubleValue]
In Dotty (Scala 3) we might use union types, for example,
class myClass[T <: (Long | java.math.BigDecimal)]() {
def display(x: T) =
println(
x match {
case t: Long => t.doubleValue
case t: java.math.BigDecimal => t.doubleValue
}
)
}
new myClass().display(new java.math.BigDecimal(100)) // OK
new myClass().display(100L) // OK
new myClass().display("100") // Error
scala> class C private (n: Number) {
| def this(i: Long) = this(i: Number)
| def this(b: BigDecimal) = this(b: Number)
| def d = n.doubleValue
| }
defined class C
scala> new C(42L).d
res0: Double = 42.0
scala> new C(BigDecimal("123456789")).d
res1: Double = 1.23456789E8
or with a type parameter
scala> class C[A <: Number] private (n: A) { def d = n.doubleValue ; def a = n } ; object C {
| def apply(i: Long) = new C(i: Number) ; def apply(b: BigDecimal) = new C(b) }
defined class C
defined object C

Using a double value in a Fractional[T] method

I have the following function which generates a Uniform distributed value between 2 bounds:
def Uniform(x: Bounded[Double], n: Int): Bounded[Double] = {
val y: Double = (x.upper - x.lower) * scala.util.Random.nextDouble() + x.lower
Bounded(y, x.bounds)
}
and Bounded is defined as follows:
trait Bounded[T] {
val underlying: T
val bounds: (T, T)
def lower: T = bounds._1
def upper: T = bounds._2
override def toString = underlying.toString + " <- [" + lower.toString + "," + upper.toString + "]"
}
object Bounded {
def apply[T : Numeric](x: T, _bounds: (T, T)): Bounded[T] = new Bounded[T] {
override val underlying: T = x
override val bounds: (T, T) = _bounds
}
}
However, I want Uniform to work on all Fractional[T] values so I wanted to add a context bound:
def Uniform[T : Fractional](x: Bounded[T], n: Int): Bounded[T] = {
import Numeric.Implicits._
val y: T = (x.upper - x.lower) * scala.util.Random.nextDouble().asInstanceOf[T] + x.lower
Bounded(y, x.bounds)
}
This works swell when doing a Uniform[Double](x: Bounded[Double]), but the other ones are impossible and get a ClassCastException at runtime because they can not be casted. Is there a way to solve this?
I'd suggest defining a new type class that characterizes types that you can get random instances of:
import scala.util.Random
trait GetRandom[A] {
def next(): A
}
object GetRandom {
def instance[A](a: => A): GetRandom[A] = new GetRandom[A] {
def next(): A = a
}
implicit val doubleRandom: GetRandom[Double] = instance(Random.nextDouble())
implicit val floatRandom: GetRandom[Float] = instance(Random.nextFloat())
// Define any other instances here
}
Now you can write Uniform like this:
def Uniform[T: Fractional: GetRandom](x: Bounded[T], n: Int): Bounded[T] = {
import Numeric.Implicits._
val y: T = (x.upper - x.lower) * implicitly[GetRandom[T]].next() + x.lower
Bounded(y, x.bounds)
}
And use it like this:
scala> Uniform[Double](Bounded(2, (0, 4)), 1)
res15: Bounded[Double] = 1.5325899033654382 <- [0.0,4.0]
scala> Uniform[Float](Bounded(2, (0, 4)), 1)
res16: Bounded[Float] = 0.06786823 <- [0.0,4.0]
There are libraries like rng that provide a similar type class for you, but they tend to be focused on purely functional ways to work with random numbers, so if you want something simpler you're probably best off writing your own.

Getting method's function type from the MethodMirror instance in Scala

Assume I have an instance of MethodMirror created for a certain method of an object. By mirror's fields I can easily access return type and parameters of the method. But I actually need to obtain the type this method would have as a function.
Here is a toy code example which will help me explain, what I want to achieve. I'm using Scala 2.11.6.
import scala.reflect.runtime.universe._
object ForStackOverflow {
object Obj {
def method(x:String, y:String):Int = 0
def expectedRetType():((String, String) => Int) = ???
}
def main(args: Array[String]) {
val mirror:Mirror = runtimeMirror(getClass.getClassLoader)
val instanceMirror = mirror.reflect(Obj)
val methodSymbol:MethodSymbol = instanceMirror.symbol.toType.decl(TermName("method")).asMethod
val methodMirror = instanceMirror.reflectMethod(methodSymbol)
println(methodMirror.symbol.returnType)
println(methodMirror.symbol.paramLists(0).map { x => x.info.resultType }.mkString(", "))
val expectedSymbol:MethodSymbol = instanceMirror.symbol.toType.decl(TermName("expectedRetType")).asMethod
println("I would like to produce from a 'methodMirror' this: "+expectedSymbol.returnType)
}
}
I want to produce Type instance from the methodMirror which would represent a function. For this example it should be (String, String) => Int. I would prefer a solution that doesn't depend too much on the concrete Scala's FunctionX classes.
The method getEtaExpandedMethodType below does what you asked, and even handles methods with multiple parameter lists.
On the other hand it does not handle generic methods. By example def method[T](x: T) = 123, when eta-expanded, creates a function of type Any => Int, but getEtaExpandedMethodType will report T => Int which is not only incorrect but does not make sense at all (T has no meaning in this context).
def getEtaExpandedMethodType(methodSymbol: MethodSymbol): Type = {
val typ = methodSymbol.typeSignature
def paramType(paramSymbol: Symbol): Type = {
// TODO: handle the case where paramSymbol denotes a type parameter
paramSymbol.typeSignatureIn(typ)
}
def rec(paramLists: List[List[Symbol]]): Type = {
paramLists match {
case Nil => methodSymbol.returnType
case params :: otherParams =>
val functionClassSymbol = definitions.FunctionClass(params.length)
appliedType(functionClassSymbol, params.map(paramType) :+ rec(otherParams))
}
}
if (methodSymbol.paramLists.isEmpty) { // No arg method
appliedType(definitions.FunctionClass(0), List(methodSymbol.returnType))
} else {
rec(methodSymbol.paramLists)
}
}
def getEtaExpandedMethodType(methodMirror: MethodMirror): Type = getEtaExpandedMethodType(methodMirror.symbol)
REPL test:
scala> val mirror: Mirror = runtimeMirror(getClass.getClassLoader)
mirror: reflect.runtime.universe.Mirror = ...
scala> val instanceMirror = mirror.reflect(Obj)
instanceMirror: reflect.runtime.universe.InstanceMirror = instance mirror for Obj$#21b6e507
scala> val tpe = instanceMirror.symbol.toType
tpe: reflect.runtime.universe.Type = Obj.type
scala> getEtaExpandedMethodType(tpe.decl(TermName("method1")).asMethod)
res28: reflect.runtime.universe.Type = (String, String) => scala.Int
scala> getEtaExpandedMethodType(tpe.decl(TermName("method2")).asMethod)
res29: reflect.runtime.universe.Type = () => String
scala> getEtaExpandedMethodType(tpe.decl(TermName("method3")).asMethod)
res30: reflect.runtime.universe.Type = () => scala.Long
scala> getEtaExpandedMethodType(tpe.decl(TermName("method4")).asMethod)
res31: reflect.runtime.universe.Type = String => (scala.Float => scala.Double)
scala> getEtaExpandedMethodType(tpe.decl(TermName("method5")).asMethod)
res32: reflect.runtime.universe.Type = T => scala.Int
scala> getEtaExpandedMethodType(tpe.decl(TermName("method6")).asMethod)
res33: reflect.runtime.universe.Type = T => scala.Int
Here is probably the most straightforward solution using universe.appliedType. It doesn't work in the case of multiple parameter lists. I post this to show an alternative way of solving this problem.
def getEtaExpandedMethodType2(methodSymbol: MethodSymbol): Type = {
val typesList = methodSymbol.info.paramLists(0).map(x => x.typeSignature) :+ methodSymbol.returnType
val arity = methodSymbol.paramLists(0).size
universe.appliedType(definitions.FunctionClass(arity), typesList)
}

How do I use the type member A in IsTraversableLike?

I am trying to write some extension methods for the Scala collections, and running into trouble fully generifying them.
A first attempt at tailOption yields something like:
implicit class TailOption[A, Repr <: GenTraversableLike[A, Repr]](val repr: Repr) {
def tailOption: Option[Repr] =
if (repr.isEmpty) None
else Some(repr.tail)
}
unfortunately, this doesn't work:
scala> List(1,2,3).tailOption
<console>:19: error: value tailOption is not a member of List[Int]
List(1,2,3).tailOption
Scala 2.10 provides the IsTraversableLike type-class to help adapt this sort of thing for all collections (including odd ones, like Strings).
With this I can for instance implement tailOption quite easily:
implicit class TailOption[Repr](val r: Repr)(implicit fr: IsTraversableLike[Repr]) {
def tailOption: Option[Repr] = {
val repr = fr.conversion(r)
if (repr.isEmpty) None
else Some(repr.tail)
}
}
scala> List(1,2,3).tailOption
res12: Option[List[Int]] = Some(List(2, 3))
scala> "one".tailOption
res13: Option[String] = Some(ne)
The result is of the correct type: Option[<input-type>]. Specifically, I have been able to preserve the Repr type when calling methods that return Repr, like `tail.
Unfortunately, I can't seem to use this trick to preserve the type of the elements of the collection. I can't call methods that return an element.
IsTraversableLike does have a member A but it doesn't seem very useful. In particular I can't reconstruct my original element type and the member is not equivalent in type. For instance, without further work, headTailOption looks like this:
implicit class HeadTailOption[Repr](val r: Repr)(implicit val fr: IsTraversableLike[Repr]) {
def headTailOption: Option[(fr.A, Repr)] = {
val repr = fr.conversion(r)
if (repr.isEmpty) None
else Some(repr.head -> repr.tail)
}
}
scala> val Some((c, _)) = "one".headTailOption
c: _1.fr.A forSome { val _1: HeadTailOption[String] } = o
As we can see, c has a wonderfully baroque type. But, this type is not equivalent to Char:
scala> val fr = implicitly[IsTraversableLike[String]]
fr: scala.collection.generic.IsTraversableLike[String] = scala.collection.generic.IsTraversableLike$$anon$1#60ab6a84
scala> implicitly[fr.A <:< Char]
<console>:25: error: Cannot prove that fr.A <:< Char.
implicitly[fr.A <:< Char]
I have tried all sorts of tricks including having Repr[A] <: GenTraversableLike[A, Repr[A]] none of which help. Can anyone work out the magic sauce to make headTailOption return the right types for:
val headTailString: Option[(Char, String)] = "one".headTailOption
val headTailList: Option[(Int, List[Int])] = List(1,2,3).headTailOption
A partial answer. You have probably started from the scaladoc example for IsTraversableLike. It still uses the "old approach" of separating implicit conversion and instantiating the wrapper class, instead of going in one step through an implicit class. It turns out that the "old approach" does work:
import collection.GenTraversableLike
import collection.generic.IsTraversableLike
final class HeadTailOptionImpl[A, Repr](repr: GenTraversableLike[A, Repr]) {
def headTailOption: Option[(A, Repr)] = {
if (repr.isEmpty) None
else Some(repr.head -> repr.tail)
}
}
implicit def headTailOption[Repr](r: Repr)(implicit fr: IsTraversableLike[Repr]):
HeadTailOptionImpl[fr.A,Repr] = new HeadTailOptionImpl(fr.conversion(r))
// `c` looks still weird: `scala.collection.generic.IsTraversableLike.stringRepr.A`
val Some((c, _)) = "one".headTailOption
val d: Char = c // ...but it really is a `Char`!
val headTailString: Option[(Char, String)] = "one".headTailOption
val headTailList: Option[(Int, List[Int])] = List(1,2,3).headTailOption
As Miles points out, the split seems essential for this to work with the implicit search and type inference.
Another solution, although of course less elegant, is to give up the unification of strings and collections:
trait HeadTailOptionLike[A, Repr] {
def headTailOption: Option[(A, Repr)]
}
implicit class GenHeadTailOption[A, Repr](repr: GenTraversableLike[A, Repr])
extends HeadTailOptionLike[A, Repr] {
def headTailOption =
if (repr.isEmpty) None
else Some(repr.head -> repr.tail)
}
implicit class StringHeadTailOption(repr: String)
extends HeadTailOptionLike[Char, String] {
def headTailOption =
if (repr.isEmpty) None
else Some(repr.head -> repr.tail) // could use repr.charAt(0) -> repr.substring(1)
}
List(1,2,3).headTailOption
"one".headTailOption
You can write it as an implicit class if you extract the type A from the IsTraversableLike.
import collection.generic.IsTraversableLike
implicit class HeadTailOption[Repr,A0](val r: Repr)(implicit val fr: IsTraversableLike[Repr]{ type A = A0 }) {
def headTailOption: Option[(A0, Repr)] = {
val repr = fr.conversion(r)
if (repr.isEmpty) None
else Some(repr.head -> repr.tail)
}
}
Or equivalently:
import collection.generic.IsTraversableLike
type IsTraversableLikeAux[Repr,A0] = IsTraversableLike[Repr]{ type A = A0 }
implicit class HeadTailOption[Repr,A](val r: Repr)(implicit val fr: IsTraversableLikeAux[Repr,A]) {
def headTailOption: Option[(A, Repr)] = {
val repr = fr.conversion(r)
if (repr.isEmpty) None
else Some(repr.head -> repr.tail)
}
}
And then everything works fine.
scala> val Some((c, _)) = "one".headTailOption
c: scala.collection.generic.IsTraversableLike.stringRepr.A = o
scala> c.isSpaceChar
res0: Boolean = false
The compiler knows that scala.collection.generic.IsTraversableLike.stringRepr.A is the same as Char.

Extending collection classes with extra fields in Scala

I'm looking to create a class that is basically a collection with an extra field. However, I keep running into problems and am wondering what the best way of implementing this is. I've tried to follow the pattern given in the Scala book. E.g.
import scala.collection.IndexedSeqLike
import scala.collection.mutable.Builder
import scala.collection.generic.CanBuildFrom
import scala.collection.mutable.ArrayBuffer
class FieldSequence[FT,ST](val field: FT, seq: IndexedSeq[ST] = Vector())
extends IndexedSeq[ST] with IndexedSeqLike[ST,FieldSequence[FT,ST]] {
def apply(index: Int): ST = return seq(index)
def length = seq.length
override def newBuilder: Builder[ST,FieldSequence[FT,ST]]
= FieldSequence.newBuilder[FT,ST](field)
}
object FieldSequence {
def fromSeq[FT,ST](field: FT)(buf: IndexedSeq[ST])
= new FieldSequence(field, buf)
def newBuilder[FT,ST](field: FT): Builder[ST,FieldSequence[FT,ST]]
= new ArrayBuffer mapResult(fromSeq(field))
implicit def canBuildFrom[FT,ST]:
CanBuildFrom[FieldSequence[FT,ST], ST, FieldSequence[FT,ST]] =
new CanBuildFrom[FieldSequence[FT,ST], ST, FieldSequence[FT,ST]] {
def apply(): Builder[ST,FieldSequence[FT,ST]]
= newBuilder[FT,ST]( _ ) // What goes here?
def apply(from: FieldSequence[FT,ST]): Builder[ST,FieldSequence[FT,ST]]
= from.newBuilder
}
}
The problem is the CanBuildFrom that is implicitly defined needs an apply method with no arguments. But in these circumstances this method is meaningless, as a field (of type FT) is needed to construct a FieldSequence. In fact, it should be impossible to construct a FieldSequence, simply from a sequence of type ST. Is the best I can do to throw an exception here?
Then your class doesn't fulfill the requirements to be a Seq, and methods like flatMap (and hence for-comprehensions) can't work for it.
I'm not sure I agree with Landei about flatMap and map. If you replace with throwing an exception like this, most of the operations should work.
def apply(): Builder[ST,FieldSequence[FT,ST]] = sys.error("unsupported")
From what I can see in TraversableLike, map and flatMap and most other ones use the apply(repr) version. So for comprehensions seemingly work. It also feels like it should follow the Monad laws (the field is just carried accross).
Given the code you have, you can do this:
scala> val fs = FieldSequence.fromSeq("str")(Vector(1,2))
fs: FieldSequence[java.lang.String,Int] = FieldSequence(1, 2)
scala> fs.map(1 + _)
res3: FieldSequence[java.lang.String,Int] = FieldSequence(2, 3)
scala> val fs2 = FieldSequence.fromSeq("str1")(Vector(10,20))
fs2: FieldSequence[java.lang.String,Int] = FieldSequence(10, 20)
scala> for (x <- fs if x > 0; y <- fs2) yield (x + y)
res5: FieldSequence[java.lang.String,Int] = FieldSequence(11, 21, 12, 22)
What doesn't work is the following:
scala> fs.map(_ + "!")
// does not return a FieldSequence
scala> List(1,2).map(1 + _)(collection.breakOut): FieldSequence[String, Int]
java.lang.RuntimeException: unsupported
// this is where the apply() is used
For breakOut to work you would need to implement the apply() method. I suspect you could generate a builder with some default value for field: def apply() = newBuilder[FT, ST](getDefault) with some implementation of getDefault that makes sense for your use case.
For the fact that fs.map(_ + "!") does not preserve the type, you need to modify your signature and implementation, so that the compiler can find a CanBuildFrom[FieldSequence[String, Int], String, FieldSequence[String, String]]
implicit def canBuildFrom[FT,ST_FROM,ST]:
CanBuildFrom[FieldSequence[FT,ST_FROM], ST, FieldSequence[FT,ST]] =
new CanBuildFrom[FieldSequence[FT,ST_FROM], ST, FieldSequence[FT,ST]] {
def apply(): Builder[ST,FieldSequence[FT,ST]]
= sys.error("unsupported")
def apply(from: FieldSequence[FT,ST_FROM]): Builder[ST,FieldSequence[FT,ST]]
= newBuilder[FT, ST](from.field)
}
In the end, my answer was very similar to that in a previous question. The difference with that question and my original and the answer are slight but basically allow anything that has a sequence to be a sequence.
import scala.collection.SeqLike
import scala.collection.mutable.Builder
import scala.collection.mutable.ArrayBuffer
import scala.collection.generic.CanBuildFrom
trait SeqAdapter[+A, Repr[+X] <: SeqAdapter[X,Repr]]
extends Seq[A] with SeqLike[A,Repr[A]] {
val underlyingSeq: Seq[A]
def create[B](seq: Seq[B]): Repr[B]
def apply(index: Int) = underlyingSeq(index)
def length = underlyingSeq.length
def iterator = underlyingSeq.iterator
override protected[this] def newBuilder: Builder[A,Repr[A]] = {
val sac = new SeqAdapterCompanion[Repr] {
def createDefault[B](seq: Seq[B]) = create(seq)
}
sac.newBuilder(create)
}
}
trait SeqAdapterCompanion[Repr[+X] <: SeqAdapter[X,Repr]] {
def createDefault[A](seq: Seq[A]): Repr[A]
def fromSeq[A](creator: (Seq[A]) => Repr[A])(seq: Seq[A]) = creator(seq)
def newBuilder[A](creator: (Seq[A]) => Repr[A]): Builder[A,Repr[A]] =
new ArrayBuffer mapResult fromSeq(creator)
implicit def canBuildFrom[A,B]: CanBuildFrom[Repr[A],B,Repr[B]] =
new CanBuildFrom[Repr[A],B,Repr[B]] {
def apply(): Builder[B,Repr[B]] = newBuilder(createDefault)
def apply(from: Repr[A]) = newBuilder(from.create)
}
}
This fixes all the problems huynhjl brought up. For my original problem, to have a field and a sequence treated as a sequence, a simple class will now do.
trait Field[FT] {
val defaultValue: FT
class FieldSeq[+ST](val field: FT, val underlyingSeq: Seq[ST] = Vector())
extends SeqAdapter[ST,FieldSeq] {
def create[B](seq: Seq[B]) = new FieldSeq[B](field, seq)
}
object FieldSeq extends SeqAdapterCompanion[FieldSeq] {
def createDefault[A](seq: Seq[A]): FieldSeq[A] =
new FieldSeq[A](defaultValue, seq)
override implicit def canBuildFrom[A,B] = super.canBuildFrom[A,B]
}
}
This can be tested as so:
val StringField = new Field[String] { val defaultValue = "Default Value" }
StringField: java.lang.Object with Field[String] = $anon$1#57f5de73
val fs = new StringField.FieldSeq[Int]("str", Vector(1,2))
val fsfield = fs.field
fs: StringField.FieldSeq[Int] = (1, 2)
fsfield: String = str
val fm = fs.map(1 + _)
val fmfield = fm.field
fm: StringField.FieldSeq[Int] = (2, 3)
fmfield: String = str
val fs2 = new StringField.FieldSeq[Int]("str1", Vector(10, 20))
val fs2field = fs2.field
fs2: StringField.FieldSeq[Int] = (10, 20)
fs2field: String = str1
val ffor = for (x <- fs if x > 0; y <- fs2) yield (x + y)
val fforfield = ffor.field
ffor: StringField.FieldSeq[Int] = (11, 21, 12, 22)
fforfield: String = str
val smap = fs.map(_ + "!")
val smapfield = smap.field
smap: StringField.FieldSeq[String] = (1!, 2!)
smapfield: String = str
val break = List(1,2).map(1 + _)(collection.breakOut): StringField.FieldSeq[Int]
val breakfield = break.field
break: StringField.FieldSeq[Int] = (2, 3)
breakfield: String = Default Value
val x: StringField.FieldSeq[Any] = fs
val xfield = x.field
x: StringField.FieldSeq[Any] = (1, 2)
xfield: String = str