In Scala, how can i add a container trait (like Traversable[Content]) to another one that extends the container (and thus has limited visibility of its content ?
For example, the code below tries to define a trait WithIter for a container requiring Traversable (of course, i have in fact other things in Container).
import scala.collection._
trait Container {
type Value
}
trait WithIter extends Container with immutable.Traversable[Container#Value]
class Instance extends WithIter {
type Value = Int
def foreach[U](f : (Value) => (U)) : Unit = {}
}
Compiler (scalac 2.8.0.Beta1-RC8) finds an error:
error: class Instance needs to be abstract, since method foreach in trait GenericTraversableTemplate of type [U](f: (Container#Value) => U)Unit is not defined
Is there any simple way?
class Instance extends WithIter {
type Value = Int
def foreach[U](f : (Container#Value) => (U)) : Unit = {}
}
If you do not specify OuterClass# when speaking of an inner class, then this. (ie, instance-specific) will be assumed.
Why do you use an abstract type? Generics are straightforward:
import scala.collection._
trait Container[T] {}
trait WithIter[T] extends Container[T] with immutable.Traversable[T]
class Instance extends WithIter[Int] {
def foreach[U](f : (Int) => (U)) : Unit = {println(f(1))}
}
new Instance().foreach( (x : Int) => x + 1)
Related
In the simplified implementation of Actor in the RedBook, they use node-based MPSC node based queue for Actor. They define the node by this line of code:
private class Node[A](var a: A = null.asInstanceOf[A]) extends AtomicReference[Node[A]]
But how can we use Node[A] as the type parameter of AtomicReference because we do not have class Node[A] yet? Is it a way of declaring recursive type in Scala?
You are allowed to use recursion in class/trait definition:
abstract class Example[A] extends (A => Example[A])
def example(prefix: String): Example[String] = new Example[String] {
def apply(s: String): Example[String] = {
val t = prefix + s
println(t)
example(t)
}
}
example("1")("2")("3")
//12
//123
If you have X extends F[X] then you ended up with something known to C++ developers as curiously recurring template pattern and in type theory in general as F-bounded types.
You can find it even in Java because each enum X is underneath abstract class X extends Enum[X].
I was trying to implement a similar structure with an idea to have a common trait to work with different Input instances regardless of their InType.
trait AnyInput {
type InType
val obj : InType
}
abstract class Input[T](obj: T) extends AnyInput {
type InType = T
}
case class InpImage(image: ByteStream) extends Input[ByteStream](image)
case class InpString(text: String) extends Input[String](text)
.
.
.
trait InputProcessor[T <: Input[T#InType]] {
...
}
and I get the "cyclic reference involving type T error" in the InputProcessor definition
It is important to notice, that there might be a couple different case class implementing Input[String] or Input[ByteStream]. So writing it out as
case class StringInput(s: String) extends Input[String](s)
case class IntInput(numb: Int) extends Input[Int](numb)
is not the best workaround
Maybe you can use
trait InputProcessor[S, T <: Input[S]] {
// ...
}
you can try something like this
trait InputProcessor[S <: AnyInput, T <: Input[S#InType]] {
implicit val evidence: T =:= S = implicitly[T =:= S]
}
and than the implementation would be:
class ImageProcessor extends InputProcessor[InpImage, InpImage] { }
you can read more about =:= here: https://stackoverflow.com/a/3427759/245024
EDIT:
added an example and the implementation to the evidence
notice that when extending InputProcessor, if you pass 2 different type parameters, the code won't compile (as you would expect)
How can one let a superclass have access to its concrete instance's type?
class Base {
val t = typeOf[this.type]
}
class X extends Base {
}
assert((new X).t =:= typeOf[X]) <-- fails!!!
So, the idea is that Base.t should reflect the concrete type of the instance...
It's unfortunately a common misunderstanding of this.type: it isn't the class of the instance, it's the singleton type (i.e. the type which only has one member: this). It won't work without inheritance either.
This can be done using F-bounded polymorphism:
class Base[A <: Base[A] : TypeTag] {
val t = typeOf[A]
}
class X extends Base[X]
How about making t a method and making that generic.
import scala.reflect.runtime.universe._
class Base {
def myActualType[T <: Base](b: T)(implicit tt: TypeTag[T]) = typeOf[T]
}
class Foo extends Base
class Bar extends Foo
val bar = new Bar
assert(bar.myActualType(bar) =:= typeOf[Bar])
The downside is that you always have to send the object reference to it when you call it, but you get what you want.
I have a super class:
class P(name:String)
And a helper trait:
trait SysConfig {
def prop(key:String) = System.getProperty(key)
}
Then I want to define an object which extends P:
object C extends P(prop("user.name")
It's not compiled, because it can't find the prop method. So I with the SysConfig:
object C extends P(prop("user.name") with SysConfig
Unfortunately, it still can't be compiled
Is there any way to make it work?
The arg is evaluated in a context outside the current definition, so no.
You have to put the computation in another object.
If you were thinking this, the answer also turns out to be no:
scala> class P(name: String)
defined class P
scala> trait Prop { def prop(k: String) = sys.props(k) }
defined trait Prop
scala> class C(p: String = C.prop("user.name")) extends P(p); object C extends C() with Prop
<console>:9: error: module extending its companion class cannot use default constructor arguments
class C(p: String = C.prop("user.name")) extends P(p); object C extends C() with Prop
^
That's because default args are methods defined by the companion.
Similarly,
scala> class C(p: String) extends P(p); object C extends C(C.prop("user.name")) with Prop
<console>:9: error: super constructor cannot be passed a self reference unless parameter is declared by-name
class C(p: String) extends P(p); object C extends C(C.prop("user.name")) with Prop
^
If I dont misunderstand this :), I think there are 2 things are impossible here.
trait composition or stackable trait is always make right trait wins. In this example, it tries to use left one override the right one.
when we use trait composition, trait structure would not change. The only flexible thing we can do is the sub-trait polymorphism. Cake pattern is using this way, but linearization is a problem. However, it is not related to this.
I think the correct way to do this, is to create a class/trait to do the override thing
class P(name:String)
trait SysConfig {
def prop(key:String) = System.getProperty(key)
}
class C extends P("123") with SysConfig {
override def prop(key: String) = "123"
}
trait Foo extends P with SysConfig {
override def prop(key: String) = "123"
}
new C
The question is not about AnyRef.clone(), it is about case with similar semantic.
I'd like to define an interface for classes that may create copy of itself:
trait Cloneable {
def clone() : this.type
}
class Test(val store : Int) extends Cloneable {
def clone() = new Test(store)
}
Path-dependent this.type would not work since this.type is different for the Test class type and for a class extending the Test. The descendant should then override clone method to match its own type.
How should I define type requirement for the Cloneable trait?
I've peeked into scala collections and found here tip: define TestLike trait, that handles type restrictions, and class Test that embodies corresponding trait.
I'd like to avoid unnecessary clumsiness if possible
trying self-recurring pattern as suggested:
trait Cloneable[A <: Cloneable[A]] {
def clone() : A
}
class Store[A <: Cloneable[A]](val store : Int) extends Cloneable[A] {
override def clone() : A = new Store[A](store)
}
failed with error:
Cloneable.scala:6: error: type mismatch;
found : Store[A]
required: A
override def clone() : A = new Store[A](store)
another issue in the recurring template: premature finalization
class Store(val store : Int) extends Cloneable[Store] {
override def clone() = new Store(store)
}
class SubStore(store : Int, val stash : Double) extends Store(store)
val ss1 = new SubStore(1, 0.5)
val ss2 = ss1.clone()
assert(ss2.isInstanceOf[SubStore])
The issue with SubStore is with type system ignoring absent clone() method in the SubStore class although SubStore is the Cloneable descendant via Store. But the Store finalize Cloneable interface with type parameter Store and all its descendants lacks proper clone() method restriction
Scala type variance allows to you implement what you need in a simple way, but you have to move away from inheritance and go to typeclasses.
trait Cloner[A]{
def cloneObject(input:A):A
}
trait CloningFunctions{
def cloneObject[A](input:A)(implicit cloner:Cloner[A]) = cloner.cloneObject(input)
}
object CloningFunctions extends CloningFunctions
class MyClass1(val b:Int)
class MyClass2(val a:Int,b:Int) extends MyClass1(b)
object Example {
implicit val cloner = new Cloner[MyClass1]{
def cloneObject(input: MyClass1): MyClass1 = new MyClass1(input.b)
}
import CloningFunctions._
cloneObject(new MyClass2(3,4))
}
The idea here is that since Cloner[A] is invariant in type A, the following code won't compile:
could not find implicit value for parameter cloner: Cloner[MyClass2]
cloneObject(new MyClass2(3,4))
because you have a Cloner[MyClass1] but not a Cloner[MyClass2] in scope.
While cloneObject(new MyClass1(3)) will compile.