What is a convenient way to use implicit values that are simple types? Ideally, I would like to do something like this:
scala> :paste
// Entering paste mode (ctrl-D to finish)
type A = String
type B = String
implicit val a: A = "a"
implicit val b: B = "b"
def c(implicit ab: A) = println(ab)
// Exiting paste mode, now interpreting.
defined type alias A
defined type alias B
a: A = a
b: B = b
c: (implicit ab: A)Unit
scala> c
<console>:13: error: ambiguous implicit values:
both value a in object $iw of type => A
and value b in object $iw of type => B
match expected type A
One can't subclass final case classes like String or Long either
scala> class C extends String
<console>:11: error: illegal inheritance from final class String
class C extends String
While Tim is correct, his approach would create a wrapper around the string and thus introduce runtime overhead. We can let the compiler do all this without the need to create new objects with a technique called type tagging. Following code is shamelessly taken from the shapeless source:
trait Tagged[U]
type ##[+T, U] = T with Tagged[U]
class Tagger[U] {
def apply[T](t : T) : T ## U = t.asInstanceOf[T ## U]
}
def tag[U] = new Tagger[U]
With those definitions you can write the following:
trait A
trait B
implicit def a: String ## A = tag[A]("foo")
implicit def b: String ## B = tag[B]("bar")
def foo(implicit a: String ## A) = a.toString
def bar(implicit b: String ## B) = b.toString
scala> foo
res21: String = foo
scala> bar
res22: String = bar
When you use "type" you're defining an alias for a type, not an actual new type.
What you want to do is define an actual new type.
case class A(a: String)
case class B(b: String)
implicit val a = A("a")
implicit val b = B("b")
def c(implicit ab: A) = println(ab.a)
Related
I'm using a class (that I cannot modify) containing a method which receives a value of type Any as parameter, like the following example:
class Foo(value: Int) {
def +(other: Any): Foo = ???
}
I would like to add a custom implementation for the method +() when it's used with a specific type. I would expect to be able to do something like:
implicit class RichFoo(foo: Foo) {
def +(other: Int): Foo = ???
}
// or
implicit class RichFoo(foo: Foo) {
def +[T <: Bar](other: T): T = ???
}
However, these approaches don't work.
Is it possible to do without extending the original class?
No.
To the compiler, implicit conversions and other rewrite rules (like those around Dynamic) are a "last resort" of sorts. They are only applied if code does not already typecheck as-is. When you do foo + x, the compiler already knows that + takes Any, so it doesn't even try to look for implicits. If you did foo - x, and Foo had no - of the correct type, only then would the compiler search for a conversion.
Instead, you can create a method with a new name, maybe add, that is not present in Foo but is present in RichFoo. This will not, however, protect you from doing foo + 1 instead of foo add 1, since both methods are valid.
implicit class RichFoo(foo: Foo) {
def add(other: Int): Foo = ???
}
You can use a phantom type to track what is convertible.
scala> trait Tagged[B]
defined trait Tagged
scala> type Of[+A, B] = A with Tagged[B]
defined type alias Of
scala> class Tagger[B] { def apply[A](a: A): A Of B = a.asInstanceOf[A Of B] }
defined class Tagger
scala> object tag { def apply[B]: Tagger[B] = new Tagger[B] }
defined object tag
The given thing:
scala> case class C(i: Int) { def +(x: Any): C = C(i + x.toString.toInt) }
defined class C
and a marker trait:
scala> trait CC
defined trait CC
Normally:
scala> C(42) + "17"
res0: C = C(59)
This works:
scala> val cc = tag[CC](C(42))
cc: Of[C,CC] = C(42)
But not this:
scala> val cc = tag[CC](C(42): Any)
java.lang.ClassCastException: C cannot be cast to Tagged
... 29 elided
Maybe this:
scala> val cc = tag[CC](C(42): Serializable)
cc: Of[Serializable,CC] = C(42)
Then:
scala> implicit class XC(v: Serializable Of CC) {
| def +(x: Any): C Of CC = tag[CC] {
| println("OK")
| v.asInstanceOf[C] + x
| }}
defined class XC
Abnormally:
scala> val valueAdded = cc + "17"
OK
valueAdded: Of[C,CC] = C(59)
There's surely a better way to do this:
scala> implicit def untagit(x: Serializable Of CC): C Of CC = tag[CC](x.asInstanceOf[C])
untagit: (x: Of[Serializable,CC])Of[C,CC]
scala> cc.i
res9: Int = 42
because that ruins it:
scala> val res: C = cc + "17"
<console>:18: error: type mismatch;
found : <refinement>.type (with underlying type Of[Serializable,CC])
required: ?{def +(x$1: ? >: String("17")): ?}
Note that implicit conversions are not applicable because they are ambiguous:
both method XC of type (v: Of[Serializable,CC])XC
and method untagit of type (x: Of[Serializable,CC])Of[C,CC]
are possible conversion functions from <refinement>.type to ?{def +(x$1: ? >: String("17")): ?}
val res: C = cc + "17"
^
<console>:18: error: value + is not a member of Of[Serializable,CC]
val res: C = cc + "17"
^
In Idris, types are first-class values:
FooType : (Type, Type)
FooType = (Int, Int)
fst FooType -- Int : Type
I would like to use somehow this feature in Scala so that I can reuse type members over different methods:
class Foo {
type FooType = (Int, Int)
def foo : FooType = { ... }
def bar : Int = { ... } // Here I would like to reuse the first type of FooType (Int)
}
What is the recommended way to accomplish this in Scala?
I think the closest you can get is using a type member:
trait TupleType[T] { type Member = T }
implicit def toTuple[T](a: (T, T)) = new TupleType[T] {}
type FooType = TupleType[Int]
def foo: FooType = (1, 2)
def bar: FooType#Member = 1
Otherwise you could just use a type alias for your tuple member type:
type A = Int
type FooType = (A, A)
def foo: FooType = (1, 2)
def bar: A = 1
It is more or less possible if you create the necessary infrastructure yourself. In scala type level functions aren't really first class. They are implemented at the library level with implicits.
scala> :paste
// Entering paste mode (ctrl-D to finish)
sealed trait Deconstruct[T <: (_,_)] {
type fst
type snd
def fst(t: T): fst
def snd(t: T): snd
}
object Deconstruct {
implicit def mkDeconstruct[A,B] = new Deconstruct[(A,B)] {
type fst = A
type snd = B
def fst(t: (A,B)): A = t._1
def snd(t: (A,B)): B = t._2
}
}
// Exiting paste mode, now interpreting.
defined trait Deconstruct
defined module Deconstruct
scala> type FooType = (Int,Int)
defined type alias FooType
scala> def foo: FooType = (1,2)
foo: (Int, Int)
scala> def bar(implicit d: Deconstruct[FooType]) = d.fst(foo)
bar: (implicit d: Deconstruct[(Int, Int)])d.fst
scala> bar
res0: Int = 1
This thread addressed how to use TypeTag to get runtime type of type parameters when used with Existential type. Another thread addressed how to cast a variable to its runtime type retrieved from TypeTag.
My question builds on the aforementioned threads (kind of a combination of the two scenarios). Parts of the code is duplicated from the two threads for clarity.
scala> import scala.reflect.runtime.universe._
import scala.reflect.runtime.universe._
scala> def cast[A](a: Any, tt: TypeTag[A]): A = a.asInstanceOf[A]
cast: [A](a: Any, tt: reflect.runtime.universe.TypeTag[A])A
scala> abstract class Animal[T](implicit tt: TypeTag[T]) {
| val ttag = tt
| }
defined class Animal
scala> case object Dog extends Animal[Int]
defined object Dog
scala> case object Cat extends Animal[String]
defined object Cat
scala> val aa: List[(Animal[_], Any)] = List((Dog, 5), (Cat, "stringgg"), (Dog, 2))
aa: List[(Animal[_], Any)] = List((Dog,5), (Cat,stringgg), (Dog,2))
scala> aa(0)._1.ttag
res25: reflect.runtime.universe.TypeTag[_] = TypeTag[Int]
scala> aa(1)._1.ttag
res26: reflect.runtime.universe.TypeTag[_] = TypeTag[String]
scala> cast(aa(0)._2, aa(0)._1.ttag)
res27: Any = 5
scala> cast(aa(1)._2, aa(1)._1.ttag)
res28: Any = stringgg
In short, the last two lines: cast(value, TypeTag[_]) always return a value of type Any. But my intention is to cast these values to the correct type stored in Dog|Cat.ttag, which, unfortunately, is not TypeTag[Int] or TypeTag[String] but TypeTag[_] due to usage of existential type. Is there any solution for it?
Edit 1:
Despite the field ttag is of type TypeTag[_], ttag.tpe does have the right "type" (but as an instance of reflect.runtime.universe.Type). Is it possible to use the typetag.tpe to cast to the right type?
You could change the cast method as,
def cast[A](a: Any, tt: TypeTag[_]): A = a.asInstanceOf[A] and
val x: Int = cast(aa(0)._2, aa(0)._1.ttag)
pair with path dependent type, you can type cast as following code shows:
import languageFeature.existentials
object TestExistential {
def main(args: Array[String]): Unit = {
val aa: Array[(Animal[T], T) forSome {type T}] = Array((Dog, 5:Integer), (Cat, "stringgg"), (Dog, 2:Integer))
aa.foreach(p=>{
val ani = p._1
val attr = p._2 // compiler weakness: existential type T is not unify with ani.castType
assert(ani.attrTyp.isAssignableFrom(attr.getClass))// because of boxing, real type is Integer not Int
assert(ani.clzTyp.isAssignableFrom(ani.getClass))
val typedAni:ani.castType = ani.asInstanceOf[ani.castType]
println(s"$typedAni of type Animal[${ani.attrTyp}] with $attr")
})
}
abstract class Animal[T]{
type castType = Animal[T]
val attrTyp: Class[T]
val clzTyp: Class[castType]
}
case object Dog extends Animal[Integer] {
override val attrTyp: Class[Integer] = classOf[Integer]
override val clzTyp: Class[Dog.castType] = classOf[Dog.castType]
}
case object Cat extends Animal[String] {
override val attrTyp: Class[String] = classOf[String]
override val clzTyp: Class[Cat.castType] = classOf[Cat.castType]
}
}
if typing in scala repl, you can see the reply:
scala> val typedAni:ani.castType = ani.asInstanceOf[ani.castType]
typedAni: ani.castType = Dog
scala> typedAni
res0: ani.castType = Dog
How would I write use a variable as a type? For example:
scala> class A
defined class A
scala> class B extends A
defined class B
scala> def convert[F, T](from: F): T = from.asInstanceOf[T]
convert: [F, T](from: F)T
scala> val b = new B
b: B = B#54038f36
scala> convert[B, A](b)
res18: A = B#54038f36
This works fine. But I am interested in doing:
scala> val aType = classOf[A]
aType: Class[A] = class A
scala> convert[B, aType](b)
<console>:12: error: not found: type aType
convert[B, aType](b)
How would I do this without initializing an object and using obj.type in there? I suspect that I need to use some reflection features (maybe TypeTag?), but I couldn't find out what the correct thing to use here.
Thanks!
Java's Class has a method cast which does exactly what you need:
val aType = classOf[A]
aType.cast(b)
Now as a method:
def convert[F,T](from: F, clazz: Class[T]) = clazz.cast(from)
And call:
convert(b, aType)
I have seen a function named implicitly used in Scala examples. What is it, and how is it used?
Example here:
scala> sealed trait Foo[T] { def apply(list : List[T]) : Unit }; object Foo {
| implicit def stringImpl = new Foo[String] {
| def apply(list : List[String]) = println("String")
| }
| implicit def intImpl = new Foo[Int] {
| def apply(list : List[Int]) = println("Int")
| }
| } ; def foo[A : Foo](x : List[A]) = implicitly[Foo[A]].apply(x)
defined trait Foo
defined module Foo
foo: [A](x: List[A])(implicit evidence$1: Foo[A])Unit
scala> foo(1)
<console>:8: error: type mismatch;
found : Int(1)
required: List[?]
foo(1)
^
scala> foo(List(1,2,3))
Int
scala> foo(List("a","b","c"))
String
scala> foo(List(1.0))
<console>:8: error: could not find implicit value for evidence parameter of type
Foo[Double]
foo(List(1.0))
^
Note that we have to write implicitly[Foo[A]].apply(x) since the compiler thinks that implicitly[Foo[A]](x) means that we call implicitly with parameters.
Also see How to investigate objects/types/etc. from Scala REPL? and Where does Scala look for implicits?
implicitly is avaliable in Scala 2.8 and is defined in Predef as:
def implicitly[T](implicit e: T): T = e
It is commonly used to check if an implicit value of type T is available and return it if such is the case.
Simple example from retronym's presentation:
scala> implicit val a = "test" // define an implicit value of type String
a: java.lang.String = test
scala> val b = implicitly[String] // search for an implicit value of type String and assign it to b
b: String = test
scala> val c = implicitly[Int] // search for an implicit value of type Int and assign it to c
<console>:6: error: could not find implicit value for parameter e: Int
val c = implicitly[Int]
^
Here are a few reasons to use the delightfully simple method implicitly.
To understand/troubleshoot Implicit Views
An Implicit View can be triggered when the prefix of a selection (consider for example, the.prefix.selection(args) does not contain a member selection that is applicable to args (even after trying to convert args with Implicit Views). In this case, the compiler looks for implicit members, locally defined in the current or enclosing scopes, inherited, or imported, that are either Functions from the type of that the.prefix to a type with selection defined, or equivalent implicit methods.
scala> 1.min(2) // Int doesn't have min defined, where did that come from?
res21: Int = 1
scala> implicitly[Int => { def min(i: Int): Any }]
res22: (Int) => AnyRef{def min(i: Int): Any} = <function1>
scala> res22(1) //
res23: AnyRef{def min(i: Int): Int} = 1
scala> .getClass
res24: java.lang.Class[_] = class scala.runtime.RichInt
Implicit Views can also be triggered when an expression does not conform to the Expected Type, as below:
scala> 1: scala.runtime.RichInt
res25: scala.runtime.RichInt = 1
Here the compiler looks for this function:
scala> implicitly[Int => scala.runtime.RichInt]
res26: (Int) => scala.runtime.RichInt = <function1>
Accessing an Implicit Parameter Introduced by a Context Bound
Implicit parameters are arguably a more important feature of Scala than Implicit Views. They support the type class pattern. The standard library uses this in a few places -- see scala.Ordering and how it is used in SeqLike#sorted. Implicit Parameters are also used to pass Array manifests, and CanBuildFrom instances.
Scala 2.8 allows a shorthand syntax for implicit parameters, called Context Bounds. Briefly, a method with a type parameter A that requires an implicit parameter of type M[A]:
def foo[A](implicit ma: M[A])
can be rewritten as:
def foo[A: M]
But what's the point of passing the implicit parameter but not naming it? How can this be useful when implementing the method foo?
Often, the implicit parameter need not be referred to directly, it will be tunneled through as an implicit argument to another method that is called. If it is needed, you can still retain the terse method signature with the Context Bound, and call implicitly to materialize the value:
def foo[A: M] = {
val ma = implicitly[M[A]]
}
Passing a subset of implicit parameters explicitly
Suppose you are calling a method that pretty prints a person, using a type class based approach:
trait Show[T] { def show(t: T): String }
object Show {
implicit def IntShow: Show[Int] = new Show[Int] { def show(i: Int) = i.toString }
implicit def StringShow: Show[String] = new Show[String] { def show(s: String) = s }
def ShoutyStringShow: Show[String] = new Show[String] { def show(s: String) = s.toUpperCase }
}
case class Person(name: String, age: Int)
object Person {
implicit def PersonShow(implicit si: Show[Int], ss: Show[String]): Show[Person] = new Show[Person] {
def show(p: Person) = "Person(name=" + ss.show(p.name) + ", age=" + si.show(p.age) + ")"
}
}
val p = Person("bob", 25)
implicitly[Show[Person]].show(p)
What if we want to change the way that the name is output? We can explicitly call PersonShow, explicitly pass an alternative Show[String], but we want the compiler to pass the Show[Int].
Person.PersonShow(si = implicitly, ss = Show.ShoutyStringShow).show(p)
Starting Scala 3 implicitly has been replaced with improved summon which has the advantage of being able to return a more precise type than asked for
The summon method corresponds to implicitly in Scala 2. It is
precisely the same as the the method in Shapeless. The difference
between summon (or the) and implicitly is that summon can return a
more precise type than the type that was asked for.
For example given the following type
trait F[In]:
type Out
def f(v: Int): Out
given F[Int] with
type Out = String
def f(v: Int): String = v.toString
implicitly method would summon a term with erased type member Out
scala> implicitly[F[Int]]
val res5: F[Int] = given_F_Int$#7d0e5fbb
scala> implicitly[res5.Out =:= String]
1 |implicitly[res5.Out =:= String]
| ^
| Cannot prove that res5.Out =:= String.
scala> val x: res5.Out = ""
1 |val x: res5.Out = ""
| ^^
| Found: ("" : String)
| Required: res5.Out
In order to recover the type member we would have to refer to it explicitly which defeats the purpose of having the type member instead of type parameter
scala> implicitly[F[Int] { type Out = String }]
val res6: F[Int]{Out = String} = given_F_Int$#7d0e5fbb
scala> implicitly[res6.Out =:= String]
val res7: res6.Out =:= String = generalized constraint
However summon defined as
def summon[T](using inline x: T): x.type = x
does not suffer from this problem
scala> summon[F[Int]]
val res8: given_F_Int.type = given_F_Int$#7d0e5fbb
scala> summon[res8.Out =:= String]
val res9: String =:= String = generalized constraint
scala> val x: res8.Out = ""
val x: res8.Out = ""
where we see type member type Out = String did not get erased even though we only asked for F[Int] and not F[Int] { type Out = String }. This can prove particularly relevant when chaining dependently typed functions:
The type summoned by implicitly has no Out type member. For this
reason, we should avoid implicitly when working with dependently typed
functions.
A "teach you to fish" answer is to use the alphabetic member index currently available in the Scaladoc nightlies. The letters (and the #, for non-alphabetic names) at the top of the package / class pane are links to the index for member names beginning with that letter (across all classes). If you choose I, e.g., you'll find the implicitly entry with one occurrence, in Predef, which you can visit from the link there.