Given an annotated trait, how should I go about generating an abstract class which implements the trait?
So, given the following user trait...
#Neuron
trait SomeTrait {
// ...
}
... in my library I want to insert something like the following next to it:
abstract class SomeTraitImpl extends SomeTrait
Note that I know nothing about the given trait except it's annotated with #Neuron.
I've tried to do this with ASM, implementing the concept explained in the answer to the question Using Scala traits with implemented methods in Java, but this concept scratches only the surface of what the Scala compiler emits as byte code. Even if I succeeded to master all possible combinations of var, val, lazy val, abstract override etc the odds are high that it will break with the next release of the Scala compiler.
So it looks like I should write a compile time macro instead. However, I am scratching my head over the documentation for Scala macros, so I wonder if anyone could draft something which gets me started? Any hint is appreciated, please!
The correct approach to do this is to make #Neuron a macro annotation (using the Macro Paradise compiler plugin) and implement the macro to do the code transformation. The resulting code is now part of Neuron DI, a framework for dependency injection which I wrote.
So, I was trying to make a finagle server, talk to sentry (not important), and stumbled upon a case, where I needed to inherit from two classes (not traits) at the same time, let's call them class SentryHandler extends Handler and class TwitterHandler extends Handler, and assume, that I need to create MyHandler, that inherits from both of them.
After a moment of stupidity, when I thought it was impossible without using a dreaded "delegation pattern", I found a solution:
trait SentryTrait extends SentryHandler
class MyHandler extends TwitterHandler with SentryTrait
Now, this got me thinking: what is the purpose of having the notion of "trait" to being with? If the idea was to enforce that you can inherit from multiple traits but only a single class, it seems awfully easy to get around. It kinda sounds like class is supposed to be the "main" line of inheritance (that you "extend a class with traits", but that isn't true either: you can extend a trait with (or without) a bunch of other traits, and no class at all.
You cannot instantiate a trait, but the same holds for an abstract class ...
The only real difference I can think of is that a trait cannot have constructor parameters. But what is the significance of that?
I mean, why not? What would the problem with something like this?
class Foo(bar: String, baz: String) extends Bar(bar) with Baz(baz)
Your solution (if I understood correctly) - doesn't work. You cannot multiinherit classes in scala:
scala> class Handler
defined class Handler
scala> class SentryHandler extends Handler
defined class SentryHandler
scala> class TwitterHandler extends Handler
defined class TwitterHandler
scala> trait SentryTrait extends SentryHandler
defined trait SentryTrait
scala> class MyHandler extends TwitterHandler with SentryTrait
<console>:11: error: illegal inheritance; superclass TwitterHandler
is not a subclass of the superclass SentryHandler
of the mixin trait SentryTrait
class MyHandler extends TwitterHandler with SentryTrait
As for the question - why traits, as I see it, this is because traits are stackable in order to solve the famous diamond problem
trait Base { def x: Unit = () }
trait A extends Base { override def x: Unit = { println("A"); super.x}}
trait B extends Base { override def x: Unit = { println("B"); super.x}}
class T1 extends A with B {}
class T2 extends B with A {}
(new T1).x // Outputs B then A
(new T2).x // Outputs A then B
Even though trait A super is Base (for T1) it calls B implementation rather then Base. This is due to trait linearization
So for classes if you extend something - you can be sure that this base will be called next. But this is not true for traits. And that's probably why you do not have trait constructor parameters
The question should rather be: why do we need classes in Scala? Martin Odersky has said that Scala could get by with just traits. We would need to add constructors to traits, so that instances of traits can be constructed. That's okay, Odersky has said that he has worked out a linearization algorithm for trait constructors.
The real purpose is platform interoperability.
Several of the platforms Scala intends to integrate with (currently Java, formerly .NET, maybe in the future Cocoa/Core Foundation/Swift/Objective-C) have a distinct notion of classes, and it is not always easy to have a 1:1 mapping between Scala traits and platform classes. This is different, for example, from interfaces: there is a trivial mapping between platform interfaces and Scala traits – a trait with only abstract members is isomorphic to an interface.
Classes, packages, and null are some examples of Scala features whose main purpose is platform integration.
The Scala designers try very hard to keep the language small, simple, and orthogonal. But Scala is also explicitly intended to integrate well with existing platforms. In fact, even though Scala is a fine language in itself, it was specifically designed as a replacement for the major platform languages (Java on the Java platform, C# on the .NET platform). And in order to do that, some compromises have to be made:
Scala has classes, even though they are redundant with traits (assuming we add constructors to traits), because it's easy to map Scala classes to platform classes and almost impossible to map traits to platform classes. Just look at the hoops Scala has to jump through to compile traits to efficient JVM bytecode. (For every trait there is an interface which contains the API and a static class which contains the methods. For every class the trait is mixed into, a forwarder class is generated that forwards the method calls to trait methods to the static class belonging to that trait.)
Scala has packages, even though they are redundant with objects. Scala packages can be trivially mapped to Java packages and .NET namespaces. Objects can't.
Package Objects are a way to overcome some of the limitations of packages, if we didn't have packages, we wouldn't need package objects.
Type Erasure. It is perfectly possible to keep generic types around when compiling to the JVM, e.g. you could store them in annotations. But third-party Java libraries will have their types erased anyway, and other languages won't understand the annotations and treat Scala types as erased, too, so you have to deal with Type Erasure anyway, and if you have to do it anyway, then why do both?
null, of course. It is just not possible to automatically map between null and Option in any sane way, when interoperating with real-world Java code. You have to have null in Scala, even though we rather wished it weren't there.
The problem with having constructors and state in a trait (which then makes it a class) is with multiple inheritance. While this is technically possible in a hypothetical language, it is terrible for language definition and for understanding the program code. The diamond problem, mentioned in other responses to this question), causes the highest level base class constructor to be called twice (the constructor of A in the example below).
Consider this code in a Scala-like language that allows multiple inheritance:
Class A(val x: Int)
class B extends A(1)
class C extends A(2)
class D extends B, C
If state is included, then you have to have two copies of the value x in class A. So you have two copies of class A (or one copy and the diamond problem - so called due to the diamond shape of the UML inheritance diagram).
Diamond Multiple Inheritance
The early versions of the C++ compiler (called C-Front) had lots of bugs with this and the compiler or the compiled code often crashed handling them. Issues include if you have a reference to B or C, how do you (the compiler, actually) determine the start of the object? The compiler needs to know that in order to cast the object from the Base type (in the image below, or A in the image above) to the Descendant type (D in the image above).
Multiple Inheritance Memory Layout
But, does this apply to traits? The way I understand it, Traits are an easy way to implement composition using the Delegation Pattern (I assume you all know the GoF patterns). When we implement Delegation in any other language (Java, C++, C#), we keep a reference to the other object and delegate a message to it by calling the method in its class. If traits are implemented in Scala internally by simply keeping a reference and calling its method, then traits do exactly the same thing as Delegation. So, why can't it have a constructor? I think it should be able to have one without violating its intent.
The only real difference I can think of is that a trait cannot have constructor parameters. But what is the significance of that? I mean, why not?
Consider
trait A(val x: Int)
trait B extends A(1)
trait C extends A(2)
class D extends B with C
What should (new D {}).x be? Note: there are plans to add trait parameters in Scala 3, but still with restrictions, so that the above is not allowed.
I am using macros to add synthetic companion objects (with apply method and other stuff) to annotated classes. Such as
#myTransform class Foo(i: Int)
that will output
object Foo {
def apply(i: Int): Foo = new Foo(i)
}
class Foo(i: Int)
Now if I write in the source code of a sub-project that depends on these macros, Foo(1234), this is highlighted as error by IntelliJ IDEA.
Is it possible to configure the presentation compiler of IntelliJ IDEA to respect these kind of macros and invoke them to operate on the properly transformed code, avoiding these highlighting errors?
The IntelliJ Scala plugin now has an API for macro support: https://blog.jetbrains.com/scala/2015/10/14/intellij-api-to-build-scala-macros-support/
I'm rather new to Scala, and I am trying to use lift-squeryl-record in Lift. Scala is 2.8.1 and Lift is 2.3. My problem is that I wanted to use (Mega)ProtoUser from Record, but it conflicts with lift-squeryl-record.
I followed the instruction of:
lift-squeryl-record example
which did not use ProtoUser, and tried to define my user like this:
trait AbstractUser[MyType <: AbstractUser[MyType]] extends
ProtoUser[MyType] with Record[MyType] with KeyedRecord[Long] {
NB: KeyedRecord is from package net.liftweb.squerylrecord, not net.liftweb.record
Then I get the following error:
overriding lazy value id in trait ProtoUser of type net.liftweb.record.field.LongField[MyType]; method id in trait KeyedRecord of type => Long needsoverride' modifier`
Because both KeyedRecord and ProtoUser define a differing id method. Since I do not control the code of neither classes/traits, is there any "Scala" way around it, like renaming one of the methods? I really don't want to have to choose between the two. :(
No you cannot rename methods in a subclass. If there are two conflicting method signatures from parent types, you will need to resort to another pattern, such as indirection through delegation ( http://en.wikipedia.org/wiki/Delegation_pattern )
trait AbstractUser[MyType <: AbstractUser[MyType]] extends ProtoUser[MyType] {
def record: Record[MyType] with KeyedRecord[Long]
}
I want to define some annotations and use them in Scala.
I looked into the source of Scala, found in scala.annotation package, there are some annotations like tailrec, switch, elidable, and so on. So I defined some annotations as them do:
class A extends StaticAnnotation
#A
class X {
#A
def aa() {}
}
Then I write a test:
object Main {
def main(args: Array[String]) {
val x = new X
println(x.getClass.getAnnotations.length)
x.getClass.getAnnotations map { println }
}
}
It prints some strange messages:
1
#scala.reflect.ScalaSignature(bytes=u1" !1* 1!AbCaE
9"a!Q!! 1gn!!.<b iBPE*,7
Ii#)1oY1mC&1'G.Y(cUGCa#=S:LGO/AA!A 1mI!)
Seems I can't get the annotation aaa.A.
How can I create annotations in Scala correctly? And how to use and get them?
FWIW, you can now define scala annotation in scala 2.10 and use reflection to read them back.
Here are some examples:
Reflecting Annotations in Scala 2.10
Could it have something to do with retention? I bet #tailrec is not included in the bytecode getting generated.
If I try to extend ClassfileAnnotation (in order to have runtime retention), Scala tells me that it can't be done, and it has to be done in Java:
./test.scala:1: warning: implementation restriction: subclassing Classfile does not
make your annotation visible at runtime. If that is what
you want, you must write the annotation class in Java.
class A extends ClassfileAnnotation
^
I think you can only define annotations in Java now.
http://www.scala-lang.org/node/106
You can find a nice description of how annotations are to be used in Scala in Programming Scala.
So you can define or use annotations in scala. However there is at least one limitation:
Runtime retention is not quite possible. In theory you should subclass ClassFileAnnotation to achieve this, but currently scalac reports the following warning if you do it:
"implementation restriction: subclassing Classfile does not make your annotation visible at runtime. If that is what you want, you must write the annotation class in Java."
It also means that your code is fine as it is (at least as fine as it is currently possible in Scala), but the annotation is on the class only during compile time. So you could use it e.g. in compiler plugins, but you will not be able to access it runtime.
With scala 2.11.6, this works to extract values of a annotation:
case class MyAnnotationClass(id: String) extends scala.annotation.StaticAnnotation
val myAnnotatedClass: ClassSymbol = u.runtimeMirror(Thread.currentThread().getContextClassLoader).staticClass("MyAnnotatedClass")
val annotation: Option[Annotation] = myAnnotatedClass.annotations.find(_.tree.tpe =:= u.typeOf[MyAnnotationClass])
val result = annotation.flatMap { a =>
a.tree.children.tail.collect({ case Literal(Constant(id: String)) => doSomething(id) }).headOption
}