How do I pass an inherited variable into a Auxiliary constructor from a trait - scala

I'm looking to get the value bork and pass it to a class into the class in the constuctor.
trait dog {
lazy val bork = "bork"
}
class Animal(val firstName: String, dogCommand: DogCommand) extends dog{
def this(firstName: String) {
this(firstName, DogCommand(bork))
}
def getDogCommand(): Unit = {
dogCommand.getCommand()
}
}
case class DogCommand(command: String) {
def getCommand() :Unit = {
println(command)
}
}
val myDog = new Animal("first")
myDog.getDogCommand()
I usually get - error: not found: value bork

The problem is that bork is a value on dog but there is no instance of dog available to read the bork from. this is a constructor so it doesn't have access to the value that is being constructed.
This is one solution that retains most of the original code:
trait dog {
def bork = dog.DefaultBork
}
object dog {
val DefaultBork = "bork"
}
class Animal(val firstName: String, dogCommand: DogCommand) extends dog {
def this(firstName: String) = this(firstName, DogCommand(dog.DefaultBork))
...
}
You could consider removing the default value of bork in dog so that any class implementing the trait is required to provide a value for bork. (It can always use DefaultBork if it wants to retain the default value)

For one item, your this constructor is incorrect. I also renamed Dog. As for your lazy val that wouldn't work on a trait. See more here why scala don't allow define lazy val in trait?. Even if you make it non-lazy, that value is not initialized yet until construction when that val is not available, yet. Another problem would also be logic, an Animal is not Dog, but the other way around. Here is an alternative: https://scastie.scala-lang.org/WnhxzSn6QtOf5vo1epDDqQ Hope that helps. ;)
trait Dog {
lazy val bork = "bork"
}
class Animal(val firstName: String, dogCommand: DogCommand) extends Dog {
def this(firstName: String) = this(firstName, DogCommand(bork))
def getDogCommand(): Unit = {
dogCommand.getCommand()
}
}
case class DogCommand(command: String) {
def getCommand() :Unit = {
println(command)
}
}
val myDog = new Animal("first")
myDog.getDogCommand()

Related

How can I reference a companion object's method in a generic class?

So I am a bit new to scala.
How does one write scala code to reference a method from case class's companion object in a generic fashion? I have tried a couple of different approaches and can't seem to find one that works.
Below is some sample code that works, but I have to manually build each subclass.
For example:
class One extends Act[LetterA] {
val intro = LetterA.sayhi
}
I would much rather do something like:
class AllOfThem[T <: LettersClass, S <: LettersSingleton] extends Act[T] {
val intro = S.sayhi
}
but I can't seem to find syntax that works or will compile. What is the proper way to do this, or am I looking for something that is not supported in the language? I recognise I am probably a little off on how I am structuring my classes and traits, but I am not sure how to best tackle this desired behaviour.
Additionally, is there a way to something similar to what I have commented out in the method 'actionTwo' in the Act class?
Sample Code listing:
trait LettersSingleton {
def sayhi() : String
}
trait LettersClass {
val id : Int
}
// trait Letters extends LettersClass with LettersSingleton { }
object LetterA extends LettersSingleton {
def sayhi = "Hi I am A"
}
object LetterB extends LettersSingleton {
def sayhi = "Hi I am B"
}
case class LetterA( val id : Int ) extends LettersClass { }
case class LetterB( val id : Int, val name:String ) extends LettersClass { }
abstract class Act[ T <: LettersClass ] {
val intro : String
def actionOne( a : T ) = {
println( a.id + " is my id" )
}
def actionTwo() = {
// println( T.sayhi )
}
}
class One extends Act[LetterA] {
val intro = LetterA.sayhi
}
class Two extends Act[LetterB] {
val intro = LetterB.sayhi
}
So you can't do exactly what you want, but you can get very close with the commonly used typeclass pattern:
//add a type parameter, now you have a typeclass
trait LettersSingleton[T] {
def sayhi() : String
}
//LettersClass stays the same
object Implicits {
//implicit classes/objects have to go inside an object
//create typeclass instances as implicit objects
implicit object LetterASingleton extends LettersSingleton[LetterA] {
def sayhi = "Hi I am A"
}
implicit object LetterBSingleton extends LettersSingleton[LetterB] {
def sayhi = "Hi I am B"
}
}
import Implicits._
//add an implicit parameter to the class
abstract class Act[ T <: LettersClass ](implicit singleton: LettersSingleton[T]) {
def actionTwo() = {
println( singleton.sayhi )
}
}
(new Act[LetterA]).actionTwo() //prints "Hi I am A"
(new Act[LetterB]).actionTwo() //prints "Hi I am B"
So basically what happens is any time you create a new Act[T], the compiler is going to try to fill in the implicit parameter for you by looking for any implicit objects or vals of the correct type in scope. So
val a = new Act[LetterA]
will actually become
val a = new Act[LetterA](LetterASingleton)
You'll notice that the singletons are no longer the companion objects of the case classes, which is fine. You have to define a trait regardless, so it doesn't make much different whether it's the companion object or some other object that implements it.

Scala: Requiring members on companion objects of abstract classes

I'd like to create an abstract class, and be able to add members to it that reference attributes of the implementing class's companion object. Something like this (Scala pseudocode):
abstract class Fruit(cultivar: String) {
// How do I reference the implementing class's companion object here?
def isTastyCultivar(): Boolean = Fruit.tastyCultivars.contains(cultivar)
}
// how do I implement what I am thinking of as "the abstract companion object"
abstract object Fruit {
val tastyCultivars: Set[String] // must be implemented
// by the concrete object
}
class Apple(cultivar: String) extends Fruit(cultivar) {
}
object Apple extends Fruit{ // presumably this is not correct;
// it needs to extend the FruitObject
// or whatever it is
val tastyCultivars: Set[String] = Set("Red Delicious", "Granny Smith")
}
class Tomato(cultivar: String) extends Fruit(cultivar) {
}
object Tomato extends Fruit{
val tastyCultivars = Set("Roma")
}
val a1 = new Apple("Red Delicious")
val a2 = new Apple("Honeycrisp")
a1.isTastyCultivar() // should return true
a2.isTastyCultivar() // should return false
val t1 = new Tomato("Roma")
val t2 = new Tomato("San Marzano")
t1.isTastyCultivar() // should return true
t2.isTastyCultivar() // should return false
Sorry if this is a dumb question, or if asked previously (I'm not confident in how to word this question so I couldn't easily search for it). Thanks in advance!
One possible solution is to use the type class pattern. We have our domain model (or algebra) via ADTs:
sealed trait Fruit
case class Apple() extends Fruit
case class Orange() extends Fruit
We have our type class, which defines the structure we want to supply:
trait TastyCultivarSupplier[T <: Fruit] {
def tastyCultivars: Set[String]
}
And now each type which has tasty cultivars will need to implement the type class in order to provide them. One possible way to do this is to implement the typeclass inside the companion object:
object Apple {
implicit def appleTastyCultivars = new TastyCultivarSupplier[Apple] {
override def tastyCultivars: Set[String] = Set("Yummy stuff")
}
}
Inside the consumer, or the type which wants to get the tasty cultivars, we require an implicit evidence of a TastyCultivarSupplier:
class TastyCultivarConsumer {
def isTasty[T: TastyCultivarSupplier](name: String): Boolean =
implicitly[TastyCultivarSupplier[T]].tastyCultivars.contains(name)
}
When isTasty is invoked, it will need to have one of the suppliers in scope, otherwise a compile time error will occur:
def main(args: Array[String]): Unit = {
println(new TastyCultivarConsumer().isTasty("Yummy stuff"))
}
Will give us:
Error:(33, 48) could not find implicit value for evidence parameter
of type TastyCultivarSupplier[T]
println(new TastyCultivarConsumer().isTasty("Yummy stuff"))
To fix this, we import the supplier we want:
def main(args: Array[String]): Unit = {
import Apple._
println(new TastyCultivarConsumer().isTasty("Yummy stuff"))
}
And now our code compiles. Note that the implementer isn't forced to write the evidence inside the companion object, he is free to do so anywhere he wants, as long as it's in scope for the compiler to find.
A simple solution (the one Scala Collections use): just add a method returning the companion to the class.
trait FruitCompanion {
val tastyCultivars: Set[String]
}
abstract class Fruit(cultivar: String) {
def companion: FruitCompanion
def isTastyCultivar(): Boolean = companion.tastyCultivars.contains(cultivar)
}
class Apple(cultivar: String) extends Fruit(cultivar) {
def companion = Apple
}
object Apple extends FruitCompanion {
val tastyCultivars: Set[String] = Set("Red Delicious", "Granny Smith")
}
Note that you can't enforce that the companion actually returns the companion object, but you don't really need it.
It is not possible to do what you are asking.
You are asking about overriding members of object. objects in scala are equivalent of static classes in Java with all members being static.
Companion object with its class would be a class with both static and none static members in Java.
You can't override them. You can't do it in Java and you can't do it in Scala.
Alternative solution:
Just define tastyCultivars in class.
abstract class Fruit(cultivar: String) {
val tastyCultivars: Set[String]
def isTastyCultivar(): Boolean = tastyCultivars.contains(cultivar)
}
class Apple(cultivar: String) extends Fruit(cultivar) {
val tastyCultivars: Set[String] = Set("Red Delicious", "Granny Smith")
}
class Tomato(cultivar: String) extends Fruit(cultivar) {
val tastyCultivars = Set("Roma")
}
val a1 = new Apple("Red Delicious")
val a2 = new Apple("Honeycrisp")
println("Should return true, is " + a1.isTastyCultivar())
println("Should return false, is " +a2.isTastyCultivar())
val t1 = new Tomato("Roma")
val t2 = new Tomato("San Marzano")
println("Should return true, is " +t1.isTastyCultivar())
println("Should return false, is " +t2.isTastyCultivar())
Output:
$ scala fruit.scala
Should return true, is true
Should return false, is false
Should return true, is true
Should return false, is false
Many thanks to Yuval for teaching me about typeclasses; I have written a solution using his technique which satisfies all my original criteria:
// Fruit instance members
abstract class FruitClass(cultivar: String) {
def getCultivar: String = cultivar
}
// Obviously not really an object but serves the purpose of
// the thing I envisioned as the "abstract object" which is not a thing
// I.e., a place to put fruit static members
trait FruitObject[A <: FruitClass] {
// Any subclass of fruit must (statically) specify their set of tasty cultivars...
val tastyCultivars: Set[String]
// ...but they can inherit the common implementation of isTastyCultivar()
def isTastyCultivar(x: A): Boolean = tastyCultivars contains x.getCultivar
}
// Subclass #1: Apples
class Apple(cultivar: String) extends FruitClass(cultivar)
implicit object AppleIsFruit extends FruitObject[Apple] {
val tastyCultivars = Set("Red Delicious", "Granny Smith")
}
// Subclass #2: Tomatoes
class Tomato(cultivar: String) extends FruitClass(cultivar)
implicit object TomatoIsFruit extends FruitObject[Tomato] {
val tastyCultivars = Set("Roma")
}
def isTastyCultivar[A <: FruitClass: FruitObject](thing: A) =
implicitly[FruitObject[A]].isTastyCultivar(thing)
isTastyCultivar(new Apple("Red Delicious")) // true
isTastyCultivar(new Apple("Honeycrisp")) // false
isTastyCultivar(new Tomato("Roma")) // true
isTastyCultivar(new Tomato("San Marzano")) // false
Gustek is quite right that object members cannot be overridden but this method seems to achieve the same effect without actually using a companion object for Fruit to declare static members.

Scala - object extends abstract class and takes parameters

//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)

How to create a factory for a parameterized class?

I'm trying to build a factory for implementations of a generic trait.
Given my domain model:
trait Person
case class Man(firstName: String, lastName: String) extends Person
case class Woman(firstName: String, lastName: String) extends Person
I created a repository for those classes like this:
trait Repository[T <: Person] {
def findAll(): List[T]
}
class ManRepository extends Repository[Man] {
override def findAll(): List[Man] = {
List(
Man("Oliver", "Smith"),
Man("Jack", "Russel")
)
}
}
class WomanRepository extends Repository[Woman] {
override def findAll(): List[Woman] = {
List(
Woman("Scarlet", "Johnson"),
Woman("Olivia", "Calme")
)
}
}
So far so good, some pretty simple classes. But I'd wanted to create a factory to create an instance of these repositories depending on some parameters.
object RepositoryFactory {
def create[T <: Person](gender: String): Repository[T] = {
gender match {
case "man" => new ManRepository()
case "woman" => new WomanRepository()
}
}
}
But this last piece won't compile. If I ommit the explicit return type of the factory, it compiles but returns a repository of type Repository[_1] instead of Repository[Man]
I can't seem to find a proper solution, do any of you guys have got some tips for me?
How about this?
Instead of using a string, use a sealed trait that knows how to create the appropriate repo
Use dependent types to return the correct type of repository
Code:
object GenderStuff {
trait Person
case class Man(firstName: String, lastName: String) extends Person
case class Woman(firstName: String, lastName: String) extends Person
// Note that Repository has to be covariant in P.
// See http://blogs.atlassian.com/2013/01/covariance-and-contravariance-in-scala/ for explanation of covariance.
trait Repository[+P <: Person] {
def findAll(): List[P]
}
class ManRepository extends Repository[Man] {
override def findAll(): List[Man] = {
List(
Man("Oliver", "Smith"),
Man("Jack", "Russel")
)
}
}
class WomanRepository extends Repository[Woman] {
override def findAll(): List[Woman] = {
List(
Woman("Scarlet", "Johnson"),
Woman("Olivia", "Calme")
)
}
}
sealed trait Gender {
type P <: Person
def repo: Repository[P]
}
case object Male extends Gender {
type P = Man
def repo = new ManRepository()
}
case object Female extends Gender {
type P = Woman
def repo = new WomanRepository()
}
object RepositoryFactory {
def create(gender: Gender): Repository[gender.P] = gender.repo
// or if you prefer you can write it like this
//def create[G <: Gender](gender: G): Repository[G#P] = gender.repo
}
val manRepo: Repository[Man] = RepositoryFactory.create(Male)
val womanRepo: Repository[Woman] = RepositoryFactory.create(Female)
}
Of course, this makes the factory object pretty pointless - it's easier to just call Male.repo directly :)
You should probably think some more about what you're trying to achieve. In your example, what type would you expect to be returned by RepositoryFactory.create[Man]("woman")? The compiler has no way to associate those arbitrary strings with types.

How can I create one copy of a piece of data per subclass?

I have the following trait:
trait Mappable {
def toMap = {
val mappableFields = this.getClass.getDeclaredFields.filter(...)
...
}
}
mappableFields lists this.declaredFields and then applies static filters to the list; as such it is invariant for each class that implements Mappable, and ideally I'd like to be able to put it in the subclasses' singleton objects or something along those lines. My current solution is
object Mappable {
import scala.collection.mutable.Map
private val fieldMap = Map[Class[_], Array[Field]]()
def getFieldMap(clazz: Class[_]) = {
fieldMap.get(clazz) match {
case Some(array) => array
case _ => {
val mapFields = clazz.getDeclaredFields.filter(...)
fieldMap.put(clazz, mapFields)
mapFields
}}}}
trait Mappable {
def toMap = {
val mappableFields = Mappable.getFieldMap(this.getClass)
...
}
}
but I'm wondering if there's a better solution e.g. one that doesn't require a call to Map#get. I can't turn the trait into a class.
You could do something like this:
trait Mappable {
def companion: MappableCompanion
def toMap = {
val mappableFields = companion.mappableFields
...
}
}
trait MappableCompanion {
def thisClass: Class[_]
val mappableFields = thisClass.getDeclaredFields.filter(...)
}
Subtypes of Mappable would then also define a companion object:
class Foo extends Mappable {
def companion = Foo
}
object Foo extends { val thisClass = classOf[Foo] } with MappableCompanion
If you don't like the early initializer you can make MappableCompanion a class.