I have this code:
trait base{
def msg: Unit= {
println{"base"}
}
}
trait foo extends base {
abstract override def msg: Unit ={
super.msg
println("foo")
}
}
class base2{
def msg:Unit = {
println{"base 2"}
}
}
class test extends base2 with foo{
override def msg: Unit ={
super.msg
println("done")
}
}
If I call (new test).msg, this prints out things like: base, foo, done
However, if I change the base trait to:
trait base{
def msg: Unit
}
it prints out things like: base 2, foo, done
I understand the order of with is from right to left (last one comes first) but how about extends? How come sometimes it prints base2, but sometimes base?
When you omit the implementation, base is a template of a trait and has different evaluation rules. See the Scala specification
Scala has something called type linearization. It defines initialization order. Read here http://eed3si9n.com/constraining-class-linearization-in-Scala
Related
I'm trying to upgrade scala 2.12 to scala 2.13.5
Class linearization is not properly working for me, IntelliJ and Scala compiler throws an error but ideally it should work. Below is the problem.
trait A[E] {
def getObject: E = {
// some implementation
}
}
abstract class B[T](e: Object) {
def getObject: T = {
// some implemntation
}
}
class C[T] extends B[T](null) with A[String] {
def myMethod(): Unit = {
println(this.getObject.someMethodWhichIsNotInStringClassButAvailableInTClass)
}
}
In the above sample program as well, this.getObject is coming from A where I'm expecting it to come from B. Looks like my understanding is wrong. But need to understand this class linearization problem in detail.
Because of the above issue, my code is not compiling as the required method is not available in String class.
Also the same code compiles with scala 2.12 but not with scala 2.13.5.
Another reference - https://stackoverflow.com/a/49832570/819866
This should not compile at all ... and it indeed does not for me (2.13.1):
error: class C inherits conflicting members:
def getObject: T (defined in trait B) and
def getObject: String (defined in trait A)
(note: this can be resolved by declaring an `override` in class C.)
You cannot inherit different methods with the same name.
Also, if your inheritance was actually valid, linearization would still work left to right:
trait A { def foo: Sting }
trait B extends A { def foo = "b" }
trait C extends A { def foo = "c" }
class D extends B with C
println(new D().foo)
This prints "c".
I want to extend a trait from Scala object and override those methods which are in trait. So my doubt is those methods will become static to that Object
or instance methods, and is this good approach to extend from trait to Scala Object. Please help on this
trait A{
def show:Unit
}
object B extends A{
override def show(): Unit = {
println("inside Object")
}
}
There are no static methods in Scala. object can indeed extend a trait. Overriden methods, like show, do not become static methods, instead they belong to a single instance of B.type. This is the singleton pattern provided by Scala's object definition facility.
Try the following in Scala REPL:
object B
B
It should output something like
res0: B.type = B$#5688722f
Note how the value B has type B.type, so B is just a value/instance, nothing to do with statics.
Hm, I think a common example/usecase of what you've just described is extending the App trait and overriding the main definition.
object test extends App
{
override def main (args: Array[String]): Unit = {
println("Hello, let's get started")
}
}
In general though, why don't you define the class itself to extend the trait?
If you are going to instantiate new instances of B using B() (instead of new B()) it makes sense to do this.
trait A{
def show:Unit
}
object B { // companion aka singleton object
def apply(){
...
}
}
class B extends A{
override def show(): Unit = {
println("inside Object")
}
}
Given this code: (no matter whether it doesn't make much sense)
object Test {
def main(args: Array[String]) {
(new FooImpl2()).foo()
}
trait Foo {
def foo()
}
trait M extends Foo {
abstract override def foo() {println("M"); super.foo()}
}
abstract class FooImpl1 extends Foo {
}
class FooImpl2 extends FooImpl1 with M{
override def foo() {println("Impl2")}
}
}
At compile time, this error occurs:
error: overriding method foo in trait M of type ()Unit;
method foo needs `abstract override' modifiers
override def foo() {println("Impl2")}
So at this place:
class FooImpl2 extends FooImpl1 with M{
override def foo() {println("Impl2")}
}
Why doesn't override apply on FooImpl1 (in order to provide a concrete implementation for abstract trait method)? It seems like it matches the trait method's instead...and obviously there's a huge conflict with the pattern "abstract override"
M needs to be mixed-in after the concrete def (in linearization order).
I'm new to scala macros and I'm using scala 2.10.0-RC3.
I want to write a macro that adds a function to a class. Usage example:
trait MyTrait {
def addF = macro { /*add "def f = 3" to class*/ }
}
class MyClass extends MyTrait {
addF //Adds the "def f" to MyClass
}
object Main {
val t = new MyClass
assert(t.f==3)
}
I need this in the following scenario. My first try didn't use macros but didn't work, because I can't inherit the same trait twice.
trait AddF[T] {
def f(t: T) { /* ...do sthg ... */ }
}
class MyClass extends AddF[Int] with AddF[String]
With the macro solution I could write
class MyClass extends MyTrait {
addF[Int]()
addF[String]()
}
Is there a way to do this with scala macros? Or is there another way to achieve this?
It is currently impossible to add, modify or remove definitions visible outside the macro. I.e. you can create a class or a method local to the expansion (e.g. emit a ClassDef tree as a part of the result returns by your macro), but there's no facility to affect the outside world.
However we plan to experiment with this functionality as roughly sketched in http://scalamacros.org/future.html. Also there's already a solid prototype that can generate new top-level classes. Contact me for details if you would like to take a look.
In case I'm not completely confused, simple overloading should provide the desired behavior? For instance, this would work:
trait MyTrait {
def f(i: Int)
def f(i: String)
}
class MyClass extends MyTrait {
def f(i: Int) {
println(i + " was an Int")
}
def f(s: String) {
println(s + " was a String")
}
}
// this allows:
val c = new MyClass()
c.f("hello")
c.f(42)
I'm trying to implement a Scala trait that handles the details of interfacing with a Java library that requires us to create
What I want to do is something like:
trait SomeTrait[A] extends JavaAPI {
def foo = {
callApi(classOf[A])
}
override def bar = {
foo
}
}
Note that bar is actually overriding a method from a base class, so I can't change it's signature.
I've tried several variations with Manifests, etc., but can't quite get this to work. Is there a way to get the runtime class of a parameterized type?
This flavour should do the trick:
trait SomeTrait[A] {
def foo(implicit ev: Manifest[A]) = {
callApi(ev.erasure)
}
}
update At some point, the manifest must be injected via a method parameter. A constructor would be a good choice, if traits could have them.
Actually, they can! The trait has the constructor of whatever it's mixed-in to, so if you specify an abstract manifest that deriving classes must define...
trait SomeTrait {
def ev: Manifest[_] //abstract
def foo = println(ev.erasure)
}
//this `ev` provides the implementation, note that it MUST be a val, or var
class Concrete[T](implicit val ev: Manifest[T]) extends SomeTrait
And all is good again.
You have to get the manifest in there somehow, and traits have no constructor parameters. Only you can say what tradeoff you want to make. Here's another one.
trait SomeTrait[A] {
implicit def manifesto: Manifest[A]
def foo = println(manifest[A].erasure)
}
object SomeTrait {
def apply[A: Manifest] : SomeTrait[A] = new SomeTrait[A] { def manifesto = manifest[A] }
}
Due to type erasure, the compiler has no way to figure out what the type should be within the trait. Thus what you want can't be done. However, you could make it a class. That way the compiler can pass an evidence parameter when an instance is created.
class SomeTrait[A](implicit ev: Manifest[A]) extends JavaApi {
def foo = {
callApi(ev.erasure)
}
override def bar = {
foo
}
}
It might be a little inconvenient to do so in your code, but you can do this
trait SomeTrait[A] extends JavaAPI {
def objType: Class[A]
def foo = {
callApi(objType)
}
override def bar = {
foo
}
}
object SomeImplementation with SomeTrait[SomeObject] {
val objType: Class[SomeObject] = classOf[SomeObject]
}
I know it is a little wordy, but that's the way I solved this problem. I hope to find a better solution in the future, but this is what I'm using now. Let me know if that helps you.