I find some confusing use of trait in some unittesting code, such as:
trait MyTrait {
val t1 = ... //some expression
val t2 = ... //some expression
}
And then instantiate the trait using new and meanwhile some expressions wrapped by curly braces followed the instantiation.
test("it is a test") {
new MyTrait {
// do something with t1 and t2
}
}
I am confused by this strange syntax.
My question is:
why use follow trait instantiation by curly braces?
what is the purpose of trait instantiation in this case and other cases might also be helpful?
You are not instantiating the traits: traits by themselves cannot be instantiated; only non-abstract classes can. What you are doing here is using Scala's shorthand for both defining an anonymous/nameless class that extends the trait and instantiating it in the same statement.
val anonClassMixingInTrait = new MyTrait {
def aFunctionInMyClass = "I'm a func in an anonymous class"
}
Is the equivalent of:
class MyClass extends MyTrait {
def aFunctionInMyClass = "I'm a func in a named class"
}
val namedClassMixingInTrait = new MyClass
The difference is you can only instaniate that anonymous class at the time of definition since it doesn't have a name and it can't have constructor arguments.
Steve Buzzard already explained, what anonymous classes are, but you also asked for the purpose. The purpose here is, that in tests you often have some default values, you want to use in every test. Sometimes you also have state, that may be changed by some of the tests. To always start with correct values (tests may also run in parallel) you can encapsulate them in these anonymous instances. The code inside this anonymous instance is the constructor, which will be evaluated at instantiation, thus executing your tests.
val t = new MyTrait {
val t1 = ... //some expression
val t2 = ... //some expression
}
is the same as
val t = new AnyRef with MyTrait {
val t1 = ... //some expression
val t2 = ... //some expression
}
is the same as
val t = new Object with MyTrait {
val t1 = ... //some expression
val t2 = ... //some expression
}
Example from "Hands on Scala" by Li HAOYI. Chapter 5.
trait StrParser[T]{ def parse(s: String): T }
object StrParser{
implicit object ParseInt extends StrParser[Int]{
def parse(s: String) = s.toInt
}
implicit object ParseBoolean extends StrParser[Boolean]{
def parse(s: String) = s.toBoolean
}
implicit object ParseDouble extends StrParser[Double]{
def parse(s: String) = s.toDouble
}
}
def parseFromString[T](s: String)(implicit parser: StrParser[T]) = {
parser.parse(s)
}
implicit def ParseSeq[T](implicit p: StrParser[T]) = new StrParser[Seq[T]]{
def parse(s: String) = s.split(',').toSeq.map(p.parse)
}
parseFromString[Seq[Int]]("1,2,3")
ParseSeq is Constructor for StrParser with Type Seq[T] and implicit parameter p:StrParser[T].
And one more StrParser Constructor for Type [T, V]
implicit def ParseTuple[T, V](implicit p1: StrParser[T], p2: StrParser[V]) =
new StrParser[(T, V)]{
def parse(s: String) = {
val Array(left, right) = s.split('=')
(p1.parse(left), p2.parse(right))
}
}
Now we can make
parseFromString[Seq[(Int, Boolean)]]("1=true,2=false,3=true,4=false")
Result is Seq[(Int, Boolean)] = ArraySeq((1,true), (2,false), (3,true), (4,false))
Related
Let's say we have the following traits:
trait MyValue
object MyValue {
case class MyBoolean(record: Boolean) extends MyValue
case class MyLong(record: Long) extends MyValue
}
trait MyValueExtractor[T] {
def apply(record: T): Option[MyValue]
}
trait MyThing[T] {
def name: String
def myValueExtractor: MyValueExtractor[T]
def myValue(record: T): Option[MyValue] = myValueExtractor(record)
}
What I want is something like this but without the second type parameter.
Note: I can't actually update the MyThing trait; I'm just using this as an illustration of the intended functionality.
trait MyThing[T, U] {
def name: String
def myValueExtractor: MyValueExtractor[T]
def myValue(record: T): Option[MyValue] = myValueExtractor(record)
def myRelatedValue(record: T): Option[U]
}
I'm wondering if I could use the type class pattern to help solve this (i.e., import some rich class that implicitly gives me a myRelatedValue method)?
Here's the rub. Every time T (above) is MyValue.MyBoolean, U must be a String. Every time T is MyValue.MyLong, U must be a Double. In other words, there's a sort of underlying mapping between T and U.
Is there a good way to do this using type class?
Sure. You just need to define some Mapping typeclass with implementations for your desired pairs of types. Then MyThing can have a method that takes an implicit typeclass instance and simply invokes its method.
Here's the code (I removed the unneeded details)
// types
case class MyBoolean(record: Boolean)
case class MyLong(record: Long)
// trait which uses the Mapping typeclass
trait MyThing[T] {
def myRelatedValue[U](record: T)(implicit ev: Mapping[T, U]): Option[U] = ev.relatedValue(record)
}
// typeclass itself
trait Mapping[T, U] {
def relatedValue(record: T): Option[U]
}
object Mapping {
implicit val boolStringMapping = new Mapping[MyBoolean, String] {
def relatedValue(record: MyBoolean) = Some(record.record.toString)
}
implicit val longDoubleMapping = new Mapping[MyLong, Double] {
def relatedValue(record: MyLong) = Some(record.record)
}
}
// usage
val myBoolThing = new MyThing[MyBoolean] {}
val myLongThing = new MyThing[MyLong] {}
val myStringThing = new MyThing[String] {}
myBoolThing.myRelatedValue(MyBoolean(true)) // Some(true)
myLongThing.myRelatedValue(MyLong(42L)) // Some(42.0)
myStringThing.myRelatedValue("someString") // error: could not find implicit value
Note that e.g. myBoolThing.myRelatedValue(MyBoolean(true)) will yield a type Option[U]. However, since myRelatedValue is parameterized, you can help the compiler and invoke it as myBoolThing.myRelatedValue[String](MyBoolean(true)), in which case you will obtain an Option[String]. If you try something other than String for MyBoolean, you will get an error.
I'm trying to use mixin composition using functions, but I have an error in the apply method of obj object:
Overriding method apply in trait t of type (s: String)String; method apply needs abstract override modifiers.
How to solve this error and which is the correct implementacion?
trait t extends Function1[String,String] {
abstract override def apply(s: String): String = {
super.apply(s)
println("Advice" + s)
s
}
}
object MixinComp {
def main(args: Array[String]) {
val obj = new Function1[String, String] with t {
override def apply(s: String) = s
}
println(obj.apply("Hi"))
}
}
Your immediate problem (the reason it complains about the error) is that you can't have an abstract call in your linearization flow (your t.apply calls super.apply, which is abstract).
Also, the apply method you define in the top level anonymous class overrides everything, and does not call super, making the t being mixed in completely irrelevant.
Something like this would solve both problems:
trait t extends Function1[String,String] {
abstract override def apply(s: String): String = {
println("Advice" + s)
super.apply(s) // I rearranged this a little, because it kinda makes more sense this wat
}
}
// Note, this extends `Function1`, not `t`, it, just a "vanilla" Function1
class foo extends Function1[String, String] {
def apply(s: String): String = s
}
// Now I am mixing in the t. Note, that the apply definition
// from foo is now at the bottom of the hierarchy, so that
// t.apply overrides it and calls it with super
val obj = new foo with t
obj("foo")
You won't need to use the abstract modifier in your t trait definition, if you don't call the super.apply. And in this particular case I dont see any need for calling super.apply as Function1's apply is abstract. You probably need custom apply implementations. The following code should work.
trait t extends Function1[String, String] {
override def apply(s: String): String = {
// super.apply(s)
println("Advice" + s)
s
}
}
Case1: use the overridden apply method in t trait:
val obj = new Function1[String, String] with t {}
obj.apply("hello") // prints: Advicehello
Case 2: override the apply method in t trait in an anonymous class:
val obj = new Function1[String, String] with t {
override def apply(s: String): String = s
}
obj.apply("hello") // prints hello
Is there a way in scala to call a method belonging to a type? For example, suppose I have a trait called Constructable that describes types than can construct a default instance of themselves. Then, I can write the following code:
trait Constructable[A] {
def construct: A
}
class Foo(x: Int) extends Constructable[Foo] {
def construct = new Foo(0)
}
def main(args: Array[String]) {
val f = new Foo(4)
println(f.construct)
}
This is ok, but what I really want is to be able to construct a default object given only the type of object. For example, suppose I want to accept a list of constructables and prepend a default object at the beginning of the list:
def prependDefault1[A <: Constructable[A]](c: List[A]): List[A] = {
val h = c.head
h.construct :: c
}
The above code works, but only if c is not empty. What I'd really like is to write something like the following:
def prependDefault2[A <: Constructable[A]](c: List[A]): List[A] = {
A.construct :: c
}
Is there any way to achieve this, possibly by changing the definition of a Constructable so that the construct method belongs to the "class" rather than the "instance" (to use Java terminology)?
You can't do this way, but you can do this using typeclasses:
trait Constructable[A] {
def construct: A
}
// 'case' just so it's printed nicely
case class Foo(x: Int)
// implicit vals have to be inside some object; omitting it here for clarity
implicit val fooConstructable = new Constructable[Foo] {
def construct = new Foo (0)
}
def prependDefault2[A : Constructable](c: List[A]): List[A] = {
implicitly[Constructable[A]].construct :: c
}
And then:
scala> prependDefault2(Nil: List[Foo])
res7: List[Foo] = List(Foo(0))
Some final remarks:
Implicits have to live inside an object. There are three places it can be located:
object Constructable { implicit val fooConstructable = ... (companion object of the typeclass trait)
object Foo { implicit val fooConstructable = ... (companion object of the class we implement typeclass for)
object SomethingElse { implicit val fooConstructable = ... (some random unrelated object)
Only in the last case you need to use import SomethingElse._ in order to be able to use the implicit.
After creating a ScalaIDE Worksheet named test.WsTemp, I wrote the code below and am receiving three errors for a single line in trait Enum:
Diverging implicit expansion for type scala.math.Ordering[U] starting with method ordered in trait LowPriorityOrderingImplicits
No implicit Ordering defined for U
Not enough arguments for method sorted: (implicit ord: scala.math.Ordering[U])List[U], Unspecified value parameter ord.
Why isn't this working since it's obvious Val extends Ordered[Val]?
object WsTemp {
trait Val extends Ordered[Val] {
val id: Int
val name: String
final def compare(that: Val) = this.id - that.id
override def toString: String = name
}
trait Enum[U <: Val] {
protected def init: Set[U]
val all = init
val allOrdered = all.toList.sorted // <-- Receiving error here
val byId = all.map(x => (x.id, x)).toMap
val byName = all.map(x => (x.name, x)).toMap
def apply(id: Int) = byId.get(id)
def apply(name: String) = byName.get(name)
}
sealed class Value(val id: Int, val name: String) extends Val
object Suit extends Enum[Value] {
override def init: Set[Value] = //Set()
Set(
new Value(0, "Spade")
, new Value(1, "Club")
, new Value(2, "Diamond")
, new Value(3, "Heart")
)
val Spade = Suit.byId(0)
val Club = Suit.byId(1)
val Diamond = Suit.byId(2)
val Heart = Suit.byId(3)
}
val all = Suit.all
val allOrdered = Suit.allOrdered
val byId = Suit.byId
val byName = Suit.byName
val spade = Suit.Spade
}
Ordering and Ordered are both invariant , so the fact that U is a sub-type of Val (as expressed by the relation U <: Val) does not imply that Ordering[Val] can be used as an Ordering[U].
So even though the fact that Val extends Ordered[Val] means that you implicitly get an Ordering[Val], this means nothing regarding Ordering[U].
So the compiler is right to complain that it cannot find an implicit value of type Ordering[U] (which is required by the call to sorted).
The prolbem is easy to illustrate with a small code snippet that mimics what happens with Ordered and Ordering:
object WsTemp {
trait MyOrdered[T]
trait MyOrdering[T]
object MyOrdering {
implicit def toOrdering[A <% MyOrdered[A]]: MyOrdering[A] = new MyOrdering[A]{}
}
trait Val extends MyOrdered[Val]
def test[T](implicit ord: MyOrdering[T]) {}
trait Enum[U <: Val] {
def callTest() { test[U] }
}
}
Which produces the following error:
<console>:20: error: could not find implicit value for parameter ord: WsTemp.MyOrdering[U]
def callTest() { test[U] }
But if you make MyOrdered and MyOrdering covariant, this compiles fine:
trait MyOrdered[+T]
trait MyOrdering[+T]
...
Obviously, you cannot change scala's Ordering nor Ordered to make them invariant.
Now, one way to solve your problem is to arrange your code so that Val does not extend Ordered[Val], but instead extends Ordered[X] where X is the actual type that you want to have an Ordering for (here, X = U). This can be achieved with F-bounded polymorphism:
trait Val[Self<:Val[Self]] extends Ordered[Self] {
//...
}
trait Enum[U <: Val[U]] {
//...
}
sealed class Value(val id: Int, val name: String) extends Val[Value]
//...
U is now a sub-type of Val[U], which is a sub-type of Ordered[U] (as opposed to a sub-type of Ordered[Val] as before), and so you now implicitly get an Ordering[U], which is (implicitly) passed to sorted. Problem solved.
As RĂ©gis Jean-Gilles said, "Ordering and Ordered are both invariant , so the fact that U is a sub-type of Val (as expressed by the relation U <: Val) does not imply that Ordering[Val] can be used as an Ordering[U]. So even though the fact that Val extends Ordered[Val] means that you implicitly get an Ordering[Val], this means nothing regarding Ordering[U]."
A very simple way to fix this is to specify the type to use for the sorted method. Replace:
val allOrdered = all.toList.sorted
with:
val allOrdered = all.toList.sorted[Val]
If I have a class C defined as
class C[A]
is there any way to create a new instance of A within C? Something like
class C[A] {
def f(): A = new A()
}
I understand that, if this were possible, you'd probably have to specify the constructor arguments somewhere, and that's fine.
If it's not possible, are there any design patterns for dealing with the sort of situation where you'd like to create a new instance of a type?
You could use a type class to abstract instantiation:
trait Makeable[T] {
def make: T
}
class C[T: Makeable] {
def f(): T = implicitly[Makeable[T]].make
}
For example,
implicit object StringIsMakeable extends Makeable[String] {
def make: String = "a string"
}
val c = new C[String]
c.f // == "a string"
When you instantiate C, you'll need to provide, explicitly or implicitly, a Makeable that will act as a factory of the appropriate type. That factory, of course, would be responsible for supplying any constructor arguments when it invokes the constructor.
Alternatively, you could use a Manifest, but be warned that this approach relies on reflection and is not type safe:
class C[T: Manifest] {
def f(): T = manifest[T].erasure.newInstance.asInstanceOf[T]
}
For completeness, you can also easily extend this approach to pass some or all of the constructor parameters in to the make method:
trait Makeable[Args, T] { def make(a: Args): T }
class C[Args, T](implicit e: Makeable[Args, T]) {
def f(a: Args): T = e.make(a)
}
// some examples
case class Person(firstName: String, lastName: String)
implicit val personFactory1 = new Makeable[(String, String), Person] {
def make(a: (String, String)): Person = Person(a._1, a._2)
}
implicit val personFactory2 = new Makeable[String, Person] {
def make(a: String): Person = Person(a, "Smith")
}
val c1 = new C[String, Person]
c1.f("Joe") // returns Person("Joe", "Smith")
val c2 = new C[(String, String), Person]
c2.f("John", "Smith") // returns Person("John", "Smith")
You can demand an implicit parameter, like so:
class A[T](implicit newT : T) {
val t = newT
}
All you need then is to have an implicit factory of the desired type in scope when you instanciate A, e.g. the following works:
implicit def newSeq[T] = Seq[T]()
val a = new A[Seq[String]]
As shown by:
scala> a.t
res22: Seq[String] = List()
The same as #Raphael's answer with a case class's apply method:
class Container[A](contained: A)
case class Person(name: String)
case class PersonContainer(person: Person) extends Container[Person](person)
implicit def _ = PersonContainer.apply _
class Creator {
def deserializeAndPackage[A, B <: Container[A]](data: Array[Byte])
(implicit containerCreator: (A => B)): B = {
val p = /* deserialize data as type of A */
containerCreator(p)
}
}