So. Assume we have a trait Animal
trait Animal {
val typeAnimal: String
val name: String
}
And now I want to create a class Dog, that extends this trait. But I want to use the Companion Object to override the typeAnimal to Mammal, instead to do it on the class Dog itself.
Something like
class Dog(override val name: String) extends Animal
object Dog {
override val typeAnimal = "Mammal"
}
This doesn't work. It raises an error saying to me:
class Dog doesn't implement typeAnimal
the override of typeAnimal on the companion object does not override anything
Is it even possible?
Does it have make sense what I'm trying to achieve?
EDIT
I assume it's not possible to achieve what I'm trying here following Jorg's comment.
What I was trying to do is: a trait define some static value that each class should implement, like typeAnimal, and, since this belongs to all the instance of each class that implements this trait (e.g. Dog is a mammal, so I don't see any reason why the typeAnimal should be a instance variable instead of a static one) I would like to override in the companion object
If you want typeAnimal to be "static", it shouldn't be a member of the trait itself. You can do this instead:
trait Animal {
val name: String
def companion: AnimalCompanion
// optional: def typeAnimal = companion.typeAnimal
}
trait AnimalCompanion {
val typeAnimal: String
}
class Dog(override val name: String) extends Animal {
override def companion = Dog
}
object Dog extends AnimalCompanion {
override val typeAnimal = "Mammal"
}
The standard library does that with collections.
Related
I am implementing an extension of ml.Transformer in Spark; but this question is Scala specific. Here is an example object (part of a Class/Object pair):
abstract class UDFTransformer(func: UserDefinedFunction,
inputFieldNames: Seq[String],
outputFieldName: String) extends Transformer with MLWritable with Serializable {
... definitions here ...
}
object UDFTransformer extends MLReadable[UDFTransformer] {
// Since there are no parameters associted with the UDF, there is nothing to save!
class Writer(instance: UDFTransformer) extends MLWriter {
override protected def saveImpl(path: String): Unit = {}
}
abstract protected class Reader extends MLReader[UDFTransformer]
override def read: MLReader[UDFTransformer] = new Reader
override def load(path: String): UDFTransformer = super.load(path)
}
The new Reader does not compile because the class is abstract and cannot be instantiated. But; any child class will have to define it; along with its necessary members. I cannot just make read abstract as well, this gives me a warning Only classes can have declared but undefined methods.
The fundamental problem is that each child class of my UDFTransformer is going to wrap a specific UDF. Therefore, the reader needs to be able to generate a specific UDF object; this can't be declared in the superclass. But this 'factory' belongs in the companion object, not in the abstract class itself.
How can I go about building a companion object for an abstract class that can leave the definition of read undefined?
The normal way to do it is by creating an abstract class or trait for the companion objects. Something like
abstract class UDFTransformerCompanion[T <: UDFTransformer] extends MLReadable[T] {
abstract def read: MLReader[T]
override def load(path: String): T = super.load(path)
}
class SomeTransformer extends UDFTransformer { ... }
object SomeTransformer extends UDFTransformerCompanion[SomeTransformer] {
override def read: MLReader[SomeTransformer] = ...
}
Not sure why you have the load = super.load override, and it doesn't look like you can have a companion object for the UDFTransformer itself, at least not one extending this abstract class.
See GenericTraversableTemplate for a standard library example.
I want to get the instance of a singleton type in Scala, is this possible?
Example: (I know it can be done easier in this case)
sealed trait Animal
case object Dog extends Animal
case object Cat extends Animal
trait Person {
def name: String
// Is there a "FavoriteAnimal.instance" syntax?
def mostImportantThings = (FavoriteAnimal.instance, name)
protected type FavoriteAnimal <: Animal with scala.Singleton
}
case class DogPerson(override val name: String) extends Person {
override type FavoriteAnimal = Dog.type
}
case class CatPerson(override val name: String) extends Person {
override type FavoriteAnimal = Cat.type
}
Using shapeless.Witness correct syntax is
sealed trait Animal
case object Dog extends Animal
case object Cat extends Animal
trait Person {
def name: String
def mostImportantThings(implicit
witness: Witness.Aux[FavoriteAnimal]
): (FavoriteAnimal, String) = (witness.value, name)
protected type FavoriteAnimal <: Animal with scala.Singleton
}
case class DogPerson(override val name: String) extends Person {
override type FavoriteAnimal = Dog.type
}
case class CatPerson(override val name: String) extends Person {
override type FavoriteAnimal = Cat.type
}
DogPerson("A Dog Person").mostImportantThings // (Dog, A Dog Person)
Unfortunately in the current version of Shapeless (2.3.3) there is a bug and this code doesn't compile. But after fix it does.
Maybe you want something like
sealed trait Animal
case object Dog extends Animal
case object Cat extends Animal
trait Person[A <: Animal] {
def name: String
def animal: A
def mostImportantThings = (animal, name)
}
case class DogPerson(override val name: String) extends Person[Dog.type] {
override val animal = Dog
}
case class CatPerson(override val name: String) extends Person[Cat.type] {
override val animal = Cat
}
We can supply parameter to a class extending trait with the same name as an abstract method like
trait Trr{
def m: String
}
case class Trrrr(m: String) extends Trr //fine
This example compiles fine. But I tried to do something like that with case objects and failed:
trait Command{
def name: String
}
case object Unload("unld") extends Command //compile error
Is there a way to write this concisely while leaving Command a trait, not an abstract class with parameter? I mean not like that:
case object Unload extends Command {
override def name: String = "unld"
}
or
abstract class Command(name: String)
case object Unload extends Command("unld")
case object Unload extends Command { val name = "unld" }
Object don't have arguments, things won't get any shorted than the above...
You can instantiate the trait directly like so:
val newTrr = new Trr { val m = "example" }
At this point you can use the newTrr value just like any class instance...
println(newTrr.m)
which will print out: "example".
//File Animal.scala
abstract class Animal {
val name: String
def getSomething(tClass: TypeClass): String = {
tClass.tName.split('.').lift(0)
}
def apply(tClass: TypeClass): SomeOtherClassType = {
// something...
}
// File: DogSpike, this is used for some specific cases (overwrites
base class val)
object DogSpike extends Animal {
override val name: String = "Spike"
}
this call then works (calls apply)
myTransformation(() => DogSpike(this))
Now I would like to create a more generic object that one can pass arguments but I am unable to.
It would work to create a derived Object from Animal that takes one arguments and being able to use the apply call
object TheDog(name: String) extends Animal {
override val name: String = "Spike"
//...
}
not sure how to implicitly call Animal.apply for TheDog object where I could pass a parameter (name)
myTransformation(() => TheDog(this))
// also this seems to be incorrect "*Wrong top statement declaration*"
object TheDog(val n: String) extends Animal {
override val name: String = n
//...
}
As of *Wrong top statement declaration* (I can understand only this part of your question) - you can't have constructor in object as object is a singleton, so you should use a case class (ADT):
final case class TheDog(name: String) extends Animal
scala>TheDog("Spike")
res2_2: TheDog = TheDog("Spike")
val and companion object with apply is added automatically for case classes, so you don't need to define your own own apply in Animal. case class TheDog(val name: String) is same as case class TheDog(name: String).
I's also use traits instead of abstract class:
trait Animal {
val name: String
def getSomething: String = {
"Dog: " + name
}
}
I don't understand your TypeClass type, but if you really want type classes:
trait Animal {
def name: String
}
final case class TheDog(name: String) extends Animal
final case class TheCat(name: String) extends Animal
implicit class RichDog(dog: TheDog){
def getSomething: String = {
"Dog" + dog.name
}
}
implicit class RichCat(cat: TheCat){
def getSomething: String = {
"Cat: " + cat.name
}
}
scala> TheDog("Spike").getSomething
res4_5: String = "DogSpike"
scala> TheCat("Tom").getSomething
res4_6: String = "Cat: Tom"
About calling apply "implicitly", I don't know why would anyone need this, but:
trait AnimalFactory[A <: Animal] {
def apply(name: String)(implicit constructor: String => A) = constructor(name)
}
object TheeeDog extends AnimalFactory[TheDog]
implicit def createDog(name: String) = TheDog(name)
TheeeDog("Spike")
Of course you have to provide createDog and make it visible for a client, but it doesn't really make sense if you can just use ADTs and define additional required applys in companion object:
case class TheMouse(name: String)
object TheMouse{
def apply(isJerry: Boolean): TheMouse = if (isJerry) TheMouse("Jerry") else TheMouse("NotJerry")
}
TheMouse(true)
If you want to add some parameter to constructor, just add it:
class AnimalFactory(clazz: SomeClass){
def doSomething = clazz.name
def apply(name: String)
}
val dogFactory = new AnimalFactory(dogClassDescriptor)
val catFactory = new AnimalFactory(catClassDescriptor)
dogFactory("Spike")
catFactory("Tom")
You can even create a factory for factory (I wouldn't recommend - this solution already looks overcomplicated):
object AnimalFactory{ //please don't use classes for that - avoiding `new` is not their purpose
def apply(clazz: SomeClass) = new AnimalFactory(clazz)
}
val dogFactory = AnimalFactory(dogClassDescriptor)
//or even `val spike = AnimalFactory(dogClassDescriptor)("Spike")`
But still what's the point if you could just provide underlying clazz either as a member or just in a wrapper:
final case class ClazzWrapper[T <: Animal](clazz: SomeClass, animal: T)
Assuming I have a simple abstract base class like so:
abstract class MyAbstractBaseClass {
def hello : Unit
}
and then I write a "stacking" trait like so:
trait MyTrait extends MyAbstractBaseClass {
abstract override def hello : Unit =
{
super.hello
println("How are you?");
}
}
then why won't Scala let me define a subclass as follows:
class MyClass extends MyAbstractBaseClass with MyTrait {
override def hello : Unit = println("Hello!")
}
error: overriding method hello in trait MyTrait of type => Unit;
method hello needs `abstract override' modifiers
If I try their suggestion of using 'abstract override':
class MyClass extends MyAbstractBaseClass with MyTrait {
abstract override def hello : Unit = println("Hello!")
}
error: `abstract override' modifier only allowed for members of traits
Can anyone help me understand this?
P.S. I know that the below does work:
class MyClass extends MyAbstractBaseClass {
override def hello : Unit = println("Hello!")
}
val x = new MyClass with MyTrait
x.hello
Hello!
How are you?
but am trying to understand why the former does not.
In summary: why can't I provide an implementation of the abstract base class - while also taking advantage of the trait's functionality?
The trick is that you can't have an "abstract" method in the flow of the linearization, that is called from a super call.
Try this, you will see it compiles:
abstract class MyAbstractBaseClass {
def hello : Unit
}
class SubClass extends MyAbstractBaseClass {
def hello {
println("toto")
}
}
trait MyTrait extends MyAbstractBaseClass {
abstract override def hello : Unit =
{
super.hello
println("How are you?")
}
}
class MyClass extends SubClass with MyTrait { //note the CONCRETE SubClass here
override def hello : Unit = println("Hello!")
}
new MyClass().hello
You got the error, because the compiler starts with MyTrait (at the top of the stack, so the first to be called) and that MyTrait calls through super an abstract method... (of MyAbstractBaseClass) => it crashes since your super call can't target immediately a concrete method.
In my code snippet, you will notice that MyTrait is "at the top" (during linearization) of a concrete Subclass class, that makes the trick.