scala - find objects derived from class - scala

Is there a way in scala to get list of all objects(by object I mean scalas object) that derive from specified abstract class?
something like that:
abstract class A
object B extends A //in different file
object C extends A //in different file
def findObjectsDerivingFromA(): Seq[A] //which will give result: Seq(B, C)
I know from here : Can I get a compile-time list of all of the case objects which derive from a sealed parent in Scala?
that it's possible with sealed base trait/class but in my case objects B and C will be pretty complex so I need to have them in different files.
edit:
I've changed method name because previous one was misleading.

Related

Why and when should trait and object have same name?

What is the reason that
trait Dog {
def bark = "woof"
}
object Dog extends Dog
works, but the following does not
trait Dog {
def bark = "woof"
}
class Dog extends Dog
I read somewhere that in the first case mentioned above the object is not a companion object. What is the scenario when object and trait should have the same name ?
From introduction to Chapter 2 (Identifiers, Names & Scopes):
There are two different name spaces, one for types and one for terms.
Section 5.5 (Object definitions) contains almost exactly your example (with Point instead of Dog), with the following comment:
Note that the double use of the name Point is legal, since the class definition defines the name Point in the type name space, whereas the object definition defines a name in the term namespace.
(emphasis mine)
Your second example with class Dog extends Dog does not work, because both the class Dog and trait Dog end up in the namespace for types, and this results in a conflict.
Companion objects are used whenever you would use static methods in e.g. Java (except that companion objects are much nicer, because they are, well, objects, and can be passed around as ordinary values).
The situation object Foo extends Foo appears somewhat contrived and rather uncommon. Have you an actual example where it is used? If not, then it's just a corner case that is formally valid, simply because it's not explicitly prohibited.
EDIT: object AnsiColor extends AnsiColor seems to be one of the most "important" applications of the object X extends X pattern.
The reason the second example fails here, is not because Dog is not a companion object, but because you define a new duplicate class Dog. I always view traits and classes as one category, and objects as another - and object is an singleton instance of either trait or class.
Why you can't create classes with the same name?
It's impossible to distinguish two entities if that's allowed.
Why you can create (class/trait) and object with the same name?
You can distinguish them, because class or trait is type and object is a value.
When should you name your objects the same name as classes?
If you wan't to define companion object, so your implicits for the object would work. Or if you want to define convenient apply method on an object. Otherwise I don't bother myself at all with either object is companion or not, but often create objects with the class name for convenience.

References to case objects with trait usage

I've encountered something which I don't quite understand, so lets begin:
If i've got this object:
case object StartMessage
written like above and then obtain its references from two different classes:
class Test2 {
def print(){
println(Integer.toHexString(System.identityHashCode(StartMessage)))
}
}
class Test1 {
def print(){
println(Integer.toHexString(System.identityHashCode(StartMessage)))
}
}
as expected result is:
object ActorMain extends App{
new Test1().print()//45c8e616
new Test2().print()//45c8e616
}
But when i change case object to pack it in trait:
trait model{
case object StartMessage
}
then my classes will have declaration like:
class Test1 extends model{
class Test2 extends model{
I receive:
45c8e616
7d417077
*1. Could you explain it to me? I was thinking that objects are one in whole application, so when i create Trait with objects in it, every time i will extends (use "with") those trait, the object will be the same, not somewhat trait scoped.
*2. Is there another way to obtain functionality to "add" same objects only with extending trait to concrete classes, and not make them visible for whole application? Case is to have cleaner code with possibility to "mark" classes as "they use those objects, while others don't"
Objects defined within trait are singletons given trait scope. It is actually referring to the instance of a trait, not the trait itself. And the resulting behavior is the one that you see -> objects are created per instance. And this leads to the conclusion that you cannot define objects by extending traits to be shared across different classes. There was similar question on SO some time ago, I'll try to find it later.
Personally I would go for passing to classes some sort of a context to provide shared resources.

Is it possible to alias trait members in scala?

Imagine I have a trait:
trait A {
type Elem
def list(e: Elem): List[Elem]
}
Is it possible somehow to create an object that extends this twice?
I know you can't inherit the same trait twice, but it could (in certain circumstances) be possible to have something like:
trait B extends A
object Server extends A with B {
}
So, is it possible to somehow alias the members of trait A in B? E.g. so then in Server I could set A.Elem = Int, B.Elem = String and have scala use method overloading to call the appropriate list function?
My use case for this is I've built an HTTP endpoint that accepts a specific implementation of a form class. However, I want to allow it to handle several different form classes (e.g. DetailedRegistration, SimpleRegistration) and to reuse the relevant logic.

Scala: Type resolution of an inner case class in extending classes

I have something similar to a tree like structure.
I have a trait T. And two classes (A and B) that extends T.
A is like the root node that creates new instances from B while B itself can create new instances from B.
In trait T I define a case class C that I use to save some specific values as well as a List[C] (lets call it listC to keep things simple) that contains all instances of C.
Also every B knows its parent. What I want to do is listC = parent.listC. However this does not work as listC expects the typ List[C] but gets List[parent.C].
How can I solve this issue?
Additionally here are some solutions that I tried but didn't work / are not possible:
I can not define the case class outside of the trait as its values have types that only get defined within the trait.
An easy solution would be to drop the class and use a Tuple instead. However I would like to stick with the class to enhance readability. It's just nice to call x.varName as x._4
If you want that the type C in different subclasses of T to be the same type you cannot define the type as a path dependent type in T.
Tuple2[A.D, A.E] will not be the same as Tuple2[B.D, B.E], this is the exact same problem.
But if a tuple would work, then you should be able to just define the C case class in the companion object of T for example just as well as using a tuple.
One way to do this could be to put bounds on what the nested types can be and use a common supertype in your C/Tuples

What is a sealed trait?

Sealed classes are described in 'Programming in Scala', but sealed traits are not.
Where can I find more information about a sealed trait?
I would like to know, if a sealed trait is the same as a sealed class?
Or, if not, what are the differences?
When is it a good idea to use a sealed trait (and when not)?
A sealed trait can be extended only in the same file as its declaration.
They are often used to provide an alternative to enums. Since they can be only extended in a single file, the compiler knows every possible subtypes and can reason about it.
For instance with the declaration:
sealed trait Answer
case object Yes extends Answer
case object No extends Answer
The compiler will emit a warning if a match is not exhaustive:
scala> val x: Answer = Yes
x: Answer = Yes
scala> x match {
| case No => println("No")
| }
<console>:12: warning: match is not exhaustive!
missing combination Yes
So you should use sealed traits (or sealed abstract class) if the number of possible subtypes is finite and known in advance. For more examples you can have a look at list and option implementations.
a sealed trait is the same as a sealed class ?
As far as sealed goes, yes. They share the normal differences between trait and class, of course.
Or, if not, what are the differences ?
Moot.
When is it a good idea to use a sealed trait (and when not) ?
If you have a sealed class X, then you have to check for X as well as any subclasses. The same is not true of sealed abstract class X or sealed trait X. So you could do sealed abstract class X, but that's way more verbose than just trait and for little advantage.
The main advantage of using an abstract class over a trait is that it can receive parameters. That advantage is particularly relevant when using type classes. Let's say you want to build a sorted tree, for instance. You can write this:
sealed abstract class Tree[T : Ordering]
but you cannot do this:
sealed trait Tree[T : Ordering]
since context bounds (and view bounds) are implemented with implicit parameters. Given that traits can't receive parameters, you can't do that.
Personally, I prefer sealed trait and use it unless some particular reason makes me use a sealed abstract class. And I'm not talking about subtle reasons, but in-your-face reasons you cannot ignore, such as using type classes.
From the daily-scala blog:
When a trait is "sealed" all of its subclasses are declared within the
same file and that makes the set of subclasses finite which allows
certain compiler checks.
Also I feel the need to point you to the specifications:
The sealed modifier applies to class definitions. A sealed class may not be directly inherited, except if the inheriting template is defined in the same source
file as the inherited class. However, subclasses of a sealed class can be inherited anywhere.
— M. Odersky. The Scala language specification, version 2.8. online, Sept., 2013.
‌‌Briefly:
Sealed traits can only be extended in the same file
List this lets the compiler easily know all possible subtypes
Use sealed traits when the number of possibly subtypes is finite and known in advance
A way of creating something like enum in Java
Help to define algebraic data types (ADTs)
and for more details
Everything about sealed traits in Scala
Traits can also be defined sealed, and only extended by a fixed set of case classes.
The core difference between normal traits and sealed traits can be summarized as follows:
Normal traits are open, so any number of classes can inherit from the trait as long as they provide
all the required methods, and instances of those classes can be used interchangeably via the trait's
required methods.
A normal trait hierarchy makes it easy to add additional sub-classes: just define your class and
implement the necessary methods. However, it makes it difficult to add new methods: a new
method needs to be added to all existing subclasses, of which there may be many.
Sealed traits are closed: they only allow a fixed set of classes to inherit from them, and all
inheriting classes must be defined together with the trait itself in the same file or REPL command.
A sealed trait hierarchy is the opposite: it is easy to add new methods, since a new method can
simply pattern match on each sub-class and decide what it wants to do for each. However, adding
new sub-classes is difficult, as you need to go to all existing pattern matches and add the case to
handle your new sub-class.
As an example
object SealedTraits extends App{
sealed trait Point
case class Point2D(x: Double, y: Double) extends Point
case class Point3D(x: Double, y: Double, z: Double) extends Point
def hypotenuse(p: Point) = p match {
case Point2D(x, y) => math.sqrt(x x + y y)
case Point3D(x, y, z) => math.sqrt(x x + y y + z z)
}
val points: Array[Point] = Array(Point2D(1, 2), Point3D(4, 5, 6))
for (p <- points) println(hypotenuse(p))
// 2.23606797749979
// 8.774964387392123
In general, sealed traits are good for modelling hierarchies where you expect the number of sub-classes
to change very little or not-at-all. A good example of something that can be modeled using sealed trait is
JSON.
A JSON value can only be JSON null, boolean, number, string, array, or dictionary.
JSON has not changed in 20 years, so it is unlikely that anyone will need to extend our JSON
with additional subclasses.
While the set of sub-classes is fixed, the range of operations we may want to do on a JSON blob is
unbounded: parse it, serialize it, pretty-print it, minify it, sanitize it, etc.
Thus it makes sense to model a JSON data structure as a closed sealed trait
hierarchy rather than a normal open trait hierarchy.
sealed trait Json
case class Null() extends Json
case class Bool(value: Boolean) extends Json
case class Str(value: String) extends Json
case class Num(value: Double) extends Json
case class Arr(value: Seq[Json]) extends Json
case class Dict(value: Map[String, Json]) extends Json