While this compiles:
implicit class Container[T](val value:T) extends AnyVal{
def addInt(x:Int)(implicit ev:T=:=Int) = value+x
}
This complains about type mismatch, expected T, actual Int, as if it ignores the type bound.
implicit class Container[T](val value:T=>Int) extends AnyVal{
def addInt(x:Int)(implicit ev:T=:=Int) = value(x)
}
Why?
Your type constraint is backwards, actually. T =:= Int provides implicit evidence that T is Int, but not exactly that Int is T. If you look at the declaration if =:=, you'll see that it only goes one way:
sealed abstract class =:=[From, To] extends (From => To) with Serializable
Your first example works because value is a T, and the constraint is T =:= Int, which implicitly converts T to Int. But for the second example, we need to feed a T to value: T => Int, so we need the other direction.
This works:
implicit class Container[T](val value: T => Int) extends AnyVal {
def addInt(x: Int)(implicit ev: Int =:= T) = value(x)
}
The reason why your second example using Int <:< T also works is because <:< provides the implicit conversion from Int => T.
Oh probably the issue is the contra-variance of the function. This works now:
implicit class Container[T](val value:T=>Int) extends AnyVal{
def addInt(x:Int)(implicit ev:Int<:<T) = value(x)
}
Related
I have a list of existientially-typed objects I want to map over. Something like this:
sealed abstract class IntBox(val v: Int)
case object IB1 extends IntBox(1)
case object IB2 extends IntBox(2)
case class Adder[A <: IntBox](ib: A, v: Int) {
def add(i: A) = v + i.v
}
val adders: List[Adder[_ <: IntBox]] = List(Adder(IB1, 0), Adder(IB2, 0))
adders.map(adder => adder.add(adder.ib))
However, I'm getting an error like
found: adder.ib.type
required: _$1
I feel it's something like because the map somehow unifies the different IntBoxs into one unobtainable anonymous type...
Can I get what I want without casting (i.e. adder.asInstanceOf[Adder[adder.ib.type]]...?
The type is not unobtainable, you can get it using type pattern matching:
adders.map{ case a: Adder[t] => a.add(a.ib) }
Here, the existential type parameter is bound to type variable t, and the compiler can correctly infer additional properties of t that it cannot infer for the whole list.
Refer to section 8.3.1 of the Specification for more details.
Full code with trait replaced by class to make it compile
sealed abstract class IntBox(val v: Int)
case object IB1 extends IntBox(1)
case object IB2 extends IntBox(2)
case class Adder[A <: IntBox](ib: A, v: Int) {
def add(i: A) = v + i.v
}
val adders: List[Adder[_ <: IntBox]] = List(Adder(IB1, 0), Adder(IB2, 0))
adders.map{ case a: Adder[t] => a.add(a.ib) }
Is it possible to define value class in scala for some Numeric[T]? I tried something like this:
case class Inches[T <: Numeric[T]](value: T)(implicit num: Numeric[T]) extends AnyVal
However I get compilation error that value classes can have only one parameter.
Is there any way to bypass this?
Thanks beforehand.
You can move the Numeric parameter from class to the methods which require it:
case class Inches[T](value: T) extends AnyVal {
def foo()(implicit num: Numeric[T]) = ...
}
(T <: Numeric[T] is wrong.)
Does AnyVal (Int, Double) extend scala.Serializable and what is the different between java.io.Serializable and scala.Serializable as a method parameter in Scala?
def f (p : scala.Serializable): Unit = {}
def g (p : java.io.Serializable): Unit = {}
//f(1) Type mismatch, expected:Serializable,actual:Int
g(1) //It works
The Scala doc says that Int is a subType of scala.Serializable(http://www.scala-lang.org/api/2.10.6/index.html#scala.Serializable).However,scala.Serializable extends java.io.Serializable. so I think the value of Int is kind type of scala.Serializable and java.io.Serializable and both can be the parameter above.
Thanks.
Actually Int does not extend Serializable. The link (from known subclasses) is this one which is just an Ordering[Int] implicit instance. Int and AnyVal are defined like so:
final abstract class Int private extends AnyVal
abstract class AnyVal extends Any
So as you can see, they're not java.io.Serializable or scala.Serializable.
As for why the code works, check out scala.Predef to find the implicit conversion from scala.Int to java.lang.Integer (which implements java.io.Serializable). And scala.Predef is imported implicitly so that's why it works:
object Predef {
...
implicit def int2Integer(x: Int) = java.lang.Integer.valueOf(x)
...
}
So behind the scene your code is the following:
g(1)
// After the implicit conversion g(1) is actually:
g(Integer.valueOf(1))
I hope this clears up the confusion, I've been there myself :)
I believe that a generic class may make one of its methods available only assuming that its type parameters conform to some additional restrictions, something like (syntax improvised on the spot):
trait Col[T] extends Traversable[T] {
def sum[T<:Int] :T = (0/:this)(_+_)
}
I guess I could use implicit parameters as evidence... Is there a language feature for this?
You can also use a type bound on the type parameter, which is enforced by an implicit argument:
trait Col[T] extends Traversable[T] {
def sum(implicit ev: T <:< Int) :T = (0/:this)(_+_)
}
<:< is actually a class, expressed in infix notation, defined in Predef.scala and explained in many places, including here
<:< means 'must be a subtype of'
You can also use =:= 'must be equal to' and X <%< Y 'must be viewable as' (ie. there is an implicit conversion to X from Y)
For a more detailed explanation of type constraints, see this SO question.
In this case you can only use an implicit parameter, as the type gets determined before the method call.
trait Col[T] extends Traversable[T] {
def sum(implicit num: Numeric[T]) :T = ???
}
If the method you are calling would be parameterized, you could use context bounds, which are just syntactic sugar for the implicit parameter bound to the type parameter:
def foo[A](implicit ev: Something[A]) = ???
is equivalent to
def foo[A : Something] = ???
there is another option involving implicit classes conversions
trait Col[T] extends Traversable[T]
implicit class ColInt[T <: Int](val v : Col[T]) extends AnyVal {
def sum : T = (0 /: v)(_ + _)
}
in this context you don't need the empty trait Col anymore, so you could further comprimize it to this:
implicit class ColInt[T <: Int](val v : Traversable[T]) extends AnyVal {
def sum : T = (0 /: v)(_ + _)
}
The advantage of this method is, that it tells the compiler, that type T is really a subtype of Int, so List[T] <: List[Int] is still valid in this context, and no explicit conversion needs to be added. The implicit parameter adds implicit conversions that wouldn't work on List[T], because it only introduces an implicit conversion from T to Int, not from List[T] to List[Int]
I thought this would be correct usage of the new implicit classes of Scala 2.10:
implicit case class IntOps(i: Int) extends AnyVal {
def twice = i * 2
}
11.twice
Apparently not:
<console>:13: error: value twice is not a member of Int
11.twice
^
Am I missing something (Scala 2.10.0-M6)?
A clue is the desugaring of implicit classes, explained in the SIP-13:
implicit class RichInt(n: Int) extends Ordered[Int] {
def min(m: Int): Int = if (n <= m) n else m
...
}
will be transformed by the compiler as follows:
class RichInt(n: Int) extends Ordered[Int] {
def min(m: Int): Int = if (n <= m) n else m
...
}
implicit final def RichInt(n: Int): RichInt = new RichInt(n)
As you can see, the implicit function that is created has the same name as the original classes. I guess it's done like this to make implicit classes easier to import.
Thus in your case, when you create an implicit case class, there is a conflict between the method name created by the implicit keyword and the companion object created by the case keyword.
This shows there is an ambiguity:
val ops: IntOps = 11
<console>:11: error: ambiguous reference to overloaded definition,
both method IntOps of type (i: Int)IntOps
and object IntOps of type IntOps.type
match argument types (Int) and expected result type IntOps
val ops: IntOps = 11
^
Not sure what exactly happens. But when not using a case class it seems fine:
implicit class IntOps(val i: Int) extends AnyVal {
def twice = i * 2
}
11.twice // ok