Error : case class implementing parent's abstract method - scala

I am learning scala, so bear with me if this a stupid question. I am experimenting with case classes and trying out the following:-
case class A {
def eval(x: Int): Boolean
}
case class B extends A
case class C extends A {
override def eval(x: Int): Boolean = true
// Compiler error is -
// Multiple markers at this line
// - Missing closing brace `}' assumed here
// - expected start of definition
}
Is it not possible for case classes to implement abstract methods?

A case class cannot inherit another case class (the compiler does a lot of magic). In scala, you would typically use a trait, so your code would look like:
trait A {
def eval(x: Int): Boolean
}
case class C() extends A {
override def eval(x: Int): Boolean = true
}

abstract case class is a contradiction in terms. It is not advisable to extend from a case class and by making a case class abstract you are forced to sub-class it to have an instantiable class.
The common pattern is an abstract class or trait as the base with one or more (often more than one) case classes always at the leafs of the inheritance tree.

Related

How to combine ADTs in Scala?

I have two layers in my app: domain and application. Each layer has its own "error" ADT. For instance:
package com.domain.person
sealed trait DomainError
case object NoPermission extends DomainError
final case class Person(hasPermission: Boolean): Either[DomainError, ???] {
def doSomething() = {
if (!hasPermission)
Left(NoPermission)
else
...
}
}
and in my application layer (another package):
package com.application.person
sealed trait ApplicationError
case object PersonNotFound extends ApplicationError
case object UnexpectedFatalError extends ApplicationError
// and a function f :: Either ApplicationError Something
The issue is, since DomainError lives in another package, I can't just simply extend my ApplicationError trait:
sealed trait ApplicationError extends DomainError // compilation error
I could create yet another case object to wrap DomainError:
sealed trait ApplicationError
// n list of errors, and then:
final case class WrappedDomainError(d: DomainError) extends ApplicationError
but that solution is suboptimal at best.
And also, what if I want to be more specific in my doSomething() and, instead of returning a whole DomainError, a different subset?
doSomething :: Either DoSomethingErrors ???
I would have to account for all cases in each of my domain layer's functions.
Is there any way I can do a proper sum type in Scala?
Thanks
Wrapping your domain error in application error is not a bad idea, TBH. It's what I would've done in your situation. A few more options to consider:
make your DomainError and ApplicationError extends a common supertype Error, CommonError, Failure, etc. My personal preference is to extend Throwable - this way your error ASTs can become isomorphic to exceptions which can come in handy for Java interop reasons.
error channel also being composed of unions. Your final type will look somewhat like Either[ApplicationError Either DomainError, A]. It's a bit mouthful but you can make it look less ugly by introducing aliases.
type Result[+A] = Either[ApplicationError Either DomainError, A]
def doSomething: Result[???]
replace either with your own AST or use scalaz or other library's alternatives to Either3
sealed trait Result[+A]
case class Success[A](a: A) extends Result[A]
case class ApplicationErr(err: ApplicationError) extends Result[Nothing]
case class DomainErr[A](err: DomainErr) extends Result[Nothing]
def doSomething: Result[???]
Interpret DomainErrors into ApplicationErrors
val maybeDomainErrorVal: Either[DomainError, ???] = ???
val maybeApplicationErrorVal: Either[ApplicationError, ???] =
maybeDomainErrorVal.leftMap {
case NoPermission => UnexpectedFatalError
}

In Scala, how can an Inner case class consistently override a method?

I recently discovered that Scala compiler has an interesting feature for case class: Since it generates both a class & an object signature, if defined as an inner class, it can be used to override an abstract type definition and a function definition of its super class with minimal boilerplate code, here is an example:
object InnerCaseClassOverridingBoth {
trait AALike
trait SS {
type AA <: AALike
def AA(): AnyRef
}
trait SS_Clear extends SS {
def AA(): AnyRef
}
class SSA extends SS_Clear {
case class AA() extends AALike
}
object SSA extends SSA {}
}
This will compile without any error. However the shortcut stops here, if the function definition def AA is parameterized, then neither the inner case class nor inner object is capable of overriding it: the apply function of the inner object doesn't automatically expand to a method of its outer class:
trait SS_Parameterised extends SS {
def AA(ii: Int): AnyRef
}
class SSB extends SS_Parameterised {
case class AA(ii: Int) extends AALike
}
object SSB extends SSB {}
This gives an error:
class SSB needs to be abstract, since method AA in trait
SS_Parameterised of type (ii: Int)AnyRef is not defined
class SSB extends SS_Parameterised {
My question is, is there a shortcut in this case? Why is the Scala compiler is designed to link case 1 but not case 2?
It's not particularly designed at all; or, it is, but not in the way you seem to think. You aren't overriding def AA() with a method that constructs AA, you are overriding it with the object AA itself. Notice
trait T {
type I <: AnyRef
def I(): AnyRef
}
object O extends T {
case class I(val i: Int)
}
This works fine.
> (O: T).I()
I
> (O: T).I().getClass
class O$I$
> O.I(5)
I(5)
> O.I(5).getClass
class O$I
The salient design choices are "objects can override no-param defs" (and so can vals, vars and, of course, no-param defs) and "case classes automatically generate objects". "Inner case classes override methods of the same name in their outer class with their constructors," is not one of Scala's rules. object O contains a case class I and an object I, and the abstract def I(): AnyRef is overridden to return said object I. The contents of object I don't matter, because def I() only has to return an AnyRef, which means no restrictions are imposed. It makes perfect sense that
trait U {
type I <: AnyRef
def I(i: Int): AnyRef
}
object P extends U {
case class I(i: Int)
}
fails, then. object P contains a case class I and an associated object I, but it also needs a def I(i: Int): AnyRef, which it lacks.
I am guessing it is simply related to the role apply plays in case classes. See Case Class default apply method
SSA satisfies SS_Clear.AA via companion object of SSA (SSA.apply).
When you add a parameter to the method you no longer have the 0-parameter apply method to fulfill that role.
OK I found 2 ways of doing this
Method 1: overriden by case class:
trait SS_Parameterised {
type AA <: AALike
def AA: Int => AnyRef
}
Method 2: overriden by implicit class:
trait SS_Parameterised {
type AA <: AALike
implicit def AA(ii: Int): AnyRef
}
class SSB extends SS_Parameterised {
implicit class AA(ii: Int) extends AALike
}
End of story :) One case class overriding 2 declarations? No problem.
(Method 2 works as scala internally generates an implicit function for every implicit class)

Default type class implementation in trait for sub-classes in Scala

I have the following relations:
trait Instrument
trait EquityOption extends Instrument { ... }
case class CallEquityOption(...) extends EquityOption
case class PutEquityOption(...) extends EquityOption
trait Priceable[I <: Instrument] { def price(I : Instrument) }
I can use exactly the same implementation of Priceable for the case classes CallEquityOptionand PutEquityOption. By having a match case to differentiation between the Call... and Put.... However, if I try to implement it directly as Priceable[EquityOption] under object EquityOption, the implicit cannot be found since it doesn't exactly match the type.
How can I make it work without needing to duplicate code?
You'll have to prove that you can provide an instance for every subtype of EquityOption.
implicit def allEquityOptions[T <: EquityOption]: Pricable[T] = ???

Enforce that all subclasses implement a given type class

Given a superclass or trait, and assuming an open hierarchy, how can I enforce that all extending classes implement a particular type class?
For instance, assuming the type class Default
trait Default[T] { def default: T }
and some trait Super:
trait Super { }
I would like to enforce that the following (by itself) is not allowed:
class A(val i: Int) extends Super
...while the following is:
class B(val i: Int) extends Super
implicit val bHasDef = new Default[B] { def default = B(42) }
Assuming the above is possible, can I then access the type class evidence for the subtypes from a method within Super? I.e, something like:
trait Super {
def magic: Default[this.type] = ???
}
I hardly think you can enforce that, at least in a simple enough way, maybe it's possible with something more complex like shapeless.
What I would do is add some modifications to the super trait and make it take a self reference to Default
trait Default[T] { def default: T }
trait Super[T] {
self: Default[T] =>
}
class B(val i: Int) extends Super[Int] with Default[Int] {
override def default: Int = ???
}
class A(val i: Int) extends Super[Int] // doesn't compile, needs a Default
This should also solve the second part of your question, the disadvantage is that now one trait is bundled to the other.

Scala: what is the purpose of 'override'

I'm not sure what the purpose of override keyword is, in scala. If I have
trait Shape { def foo(v: Int) }
class Triangle extends Shape { override def foo(v: Int) {} }
it behaves (apparently at least) exactly the same as it does without override.
In the case you are implementing an abstract method as in your example, it is not strictly necessary to add the override modifier.
However, in case you want to override a concrete method from the superclass, the override modifier is necessary. This is to avoid accidental overrides which could happen with mixing composition -- mixing-in traits during some refactoring could easily introduce a method definition that could be overridden by the method defined in the body of the class, hence the need for explicitly stating that a method is an override.
In your particular case, you got a comprehensive answer from axel22. I just want to add, that there is at least one more case where you may encounter override modifier. The keyword can also be used with trait methods.
Imagine that you have an abstract class:
abstract class Writer {
def print(str: String)
}
and its concrete implementation that prints on a console
class ConsoleWriter extends Writer {
def print(str: String) = println(str)
}
Now, you want to create a trait that will modify its behaviour. Look at the following implementation:
trait Uppercase extends Writer {
abstract override def print(str: String) =
super.print(str.toUpperCase())
}
Notice that a method has two modifiers: abstract and override. This is only allowed for traits and it means that the trait must be mixed into some class that has a concrete definition of the method in question
With the definition above, you can do:
val writer = new ConsoleWriter with Uppercase
writer.print("abc")
which will yield the result
ABC
Much in the same vain, you can add more traits:
trait WithSpaces extends Writer {
abstract override def print(str: String) =
super.print(str.split("").mkString(" ").tail)
}
Now when you call
val writer = new ConsoleWriter with Uppercase with WithSpaces
writer.print("abc")
you will see:
A B C
The above usage of an override modifier in traits is a distinguishing feature in scala and you won't see it in java.
It's for error checking.
Suppose you have
trait Shape { def foo(v: Int) = 1 }
class Triangle extends Shape { override def foo(v: Int) = 2 }
and then you change Shape to
trait Shape { def bar(v: Int) = 1 }
In that case the "override" will tell you that the foo in Triangle overrides nothing.
See also:
http://docs.oracle.com/javase/7/docs/api/java/lang/Override.html
http://en.wikipedia.org/wiki/C%2B%2B11#Explicit_overrides_and_final