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
Related
I have a Trait LoggerHelper. Inside I have some function definitions. I want them to be accessible by the classes extending this trait but I would like to restrict the access for the classes injecting the classes extending this trait.
Example:
Trait LoggerHelper {
def log() = ???
}
Class A extends LoggerHelper {
log() //OK
}
Class B #Inject() (a: A) {
a.log() //I want this line does not compile
}
Is it possible to achieve this?
A protected member can be accessed only from subclasses of the class where the member is defined:
scala> trait LoggerHelper {
| protected def log() = ???
| }
defined trait LoggerHelper
scala> class A extends LoggerHelper {
| log()
| }
defined class A
scala> class B(a: A) {
| a.log()
| }
<console>:13: error: method log in trait LoggerHelper cannot be accessed in A
Access to protected method log not permitted because
enclosing class B is not a subclass of
trait LoggerHelper where target is defined
a.log()
^
A member protected using protected[this] may only be accessed from this instance of the class, and its subclasses.
class Base{
protected val alpha ="Alpha";
protected[this] def sayHello = "Hello";
def foo = Console println(new Base().sayHello) // won't compile
def bar = Console println(this.sayHello)
}
class Derived extends Base{
def hello = println(this.sayHello) ;
//def hello2 = println((new Derived() .sayHello) // won't compile
}
A member protected using protected may be accessed from any instance of the class where the member is defined, and from their subclasses.
class Base{
protected val alpha ="Alpha";
protected def sayHello = "Hello";
}
class Derived extends Base{
def hello = println(this.sayHello);
def hello2 = println((new Derived()).sayHello); // has access to sayHello() in the original instance
}
Restrict protected method with [this], like
trait LoggerHelper {
protected[this] def log() = ???
}
Is there a way in scala to use a method m in the implementation of the method overriding the same method m?
As an example here is what I tried (note that toUpperCase is not implemented):
abstract class Person {
def greet: String
}
class EnglishMan extends Person {
abstract override def greet: String =
{
return "hello"
}
}
trait Angry extends Person {
abstract override def greet: String =
{
return toUpperCase(greet)
}
Is this what you want?
scala> trait Person { def greet: String }
defined trait Person
scala> class EnglishMan extends Person { def greet = "hello" }
defined class EnglishMan
scala> class Angry extends EnglishMan { override def greet = super.greet.toUpperCase }
defined class Angry
scala>
scala> new EnglishMan().greet
res3: String = hello
scala> new Angry().greet
res4: String = HELLO
Note that trait Person is completely irrelevant to this exercise. You can invoke your superclass' methods (even when overriding that very method), but you can't have 2 methods on the same scope with the same name (that would be ambiguous for the compiler).
I have a trait and a class that extends the trait. I can use the methods from the trait as follows:
trait A {
def a = ""
}
class B(s: String) extends A {
def b = a
}
However, when I use the trait's method in the constructor like this:
trait A {
def a = ""
}
class B(s: String) extends A {
def this() = this(a)
}
then the following error appears:
error: not found: value a
Is there some way to define default parameters for the construction of classes in the trait?
EDIT: To clarify the purpose: There is the akka-testkit:
class TestKit(_system: ActorSystem) extends { implicit val system = _system }
And each test looks like this:
class B(_system: ActorSystem) extends TestKit(_system) with A with ... {
def this() = this(actorSystem)
...
}
because I want to create common creation of the ActorSystem in A:
trait A {
val conf = ...
def actorSystem = ActorSystem("MySpec", conf)
...
}
It's a little bit tricky because of Scala initialization order. The simplest solution I found is to define a companion object for your class B with apply as factory method:
trait A {
def a = "aaaa"
}
class B(s: String) {
println(s)
}
object B extends A {
def apply() = new B(a)
def apply(s: String) = new B(s)
}
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 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()
}
}