Instantiating parameterized classes in Scala - scala

I have an Operator abstract class:
abstract class Operator[T, U] {
def setParent(op: Operator[T, U]): Unit
def newOp(): Operator[Byte, String] = {
val newOperator = new NewOperator[Byte, String]
newOperator.setParent(this)
newOperator
}
}
and another NewOperator class
class NewOperator[T, U] extends Operator[T, U] {
var parent: Operator[T,U] = null
def setParent(op: Operator[T, U]): Unit = {this.parent = op}
}
Now, in the second line in newOp() method in class Operator, I get an error
newOperator.setParent(this)
^
which says: Type mismatch: expected: Operator[Byte, String], actual: Operator[T, U].
Is the only way to resolve this, is to add .instanceOf[Operator[Byte, String]] to this?
newOperator.setParent(this.instanceOf[Operator[Byte, String]])

why not make the method newOp generic?
abstract class Operator[T, U] {
def setParent(op: Operator[T, U]): Unit
def newOp(): Operator[T, U] = {
val newOperator = new NewOperator[T, U]
newOperator.setParent(this)
newOperator
}
}
class NewOperator[T, U] extends Operator[T, U] {
var parent: Operator[T,U] = null
def setParent(op: Operator[T, U]): Unit = {this.parent = op}
}
val op = new NewOperator[Byte, String]().newOp

Your current solution restricts all your Operator[Byte, String] to have Operator[Byte, String] parent type (and you will found it only in runtime if you use asInstanceOf).
In general case if parent/child generic type may be different use:
scala> :paste
// Entering paste mode (ctrl-D to finish)
class Operator[T, U, P <: Operator[_, _, _]] {
var parent: P = null.asInstanceOf[P]
def setParent(op: P): Unit = {this.parent = op}
def newOp[TT, UU]() = {
val newOperator = new Operator[TT, UU, Operator[T, U, P]]()
newOperator.setParent(this)
newOperator
}
}
// Exiting paste mode, now interpreting.
defined class Operator
scala> new Operator[Byte, String, Null]
res19: Operator[Byte,String,Null] = Operator#5470e2f4
scala> res19.newOp[Int, String]
res20: Operator[Int,String,Operator[Byte,String,Null]] = Operator#729c1e43
scala> res20.parent
res21: Operator[Byte,String,Null] = Operator#5470e2f4
You may move newOp to some subclass and make Operator a trait, if you need to have some specific state/methods for your Operator.
Or you can use type classes for operator specific operations:
scala> new Operator[Byte, String, Null]
res23: Operator[Byte,String,Null] = Operator#728b49e2
scala> implicit class ByteOperator(o: Operator[Byte, String, _]) {
| def hello = "hello" //here you can access some members of Operator
| }
defined class ByteOperator
scala> res23.hello
res24: String = hello
If you really need children having same generic as parents:
scala> :paste
// Entering paste mode (ctrl-D to finish)
class Operator[T, U] {
var parent: Operator[T, U] = null
def newInstance: Operator[T, U] = new Operator[T, U]
def newOp: Operator[T, U] = {
val newOperator = newInstance
newOperator.setParent(this)
newOperator
}
def setParent(op: Operator[T, U]): Unit = {this.parent = op}
}
// Exiting paste mode, now interpreting.
defined class Operator
scala> new Operator[Byte, String]
res15: Operator[Byte,String] = Operator#4e6ea769
scala> res15.newOp
res16: Operator[Byte,String] = Operator#c774157
scala> res16.parent
res17: Operator[Byte,String] = Operator#4e6ea769
If you just need to model some AST (Abstract Syntax Tree), case classess may be a good solution:
trait Expression[T] {
def v: T
}
case class Value[T](v: T) extends Expression[T]
case class Plus[T1, T2](a: Expression[T1], b: Expression[T2])(implicit wrap: T1 => Arithmetic[T1, T2]) extends Expression[T1] {
def v = wrap(a.v) ++ b.v
}
abstract class Arithmetic[T1, T2](v: T1) {
def ++ (v: T2): T1
}
implicit class ArithmeticInt(val v: Int) extends Arithmetic[Int, Int](v) {
def ++ (v2: Int) = v + v2
}
implicit class ArithmeticIntDouble(val v: Int) extends Arithmetic[Int, Double](v) {
def ++ (v2: Double) = (v.toDouble + v2).toInt
}
scala> Plus(Value(5.0), Value(11.0)).v
res57: Value[Double] = Value(16.0)
scala> Plus(Value(5), Value(11.0)).v
res67: Int = 16
scala> Plus(Value(5), Value(6)).v
res68: Int = 11
scala> Plus(Value(5.0), Value(6)).v
<console>:60: error: No implicit view available from Double => Arithmetic[Double,Int].
Plus(Value(5.0), Value(6)).v
^

Instead of doing like this
newOperator.setParent(this) in abstract class operator you can do something like this
newOperator.setParent(newOperator)
This will solve your problem

Related

Get case class parameter types as a HList

I'm trying to generate instances of case class using shapeless
This works for generating instances of Foo
case class Foo(x: Int, y: String)
class Context {
val random = new Random()
}
def genInt(context: Context): Int = {
context.random.nextInt()
}
def genString(context: Context): String = {
context.random.nextString(16)
}
object ClassesToGenerators extends Poly1 {
implicit def caseInt = at[Class[Int]](_ => genInt(_))
implicit def caseString = at[Class[String]](_ => genString(_))
}
val gen = Generic[Foo]
val context = new Context()
val classes = classOf[Int] :: classOf[String] :: HNil // can't figure out how to get this hlist programmatically
val generators = classes.map(ClassesToGenerators)
gen.from(generators.zipApply(generators.mapConst(context)))
However, I'm aiming to write something reusable like
def newInstance[T] -> T:
???
which could generate instances of any case classes that takes only int and string parameters.
As mentioned in the code snippet, I'm stuck at getting a hlist of case class attribute types i.e. would like to convert case class Foo(x: Int, y: String) to classOf[Int] :: classOf[String] :: HNil. Any other approaches to this problem are also very appreciated but I'm not looking for a generic way of generating random instances of cases classes (as my use-case is different and used random generator just as an example)
IMHO, Shapeless is better used when you forget about all the fancy stuff and just focus on simple typeclass derivation using HList like this:
import shapeless.{Generic, HList, HNil, :: => :!:}
import scala.util.Random
trait Context {
def random: Random
}
object Context {
object implicits {
implicit final val global: Context = new Context {
override final val random: Random = new Random()
}
}
}
trait Generator[A] {
def generate(context: Context): A
}
object Generator {
final def apply[A](implicit ev: Generator[A]): ev.type = ev
final def generate[A](implicit ev: Generator[A], ctx: Context): A =
ev.generate(ctx)
implicit final val IntGenerator: Generator[Int] =
new Generator[Int] {
override def generate(context: Context): Int =
context.random.nextInt()
}
implicit final val StringGenerator: Generator[String] =
new Generator[String] {
override def generate(context: Context): String =
context.random.nextString(16)
}
implicit final def auto[P <: Product](implicit ev: GeneratorGen[P]): Generator[P] = ev
}
sealed trait GeneratorRepr[R <: HList] extends Generator[R]
object GeneratorRepr {
implicit final val HNilGeneratorRepr: GeneratorRepr[HNil] =
new GeneratorRepr[HNil] {
override def generate(context: Context): HNil =
HNil
}
implicit final def HConsGeneratorRepr[E, T <: HList](
implicit ev: Generator[E], tail: GeneratorRepr[T]
): GeneratorRepr[E :!: T] =
new GeneratorRepr[E :!: T] {
override def generate(context: Context): E :!: T =
ev.generate(context) :: tail.generate(context)
}
}
sealed trait GeneratorGen[P <: Product] extends Generator[P]
object GeneratorGen {
implicit final def instance[P <: Product, R <: HList](
implicit gen: Generic.Aux[P, R], ev: GeneratorRepr[R]
): GeneratorGen[P] = new GeneratorGen[P] {
override def generate(context: Context): P =
gen.from(ev.generate(context))
}
}
Which can be used like this:
import Context.implicits.global
final case class Foo(x: Int, y: String)
val result = Generator.generate[Foo]
// result: Foo = Foo(-2127375055, "鞰Ϗƨ⹼沺㗝䚮Ⴍ욏ꖱꬮӝ闉믃雦峷")
You can see the code running here.
Using built-in Shapeless type classes you can do
import shapeless.ops.hlist.FillWith
import shapeless.{Generic, HList, Poly0}
val context = new Context()
object ClassesToGenerators extends Poly0 {
implicit val caseInt = at[Int](genInt(context))
implicit val caseString = at[String](genString(context))
}
def newInstance[A] = new PartiallyApplied[A]
class PartiallyApplied[A] {
def apply[L <: HList]()(implicit
generic: Generic.Aux[A, L],
fillWith: FillWith[ClassesToGenerators.type, L]
): A = generic.from(fillWith())
}
newInstance[Foo]() // Foo(2018031886,⮐掐禃惌ᰧ佨妞꨸ዤࠒ훿柲籐妭蝱⻤)

Use the lowest subtype in a typeclass?

I have the following code:
sealed trait Animal
case class Cat(name: String) extends Animal
case class Dog(name: String) extends Animal
trait Show[A] {
def show(a: A): String
}
class Processor[A](a: A) {
def print(implicit S: Show[A]): Unit = println(S.show(a))
}
implicit val showCat: Show[Cat] = c => s"Cat=${c.name}"
implicit val showDog: Show[Dog] = d => s"Dog=${d.name}"
val garfield = Cat("Garfield")
val odie = Dog("Odie")
val myPets = List(garfield, odie)
for (p <- myPets) {
val processor = new Processor(p)
processor.print // THIS FAILS AT THE MOMENT
}
Does anyone know of a nice way to get that line processor.print working?
I can think of 2 solutions:
pattern match the p in the for loop.
create an instance of Show[Animal] and pattern match it against all its subtypes.
But I'm wondering if there's a better way of doing this.
Thanks in advance!
Compile error is
could not find implicit value for parameter S: Show[Product with Animal with java.io.Serializable]
You can make Animal extend Product and Serializable
sealed trait Animal extends Product with Serializable
https://typelevel.org/blog/2018/05/09/product-with-serializable.html
Also instead of defining implicit Show[Animal] manually
implicit val showAnimal: Show[Animal] = {
case x: Cat => implicitly[Show[Cat]].show(x)
case x: Dog => implicitly[Show[Dog]].show(x)
// ...
}
you can derive Show for sealed traits (having instances for descendants) with macros
def derive[A]: Show[A] = macro impl[A]
def impl[A: c.WeakTypeTag](c: blackbox.Context): c.Tree = {
import c.universe._
val typA = weakTypeOf[A]
val subclasses = typA.typeSymbol.asClass.knownDirectSubclasses
val cases = subclasses.map{ subclass =>
cq"x: $subclass => _root_.scala.Predef.implicitly[Show[$subclass]].show(x)"
}
q"""
new Show[$typA] {
def show(a: $typA): _root_.java.lang.String = a match {
case ..$cases
}
}"""
}
implicit val showAnimal: Show[Animal] = derive[Animal]
or Shapeless
implicit val showCnil: Show[CNil] = _.impossible
implicit def showCcons[H, T <: Coproduct](implicit
hShow: Show[H],
tShow: Show[T]
): Show[H :+: T] = _.eliminate(hShow.show, tShow.show)
implicit def showGen[A, C <: Coproduct](implicit
gen: Generic.Aux[A, C],
show: Show[C]
): Show[A] = a => show.show(gen.to(a))
or Magnolia
object ShowDerivation {
type Typeclass[T] = Show[T]
def combine[T](ctx: CaseClass[Show, T]): Show[T] = null
def dispatch[T](ctx: SealedTrait[Show, T]): Show[T] =
value => ctx.dispatch(value) { sub =>
sub.typeclass.show(sub.cast(value))
}
implicit def gen[T]: Show[T] = macro Magnolia.gen[T]
}
import ShowDerivation.gen
or Scalaz-deriving
#scalaz.annotation.deriving(Show)
sealed trait Animal extends Product with Serializable
object Show {
implicit val showDeriving: Deriving[Show] = new Decidablez[Show] {
override def dividez[Z, A <: TList, ShowA <: TList](tcs: Prod[ShowA])(
g: Z => Prod[A]
)(implicit
ev: A PairedWith ShowA
): Show[Z] = null
override def choosez[Z, A <: TList, ShowA <: TList](tcs: Prod[ShowA])(
g: Z => Cop[A]
)(implicit
ev: A PairedWith ShowA
): Show[Z] = z => {
val x = g(z).zip(tcs)
x.b.value.show(x.a)
}
}
}
For cats.Show with Kittens you can write just
implicit val showAnimal: Show[Animal] = cats.derived.semi.show
The thing is that garfield and odie in List(garfield, odie) have the same type and it's Animal instead of Cat and Dog. If you don't want to define instance of type class for parent type you can use list-like structure preserving types of individual elements, HList garfield :: odie :: HNil.
For comparison deriving type classes in Scala 3
How to access parameter list of case class in a dotty macro
The most general solution is to just pack the typeclass instances in at the creation of myPets, existentially
final case class Packaged[+T, +P](wit: T, prf: P)
type WithInstance[T, +P[_ <: T]] = Packaged[U, P[U]] forSome { type U <: T }
implicit def packageInstance[T, U <: T, P[_ <: T]]
(wit: U)(implicit prf: P[U])
: T WithInstance P
= Packaged(wit, prf)
val myPets = List[Animal WithInstance Show](garfield, odie)
for(Packaged(p, showP) <- myPets) {
implicit val showP1 = showP
new Processor(p).print // note: should be def print()(implicit S: Show[A]), so that this can be .print()
}

Finding the second matching implicit

Consider the following setup:
trait Foo[A]
object Foo extends Priority2
trait Priority0 {
implicit def foo1: Foo[Int] = new Foo[Int] {}
}
trait Priority1 extends Priority0 {
implicit def foo2: Foo[Boolean] = new Foo[Boolean] {}
}
trait Priority2 extends Priority1 {
implicit def foo3: Foo[Double] = new Foo[Double] {}
}
Now, in a REPL (having loaded the above code up), I can do the following:
scala> def implicitlyFoo[A](implicit foo: Foo[A]) = foo
implicitlyFoo: [A](implicit foo: Foo[A])Foo[A]
scala> implicitlyFoo
res1: Foo[Double] = Priority2$$anon$3#79703b86
Is there a way to encode with some typelevel magic that I want to skip over the instances with A =:= Double, but still let type inference figure out what A is?
I do not want to shadow foo3. This is an MVCE: in my real case, foo3 is a def with other implicit arguments (and may play an indirect role in deriving other Foo's).
I've tried =:!= from shapeless but to no avail:
scala> import shapeless._
import shapeless._
scala> def implicitlyFoo2[A](implicit foo: Foo[A], ev: A =:!= Double) = foo
implicitlyFoo2: [A](implicit foo: Foo[A], implicit ev: A =:!= Double)Foo[A]
scala> implicitlyFoo2
<console>:16: error: ambiguous implicit values:
both method neqAmbig1 in package shapeless of type [A]=> A =:!= A
and method neqAmbig2 in package shapeless of type [A]=> A =:!= A
match expected type Double =:!= Double
implicitlyFoo2
^
Dirty hack is to downcast macro context to its implemenation and use compiler internals.
import scala.language.experimental.macros
import scala.reflect.macros.whitebox
trait Foo[A] {
def say: String
}
trait Priority0 {
implicit def foo1: Foo[Int] = new Foo[Int] {
override def say: String = "int"
}
}
trait Priority1 extends Priority0 {
implicit def foo2: Foo[Boolean] = new Foo[Boolean] {
override def say: String = "bool"
}
}
trait Priority2 extends Priority1 {
implicit def foo3: Foo[Double] = new Foo[Double] {
override def say: String = "double"
}
}
object Foo extends Priority2
def materializeSecondFoo[A]: Foo[A] = macro impl
def impl(c: whitebox.Context): c.Tree = {
import c.universe._
val context = c.asInstanceOf[reflect.macros.runtime.Context]
val global: context.universe.type = context.universe
val analyzer: global.analyzer.type = global.analyzer
var infos = List[analyzer.ImplicitInfo]()
new analyzer.ImplicitSearch(
tree = EmptyTree.asInstanceOf[global.Tree],
pt = typeOf[Foo[_]].asInstanceOf[global.Type],
isView = false,
context0 = global.typer.context.makeImplicit(reportAmbiguousErrors = false),
pos0 = c.enclosingPosition.asInstanceOf[global.Position]
) {
override def searchImplicit(
implicitInfoss: List[List[analyzer.ImplicitInfo]],
isLocalToCallsite: Boolean
): analyzer.SearchResult = {
val implicitInfos = implicitInfoss.flatten
if (implicitInfos.nonEmpty) {
infos = implicitInfos
}
super.searchImplicit(implicitInfoss, isLocalToCallsite)
}
}.bestImplicit
val secondBest = infos.tail.head
global.gen.mkAttributedRef(secondBest.pre, secondBest.sym).asInstanceOf[Tree]
}
materializeSecondFoo.say // bool
Tested in 2.12.8. Motivated by shapeless.Cached.
In 2.13.0 materializeSecondFoo.say should be replaced with
val m = materializeSecondFoo
m.say
The latter is still working in 2.13.10.
Scala 3 implementation:
import scala.quoted.{Quotes, Type, Expr, quotes}
import dotty.tools.dotc.typer.{Implicits => dottyImplicits}
transparent inline def materializeSecondFoo: Foo[_] = ${impl}
def impl(using Quotes): Expr[Foo[_]] = {
import quotes.reflect.*
given c: dotty.tools.dotc.core.Contexts.Context =
quotes.asInstanceOf[scala.quoted.runtime.impl.QuotesImpl].ctx
val typer = c.typer
val search = new typer.ImplicitSearch(
TypeRepr.of[Foo[_]].asInstanceOf[dotty.tools.dotc.core.Types.Type],
dotty.tools.dotc.ast.tpd.EmptyTree,
Position.ofMacroExpansion.asInstanceOf[dotty.tools.dotc.util.SourcePosition].span
)
def eligible(contextual: Boolean): List[dottyImplicits.Candidate] =
if contextual then
if c.gadt.isNarrowing then
dotty.tools.dotc.core.Contexts.withoutMode(dotty.tools.dotc.core.Mode.ImplicitsEnabled) {
c.implicits.uncachedEligible(search.wildProto)
}
else c.implicits.eligible(search.wildProto)
else search.implicitScope(search.wildProto).eligible
def implicits(contextual: Boolean): List[dottyImplicits.SearchResult] =
eligible(contextual).map(search.tryImplicit(_, contextual))
val contextualImplicits = implicits(true)
val nonContextualImplicits = implicits(false)
val contextualSymbols = contextualImplicits.map(_.tree.symbol)
val filteredNonContextual = nonContextualImplicits.filterNot(sr => contextualSymbols.contains(sr.tree.symbol))
val successes = (contextualImplicits ++ filteredNonContextual).collect {
case success: dottyImplicits.SearchSuccess => success.tree.asInstanceOf[ImplicitSearchSuccess].tree
}
successes.tail.head.asExprOf[Foo[_]]
}
materializeSecondFoo.say // bool
val foo = materializeSecondFoo
foo: Foo[Boolean] // compiles
Scala 3.2.0.

Context bound for higher kinded types?

I want to do something like this:
def fold[C[A]](implicit ev: Foldable[A]): A
I am getting not found: type A
I know, I can do this instead:
def fold[C[_], A: Foldable]: A
But, I would rather invoke as fold[List[Int]] than fold[List, Int]
I played a bit with it and came up with a helper type class:
trait Helper[M[_], CA] {
type C[_]
type A
implicit def ma: M[A]
}
object Helper {
implicit def instance[M0[_], C0[_], A0](implicit ma0: M0[A0]) = new Helper[M0, C0[A0]] {
type C[X] = C0[X]
type A = A0
val ma: M0[A0] = ma0
}
}
I know the names are pretty generic, I'd suggest finding more meaningful names.
Now instead of requiring an implicit of type Foldable[A] you require instead an implicit of Helper[Foldable, CA] where CA is the type that must match against List[Int] in your example:
def fold[CA](implicit helper: Helper[Foldable, CA]): helper.A
As an example:
def fold[CA](implicit helper: Helper[Foldable, CA]): helper.A = {
import helper._
println(implicitly[Foldable[A]])
null.asInstanceOf[A]
}
scala> :paste
// Entering paste mode (ctrl-D to finish)
case class Foldable[A](name: String)
implicit val stringFoldable = Foldable[String]("String")
implicit val intFoldable = Foldable[Int]("Int")
implicit val floatFoldable = Foldable[Float]("Float")
def fold[CA](implicit helper: Helper[Foldable, CA]): helper.A = {
import helper._
println(implicitly[Foldable[A]])
null.asInstanceOf[A]
}
// Exiting paste mode, now interpreting.
defined class Foldable
stringFoldable: Foldable[String] = Foldable(String)
intFoldable: Foldable[Int] = Foldable(Int)
floatFoldable: Foldable[Float] = Foldable(Float)
fold: [CA](implicit helper: Helper[Foldable,CA])helper.A
scala> fold[List[String]]
Foldable(String)
res0: String = null
scala> fold[List[Int]]
Foldable(Int)
res1: Int = 0
scala> fold[List[Float]]
Foldable(Float)
res2: Float = 0.0
Here's what I came up with:
trait Foo[T, A]
implicit def makeFoo[A, M[_]] = new Foo[M[A], A] {}
class Helper[T] {
def apply[A]()(implicit ev: Foo[T, A]) = ev
}
def bar[T] = new Helper[T]
bar[List[Int]]()
//Foo[List[Int],Int] = $anon$1#7edf6563
The empty pair of parens might not be ideal if you really want an a no-arg method, but I can't see how to get around that at the moment.

Type parameters, upper bounds and overriding

Here's a very simple example:
scala> class A(x: Int) {
| def withX(newX: Int): A = new A(newX)
| override def toString = x.toString
| }
defined class A
scala> class B(x: Int) extends A(x) {
| override def withX(newX: Int): B = new B(newX)
| }
defined class B
So we have two classes:
A, which defines a method withX returning the object of type A, and
B, which extends A and overrides its withX method to return the object of type B.
Now I'd like to create a container, which can process instances of both A and B. It should have a method, which can accept an instance of A (or B), run withX on it and return another instance of A (or B). To be more specific, the exact functionality I want to achieve (note the return types):
scala> val a = new A(0)
a: A = 0
scala> val b = new B(0)
b: B = 0
scala> val testA = new Test[A]
testA: Test[A] = Test#4bf59a3d
scala> val testB = new Test[B]
testB: Test[B] = Test#65e565d1
scala> testA.test(a)
res1: A = 1
scala> testB.test(b)
res2: B = 1
I suppose that this can be achieved via class with upper-bounded type parameter. I've tried to do it like this, but got an error:
scala> class Test[T <: A] {
| def test(t: T): T = t withX 1
| }
<console>:9: error: type mismatch;
found : A
required: T
def test(t: T): T = t withX 1
^
The only workaround I managed to find looks somewhat ugly. Besides that, the match clause will need to be rewritten if we add some new class C extends B:
scala> class Test[T <: A] {
| def test(t: T): T = (t match {
| case b: B => b withX 1
| case a: A => a withX 1
| }).asInstanceOf[T]
| }
Can this functionality be achieved in more elegant way? I feel like I'm missing something about type parameters, type bounds and all scala type system in general.
While it's possible to override a method with a more specific return type, it's rarely a good idea. Consider the following:
class C(x: Int) extends A(x) {
override def withX(newX: Int): B = new B(x)
}
This is completely legal, but breaks your assumption that the return type of withX is the same subtype of A as the (statically known) type of the instance you're calling it on.
You can make that assumption safely (i.e. with support from the type system) by using F-bounded polymorphism:
trait Base[T <: Base[T]] {
def withX(newX: Int): T
}
class A(x: Int) extends Base[A] {
def withX(newX: Int) = new A(newX)
override def toString = x.toString
}
class B(x: Int) extends Base[B] {
def withX(newX: Int) = new B(newX)
override def toString = x.toString
}
class Test[T <: Base[T]] {
def test(t: T): T = t withX 1
}
This requires some changes to your type hierarchy, but it's a pretty standard way to encode the idea that the return type of a method is the same as the instance it's called on.
Somewhat along the lines of Travis' answer, if you want to encode the fact that a type supports a specific operation (withX in this case), you can consider using a type class.
class A(x: Int) {
override def toString = x.toString
}
class B(x: Int) extends A(x)
trait HasWithX[T] {
def withX(x: Int): T
}
implicit val AHasWithX = new HasWithX[A] {
def withX(x: Int) = new A(x)
}
implicit val BHasWithX = new HasWithX[B] {
def withX(x: Int) = new B(x)
}
class Test[T] {
def test(t: T)(implicit ev: HasWithX[T]): T = ev withX 1
}
Example:
scala> val a = new A(0)
a: A = 0
scala> val b = new B(0)
b: B = 0
scala> val testA = new Test[A]
testA: Test[A] = Test#4bf59a3d
scala> val testB = new Test[B]
testB: Test[B] = Test#65e565d1
scala> testA.test(a)
res1: A = 1
scala> testB.test(b)
res2: B = 1