Let's say I have some trait:
trait A[T] { def foo: T }
A class which extends it:
class B[T](t: T) extends A[T] { def foo = t }
And a subtrait of the parent trait:
trait C[T] extends A[T]
I want to mix C in with B.
val foo = new B("foo") with C[String]
This works fine, but I'd rather not need to specify the type parameter again, since B is already of type A[String]. However, I recognize Scala doesn't support the following:
val foo = new B("foo") with C
My question is where there's some other mechanism in the type system to support not having to specify the type parameters when C is mixed in. What I was thinking of was something as follows:
trait C {
self: A[T] => ...
}
One would think this kind of thing would fix what C could be mixed into. However, it isn't valid Scala. Something like:
trait C {
type T
self: A[T] =>
}
does not work either.
You can do this using an abstract type:
trait A {
type AT
def foo: AT
}
class B[T](t: T) extends A {
type AT = T
def foo = t
}
trait C extends A
val foo = new B("foo") with C
The definition is a bit more verbose, but your requirement of not having to type T again is satisfied.
How about this:
scala> trait C {
| self: A[_] =>
| }
defined trait C
scala> val foo = new B("foo") with C
foo: B[String] with C = $anon$1#f2df380
scala> foo.foo
res16: String = foo
Related
I'd like to get a reference to the concrete type of a self-type annotation in Scala within the self-typed trait. I have something like this:
trait Foo
class FooImpl1 extends Foo
class FooImpl2 extends Foo
trait SpecialFoo {
this:Foo =>
def |+|(that:this.type):this.type // the type signature is incorrect here
}
where if I do new FooImpl1 with SpecialFoo, I'd like the |+| method to require and return a FooImpl1 (or a subtype of FooImpl1). However, with the above code it seems to want a SpecialFoo.this.type, which is unsurprising, but not what I want.
this.type is the singleton type of whatever instance of SpecialFoo you have. As defined, |+| would only be able to be called with itself. For example:
trait Spec { def |+|(that: this.type): this.type = that }
val s = new Spec {}
val s2 = new Spec {}
scala> s |+| s
res1: <refinement>.type = $anon$1#118102ee
scala> s |+| s2
<console>:14: error: type mismatch;
found : Spec
required: <refinement>.type
s |+| s2
^
this.type is FooImpl1 in some cases, but the compiler has no way of knowing that. You need some way to capture the more refined type of FooImpl1 or FooImpl2. The self-type this: Foo => only cares that it's a Foo. There are a couple possibilities, but neither will look as nice as you want.
You can parameterize SpecialFoo:
trait Foo
class FooImpl1 extends Foo
class FooImpl2 extends Foo
trait SpecialFoo[A <: Foo] { self: A =>
def |+|(that: A): A
}
val foo = new FooImpl1 with SpecialFoo[FooImpl1] {
def |+|(that: FooImpl1): FooImpl1 = that
}
Unforunately, you need to write FooImpl1 twice, but the self-type still prevents you from mixing two different implementations.
The alternative is to use type members within Foo. You wouldn't have to specify the implementation type twice when creating a SpecialFoo, but would when creating the implementations themselves to bind the correct types.
trait Foo { type S }
class FooImpl1 extends Foo { type S = FooImpl1 }
class FooImpl2 extends Foo { type S = FooImpl2 }
trait SpecialFoo { self: Foo =>
def |+|(that: self.S): self.S
}
val foo = new FooImpl1 with SpecialFoo {
def |+|(that: FooImpl1): FooImpl1 = that
}
You could also make Foo F-bounded, i.e. trait Foo[A <: Foo], and do something similar to the above example.
I'm currently working on a A* implementation in Scala. To accomplish a clean structure I would like to use a nested case class structure which implements a self-bounded trait. However, I experience some issues when implementing this in the Scala IDE. The following code will not compile:
trait A[T <: A[T]]
class B {
case class C(int: Int) extends A[C] // A[this.C] won't work either
def make = C(5)
}
object D {
def foo[T <: A[T]](some: T) = {}
val c = new B().make
foo(c) // this does not compile
}
Is there any way I can make this structure work?
Not sure why you want this, but here's why it won't work as is:
The type of D.c is B#C. It is a path-dependent type where we don't know what instance of B it belongs to. However, C extends A[C], which is the already the same as saying A[this.C] in that context, which is bound to a specific instance of B. foo sees the type parameter T as B#C, which is not the same as b.C for some b.
You have two options to make this compile.
Relax the constraints of A to B#C:
trait A[T <: A[T]]
class B {
case class C(int: Int) extends A[B#C]
def make = C(5)
}
object D {
def foo[T <: A[T]](some: A[T]) = {}
val c = new B().make
foo(c)
}
Or handle the path-dependent type, so that c has type b.C:
trait A[T <: A[T]]
class B {
case class C(int: Int) extends A[C]
def make = C(5)
}
object D {
def foo[T <: A[T]](some: A[T]) = {}
val b = new B
val c: b.C = b.make
foo(c)
}
I've tried to come up with a composition scenario in which self-type and extends behave differently and so far have not found one. The basic example always talks about a self-type not requiring the class/trait not having to be a sub-type of the dependent type, but even in that scenario, the behavior between self-type and extends seems to be identical.
trait Fooable { def X: String }
trait Bar1 { self: Fooable =>
def Y = X + "-bar"
}
trait Bar2 extends Fooable {
def Y = X + "-bar"
}
trait Foo extends Fooable {
def X = "foo"
}
val b1 = new Bar1 with Foo
val b2 = new Bar2 with Foo
Is there a scenario where some form of composition or functionality of composed object is different when using one vs. the other?
Update 1: Thanks for the examples of things that are not possible without self-typing, I appreciate the information, but I am really looking for compositions where self and extends are possible, but are not interchangeable.
Update 2: I suppose the particular question I have is why the various Cake Pattern examples generally talk about having to use self-type instead of extends. I've yet to find a Cake Pattern scenario that doesn't work just as well with extends
Cyclic references can be done with self-types but not with extends:
// Legal
trait A { self: B => }
trait B { self: A => }
// Illegal
trait C extends D
trait D extends C
I use this sometimes to split up implementations across multiple files, when there are cyclic dependencies.
Also,
scala> trait A { def a: String ; def s = "A" }
defined trait A
scala> trait B { _: A => def s = "B" + a }
defined trait B
scala> trait C extends A { def a = "c" ; override def s = "C" }
defined trait C
scala> new C {}.s
res0: String = C
scala> new A with B { def a = "ab" }.s
<console>:10: error: <$anon: A with B> inherits conflicting members:
method s in trait A of type => String and
method s in trait B of type => String
(Note: this can be resolved by declaring an override in <$anon: A with B>.)
new A with B { def a = "ab" }.s
^
scala> new A with B { def a = "ab" ; override def s = super[B].s }.s
res2: String = Bab
The point, if there is one, is that B.s doesn't override A.s.
That's not as motivational as the other answer.
The generic parameter must be the type itself:
trait Gen[T] {self : T => ...}
I don't see how you can get this constraint in say java or C#. It may however be approximated with
trait Gen[T] {
def asT : T // abstract
}
Also,
as for self type, it needs a trait to mix in. It cannot use class or object. The weird thing is it allows to define a class can mix in with class, but it only fails compilation when you try to instantiate it. see this question:
why self-type class can declare class
The biggest difference is in the public interface that you end up with. Let's take the example you give (slightly simplified):
trait Fooable { def foo: String = "foo" }
trait Bar1 { self: Fooable =>
def Y = foo + "-bar"
}
trait Bar2 extends Fooable {
def Y = foo + "-bar"
}
// If we let type inference do its thing we would also have foo() in the public interface of b1, but we can choose to hide it
def b1:Bar1 = new Bar1 with Fooable
// b2 will always have the type members from Bar2 and Fooable
def b2:Bar2 = new Bar2{}
// Doesn't compile - 'foo' definition is only visible inside the definition of Bar1
println(b1.foo)
// Compiles - 'foo' definition is visible outside the definition of Bar2
println(b2.foo)
So if you want to use the capabilities of a trait without necessarily letting your clients know that you are mixing the trait in, then you should use the self-type annotation.
Self-type annotation does not expose the public interface of the underlying type.
Extending another type always exposes the public interface of the parent type.
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 would like to have a sealed trait which have a declared method that returns the
actual class that extends the trait. Should I use an abstract type, a parameter type or
is there any other nice way to solve this?
sealed trait Foo {
type T
def doit(other: T): T
}
or
sealed trait Foo[T] {
def doit(other: T): T
}
Note that T must be a subtype of Foo in this example. If I do it like this the type
information feels too repeated:
case class Bar(name: String) extends Foo[Bar] {
def doit(other: Bar): Bar = ...
}
They are mostly interchangeable. According to Odersky, the reason was mainly for completeness: That similarly to the fact that methods and fields (values) can be either abstract or passed as parameters, so can types.
It is better to use an abstract type when you intend to mix several traits that all use the same type name. With type parameters you need to explicitly pass the type to each
Here's an article explaining all of this: http://www.artima.com/weblogs/viewpost.jsp?thread=270195
You can cut down on the repetition somewhat by having your doit method return a factory function:
trait Foo[T] {
self: T =>
def doit: T => T
}
case class Bar(name: String) extends Foo[Bar] {
// note: types omitted
def doit = { other => Bar(name + other.name) }
}
It's not possible to do the same with an abstract type:
trait Foo {
self: T => // won't compile because T isn't defined yet
type T
def doit: T => T
}
You can write:
trait Foo[T] {
self:T =>
def doit(other: T): T
}
case class Bar(name: String) extends Foo[Bar] {
def doit(other: Bar): Bar = ...
}
The difference to your example is that Bar can't be instantiated in any other way (e.g. case class Bar(name: String) extends Foo[String]).
trait Foo[A <: Foo[A]]
This trait can only be mixed in if A is a subtype of Foo[A] and the only type satisfying that is the class Foo is being mixed into. I saw this solution in the Mapper traits in Lift.
EDIT - Below is my original answer. Your comment indicates that you wish to return an arbitrary instance of a matching type but I don't really believe that this is in any way sensible. Suppose it were, via the T.type syntax:
trait T { def foo : T.type }
trait U extends T { def foo = new U } //must be a U
class W extends U
val w : W = (new W).foo //oh dear.
This is accomplishable via this.type:
scala> trait T {
| def foo : this.type
| }
defined trait T
scala> class W extends T {
| def foo = this
| }
defined class W
scala> (new W).foo
res0: W = W#22652552
scala> res0.foo
res1: res0.type = W#22652552
And then also:
scala> ((new W) : T)
res4: T = W#45ea414e
scala> res4.foo.foo.foo
res5: res4.type = W#45ea414e