I have a class which source I cannot modify:
class Foo {
def bar() = println("bar")
}
And a trait I'd like to mix into it at runtime
trait Zee { this: Foo =>
abstract override def bar() = {
println("before bar")
super.bar()
}
}
This is throwing that bar is not a member of Object with ScalaObject
What am I doing wrong? Is it possible to achieve this without modifying Foo source?
The ultimate client code needs to look like this:
val foo = new Foo with Zee
foo.bar() // should print 'before bar' and then 'bar'
Your Zee trait has no super traits (except implicit inheritance from ScalaObject) thus super does not contain definition for bar and there is nothing to override or call (super.bar).
why don't you write this without self-reference?
class Foo {
def bar() = println("bar")
}
trait Zee extends Foo {
abstract override def bar() = {
println("before bar")
super.bar()
}
}
You can just extends the class Foo in your trait:
trait Zee extends Foo
And your code will work.
your trait needs to extend foo
trait Zee extends Foo {
abstract override def bar() = {
println("before bar")
super.bar()
}
}
Related
I want to do something like this
abstract class Foo {
def bar:String
def modifiedFoo:Foo = new Foo(){
override def bar = super.bar+"\n"
}
}
but this is not legitimate ("method bar in class Foo is accessed from super,
it may not be abstract unless it is overriden by a member declared abstract
and override" which inturn is only legal for Traits).
I could move the method modifiedFoo
into the companion object with signature modifiedFoo(foo:Foo) but this is
less elegant.
How do you handle this problem?
I think you can just use self in the following way:
abstract class Foo {
self: Foo =>
def bar: String
def modifiedFoo: Foo = new Foo() {
override def bar = self.bar + "\n"
}
}
When I extend traits I can choose which method implementation to use. Like here:
object Main {
def main(args: Array[String]): Unit = {
val c = new C
println(c.a)
println(c.b)
}
trait Parent {
def foo: String
}
trait A extends Parent {
override def foo = "from A"
}
trait B extends Parent {
override def foo = "from B"
}
class C extends A with B {
val b = super[A].foo
val a = super[B].foo
}
}
But if I want to do the same with self-types it's seems like it's not possible:
object Main {
def main(args: Array[String]): Unit = {
val c = new C with A with B
println(c.a)
println(c.b)
}
trait Parent {
def foo: String
}
trait A extends Parent {
override def foo = "from A"
}
trait B extends Parent {
override def foo = "from B"
}
class C {
self: A with B =>
val b = super[A].foo
val a = super[B].foo
}
}
This doesn't compile. Am I right and it's not possible? If I'm right, why is that and is there a workaround for it?
UPDATE:
Why do I needed in a first place? I was playing around with dependency injection using self-types instead of constructor injection. So I had a base trait Converter and child traits FooConverter and BarConverter. And I wanted to write it like that(which doesn't work of course):
object Main {
class Foo
class Bar
trait Converter[A] {
def convert(a: A): String
}
trait FooConverter extends Converter[Foo] {
override def convert(a: Foo): String = ???
}
trait BarConverter extends Converter[Bar] {
override def convert(a: Bar): String = ???
}
class Service {
this: Converter[Foo] with Converter[Bar] =>
def fooBar(f: Foo, b:Bar) = {
convert(f)
convert(b)
}
}
}
I thought it's because of generics, but it turned that it's not. So I was just wondering if it's possible to somehow invoke super method of chosen trait with self-types. Because with simple inheritance it's possible. As for my original problem I can write it like this and it will work:
object Main {
class Foo
class Bar
trait Converter[A] {
def convert(a: A): String
}
trait FooConverter extends Converter[Foo] {
override def convert(a: Foo): String = ???
}
trait BarConverter extends Converter[Bar] {
override def convert(a: Bar): String = ???
}
class Service {
this: FooConverter with BarConverter =>
def fooBar(f: Foo, b:Bar) = {
convert(f)
convert(b)
}
}
}
Probably tighter abstraction, but I'm not sure if it's bad for this kind of situation and if I need such broad abstraction like Converter[A] at all.
Calling super methods from already constructed type is impossible (you can do it only from the inside). In your example, you're trying to call foo on the instance self, which is constructed in runtime, so foo is virtual and could be overridden - compiler doesn't know which actual implementation is going to be called (formal vs real type problem). So technically - it's impossible to do what you want (call virtual method as a static one).
The naive hack is :
trait CC extends A with B {
val b = super[A].foo
val a = super[B].foo
}
class C {
self: CC =>
}
It basically provides encapsulation you want - you might wanna redefine a and b in class C as they're not going to be available (in type C itself) till you mix C with CC.
Note that in every example you provide (including my naive solution) - resulting val c has access to foo anyway and which exact foo is going to be called depends on how do you mix A and B (A with B or B with A). So, the only encapsulation you get is that type C itself isn't going to have foo method. This means that self-type gives you kind of a way to temporary close (make private) a method in "subclass" without violating LSP - but it's not the only way (see below).
Besides all of that, cake-injection that you're trying to implement is considered impractical by some authors. You might want to have a look at Thin Cake Pattern - as a remark, I successfully used something like this in real project (in combination with constructor injection).
I would implement your converter services this way:
class Foo
class Bar
trait Converter[A] {
def convert(a: A): String
}
object FooConverter1 extends Converter[Foo] {
override def convert(a: Foo): String = ???
}
object BarConverter1 extends Converter[Bar] {
override def convert(a: Bar): String = ???
}
trait FooBarConvertService {
def fooConverter: Converter[Foo]
def barConverter: Converter[Bar]
def fooBar(f: Foo, b: Bar) = {
fooConverter(f)
barConverter(b)
}
}
trait Converters {
def fooConverter: Converter[Foo] = FooConverter1
def barConverter: Converter[Bar] = BarConverter1
}
object App extends FooBarConvertService with Converters with ...
This allows you to change/mock converter implementation when putting it all together.
I'd also notice that Converter[Bar] is nothing else but Function1[Bar, String] or just Bar => String, so actually you don't need separate interface for that:
sealed trait FooBar //introduced it just to make types stronger, you can omit it if you prefer
class Foo extends FooBar
class Bar extends FooBar
trait FooBarConvertService {
type Converter[T <: FooBar] = T => String
def fooConverter: Converter[Foo]
def barConverter: Converter[Bar]
def fooBar(f: Foo, b: Bar) = {
fooConverter(f)
barConverter(b)
}
}
trait FooConverterProvider {
def fooConverter: Foo => String = ???
}
trait BarConverterProvider {
def barConverter: Bar => String = ???
}
object App
extends FooBarConvertService
with FooConverterProvider
with BarConverterProvider
You can also use def fooConverter(f: Foo): String = ??? instead def fooConverter: Foo => String = ???.
Talking about encapsulation - it's more weak here as you can access transitive dependencies, so if you really need it - use private[package] modifier.
Converters module:
package converters
trait FooBarConvertService {
type Converter[T <: FooBar] = T => String
private[converters] def fooConverter: Converter[Foo]
private[converters] def barConverter: Converter[Bar]
def fooBar(f: Foo, b: Bar) = {
fooConverter(f)
barConverter(b)
}
}
trait FooConverterProvider {
private[converters] def fooConverter: Foo => String = ???
}
trait BarConverterProvider {
private[converters] def barConverter: Bar => String = ???
}
Core module:
package client
import converters._
object App
extends FooBarConvertService
with FooConverterProvider
with BarConverterProvider
You can use objects object converters {...}; object client {...} instead of packages if you prefer.
This encapsulation is even stronger than self-type based one, as you can't access fooConverter/barConverter from the App object (in your example foo is still accessable from val c = new C with A with B):
client.App.fooBar(new Foo, new Bar) //OK
client.App.fooConverter
<console>:13: error: method fooConverter in trait FooConverterProvider cannot be accessed in object client.App
client.App.fooConverter
^
Keep in mind that self types are meant to allow you to require that any client code that uses the trait you are mixing in must also mix in another trait. In other words it is a way of declaring dependencies. But it is not classical inheritance. So when you say class C { self: A with B => } A and B actually are not there at the time. You have just defined that the client code has to mix in A and B in order to then mix in C.
But for your specific use case, it seems like you can accomplish the same goal with something like this code. In other words first create a third trait and then extend it into a specific class.
object DoubleSelfType extends App {
val c = new DoubleFoo
println(c.a)
println(c.b)
trait Parent {
def foo: String
}
trait A extends Parent {
override def foo = "from A"
}
trait B extends Parent {
override def foo = "from B"
}
trait C {
self: A with B =>
val a = ""
val b = ""
}
class DoubleFoo extends C with A with B {
override val b = super[A].foo
override val a = super[B].foo
}
}
It would appear that it is possible to change the implementation of a method on a class with a trait such as follows:
trait Abstract { self: Result =>
override def userRepr = "abstract"
}
abstract class Result {
def userRepr: String = "wtv"
}
case class ValDefResult(name: String) extends Result {
override def userRepr = name
}
val a = new ValDefResult("asd") with Abstract
a.userRepr
Live code is available here: http://www.scalakata.com/52534e2fe4b0b1a1c4daa436
But now I would like to call the previous or super implementation of the function such as follows:
trait Abstract { self: Result =>
override def userRepr = "abstract" + self.userRepr
}
or
trait Abstract { self: Result =>
override def userRepr = "abstract" + super.userRepr
}
However, none of these alternatives compile. Any idea how this could be accomplished?
Here is the answer I was looking for. Thank you Shadowlands for pointing me in the right direction with Scala's abstract override feature.
trait Abstract extends Result {
abstract override def userRepr = "abstract " + super.userRepr
}
abstract class Result {
def userRepr: String = "wtv"
}
case class ValDefResult(name: String) extends Result {
override def userRepr = name
}
val a = new ValDefResult("asd") with Abstract
a.userRepr
Live code is available here: http://www.scalakata.com/52536cc2e4b0b1a1c4daa4a4
Sorry for the confusing example code, I am writing a library that deals with the Scala AST and was not inspired enough to change the names.
I don't know if you are in a position to make the following changes, but the effect you want can be achieved by introducing an extra trait (I'll call it Repr), and using abstract override in the Abstract trait:
trait Repr {
def userRepr: String
}
abstract class Result extends Repr {
def userRepr: String = "wtv"
}
case class ValDefResult(name: String) extends Result {
override def userRepr = name
}
trait Abstract extends Repr { self: Result =>
abstract override def userRepr = "abstract-" + super.userRepr // 'super.' works now
}
Your example usage now gives:
scala> val a = new ValDefResult("asd") with Abstract
a: ValDefResult with Abstract = ValDefResult(asd)
scala> a.userRepr
res3: String = abstract-asd
abstract override is the mechanism, aka stackable traits. It's worth adding that linearization counts, because that's what determines what super means.
This question is a great addendum to the canonical Q&A on self-type vs extension.
Where the inheritance is ambiguous with self-types:
scala> trait Bar { def f: String = "bar" }
defined trait Bar
scala> trait Foo { _: Bar => override def f = "foo" }
defined trait Foo
scala> new Foo with Bar { }
<console>:44: error: <$anon: Foo with Bar> inherits conflicting members:
method f in trait Foo of type => String and
method f in trait Bar of type => String
(Note: this can be resolved by declaring an override in <$anon: Foo with Bar>.)
new Foo with Bar { }
^
Then obviously, you can choose:
scala> new Foo with Bar { override def f = super.f }
res5: Foo with Bar = $anon$1#57a68215
scala> .f
res6: String = bar
scala> new Foo with Bar { override def f = super[Foo].f }
res7: Foo with Bar = $anon$1#17c40621
scala> .f
res8: String = foo
or
scala> new Bar with Foo {}
res9: Bar with Foo = $anon$1#374d9299
scala> .f
res10: String = foo
I'm trying to create a trait in Scala:
trait First {
override def greet() {
super.greet
println("First")
}
}
but compiler says:
scala/scala_learning/traits_hierarchy.scala:3: error: value greet is not a member of java.lang.Object with ScalaObject
super.greet
^
But I would like to extend with this trait some class which superclass has method greet... Is it possible in scala?
While there are structural types in scala, I don't think you can do that for any type that has a greet method, but for a greet method in a specific trait or class.
Then if you want to have your routine change a routine not yet defined, calling it with super, it must be tagged abstract override, not simply override.
That would be
trait Greeter { def greet }
trait First extends Greeter {
abstract override def greet = {
super.greet
println("Hi, I'm first")
}
}
Then you can have greet definition
class StandardGreeter(greeting: String) extends Greeter {
def greet = println(greeting)
}
Note that First was defined without knowledge of StandardGreeter. You mix in new classes with
class FirstGreeter(greeting: String) extends StandardGreeter(greeting) with First
or create instances directly with
new StandardGreeter("whatever") with First
You may want to read this article.
I believe you can do this with structural self types:
trait Foobar {
this: { def greet() } => // self type
def go() = greet()
}
class Barbar extends Foobar { def greet() = { println("hello") }}
You are defining that Foobar can only extend a class which defines a method greet(). Using the REPL:
scala> trait Foobar { this: { def greet() } =>
| def go() = greet()
| }
defined class Foobar
scala> new Foobar()
<console>:9: error: class Foobar cannot be instantiated because it does not conform to its self-type Foobar with AnyRef{def greet(): Unit}
new Foobar()
^
scala> class Barbar extends Foobar { def greet() = { println("hello") }}
defined class Barbar
scala> new Barbar().go
hello
You can then override the greet method in Foobar (but what use this is I don't know):
trait Foobar {
this: { def greet() } => // self type
override def greet() = { println("mygreet") }
def go() = greet()
}
class Barbar extends Foobar
I have a base abstract class (trait). It has an abstract method foo(). It is extended and implemented by several derived classes. I want to create a trait that can be mixed into the derived classes so that it implements foo() and then calls the derived class's foo().
Something like:
trait Foo {
def foo()
}
trait M extends Foo {
override def foo() {
println("M")
super.foo()
}
}
class FooImpl1 extends Foo {
override def foo() {
println("Impl")
}
}
class FooImpl2 extends FooImpl1 with M
I tried self types and structural types, but I can't get it to work.
You were very close. Add the abstract modifier to M.foo, and you have the 'Stackable Trait' pattern: http://www.artima.com/scalazine/articles/stackable_trait_pattern.html
trait Foo {
def foo()
}
trait M extends Foo {
abstract override def foo() {println("M"); super.foo()}
}
class FooImpl1 extends Foo {
override def foo() {println("Impl")}
}
class FooImpl2 extends FooImpl1 with M