consider this design of a library I need to use and cannot fix:
trait Foo
class IgnoreMe extends Foo
class A extends Foo { def bar: A = ...}
class B extends Foo { def bar: B = ...}
In my code:
object Stuff {
type Barred = { def bar: Foo }
def doStuff(b:Barred) = b.bar
}
Thats all well and good except that the Stuff.doStuff will accept anything conforming to the type Barred, not just the subtypes of Foo I want.
I would like to define Barred such that it is both a subtype of Foo and has a bar method, and I cannot :( Help appreciated.
Simply
type Barred = Foo {def bar: Foo }
Have you tried:
def doStuff(b: Barred with Foo) = b.bar
Another way to achieve what you want without reflection at runtime (but with more work if a new subtype of Foo with a bar method is added to the library), would be to define a trait Barred[T] typeclass, implicit instances of Barred[A] and Barred[B], and use a type bound:
def doStuff[T : Barred](b: T)
Given your examples, this may be more suitable:
type Barred[T <: Barred[T]] = Foo { def bar: T }
This allows you to define, e.g.
def double_bar[T <: Barred[T]](x: T) = x.bar.bar
which #didierd's answer doesn't.
Related
I am trying to figure out if it is possible to get type inference to work with my complex object type being passed in. The objects outside of the scope of Test are out of my control. Currently I have to specifically define the generics I am using (the Bar types).
trait Martini[A]
trait Foo[A <: Martini[A]] {
def foo(): A
}
class Bar extends Martini[Bar] {
def whoAmI = "Bar"
}
object Bar extends Foo[Bar] {
override def foo(): Bar = new Bar()
}
object Test extends App {
// val bar: Bar = test(Bar) // Want to do this, but doesn't work
val bar: Bar = test[Bar, Bar.type](Bar) // Works
println(bar.whoAmI)
def test[A <: Martini[A], F <: Foo[A]](f: F): A = {
f.foo()
}
}
The line I commented out is what I would like to achieve. Thanks for your help.
Generally, there's no point introducing a type parameter like your F which is only used once as parameter type. It can be simplified to
def test[A <: Martini[A]](f: Foo[A]): A = {
f.foo()
}
which will fix the type inference here as well.
Consider this:
class Foo { def foo = "foo" }
trait Bar { self: Foo =>
override def foo = "bar"
}
I was pleasantly surprised to find out that this is possible, and works as expected:
new Foo with Bar foo
returns "bar". The question is whether it is possible for Bar.foo to invoke Foo.foo, like one would often do in the "ordinary" inheritance case. override def foo = super.foo + "bar" does not work (says "foo is not a member of AnyRef), and neither does override def foo = self.foo + "bar" (it ends up just calling itself, and results in infinite recursion).
I tried a few other combinations (like self.Foo.foo, Foo.this.foo etc.), but without any luck.
Is this just impossible?
No. It is impossible to call overridden method from a self type.
Firstly the trait Bar is not a successor of class Foo so it is not possible using super.foo.
And secondly it is also not possible using self.foo since self is actually of type Bar with Foo. It can be shown by printing the program after typer:
$ scalac -Xprint:typer test.scala
[[syntax trees at end of typer]] // test.scala
package <empty> {
class Foo extends scala.AnyRef {
def <init>(): Foo = {
Foo.super.<init>();
()
};
def foo: String = "foo"
};
abstract trait Bar extends scala.AnyRef { self: Bar with Foo =>
def /*Bar*/$init$(): Unit = {
()
};
override def foo: String = "bar"
};
class FooBar extends Foo with Bar {
def <init>(): FooBar = {
FooBar.super.<init>();
()
}
};
object TestApp extends scala.AnyRef {
def <init>(): TestApp.type = {
TestApp.super.<init>();
()
};
def main(args: Array[String]): Unit = {
val a: FooBar = new FooBar();
scala.this.Predef.println(a.foo)
}
}
}
So with self.foo you are trying to access the method foo of the trait Bar. Such behavior matches the Scala Specification (PDF):
The sequence of template statements may be prefixed with a formal
parameter definition and an arrow, e.g. x =>, or x: T =>. If a formal
parameter is given, it can be used as an alias for the reference this
throughout the body of the template. If the formal parameter comes
with a type T, this definition affects the self type S of the
underlying class or object as follows: Let C be the type of the class
or trait or object defining the template. If a type T is given for the
formal self parameter, S is the greatest lower bound of T and C. If no
type T is given, S is just C. Inside the template, the type of this is
assumed to be S.
It is possible to access the method using reflection but I think that it is not what you are looking for.
I am not aware of any particular syntax to disentangle the base class and the mixed-in trait.
There is, however, an easy solution to achieve the result manually by distinguishing the overridden method from the default implementation in the base class:
class Foo { def foo = defaultFoo; def defaultFoo = "foo" }
trait Bar { self: Foo => override def foo = self.defaultFoo + "bar" }
As expected
new Foo with Bar foo == "foobar"
new Foo foo == "foo"
You make your trait extend Foo instead of using the self type:
class Foo {def foo = "foo"}
trait Bar extends Foo {
override def foo = super.foo + "bar"
}
new Foo with Bar foo // barfoo
See also this answer.
I have the following code snippet:
abstract class Foo[T <: Foo[T]] { self: T =>
def bar(x: T): T
def newFoo: Foo[T] = {
new Foo[T] { self: T =>
// ...
}
}
}
I have a need to generate a new instance of Foo within a method of my abstract class. Can anyone advise me on how best to approach this?
Thanks,
Hadil
The self-type self: T => implies that your Foo[T] must also be a T. new Foo[T] { ... } isn't an instance of T for any arbitrary T that makes up Foo[T]. You also can't add a self-type to an anonymous class like new Foo[T] { ... }, because it doesn't make sense. Either the concrete class is or isn't a T at that point.
Constructing a method like def newFoo: Foo[T] in a type-safe way isn't really possible with the self-type in place, because you'd need to know how to construct an arbitrary T. You might be able to do what you want with reflection, when each T has the same constructor.
import scala.reflect._
abstract class Foo[T <: Foo[T] : ClassTag] { self: T =>
def bar(x: T): T
def newFoo: Foo[T] = classTag[T].runtimeClass.newInstance.asInstanceOf[T]
}
class Bar extends Foo[Bar] {
def bar(x: Bar): Bar = x
}
scala> val b = new Bar
b: Bar = Bar#2a2d45ba
scala> b.newFoo
res1: Foo[Bar] = Bar#146ba0ac
This ceases to work when there are constructor parameters:
case class Baz(i: Int) extends Foo[Baz] {
def bar(x: Baz): Baz = x
}
scala> val baz = new Baz(0)
baz: Baz = Baz(0)
scala> baz.newFoo
java.lang.InstantiationException: Baz
at java.lang.Class.newInstance(Class.java:427)
at Foo.newFoo(<console>:16)
Well, you do not know the concrete class where Foo will be inherited in the future. So especially, you do not know which constructor parameters this class will have and how to supply arguments for them. If you really would want to do this, you would have to make some assumptions (that you cannot enforce at compile time) to achieve this.
So what you probably should do, is, leave this method abstract and implement it in a subclass. If this is not an option, you probably have some issues with your overall class design. Better present here what you want to model and ask for help.
If you assume, that the constructor of the concrete class won't have any parameters, you can implement newFoo just as
def newFoo = this.getClass.newInstance
There is no need for classTags or other fancy stuff.
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'm very new to Scala so forgive me if this is a real easy question but I could not find anything to help me or I could not figure out the right search terms. How can I make this work?
scala> trait Foo
defined trait Foo
scala> class FooImpl extends Foo
defined class FooImpl
scala> trait Bar { def someMethod(foo: Foo) }
defined trait Bar
scala> class BarImpl extends Bar { def someMethod(foo: FooImpl) {} }
<console>:10: error: class BarImpl needs to be abstract, since method someMethod in trait Bar of type (foo: Foo)Unit is not defined
(Note that Foo does not match FooImpl)
class BarImpl extends Bar { def someMethod(foo: FooImpl) {} }
Why doesn't FooImpl match Foo since Foo is a trait? I'm guessing I need to alter the signature of someMethod in Bar to say that I'm expecting something that extends Foo or "with Foo" but I can't seem to find documentation for this.
The problem is that the Bar trait's someMethod declaration specifies that any kind of Foo can be passed as an argument. You can think of this as its "contract". The contract says that any implementation of Bar will have a method someMethod that will accept any kind of Foo.
Your BarImpl class is an implementation of Bar and has a someMethod implementation. Unfortunately, its implementation of someMethod only accepts FooImpl kinds of Foo objects: not any kind of Foo. Since it doesn't allow you to pass in Foo objects that aren't FooImpl objects, it violates the contract specified by the trait definition. Implementations can't be more restrictive than the contract specifies.
As an example:
class FooImplB extends Foo
val bar: Bar = new BarImpl
val foo: Foo = new FooImplB
bar.someMethod(foo)
Here we declare a Bar called bar and a Foo called foo. According to the definition of Foo I should be able to pass foo into bar.someMethod. Except that BarImpl.someMethod only accepts FooImpl kinds of Foos and not FooImplBs! So we have a problem.
dhg explained why this doesn't work and why you probably don't really want it.
But if you still want it, you can do it like this:
trait Foo
class FooImpl extends Foo
trait Bar[F <: Foo] { def someMethod(foo: F) }
class BarImpl extends Bar[FooImpl] {
def someMethod(foo: FooImpl) {}
}
Jens Schauder's answer works but forces you to define the type in the trait signature. Instead, you can do the same on the method level:
scala> trait Foo
defined trait Foo
scala> class FooImple extends Foo
defined class FooImple
scala> trait Bar { def methodA[T <: Foo](foo: T) }
defined trait Bar
scala> class BarImpl extends Bar { def methodA[FooImpl](foo: FooImpl){} }
defined class BarImpl