In order to understand how 'implicit' works in Scala, I have written following code but it doesn't give me the expected result.
I thought I understood the use of 'implicit' (which clearly is not true). I have three classes, Plant, Dog and myPet. Dog has a function 'sound' which returns "woof". Plant has a function "tallOrShort" which returns "tall". These functions describe features of Dog and Plant.
I want to write a generic code in myPet to which I can pass an instance of Dog or Plant. I call this function 'describe'. The describe function should print "woof" for Dog instances and "tall" for Plant instances.
Dog and Plant are independent classes (no subtype). I thought I can use 'implicit' to "add" this functionality in Dog and Plant class. My understanding is that by using implicit, Dog or Plant could be implicitly converted into 'something' which can then call 'sound' or 'tallOrShort' for Dog and Plant respectively. I have written following code but it doesn't work.
I started with Dog class to begin with
//create Dog
scala> class Dog {
| def sound = "woof"
| }
defined class Dog
//create trait (the contract interface which Dog can be member of
scala> trait myPetTrait[A] {
| def describePet(a:A):String
| }
defined trait myPetTrait
//implicit conversion should happen using this code?
scala> implicit object dogIsPet extends myPetTrait[Dog] {
| def describePet(d:Dog) = d.sound
| }
defined object dogIsPet
Now first, I thought of defining only a generic function 'describe' as follows but I am not able to pass Dog or Plant instance to it.
//'describe' function. It should work for both Dog and Plant
scala> def describe[A](implicit pt:myPetTrait[A]) = {println(pt.describePet(_:A))}
describe: [A](implicit pt: myPetTrait[A])Unit
scala> describe(new Dog)
<console>:21: error: type mismatch;
found : Dog
required: myPetTrait[?]
describe(new Dog)
Question 1 - What is wrong with above? Shouldn't Dog get converted to myPetTrait[Dog]?
Then I thought to create a class (myPet) and define 'describe' in that class. That doesn't work either
//metPet It should work for both Dog and Plant
scala> class myPet[A](a:A) {
| def describe[A](implicit pt:myPetTrait[A]) = {println(pt.describePet(_:A))}
| }
defined class myPet
scala> new myPet(new Dog).describe
<function1>
Question 2 - Why does this compile at least if I put describe in myPet? Why am I getting a function literal (function1), not the print I expect
To keep experimenting, I started REPL again and declared Plant as well before creating describe and myPet
//new REPL session. created Dog
scala> class Dog {
| def sound = "woof"
| }
defined class Dog
//created plant
scala> class Plant {
| def tallOrShort = "tall"
| }
defined class Plant
//created trait
scala> trait myPetTrait[A] {
| def describePet(a:A):String
| }
defined trait myPetTrait
//code which should I think help in implicit conversion
scala> implicit object plantIsPet extends myPetTrait[Plant] {
| def describePet(p:Plant) = p.tallOrShort
| }
defined object plantIsPet
//describe still doesn't work
//describe shuold work for both Plant and Animal
scala> def describe[A](implicit pt:myPetTrait[A]) = {println(pt.describePet(_:A))}
describe: [A](implicit pt: myPetTrait[A])Unit
//not sure why this error comes
scala> describe(new Dog)
<console>:21: error: type mismatch;
found : Dog
required: myPetTrait[?]
describe(new Dog)
//get ambiguity error in this line
scala> new myPet(new Dog).describe //myPet gives ambiguity error
I get ambiguous implicit values error stating that both object dogIsPet of type dogIsPet.type and object plantIsPet of type plantIsPet.type match expected type myPetTrait[A]
Question 3 - why does Scala complain of ambiguity? It is probably because dogIsPet.type and plantisPet.type are of same 'type'. How do I make this code work?
I think you missed this (describe must take a of type A and an implicit contract)
define describe like this in myPet
class myPet[A](a:A) {
def describe(implicit pt:myPetTrait[A]) = {
println(pt.describePet(a))
}
}
describe outside the myPet can be declared like this
def describe[A](a: A)(implicit pt:myPetTrait[A]) = {println(pt.describePet(a))}
Scala has a special syntax for this
def describe[A: myPetTrait](a: A) = println(implicitly[myPetTrait[A]].describePet(a))
Scala REPL
scala> def describe[A](a: A)(implicit pt:myPetTrait[A]) = {println(pt.describePet(a))}
describe: [A](a: A)(implicit pt: myPetTrait[A])Unit
scala> describe[Plant](new Plant)
tall
or use scala syntactic sugar
scala> def describe[A: myPetTrait](a: A) = println(implicitly[myPetTrait[A]].describePet(a))
describe: [A](a: A)(implicit evidence$1: myPetTrait[A])Unit
scala> describe[Plant](new Plant)
tall
scala> trait myPetTrait[A] { def describePet(a:A):String }
defined trait myPetTrait
scala> class Dog { def sound = "woof" }
defined class Dog
scala> implicit object dogIsPet extends myPetTrait[Dog] { def describePet(d:Dog) = d.sound }
defined object dogIsPet
scala> def describe[A: myPetTrait](a: A) = println(implicitly[myPetTrait[A]].describePet(a))
defined function describe
scala> implicit object dogIsPet extends myPetTrait[Dog] { def describePet(d:Dog) = d.sound }
defined object dogIsPet
scala> describe[Dog](new Dog)
woof
scala> class myPet[A](a:A) {
def describe(implicit pt:myPetTrait[A]) = {
println(pt.describePet(a))
}
}
defined class myPet
scala> new myPet[Dog](new Dog).describe
woof
Complete code at one place
Main.scala
object Implicits {
trait myPetTrait[A] {
def describePet(a:A):String
}
class Dog {
def sound = "woof"
}
class Plant {
def tallOrShort = "tall"
}
//evidence for Plant
implicit object plantIsPet extends myPetTrait[Plant] {
def describePet(p:Plant) = p.tallOrShort
}
//evidence for Dog
implicit object dogIsPet extends myPetTrait[Dog] {
def describePet(d:Dog) = d.sound
}
def describe[A](a: A)(implicit pt:myPetTrait[A]) = {
println(pt.describePet(a))
}
//syntactic sugar
def describe2[A : myPetTrait](a: A) =
println(implicitly[myPetTrait[A]].describePet(a))
class myPet[A](a:A) {
def describe(implicit pt:myPetTrait[A]) = {
println(pt.describePet(a))
}
}
}
object Main {
import Implicits._
def main(args: Array[String]): Unit = {
describe(new Dog)
describe(new Plant)
describe2(new Dog)
describe2(new Plant)
new myPet[Dog](new Dog).describe
new myPet[Plant](new Plant).describe
}
}
output:
woof
tall
woof
tall
woof
tall
Related
I am trying to create a List of classes, like this:
abstract class Animal {
def name = this.getClass.getName
def say: String
}
class Dog extends Animal {
def say = "Woof"
}
class Cat extends Animal {
def say = "Meow"
}
val animalClasses = List(Dog, Cat)
This falls over on the last line, with the error message:
Zoo.scala:18: error: not found: value Dog
Note that I could create a List of instances of classes easily with List(new Dog(), new Cat()), but that's not what I want.
There you go:
scala> List(classOf[Dog],classOf[Cat])
res1: List[Class[_ >: Cat with Dog <: Animal]] = List(class Dog, class Cat)
As per this:
The predefined function classOf[T] returns a runtime representation of the Scala class type T.
I think I may be doing something very silly with this but following snippet doesn't compile.
scala> case class Foo1(i: Int)
defined class Foo1
scala> trait Foo1{def testFoo[T](l1 : List[T] ) : List[T] }
defined trait Foo1
And then implementing a trait as follow
scala> implicit val foodVal = new Foo1{
| def testFoo[Foo1](l:List[Foo1] ) = {
| for{
| a <- l
| if (a.i == 1)
| } yield a
| }
| }
<console>:13: error: value i is not a member of type parameter Foo1
Update
Thanks for the responses. I am genuinely interested in understanding difference between passing a type at a trait level vs def level. in the answers I can see type is passed at a trait level which does work but following still gives me the same error
scala> trait Bar { def testFoo[T](l1: List[T] ) : List[T] }
defined trait Bar
scala> implicit val fooVal = new Bar {
| override def testFoo[Foo1](l:List[Foo1]) : List[Foo1] = {
| for { a <- l if a.i == 1} yield a
| }
| }
<console>:18: error: value i is not a member of type parameter Foo1
At a REPL, the definition:
trait Foo1{def testFoo[T](l1 : List[T] ) : List[T] }
is replacing the class definition
case class Foo1(i: Int)
If you try to do the same thing using the paste command you will see that both cannot be defined together:
scala> :paste
// Entering paste mode (ctrl-D to finish)
case class Foo1(i: Int)
trait Foo1{def testFoo[T](l1 : List[T] ) : List[T] }
// Exiting paste mode, now interpreting.
<console>:36: error: Foo1 is already defined as case class Foo1
trait Foo1{def testFoo[T](l1 : List[T] ) : List[T] }
^
As such you need to use a different name for your trait than your case class, which is sensible, as they refer to different things.
Once renamed, there are a couple of ways to achieve your goals. One is outlined by Sascha (use a type member), or you can promote type T to parameterize your trait instead of parameterizing the method on the trait.
case class Foo1(i: Int)
trait Bar[T] {
def testFoo(l1 : List[T] ) : List[T]
}
implicit val foodVal: Bar[Foo1] = new Bar[Foo1] {
override def testFoo(l: List[Foo1]): List[Foo1] = {
for { a <- l if a.i == 1 } yield a
}
}
To answer the Update question, the answer is the difference between declaration and implementation.
When I write an implementation of a parameterized trait in the form below, I am saying "replace the abstract type T with the concrete type Foo".
trait Bar[T] {...}
val instance = new Foo[Bar] { ... }
But when I override a method that is parameterized by type and change the name of the type, all I am doing is specifying a different name for that abstract type. I'm not specifying the specific concrete class to use, I'm specifying a new symbol by which to identify the abstract type that I am operating on.
trait Bar {
def something[T](t: T) : T
}
val instance = new Bar {
def something[Foo](t: Foo) : Foo = { ... }
}
So, in the example above, Foo is not a concrete type Foo, rather Foo is just a symbol that means an arbitrary type which will be made concrete based on the type of parameter passed to the method.
As such, even if there is a concrete type called Foo in the same scope, it is shadowed by the type parameter Foo that has been introduced and any reference to Foo, or an instance of Foo, within the context of that method, is a reference to the abstract type parameter Foo, not the concrete type Foo.
You have to name the trait and the case class differently form each other as two types cannot have the same name. (Mike already explained, why it compiles in REPL)
In the line def testFoo[Foo1](l: List[Foo1]) = {, Foo1 is a new generic type parameter and NOT the type of your case class Foo1.
(IMHO) It is always a good idea to annotate an implicit val with a type.
That said, here is code that should do, what you want:
case class Foo1(i: Int)
trait Foo2 {
type T
def testFoo(l1 : List[T] ) : List[T]
}
implicit val foodVal: Foo2 = new Foo2 {
type T = Foo1
def testFoo(l: List[T]) = {
for { a <- l if a.i == 1 } yield a
}
}
Update (in answer to the questions Update):
Type parameters, especially in naming, work very similar to usual parameters. The key to whether a class parameter is accessed or a identically named function parameter is the scope.
class Foo(arg: Int) {
val field: Int = 1
def func(field: String) = {
// here field will always refer to the function paramter
// if you want to access the class field you would have to call this.field
}
}
class Bar[T] {
def func[T](t: T) = {
// within the scope of the function T IS NOT "Bar#T".
// However, you cannot access the class type parameter with "this.T" in this example
}
def func2(t: T) = {
// here T is the classes type parameter T
}
}
To complete the example with access by this.
class Bar[T] {
type Inner = T
def func[Inner](t: Inner) = {
// won't compile because the "Inner" type of the class is initialized with T
val test: this.Inner = t
}
}
If you do not specify a type parameter further it can be Any(thing). If you need a type with a specific API. You need to tell the compiler that with the <: operator.
trait Api {
def func: String
}
def func[T <: Api](arg: T) = {
arg.func // yay
}
This is called an upper type bound. There are more ways of arbitrary complexity to refine a type parameter, for which you will have to read the documentation.
I wanted to try writing a type whose methods can be homogeneous and return values of the same type:
object SimpleTest {
trait Foo extends Product with Serializable {
type Self <: Foo
def bar: Self
}
case class X() extends Foo {
type Self = X
def bar = this
}
case class Y() extends Foo {
type Self = Y
def bar = this
}
trait TC[A]
implicit val tc: TC[Foo] = new TC[Foo] { }
def tester[A: TC](x: Seq[A]) = "foo"
// tester(Seq(X(), Y()))
}
Unfortunately, the commented-out line calling tester fails with the following error (Scala 2.10):
Error: could not find implicit value for evidence parameter of type
SimpleTest.TC[SimpleTest.Foo{type Self >: SimpleTest.Y with SimpleTest.X <: SimpleTest.Foo}]
tester(Seq(X(), Y()))
^
Basically, I'm confused as to why X and Y don't unify to Foo, which seems like a clear LUB for the two of them. Clearly the type member is complicating matters but its bounds appear to be respected.
At the higher level, I'm looking for a lightweight way to get the equivalent of F-bounded polymorphism without the overhead of pervasive type parameters. This mostly seems to work, but I need to add annotations that force X and Y to unify to Foo.
I think this is an example of what you are looking for:
sealed trait Event { self =>
type E >: self.type <: Event
def instance: E = self
}
case class UserJoined() extends Event {
type E = UserJoined
}
case class UserLeft() extends Event {
type E = UserLeft
}
If you would like to read more, this snippet is from a recent post that covers related concepts.
Edit: To complete the answer, it would be:
scala> trait Foo extends Product with Serializable with Event{}
defined trait Foo
scala> case class X() extends Foo {
| type Self = X
| def bar = this
| }
defined class X
scala> case class Y() extends Foo {
| type Self = Y
| def bar = this
| }
defined class Y
scala> List(X(),Y())
res9: List[Foo] = List(X(), Y())
scala> def tester[A: TC](x: Seq[A]) = "foo"
tester: [A](x: Seq[A])(implicit evidence$1: TC[A])String
scala> tester(Seq(X(), Y()))
res10: String = foo
I've been trying out a few little things to try and understand Scala's Variance and Type Bounds syntax.
class Animal() {
def says():String = "???"
}
class Dog() extends Animal {
override def says():String = "woof"
}
val adog = new Dog
class Zoo[A <: Animal](thing: A) {
def whoami()=thing.getClass
def chat()=thing.says
}
How ever, when I try to create an instance of the object I get:
scala> val cage = new Zoo[Dog](adog)
<console>:18: error: type mismatch;
found : this.Dog
required: this.Dog
val cage = new Zoo[Dog](adog)
I don't quite understand what the compiler is telling me?
tks
Is it possible to do something like this in Scala:
class MyTest {
def foo[A <: String _or_ A <: Int](p:List[A]) = {}
}
That is, the type A could be a String or Int. Is this possible?
(Similar question here)
Not really possible as you put it, but you can do it using the type class pattern. For example, from here:
sealed abstract class Acceptable[T]
object Acceptable {
implicit object IntOk extends Acceptable[Int]
implicit object LongOk extends Acceptable[Long]
}
def f[T: Acceptable](t: T) = t
scala> f(1)
res0: Int = 1
scala> f(1L)
res1: Long = 1
scala> f(1.0)
<console>:8: error: could not find implicit value for parameter ev: Acceptable[Double]
f(1.0)
^
EDIT
This works if class and object are companions. On REPL, if you type each on a different line (ie, a "result" appears between them), they are not companions. You can type it like below, though:
scala> sealed abstract class Acceptable[T]; object Acceptable {
| implicit object IntOk extends Acceptable[Int]
| implicit object LongOk extends Acceptable[Long]
| }
defined class Acceptable
defined module Acceptable
You could get a little mileage from the Either type. However the Either hierarchy is sealed and handling more than two types becomes cumbersome.
scala> implicit def string2either(s: String) = Left(s)
string2either: (s: String)Left[String,Nothing]
scala> implicit def int2either(i: Int) = Right(i)
int2either: (i: Int)Right[Nothing,Int]
scala> type SorI = Either[String, Int]
defined type alias SorI
scala> def foo(a: SorI) {a match {
| case Left(v) => println("Got a "+v)
| case Right(v) => println("Got a "+v)
| }
| }
foo: (a: SorI)Unit
scala> def bar(a: List[SorI]) {
| a foreach foo
| }
bar: (a: List[SorI])Unit
scala>
scala> foo("Hello")
Got a Hello
scala> foo(10)
Got a 10
scala> bar(List(99, "beer"))
Got a 99
Got a beer
Another solution is wrapper classes:
case class IntList(l:List[Int])
case class StringList(l:List[String])
implicit def li2il(l:List[Int]) = IntList(l)
implicit def ls2sl(l:List[String]) = StringList(l)
def foo(list:IntList) = { println("Int-List " + list.l)}
def foo(list:StringList) = { println("String-List " + list.l)}
There is this hack:
implicit val x: Int = 0
def foo(a: List[Int])(implicit ignore: Int) { }
implicit val y = ""
def foo(a: List[String])(implicit ignore: String) { }
foo(1::2::Nil)
foo("a"::"b"::Nil)
See http://michid.wordpress.com/2010/06/14/working-around-type-erasure-ambiguities-scala/
And also this question.