Drawbacks of using typeclasses in scala - scala

There are some frameworks that fully embraces the typeclass pattern. scalaz and shapeless would be good examples. So there are certainly some cases where typeclasses are preferable over normal java classes and polymorphism.
I awe implicit evidence expression power and I'm curious why this method suffer a shortage of practical applications. What reasons compel scala programmers to use basic classes. The typeclasses obviously cost in verbosity and run-time, but is there any other reason?
I came to scala without prior java experience and wonder if I've missed some essential benefits that classic scala-java classes may give.
I'm searching for some spectacular use cases showing areas where typeclasses are insufficient or ineffective.

Typeclasses and inheritance enable reuse in different ways. Inheritance excels at providing correct functionality for changed internals.
class Foo { def foo: String = "foo" }
def fooUser(foo: Foo) { println(foo.foo) }
class Bar extends Foo {
private var annotation = List.empty[String]
def annotate(s: String) { annotation = s :: annotation }
override def foo = ("bar" :: annotation.map("#" + _)).mkString(" ")
}
Now, everyone who uses Foo will be able to get the correct value if you give them a Bar, even if they only know that the type is a Foo. You don't have to have anticipated that you might want pluggable functionality (except by not labeling foo final). You don't need to keep track of the type or keep passing a witness instance forwards; you just use Bar wherever you want in place of Foo and it does the right thing. This is a big deal. If you want a fixed interface with easily-modifiable functionality under the hood, inheritance is your thing.
In contrast, inheritance is not so great when you have a fixed set of data types with easily-modifiable interface. Sorting is a great example. Suppose you want to sort Foo. If you try
class Foo extends Sortable[Foo] {
def lt(you: Foo) = foo < you.foo
def foo = "foo"
}
you could pass this to anything that could sort a Sortable. But what if you want to sort by length of name not with the standard sort? Well,
class Foo extends LexicallySortable[Foo] with LengthSortable[Foo] {
def lexicalLt(you: Foo) = foo < you.foo
def lengthLt(you: Foo) = foo.length < you.foo.length
def foo = "foo"
}
This rapidly becomes hopeless, especially since you have to hunt down all subclasses of Foo and make sure they are updated properly. You are much better off deferring the less-than computation to a typeclass which you can swap out as needed. (Or to a regular class, which you must always reference explicitly.) This kind of automatically-selected functionality is also a big deal.
You can't really replace one with the other. When you need to easily incorporate new kinds of data to a fixed interface, use inheritance. When you need a few kinds of underlying data but need to easily supply new functionality, use type classes. When you need both, you will have a lot of work to do whichever way you go about it, so use to taste.

Related

Scala type alias with companion object

I'm a relatively new Scala user and I wanted to get an opinion on the current design of my code.
I have a few classes that are all represented as fixed length Vector[Byte] (ultimately they are used in a learning algorithm that requires a byte string), say A, B and C.
I would like these classes to be referred to as A, B and C elsewhere in the package for readability sake and I don't need to add any extra class methods to Vector for these methods. Hence, I don't think the extend-my-library pattern is useful here.
However, I would like to include all the useful functional methods that come with Vector without having to 'drill' into a wrapper object each time. As efficiency is important here, I also didn't want the added weight of a wrapper.
Therefore I decided to define type aliases in the package object:
package object abc {
type A: Vector[Byte]
type B: Vector[Byte]
type C: Vector[Byte]
}
However, each has it's own fixed length and I would like to include factory methods for their creation. It seems like this is what companion objects are for. This is how my final design looks:
package object abc {
type A: Vector[Byte]
object A {
val LENGTH: Int = ...
def apply(...): A = {
Vector.tabulate...
}
}
...
}
Everything compiles and it allows me to do stuff like this:
val a: A = A(...)
a map {...} mkString(...)
I can't find anything specifically warning against writing companion objects for type aliases, but it seems it goes against how type aliases should be used. It also means that all three of these classes are defined in the same file, when ideally they should be separated.
Are there any hidden problems with this approach?
Is there a better design for this problem?
Thanks.
I guess it is totally ok, because you are not really implementing a companion object.
If you were, you would have access to private fields of immutable.Vector from inside object A (like e.g. private var dirty), which you do not have.
Thus, although it somewhat feels like A is a companion object, it really isn't.
If it were possible to create a companion object for any type by using type alias would make member visibility constraints moot (except maybe for private|protected[this]).
Furthermore, naming the object like the type alias clarifies context and purpose of the object, which is a plus in my book.
Having them all in one file is something that is pretty common in scala as I know it (e.g. when using the type class pattern).
Thus:
No pitfalls, I know of.
And, imho, no need for a different approach.

Pattern Matching Design

I recently wrote some code like the block below and it left me with thoughts that the design could be improved if I was more knowledgeable on functional programming abstractions.
sealed trait Foo
case object A extends Foo
case object B extends Foo
case object C extends Foo
.
.
.
object Foo {
private def someFunctionSemanticallyRelatedToA() = { // do stuff }
private def someFunctionSemanticallyRelatedToB() = { // do stuff }
private def someFunctionSemanticallyRelatedToC() = { // do stuff }
.
.
.
def somePublicFunction(x : Foo) = x match {
case A => someFunctionSemanticallyRelatedToA()
case B => someFunctionSemanticallyRelatedToB()
case C => someFunctionSemanticallyRelatedToC()
.
.
.
}
}
My questions are:
Is the somePublicFunction() suffering from code smell or even the whole design? My concern is that the list of value constructors could grow quite big.
Is there a better FP abstraction to handle this type of design more elegantly or even concisely?
You've just run into the expression problem. In your code sample, the problem is that potentially every time you add or remove a case from your Foo algebraic data type, you'll need to modify every single match (like in somePublicFunction) against values of Foo. In Nimrand's answer, the problem is in the opposite end of the spectrum: you can add or remove cases from Foo easily, but every time you want to add or remove a behaviour (a method), you'll need to modify every subclass of Foo.
There are various proposals to solve the expression problem, but one interesting functional way is Oleg Kiselyov's Typed Tagless Final Interpreters, which replaces each case of the algebraic data type with a function that returns some abstract value that's considered to be equivalent to that case. Using generics (i.e. type parameters), these functions can all have compatible types and work with each other no matter when they were implemented. E.g., I've implemented an example of building and evaluating an arithmetic expression tree using TTFI: https://github.com/yawaramin/scala-ttfi
Your explanation is a bit too abstract to give you a confident answer. However, if the list of subclasses of Foo is likely to grow/change in the future, I would be inclined to make it an abstract method of Foo, and then implement the logic for each case in the sub classes. Then you just call Foo.myAbstractMethod() and polymorphism handles everything neatly.
This keeps the code specific to each object with the object itself, which is keeps things more neatly organized. It also means that you can add new subclasses of Foo without having to jump around to multiple places in code to augment the existing match statements elsewhere in the code.
Case classes and pattern-matching work best when the set of sub-classes is relatively small and fixed. For example, Option[T] there are only two sub-classes, Some[T] and None. That will NEVER change, because to change that would be to fundamentally change what Option[T] represents. Therefore, it's a good candidate for pattern-matching.

scala traits - questions about testing and interface pollution

I started using Scala few weeks ago. Overall I really like all the features that this language gives to the developer, but it is hard to switch from Java habits sometimes.
This question is concerning traits. Currently almost everytime I see some part of logic that I would extract to different class in Java and add constructor parameter to dependent class I am switching to creating trait and mixing it in my class. (if all you have is a hammer, everything looks like a nail)
But I see two problems with my approach.
Testing classes with mixed in traits:
In Java if I would have class Foo that would use Bar and Baz classes I would probably inject them to my Foo class and use them. If I do this using traits I will have class Foo extends Bar with Baz.
Now in my tests I would have to write something like
trait BarMock extends Bar{
override def bar = "barMock"
}
trait BazMock extends Baz{
override def baz = "bazMock"
}
val foo = new Foo with BarMock with BazMock
if I want to swap the implementation of some trait behaviour. Maybe it is just me that is used to writing
Bar bar = mock(Bar.class);
when(bar.bar()).thenReturn("barMock");
Baz baz = mock(Baz.class);
when(baz.baz()).thenReturn("bazMock");
Foo foo = new Foo(bar, baz);
Is it normal to mock traits like I showed in Scala projects? Or I should restrain myself from mixing in mocked traits in tests.
Trait method visibility
This is also connected with my current obsession with traits. In Java if I inject Bar, Baz instances to my Foo instance, I am not automatically adding all public methods from Bar, Baz to my Foo interface. If I want to do it, I have to add each delegating method hand by hand. If I am using traits, when I mix in some trait, I am automatically "polluting" Foo interface with methods from my traits. Is there any way I could achieve something like private inheritance from C++?
The only solution that comes to my mind is declaring trait methods as protected and marking the trait as package private. This way methods will be visible in Foo, but outside of the package someone can't write val bar:Bar = new Foo. Also if I understand correctly, package private constraint will be validated only when package private trait source code will be in my project, because JVM has no way of representing the concept of package private and compiler just makes it public in bytecode.
In a word: Cake. The Cake Pattern. Much has been written about it, most marginal, but once the concept clicks into your head it's pretty easy to realize. And it's a great tool for achieving SOLID as well as testability and statically typed dependency injection and mix-and-match componentized code.
There is a price to it, but where I used to feel that price demanded a specific justification to use Cake for a given bit of your code, I now see it the other way around. You should justify not using it on a case-by-case basis.
The seminal paper on Cake is Scalable Component Abstractions (that's a paywall, but it's available free elsewhere on the 'Net). Nonetheless, as with most such things, that's not the best place to start. Simply searching the Web for "Scala Cake Pattern" produces many hits. Read a few until you find one that englightens you…

Self-type traits with abstract classes

I'm facing a design issue that my poor Scala level cannot handle.
I have an abstract class, let's say:
abstract class AbstractJob {
def run: Long
implicit val someVal: String
}
Then, I have "platforms" on which jobs can be ran.
I want to declare subclasses containing real "jobs" (no need to know what it should actually do). Ideally, I want them to be declared this way:
class OneJob with Platform1 with Platform2 {
override def run = {
... some code returning a long result ...
}
override implicit val someVal = "foo"
}
Indeed, jobs can have multiple platforms on which they can be ran.
However, the run method on jobs must be launched by the platforms. Therefore I tried to use a self-type:
trait Platform1 { self: AbstractJob =>
def runOnPlatform = someFunctionRelatedToPlatform(run(someVal))
}
Unfortunately when calling someVal value (in any job extending AbstractJob), I get a null value. I went to the conclusion that self-type in traits are directly related to the defined class (and not the actual class, which is a subtype in my case)
I tried to define another type type Jobs :> AbstractJob for the self-type in the trait but that didn't work.
I have a limited number of backup solutions, but I want to use the "full power" of Scala and avoid developers to write a lot of redundant and "plumber" code (related to platforms and AbstractJob class in my example).
AbstractJob calls directly runOnPlatform with an "abstract" function to be implemented in concrete jobs. In this case my users will only write the business code they need but I'm quite sure I can do better using Scala concepts. I'm feeling that I'm just using Java (and generally OOP) concepts in Scala...
Let the users write a hell lot of redundant code... Obviously I'm avoiding this as much as possible!!
I hope I'm clear enough!

Scala: Do classes that extend a trait always take the traits properties?

Given the following:
class TestClass extends TestTrait {
def doesSomething() = methodValue + intValue
}
trait TestTrait {
val intValue = 4
val unusedValue = 5
def methodValue = "method"
def unusedMethod = "unused method"
}
When the above code runs, will TestClass actually have memory allocated to unusedValue or unusedMethod? I've used javap and I know that there exists an unusedValue and an unusedMethod, but I cannot determine if they are actually populated with any sort of state or memory allocation.
Basically, I'm trying to understand if a class ALWAYS gets all that a trait provides, or if the compiler is smart enough to only provide what the class actually uses from the trait?
If a trait always imposes itself on a class, it seems like it could be inefficient, since I expect many programmers will use traits as mixins and therefore wasting memory everywhere.
Thanks to all who read and help me get to the bottom of this!
Generally speaking, in languages like Scala and Java and C++, each class has a table of pointers to its instance methods. If your question is whether the Scala compiler will allocate slots in the method table for unusedMethod then I would say yes it should.
I think your question is whether the Scala compiler will look at the body of TestClass and say "whoa, I only see uses of methodValue and intValue, so being a good compiler I'm going to refrain from allocating space in TestClass's method table for unusedMethod. But it can't really do this in general. The reason is, TestClass will be compiled into a class file TestClass.class and this class may be used in a library by programmers that you don't even know.
And what will they want to do with your class? This:
var x = new TestClass();
print(x.unusedMethod)
See, the thing is the compiler can't predict who is going to use this class in the future, so it puts all methods into its method table, even the ones not called by other methods in the class. This applies to methods declared in the class or picked up via an implemented trait.
If you expect the compiler to do global system-wide static analysis and optimization over a fixed, closed system then I suppose in theory it could whittle away such things, but I suspect that would be a very expensive optimization and not really worth it. If you need this kind of memory savings you would be better off writing smaller traits on your own. :)
It may be easiest to think about how Scala implements traits at the JVM level:
An interface is generated with the same name as the trait, containing all the trait's method signatures
If the trait contains only abstract methods, then nothing more is needed
If the trait contains any concrete methods, then the definition of these will be copied into any class that mixes in the trait
Any vals/vars will also get copied verbatim
It's also worth noting how a hypothetical var bippy: Int is implemented in equivalent java:
private int bippy; //backing field
public int bippy() { return this.bippy; } //getter
public void bippy_$eq(int x) { this.bippy = x; } //setter
For a val, the backing field is final and no setter is generated
When mixing-in a trait, the compiler doesn't analyse usage. For one thing, this would break the contract made by the interface. It would also take an unacceptably long time to perform such an analysis. This means that you will always inherit the cost of the backing fields from any vals/vars that get mixed in.
As you already hinted, if this is a problem then the solution is just use defs in your traits.
There are several other benefits to such an approach and, thanks to the uniform access principle, you can always override such a method with a val further down in the inheritance hierarchy if you need to.