I am new to Scala and I now started a project in Scala and I see similar to the following construct:
trait SomeTrait extends SomeOtherStuff with SomeOtherStuff2
object SomeTrait {
def someFunction():Unit = { ??? }
}
I understand that for a class, companion objects hold methods that are used in a "static", like Factory methods in Java or something alike, but what about traits, why not put these methods in traits?
The first style is called mixin, it used to be somewhat popular back in the days.
It could be replaced by the following code:
object SomeOtherStuff {
def someMethod(): String
}
object SomeObj {
import SomeOtherStuff._
//now someMethod is available
def otherMethod(): String = someMethod + "!"
}
object Caller {
import SomeObj._
import SomeOtherStuff._
//utility methods from both objects are available here
}
Pros of mixins:
If SomeTrait extends 10 other mixins then extending this trait would allow to scrap 10 import statements
Cons of mixins:
1) creates unnecessary coupling between traits
2) awkward to use if the caller doesn't extend the mixin itself
Avoiding mixins for business-logic code is a safe choice.
Although I'm aware of 2 legitimate usecases:
1) importing DSLs
e.g. ScalaTest code :
class SomeSuite extends FunSuite with BeforeAndAfter {...}
2) working (as a library author) with implicit parameters:
e.g. object Clock extends LowPriorityImplicits
(https://github.com/typelevel/cats-effect/blob/master/core/shared/src/main/scala/cats/effect/Clock.scala#L127)
Another perspective to this is the OOP principle Composition Over Inheritance.
Pros of companion objects (composition):
composition can be done at runtime while traits are defined at compile time
you can easily have multiple of them. You don't have to deal with the quirks of multiple inheritance: say you have two traits that both have a method with the name foo - which one is going to be used or does it work at all? For me, it's easier to see the delegation of a method call, multiple inheritance tends to become complex very fast because you lose track where a method was actually defined
Pros of traits (mixins):
mixins seem more idiomatic to reuse, a class using a companion object of another class is odd. You can create standalone objects though.
it's cool for frameworks because it adds the frameworks functionality to your class without much effort. Something like that just isn't possible with companion objects.
In doubt, I prefer companion objects, but it always depends on your environment.
I have case classes BFile and AFile that both extend trait File. And case classes BDir and ADir that both extend trait Dir. The classes are instantiated as their trait type.
I am trying to write implicit move methods (located on an object outside the A/BFile and A/BDir classes) that are overloaded for each combination of A/BFile & A/BDir.
I am unsure how to do this such that a different .move method will be implicitly used based on the specific classes of File and Directory. Is this even possible?
The reason why I don't want these methods implemented inside the class is because it requires me to pull in additional dependencies to use the classes; and I am unable to always provide these dependencies.
I also don't want to settle for depending on only the class since I am trying to follow the dependency inversion principle.
Edit: I think I am looking for the following or some equivalent:
trait File {
...
def move(directory: the class implementing this that extends Dir): File
def copy(directory: the class implementing this that extends Dir): File
}
trait Dir {
...
}
I just started to learn scala and currently learning about Akka through this Learning Akka course
I'm confused about the code style, the author has created a trait inside a object.
object MusicController {
sealed trait ControllerMsg
case object Play extends ControllerMsg
case object Stop extends ControllerMsg
def props = Props[MusicController]
}
I understand that Scala object provides singleton ability and a way to define all static method in class through companion object.
Can anyone help me understanding this syntax ? Thanks
You will often see this with Actors. It is good practice to define the messages that an Actor responds to in its companion object, which happens here.
The sealed trait part isn't really necessary. You just often see this in Scala with case classes/objects. Also, being sealed means that you will get a warning if your match is not exhaustive when you pattern match on instances of it.
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 have a trait which will have a finite number of subclasses. At first I used the sealed modifier and defined the trait and all its subclasses in the same file. After the classes grew, I decided I wanted to refactor them into separate files, however once I did this I could no longer use the sealed modifier on the trait due to the constraint that all subclasses of a sealed trait must be in the same file.
In Scala, Is there a similar way to have a finite number of subclasses for a trait within the same package, across separate files while still gaining the compile-time advantages of sealed traits when doing exhaustive pattern matching?
Sealing is the only way to ask for exhaustiveness checking. However, you could define package-private traits AGuts, BGuts, CGuts, etc. in separate files and then in one file create sealed subclasses A, B, C, etc. as you did before, but mixing in those guts defined elsewhere.
sealed abstract class Thing
class A extends Thing with AGuts
class B extends Thing with BGuts
...