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).
Related
I want to define a trait that forces its subtypes to override say thetoString method.
Can I do that?
In the more generic case:
trait Old {
def foo: String = "oldFoo"
}
trait New {
//some statement which would result in "oldFoo" disappearing
}
trait New1 extend New {
def foo: String = "new1Foo"
} //should compile
trait New2 extend New //shouldn't compile
I don't think what you want to do is possible, but this workaround could work
trait Old {
def foo: String = "oldFoo"
}
trait New extends Old {
override final def foo: String = newFoo
def newFoo: String
}
class New1 extends New {
override def newFoo: String = "new1Foo"
} // Compiles
class New2 extends New // Don't compiles
trait NewExtra extends New // Compiles, but any sub class of NewExtra is required to implement newFoo
I have tried to override val in Scala as this:
trait T{
val str: String
}
sealed abstract class Test extends T{
val str: String = "str"
}
class Test1 extends Test{
val str = super.str + "test1" //super may not be used on value str
}
But this refused to compile. Why? I wanted to override value in the abstract class using the abstract class's value itself. How to do this?
In my particular case I cannot pass it as a class parameter.
Scala compiler does not allow to use super on a val. If you are not caring about re-evaluation, you can just use def instead.
trait T{
def str: String
}
sealed abstract class Test extends T{
def str: String = "str"
}
class Test1 extends Test{
def str = super.str + "test1" //super may not be used on value str
}
defined trait T
defined class Test
defined class Test1
If you do care about it avoiding repeated initialization, you can extract it into a method:
sealed abstract class Test extends T {
lazy val str: String = initStr
protected def initStr = "str"
}
class Test1 extends Test{
override protected def initStr = super.initStr + "test1"
}
You can also make str non-lazy, but it's all to easy to end up with initialization order problems that way.
I want to achieve the following:
abstract class Super {
def typeSpecific: Int
}
class SubA extends Super {
def typeSpecific = 1
}
class SubB extends Super {
def typeSpecific = 2
}
class Tester[T <: Super] {
def test = T.typeSpecific
}
val testerA = new Tester[SubA]
val testerB = new Tester[SubB]
testerA.test // should return 1
testerB.test // should return 2
Is something like this possible in Scala? This fails because the value of T is not found in Tester.test.
typeSpecific is not a static member, it belongs to instances of SubA and SubB, which you don't have. You also can't statically access anything from a type parameter (it's a type, not an object).
This won't work as is, because you don't have instances of SubA and SubB, nor can you obtain them via new Tester[SubA]. But you can require that Tester mixes in a type of Super in order to make it one (and thus have typeSpecific). This would require you change Super, SubA, and SubB to traits, and would also make your instance anonymous classes.
trait Super {
def typeSpecific: Int
}
trait SubA extends Super {
def typeSpecific = 1
}
trait SubB extends Super {
def typeSpecific = 2
}
// The self-type `this: A =>` requires the mix-in.
class Tester[A <: Super] { this: A =>
def test = typeSpecific
}
val testerA = new Tester[SubA] with SubA
val testerB = new Tester[SubB] with SubB
scala> testerA.test
res2: Int = 1
scala> testerB.test
res3: Int = 2
You could also require A <: Super as a constructor parameter for Tester, which is probably the cleaner option.
abstract class Super {
def typeSpecific: Int
}
class SubA extends Super {
def typeSpecific = 1
}
class SubB extends Super {
def typeSpecific = 2
}
class Tester[A <: Super](s: A) {
def test = s.typeSpecific
}
val testerA = new Tester(new SubA)
val testerB = new Tester(new SubB)
scala> testerA.test
res5: Int = 1
scala> testerB.test
res6: Int = 2
Any way you cut it, you're going to need an instance of SubA or SubB.
You're going to have to use reflection combined with typeTags to get your desired result. I warn you, it's somewhat ugly:
import scala.reflect.runtime.universe._
abstract class SuperClass {
def typeSpecific: Int
}
class SubA extends SuperClass {
def typeSpecific = 1
}
class SubB extends SuperClass {
def typeSpecific = 2
}
class Tester[T <: SuperClass: TypeTag] {
def test = typeTag[T].mirror.runtimeClass(typeOf[T]).newInstance.asInstanceOf[T].typeSpecific
}
I also feel I should mention that typeSpecific is not static as it is part of a class, in scala static members are defined in objects/companion objects only. Using objects it would be cleaner to do something like this:
trait SuperTrait {
def typeSpecific: Int
}
object SubA extends SuperTrait {
def typeSpecific = 1
}
object SubB extends SuperTrait {
def typeSpecific = 2
}
class Tester(testObject : SuperTrait) {
def test = testObject.typeSpecific
}
new Tester(SubA).test
new Tester(SubB).test
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