The Akka docs call Actor's receive as a method. But as per the API it is a abstract type member rather than an abstract method. Any reason why receive is termed as a method?
Yeah, docs could be improved a bit.
If you take a look into the Actor trait, you will notice that receive is indeed a method. The Actor.Receive in its signature is the type member you are referring to, defined in the Actor object.
So, receive is an abstract method that every Actor needs to implement. Its type is partial function; you can easily tell because it takes a bunch of case statements, e.g.
def receive = {
case "test" => log.info("received test")
case _ => log.info("received unknown message")
}
Each case statement takes Any and returns Unit, so the actual type of the partial function is PartialFunction[Any, Unit]. For clarity and simplicity, Akka guys decided to create a placeholder for that particular type, they called it Receive and they put it in the Actor companion object.
Small digression: a lot of folks are not really happy with messages being of type Any and Akka guys have promised to introduce typed messages; not sure if they delivered it yet in the latest release though.
I work with Spark often, and it would save me a lot of time if the compiler could ensure that a type is serializable.
Perhaps with a type class?
def foo[T: IsSerializable](t: T) = {
// do stuff requiring T to be serializable
}
It's not enough to constrain T <: Serializable. It could still fail at runtime. Unit tests are a good substitute, but you can still forget them, especially when working with big teams.
I think this is probably impossible to do at compile time without the types being sealed.
Yes, it is possible, but not in the way that you're hoping. Your type class IsSerializable could provide a mechanism to convert your T to a value of a type which is guaranteed to be Serializable and back again,
trait IsSerializable[T] {
def toSerializable(t: T): String
def fromSerializable(s: String): Option[T]
}
But, of course, this is just an alternative type class based serialization mechanism in it's own right, making the use of JVM serialization redundant.
Your best course of action would be to lobby Spark to support type class based serialization directly.
I'm willing how to implement an extensible dispatch mechanism in Scala.
For example:
I have a trait called Sender (with a method 'send') and a bunch of classes that implement that trait (MailSender, IPhoneSender, AndroidSender). On top of them there is a class which implements the same trait but dispatches the message to the above senders depending the type of the message.
I know I can use pattern matching, but my problem with that approach is about extensibility: If someone wants to add another sender (i.e. WindowsPhoneSender), he must add a new case to the pattern matching method (thus breaking the open-closed principle). I don't want developers to modify the library's code, so I need this to be as extensible as possible.
I thought about a chain of responsibility approach (in Java I would do that), but is there a better way in Scala? (My knowledge in Scala is limited, but I know the Scala compiler does a lot of magical things)
Thanks!
It would be clearer if you gave a more concrete use case, but you might be looking for the typeclass pattern:
case class AndoidMessage()
case class WindowsMessage()
trait Sender[M]{
def send(message: M)
}
implicit object AndroidSender extends Sender[AndroidMessage]{...}
implicit object WindowsSender extends Sender[AndroidMessage]{...}
def mySendMethod[M: Sender](message: M) = {
// use the implicit Sender[M] to send the message
}
//AndroidSender is resolved implicitly
mySendMethod(new AndroidMessage())
//third party can define their own message and their own
//implicit sender for it (perhaps in a companion object
//so it's resolved automatically)
case class BeosMessage()
object BeosMessage{
implicit object BMSender extends Sender[BeosMessage]{...}
}
I caught myself watching a bit of the Scalawags#2 recording, and then there came this part about type erasure and Dick Wall pointing out that reflection will eventually bite you in the feet.
So I was thinking about something that I'm doing quite frequently (and I saw it the implementation of Scala Collections as well). Let's say I have a system with a serializer taking the system as type parameter:
trait Sys[S <: Sys[S]] { type Tx }
trait FooSys extends Sys[FooSys]
trait Serializer[S <: Sys[S], A] {
def read(implicit tx: S#Tx): A
}
Now there are many types A for which serializers can be constructed without value parameters, so essentially the system type parameter is "hollow". And since serializers are heavily invoked in my example, I'm saving instantiation:
object Test {
def serializer[S <: Sys[S]] : Serializer[S, Test[S]] =
anySer.asInstanceOf[Ser[S]]
private val anySer = new Ser[FooSys]
private final class Ser[S <: Sys[S]] extends Serializer[S, Test[S]] {
def read(implicit tx: S#Tx) = new Test[S] {} // (shortened for the example)
}
}
trait Test[S <: Sys[S]]
I know this is correct, but of course, asInstanceOf has a bad smell. Are there any suggestions to this approach? Let me add two things
moving the type parameter from the constructor of trait Serializer to the read method is not an option (there are specific serializers which require value arguments parametrised in S)
adding variance to Serializer's type constructor parameter is not an option
Introduction:
I am a little confused by your example and I might have misunderstood your question, I have a feeling there is a certain type recursion between S and Tx that I am not getting from your question(because if not, S#Tx could be anything and I don't understand the problem with the anySer)
Tentative Answer:
At compile time, for any instance of Ser[T] there will be a well-defined type parameter T, since you want to save it on instantiation, you will have a single anySer Ser[T] for a given specific type A
What you are saying in some way is that a Ser[A] will work as Ser[S] for any S. This can be explained in two ways, according to the relationship between type A and S.
If this conversion is possible for every A<:<S then your serializer is COVARIANT and you can initialize your anySer as a Ser[Nothing] . Since Nothing is subclass of every class in Scala, your anySer will always work as a Ser[Whatever]
If this conversion is possible for every S<:<A then your serializer is CONTRAVARIANT and you can initialize your anySer as a Ser[Any] . Since Any is subclass of every class in Scala, your anySer will always work as a Ser[Whatever]
If it's neither the one of the previous case, then it means that:
def serializer[S <: Sys[S]] : Serializer[S, Test[S]] =
anySer.asInstanceOf[Ser[S]]
Could produce an horrible failure at runtime, because there will some S for which the Serializer won't work. If there are no such S for which this could happen, then your class falls in either 1 or
Comment post-edit
If your types are really invariant, the conversion through a cast breaks the invariance relation. You are basically forcing the type system to perform an un-natural conversion because you know that nothing wrong will happen, on the basis of your own knowledge of the code you have written. If this is the case then casting is the right way to go: you are forcing a different type from the one the compiler can check formally and you are making this explicit. I would even put a big comment saying why you know that operation is legal and the compiler can't guess and eventually attach a beautiful unit test to verify that the "in-formal" relation always holds.
In general, I believe this practice should be used with extreme care. One of the benefits of strongly typed languages is that the compiler performs formal type checking that helps you catch early errors. If you intentionally break it, you give away this big benefit.
As I understand from this blog post "type classes" in Scala is just a "pattern" implemented with traits and implicit adapters.
As the blog says if I have trait A and an adapter B -> A then I can invoke a function, which requires argument of type A, with an argument of type B without invoking this adapter explicitly.
I found it nice but not particularly useful. Could you give a use case/example, which shows what this feature is useful for ?
One use case, as requested...
Imagine you have a list of things, could be integers, floating point numbers, matrices, strings, waveforms, etc. Given this list, you want to add the contents.
One way to do this would be to have some Addable trait that must be inherited by every single type that can be added together, or an implicit conversion to an Addable if dealing with objects from a third party library that you can't retrofit interfaces to.
This approach becomes quickly overwhelming when you also want to begin adding other such operations that can be done to a list of objects. It also doesn't work well if you need alternatives (for example; does adding two waveforms concatenate them, or overlay them?) The solution is ad-hoc polymorphism, where you can pick and chose behaviour to be retrofitted to existing types.
For the original problem then, you could implement an Addable type class:
trait Addable[T] {
def zero: T
def append(a: T, b: T): T
}
//yup, it's our friend the monoid, with a different name!
You can then create implicit subclassed instances of this, corresponding to each type that you wish to make addable:
implicit object IntIsAddable extends Addable[Int] {
def zero = 0
def append(a: Int, b: Int) = a + b
}
implicit object StringIsAddable extends Addable[String] {
def zero = ""
def append(a: String, b: String) = a + b
}
//etc...
The method to sum a list then becomes trivial to write...
def sum[T](xs: List[T])(implicit addable: Addable[T]) =
xs.FoldLeft(addable.zero)(addable.append)
//or the same thing, using context bounds:
def sum[T : Addable](xs: List[T]) = {
val addable = implicitly[Addable[T]]
xs.FoldLeft(addable.zero)(addable.append)
}
The beauty of this approach is that you can supply an alternative definition of some typeclass, either controlling the implicit you want in scope via imports, or by explicitly providing the otherwise implicit argument. So it becomes possible to provide different ways of adding waveforms, or to specify modulo arithmetic for integer addition. It's also fairly painless to add a type from some 3rd-party library to your typeclass.
Incidentally, this is exactly the approach taken by the 2.8 collections API. Though the sum method is defined on TraversableLike instead of on List, and the type class is Numeric (it also contains a few more operations than just zero and append)
Reread the first comment there:
A crucial distinction between type classes and interfaces is that for class A to be a "member" of an interface it must declare so at the site of its own definition. By contrast, any type can be added to a type class at any time, provided you can provide the required definitions, and so the members of a type class at any given time are dependent on the current scope. Therefore we don't care if the creator of A anticipated the type class we want it to belong to; if not we can simply create our own definition showing that it does indeed belong, and then use it accordingly. So this not only provides a better solution than adapters, in some sense it obviates the whole problem adapters were meant to address.
I think this is the most important advantage of type classes.
Also, they handle properly the cases where the operations don't have the argument of the type we are dispatching on, or have more than one. E.g. consider this type class:
case class Default[T](val default: T)
object Default {
implicit def IntDefault: Default[Int] = Default(0)
implicit def OptionDefault[T]: Default[Option[T]] = Default(None)
...
}
I think of type classes as the ability to add type safe metadata to a class.
So you first define a class to model the problem domain and then think of metadata to add to it. Things like Equals, Hashable, Viewable, etc. This creates a separation of the problem domain and the mechanics to use the class and opens up subclassing because the class is leaner.
Except for that, you can add type classes anywhere in the scope, not just where the class is defined and you can change implementations. For example, if I calculate a hash code for a Point class by using Point#hashCode, then I'm limited to that specific implementation which may not create a good distribution of values for the specific set of Points I have. But if I use Hashable[Point], then I may provide my own implementation.
[Updated with example]
As an example, here's a use case I had last week. In our product there are several cases of Maps containing containers as values. E.g., Map[Int, List[String]] or Map[String, Set[Int]]. Adding to these collections can be verbose:
map += key -> (value :: map.getOrElse(key, List()))
So I wanted to have a function that wraps this so I could write
map +++= key -> value
The main issue is that the collections don't all have the same methods for adding elements. Some have '+' while others ':+'. I also wanted to retain the efficiency of adding elements to a list, so I didn't want to use fold/map which create new collections.
The solution is to use type classes:
trait Addable[C, CC] {
def add(c: C, cc: CC) : CC
def empty: CC
}
object Addable {
implicit def listAddable[A] = new Addable[A, List[A]] {
def empty = Nil
def add(c: A, cc: List[A]) = c :: cc
}
implicit def addableAddable[A, Add](implicit cbf: CanBuildFrom[Add, A, Add]) = new Addable[A, Add] {
def empty = cbf().result
def add(c: A, cc: Add) = (cbf(cc) += c).result
}
}
Here I defined a type class Addable that can add an element C to a collection CC. I have 2 default implementations: For Lists using :: and for other collections, using the builder framework.
Then using this type class is:
class RichCollectionMap[A, C, B[_], M[X, Y] <: collection.Map[X, Y]](map: M[A, B[C]])(implicit adder: Addable[C, B[C]]) {
def updateSeq[That](a: A, c: C)(implicit cbf: CanBuildFrom[M[A, B[C]], (A, B[C]), That]): That = {
val pair = (a -> adder.add(c, map.getOrElse(a, adder.empty) ))
(map + pair).asInstanceOf[That]
}
def +++[That](t: (A, C))(implicit cbf: CanBuildFrom[M[A, B[C]], (A, B[C]), That]): That = updateSeq(t._1, t._2)(cbf)
}
implicit def toRichCollectionMap[A, C, B[_], M[X, Y] <: col
The special bit is using adder.add to add the elements and adder.empty to create new collections for new keys.
To compare, without type classes I would have had 3 options:
1. to write a method per collection type. E.g., addElementToSubList and addElementToSet etc. This creates a lot of boilerplate in the implementation and pollutes the namespace
2. to use reflection to determine if the sub collection is a List / Set. This is tricky as the map is empty to begin with (of course scala helps here also with Manifests)
3. to have poor-man's type class by requiring the user to supply the adder. So something like addToMap(map, key, value, adder), which is plain ugly
Yet another way I find this blog post helpful is where it describes typeclasses: Monads Are Not Metaphors
Search the article for typeclass. It should be the first match. In this article, the author provides an example of a Monad typeclass.
The forum thread "What makes type classes better than traits?" makes some interesting points:
Typeclasses can very easily represent notions that are quite difficult to represent in the presence of subtyping, such as equality and ordering.
Exercise: create a small class/trait hierarchy and try to implement .equals on each class/trait in such a way that the operation over arbitrary instances from the hierarchy is properly reflexive, symmetric, and transitive.
Typeclasses allow you to provide evidence that a type outside of your "control" conforms with some behavior.
Someone else's type can be a member of your typeclass.
You cannot express "this method takes/returns a value of the same type as the method receiver" in terms of subtyping, but this (very useful) constraint is straightforward using typeclasses. This is the f-bounded types problem (where an F-bounded type is parameterized over its own subtypes).
All operations defined on a trait require an instance; there is always a this argument. So you cannot define for example a fromString(s:String): Foo method on trait Foo in such a way that you can call it without an instance of Foo.
In Scala this manifests as people desperately trying to abstract over companion objects.
But it is straightforward with a typeclass, as illustrated by the zero element in this monoid example.
Typeclasses can be defined inductively; for example, if you have a JsonCodec[Woozle] you can get a JsonCodec[List[Woozle]] for free.
The example above illustrates this for "things you can add together".
One way to look at type classes is that they enable retroactive extension or retroactive polymorphism. There are a couple of great posts by Casual Miracles and Daniel Westheide that show examples of using Type Classes in Scala to achieve this.
Here's a post on my blog
that explores various methods in scala of retroactive supertyping, a kind of retroactive extension, including a typeclass example.
I don't know of any other use case than Ad-hoc polymorhism which is explained here the best way possible.
Both implicits and typeclasses are used for Type-conversion. The major use-case for both of them is to provide ad-hoc polymorphism(i.e) on classes that you can't modify but expect inheritance kind of polymorphism. In case of implicits you could use both an implicit def or an implicit class (which is your wrapper class but hidden from the client). Typeclasses are more powerful as they can add functionality to an already existing inheritance chain(eg: Ordering[T] in scala's sort function).
For more detail you can see https://lakshmirajagopalan.github.io/diving-into-scala-typeclasses/
In scala type classes
Enables ad-hoc polymorphism
Statically typed (i.e. type-safe)
Borrowed from Haskell
Solves the expression problem
Behavior can be extended
- at compile-time
- after the fact
- without changing/recompiling existing code
Scala Implicits
The last parameter list of a method can be marked implicit
Implicit parameters are filled in by the compiler
In effect, you require evidence of the compiler
… such as the existence of a type class in scope
You can also specify parameters explicitly, if needed
Below Example extension on String class with type class implementation extends the class with a new methods even though string is final :)
/**
* Created by nihat.hosgur on 2/19/17.
*/
case class PrintTwiceString(val original: String) {
def printTwice = original + original
}
object TypeClassString extends App {
implicit def stringToString(s: String) = PrintTwiceString(s)
val name: String = "Nihat"
name.printTwice
}
This is an important difference (needed for functional programming):
consider inc:Num a=> a -> a:
a received is the same that is returned, this cannot be done with subtyping
I like to use type classes as a lightweight Scala idiomatic form of Dependency Injection that still works with circular dependencies yet doesn't add a lot of code complexity. I recently rewrote a Scala project from using the Cake Pattern to type classes for DI and achieved a 59% reduction in code size.