Trying to understand scala trait - scala

I am new to scala. I don't understand scala traits properly. I have read it is similar to java interfaces but the methods need not be abstract. But how can I declare a scala trait and instantiate it in the following code. BTW, the following code is working fine.
trait fooable {
def foo: Unit = {
println("This is foo")
}
}
object Main {
def main(args: Array[String]): Unit = {
println("This is morking")
val foo = new fooable{}
foo.foo
}
}
Output -
This is morking
This is foo
Thanks in advance.

Scala traits are more general than both Java interfaces and abstract classes.
You can use a trait as an interface, you can use it to store some implementation, you can use it simply to define a common super-type:
trait Message
case class Text(text: String) extends Message
case class Data(data: ByteString) extends Message
Multiple traits can be 'mixed in' a class:
class MyClass extends TraitA with TraitB with TraitC
where any conflict with identically named methods is resolved by the simple rule: the last trait takes precedence. This code:
trait TraitA { def print() { println("A") } }
trait TraitB { def print() { println("B") } }
trait TraitC { def print() { println("C") } }
new MyClass.print()
will print "C".
Scala traits can't be instantiated. You are creating an anonymous class in you example. If you add an abstract method to your trait it will not compile.
Unrelated note:
It is a good practice to write braces "()" in methods with side effects. Your method foo has a side effect: it prints something. So you should write "foo()".

When you instantiate a trait you create an instance of an anonymous class that extends that trait it works the same way as creating anonymous classes of interfaces in java. If you had any unimplemented methods in the trait fooable the compiler would've forced you to implement them on spot when you created your anonymous class.

Indeed your code should work fine and output the same result you mentioned. However the important point to note here is TRAIT CAN NEVER EVER be instantiated. Its the same concept that Java interface can never ever be instantiated.
When scala compiler notice the code foo = new fooable{}, It internally creates an anonymous class which extends your fooable trait and thus it inherits foo() method due to inheritance. See following code snippet:
scala> val foo = new fooable{}
foo: fooable = $anon$1#277c0f21
Thus when you call foo.foo, At runtime it invokes a anonymous's class(i.e. $anon$1#277c0f21) inherited method foo().
The same understanding is true in case of Java as well, Following is perfectly legal java code:
Runnable r = new Runnable() {
public void run() {
System.out.println(" Cat");
}
};
r.run()
Happy learning !

An Scala Trait is abstract and can't be instantiated. In the code above its instantiated as
val foo = new fooable{}
and NOT as
val foo = new fooable()
The curly braces created some anonymous class which is not fooable but an empty one
What are Traits?
Traits are similar to interfaces in any other language. Scala allows traits to be instantiate during definition as well as during construction. For example if we have a trait and a abstract class
trait testTrait {
}
abstract class BaseClass {}
class Derive extends BaseClass with testTrait {
}
// ---------------------- OR----------------------
// Traits can be used during instantiation
class Derive extends BaseClass {
}
val classInst = new Derive with testTrait
Traits can also be chained using multiple with trait

Related

Can singleton object extend a trait?

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")
}
}

How to "instantiate" an abstract class in the superclass?

I am implementing an extension of ml.Transformer in Spark; but this question is Scala specific. Here is an example object (part of a Class/Object pair):
abstract class UDFTransformer(func: UserDefinedFunction,
inputFieldNames: Seq[String],
outputFieldName: String) extends Transformer with MLWritable with Serializable {
... definitions here ...
}
object UDFTransformer extends MLReadable[UDFTransformer] {
// Since there are no parameters associted with the UDF, there is nothing to save!
class Writer(instance: UDFTransformer) extends MLWriter {
override protected def saveImpl(path: String): Unit = {}
}
abstract protected class Reader extends MLReader[UDFTransformer]
override def read: MLReader[UDFTransformer] = new Reader
override def load(path: String): UDFTransformer = super.load(path)
}
The new Reader does not compile because the class is abstract and cannot be instantiated. But; any child class will have to define it; along with its necessary members. I cannot just make read abstract as well, this gives me a warning Only classes can have declared but undefined methods.
The fundamental problem is that each child class of my UDFTransformer is going to wrap a specific UDF. Therefore, the reader needs to be able to generate a specific UDF object; this can't be declared in the superclass. But this 'factory' belongs in the companion object, not in the abstract class itself.
How can I go about building a companion object for an abstract class that can leave the definition of read undefined?
The normal way to do it is by creating an abstract class or trait for the companion objects. Something like
abstract class UDFTransformerCompanion[T <: UDFTransformer] extends MLReadable[T] {
abstract def read: MLReader[T]
override def load(path: String): T = super.load(path)
}
class SomeTransformer extends UDFTransformer { ... }
object SomeTransformer extends UDFTransformerCompanion[SomeTransformer] {
override def read: MLReader[SomeTransformer] = ...
}
Not sure why you have the load = super.load override, and it doesn't look like you can have a companion object for the UDFTransformer itself, at least not one extending this abstract class.
See GenericTraversableTemplate for a standard library example.

Implicits from subclass

I am trying to implement template method pattern with implicits. Class A is the top class with 2 extensions.
Class A that is defining the template pattern and has some method doSomething(). This method uses several implicits inside. This class is abstract.
Class B and Class C are extending Class A, providing implicits in scope, implementing other abstract methods and are no more abstract.
Example (using spray's pipeline):
A:
abstract class A[T <: Any : Manifest] {
....
abstract def method: PartialFunction[T,Unit] //not interesting
def doSomething() {
//method using implicit parser HttpResponse -> T
val responseFuture: Future[T] = pipeline(Get(url))
responseFuture.onSuccess(method)
}
}
B:
import CaseClassB._ //importing implicits that transfer HttpResponse -> CaseClassB
class B extends A[CaseClassB] {
def method: PartialFunction[CaseClassB,Unit] = {//not interesting}
}
This setting does not work (compilation of Class A fails because of "could not find implicit value for evidence parameter"). Is there a better way how to overcome this problem without a need to have something like "implicit abstract def" in Class A that would need to be overriden? The reason I don't like this is that Class B and Class C are providing implicits using imports.

Override a trait method for final class in Scala

Consider the following:
trait TestTrait {
def doStuff()
}
final class TestClass {
// ...
}
I would like to instantiate an instance of TestClass that implements the method in the trait. The following does not compile:
// Illegal inheritance from final class TestClass
val t = new TestClass with TestTrait {
def doStuff() {
println("doing stuff")
}
}
This makes sense, since the anonymous class created would extend the final class. What I'm really after is an anonymous implementation of the trait mixed in to an instance of the final class.
The following works, but seems a bit roundabout. Is there a way to do this directly without the declared trait implementation?
trait TestTraitImpl extends TestTrait {
def doStuff() {
println("doing stuff")
}
}
val t = new TestClass with TestTraitImpl
As it turns out, you can't do the latter either.
final class TestClass
trait TestTrait
val t = new TestClass with TestTrait
Apparently, any Foo with Bar is creation of a new anonymous type, and thus final classes cannot have traits as mixins. This adds a great deal of theoretical significance to making a class final, as it prevents not just the concept of inheritance, but also stackable modification.
Method resolution rules are different in the two cases. In the first case an anonymous class is constructed first by whatever happens to be the methods/attributes of the type:
final class TestClass with TestTrait
and then you are trying to override a method of that, which conflicts with the final qualifier of TestClass.
In the second case you explicitly specify that you are overriding TestTrait behavior, and then the overriden behavior is mixed into TestClass.
I think it's perfectly fine to use the second method, and that it conveys more clearly what the intention is.

Scala: Trait Mixin with Abstract Base Class

I have an abstract base class (Base) that has some stacking traits defined for it (StackingTrait).
trait Base {
def foo
}
trait StackingTrait extends Base {
abstract override def foo { super.foo }
}
It would be very convenient to implement a subclass using the following syntax, but this doesn't work because the compiler says that foo needs to be declared with override and then with abstract override on recompile, which is invalid because Impl is a class.
class Impl extends Base with StackingTrait {
def foo {}
}
I cannot think of a good reason why such syntax would be disallowed; foo is logically defined with Impl so that ordering that stacking occurs in conceptually remains the same.
Note:
I figured out this workaround that will effectively do the same thing that I want, but the necessity of a helper class makes me want a better solution.
class ImplHelper extends Base {
def foo {}
}
class Impl extends ImplHelper with StackingTrait
Why does the desired syntax not compile and is there an elegant solution?
My understanding is that while the error message may be confusing, the behaviour is correct.
foo is declared as abstract override in StackingTrait, and thus in any concrete class that mixes StackingTrait there must be a concrete (not marked as abstract) implementation of foo before StackingTrait (relative to the linearization order). This is because super refers to the trait just before in the linearization order, so there definitely needs to be a concrete implementation of foo before StackingTrait is mixed in, or super.foo would be nonsensical.
When you do this:
class Impl extends Base with StackingTrait {
def foo {}
}
the linearization order is Base <- StackingTrait <- Impl. The only trait before StackingTrait is Base and Base does not define a concrete implementation of foo.
But when you do this:
traitImplHelper extends Base {
def foo {}
}
class Impl extends ImplHelper with StackingTrait
The linearization order becomes: Base <- ImplHelper <- StackingTrait <- Impl
Here ImplHelper contains a concrete definition of foo, and is definitly before StackingTrait.
For what is worth, if you had mixed ImplHelper after StackingTrait (as in class Impl extends StackingTrait with ImplHelper) you would again have the same problem and it would fail to compile.
So, this look fairly consistent to me.
I am not aware of a way to make it compile as you intended to. However if you are more concerned about making it easier to write Impl (and being able to define foo right there without a need for a separate class/trait) than making it easy to write Base or StackingTrait, you can still do this:
trait Base {
protected def fooImpl
def foo { fooImpl }
}
trait StackingTrait extends Base {
abstract override def foo { super.foo }
}
class Impl extends Base with StackingTrait {
protected def fooImpl {}
}
Just like in the original version you force each concrete class to implement foo (in the form of fooImpl) and this time it does compile.
The downside here is that while fooImpl must not call super.foo (it makes no sense and will go into an infinite loop), the compiler won't warn you about it.
Instead of extending the trait you can try to use a self-type as mentioned in the example.
https://docs.scala-lang.org/tour/self-types.html.