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.
Related
I have a simple trait
trait SomeTrait {
val sourceData: SourceData
}
SourceData class has constructor parameter p: Array[String].
Now, when I extend this trait in Object, we must provide implementation for sourceData.
object SomeObject extends SomeTrait {
override val sourceData: SourceData = ???
def main(sysArgs: Array[String]){...}
}
But what if class SourceData needs sysArgs from main method, how can I override sourceData in main method, not in body of SomeObject. Something like this:
object SomeObject extends SomeTrait {
def main(sysArgs: Array[String]){
override val sourceData: SourceData = new SourceData(sysArgs)
}
}
I do not want to use var, as val immutability is preferred. And also I want to have trait with no implementation in order to force all sub classes to implement sourceData. What other solution I have for this?
You can't avoid mutability in this situation. sourceData must have a value before main is called, and main must be able to change that value, so the value must be mutable.
One option is to make sourceData a def (which is a good idea anyway) and have it access a private var in SomeObject:
trait SomeTrait {
def sourceData: SourceData
}
object SomeObject extends SomeTrait {
private var mySource: SourceData = ???
def sourceData = mySource
def main(sysArgs: Array[String]) = {
mySource = new SourceData(sysArgs)
}
}
The root problem here is having a top-level object that needs run-time initialisation. This is required because SomeObject is a top-level object that is accessed directly from other parts of the code.
The solution to this is dependency injection rather than a global object.
trait SomeTrait {
def sourceData: SourceData
}
object SomeObject {
case class SomeData(sourceData: SourceData) extends SomeTrait
def main(sysArgs: Array[String]) = {
val theSource = SomeData(SourceData(sysArgs))
// Pass this instance to the rest of the code that needs it
restOfTheProgram(theSource)
}
}
The rest of the code uses the instance of SomeTrait that is passed to it rather than using SomeObject directly.
There is no way to do that in Scala. You need to have a class inherit SomeTrait and instantiate it from the main method.
I need to define a bunch of similar enums:
object Color extends MyEnum[Color.Color] {
type Color = Value
val Red, Green, Periwinkle = Value
}
object Shape extends MyEnum[Shape.Shape] {
type Shape = Value
val Square, Circle, Balbis = Value
}
I'd like to extract shared functionality into an abstract class or trait, to support 1) apply and unapply methods, and 2) implicit conversions from enums to their string representations:
abstract class MyEnum[T] extends Enumeration {
implicit def valueToString(value: T): String = value.toString
implicit def stringToValue(string: String): T = apply(string)
def unapply(arg: String): Option[T] =
values.find(_.toString == arg).map(_.asInstanceOf[T])
def apply(arg: String): T =
values.find(_.toString == arg)
.getOrElse(sys.error(s"Invalid value '$arg'"))
.asInstanceOf[T]
}
This doesn't compile; when I add the type param in MyEnum[Color.Color], it breaks the Value type for some reason.
Is there some way to get what I want with this enum syntax, or do I need to switch to a case object solution (or something more complicated)?
This Blog discusses the Enumeration Hell in Scala: scala-enumerations-hell
The solution is not to use Scala's Enumeration type but create your own Enumeration class. Here is the abstract class from that blog:
abstract class Enum[Enum : ClassTag] { self =>
val values = {
import runtime.universe._
val mirror = runtimeMirror(self.getClass.getClassLoader)
val classSymbol = mirror.classSymbol(self.getClass)
classSymbol.toType.members
.filter(_.isModule)
.map(symbol => mirror.reflectModule(symbol.asModule).instance)
.collect { case v: Enum => v }
}
def forName(name: String): Option[Enum] = values.find(_.name == name)
implicit class RichardEnum(enum: Enum) {
def name: String = enum.toString
}
}
There is also a framework that provides that for you: lloydmeta/enumeratum
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.
Just when I thought I understood the basics of Scala's type system... :/
I'm trying to implement a class that reads the contents of a file and outputs a set of records. A record might be a single line, but it could also be a block of bytes, or anything. So what I'm after is a structure that allows the type of Reader to imply the type of the Record, which in turn will imply the correct Parser to use.
This structure works as long as MainApp.records(f) only returns one type of Reader. As soon as it can return more, I get this error:
could not find implicit value for parameter parser
I think the problem lies with the typed trait definitions at the top, but I cannot figure out how to fix the issue...
// Core traits
trait Record[T]
trait Reader[T] extends Iterable[Record[T]]
trait Parser[T] {
def parse(r: Record[T]): Option[Int]
}
// Concrete implementations
class LineRecord[T] extends Record[T]
class FileReader[T](f:File) extends Reader[T] {
val lines = Source.fromFile(f).getLines()
def iterator: Iterator[LineRecord[T]] =
new Iterator[LineRecord[T]] {
def next() = new LineRecord[T]
def hasNext = lines.hasNext
}
}
trait TypeA
object TypeA {
implicit object TypeAParser extends Parser[TypeA] {
def parse(r: Record[TypeA]): Option[Int] = ???
}
}
trait TypeB
object TypeB {
implicit object TypeBParser extends Parser[TypeB] {
def parse(r: Record[TypeB]): Option[Int] = ???
}
}
// The "app"
object MainApp {
def process(f: File) =
records(f) foreach { r => parse(r) }
def records(f: File) = {
if(true)
new FileReader[TypeA](f)
else
new FileReader[TypeB](f)
}
def parse[T](r: Record[T])(implicit parser: Parser[T]): Option[Int] =
parser.parse(r)
}
First off you must import the implicit object in order to use them:
import TypeA._
import TypeB._
That's not enough though. It seems like you're trying to apply implicits dynamically. That's not possible; they have to be found compile time.
If you import the objects as above and change the records so that the compiler finds the correct generic it will run fine:
def records(f: File) = new FileReader[TypeA](f)
But then it may not be what you were looking for ;)
The problem is that the return type of your records method is basically FileReader[_] (since it can return either FileReader[TypeA] or FileReader[TypeB]), and you don't provide an implicit argument of type Parser[Any]. If you remove the if-expression the return type is inferred to FileReader[TypeA], which works fine. I'm not sure what you're trying to do, but obviously the compiler can't select implicit argument based upon a type that is only known at runtime.
1) Using type with implicit inside as type parameter - doesn't bind this implicit to the host type, to do this change objects to the traits and mix them instead of generalizing (type-parametrizing):
def records(f: File) = {
if(true)
new FileReader(f) with TypeA
else
new FileReader(f) with TypeB
}
2) The parser should be in scope of function that calls parse. So you may try smthg like that:
def process(f: File) = {
val reader = records(f);
import reader._
reader foreach { r => parse(r) }
}
PlanB) Simpler alternative is to define type-parameter specific implicit methods inside the AppMain (or some trait mixed in), but it will work only if TypeA/TypeB is known on compile time, so records method can return concrete type:
implicit class TypeAParser(r: Record[TypeA]) {
def parse: Option[Int] = ???
}
implicit class TypeBParser(r: Record[TypeB]) {
def parse: Option[Int] = ???
}
def process[T <: TypeAorB](f: File) =
records[T](f).foreach(_.parse)
def recordsA[T <: TypeAorB](f: File) = new FileReader[T](f)
Here is, I think, the full set of modifications you need to do to get where I think you want to go.
import scala.io.Source
import java.io.File
import reflect.runtime.universe._
// Core traits
trait Record[+T]
trait Reader[+T] extends Iterable[Record[T]]
trait Parser[-T] {
def parse(r: Record[T]): Option[Int]
}
// Concrete implementations [unmodified]
class LineRecord[T] extends Record[T]
class FileReader[T](f:File) extends Reader[T] {
val lines = Source.fromFile(f).getLines()
def iterator: Iterator[LineRecord[T]] =
new Iterator[LineRecord[T]] {
def next() = new LineRecord[T]
def hasNext = lines.hasNext
}
}
sealed trait Alternatives
case class TypeA() extends Alternatives
object TypeA {
implicit object TypeAParser extends Parser[TypeA] {
def parse(r: Record[TypeA]): Option[Int] = ???
}
}
case class TypeB() extends Alternatives
object TypeB {
implicit object TypeBParser extends Parser[TypeB] {
def parse(r: Record[TypeB]): Option[Int] = ???
}
}
class ParseAlternator(parserA: Parser[TypeA], parserB: Parser[TypeB]) extends Parser[Alternatives] {
def parse(r: Record[Alternatives]): Option[Int] = r match {
case x: Record[TypeA #unchecked] if typeOf[Alternatives] =:= typeOf[TypeA] => parserA.parse(x)
case x: Record[TypeB #unchecked] if typeOf[Alternatives] =:= typeOf[TypeB] => parserB.parse(x)
}
}
object ParseAlternator {
implicit def parseAlternator(implicit parserA: Parser[TypeA], parserB: Parser[TypeB]): Parser[Alternatives] = new ParseAlternator(parserA, parserB)
}
// The "app"
object MainApp {
import ParseAlternator._
def process(f: File) =
records(f) foreach { r => parse(r) }
def records(f: File): Reader[Alternatives] = {
if(true)
new FileReader[TypeA](f)
else
new FileReader[TypeB](f)
}
def parse[T](r: Record[T])(implicit parser: Parser[T]): Option[Int] =
parser.parse(r)
}
The gist of it is: all of this would be completely classsical if only your parse instance did not have to pattern-match on a generic type but dealt directly with an Alternative instead.
It's this limitation (inherited from the JVM) that scala can't properly pattern-match on an object of a parametric type that requires the reflection & typeOf usage. Without it, you would just have type alternatives for your content (TypeA, TypeB), which you would add to a sealed trait, and which you would dispatch on, in an implicit that produces a Parser for their supertype.
Of course this isn't the only solution, it's just what I think is the meeting point of what's closest to what you're trying to do, with what's most idiomatic.
There is the following API for Slick CRUD (Slick-2.1.0, Scala-2.11.4):
trait HasId {
type Id
def id: Option[Id]
}
trait HasIdColumn[E <: HasId] {
def id: scala.slick.lifted.Column[E#Id]
}
trait SlickExtensions {
val driver: scala.slick.driver.JdbcProfile
import driver.simple._
trait BaseDAO[T <: Table[E], E] {
val query: TableQuery[T]
}
trait HasIdActions[T <: Table[E] with HasIdColumn[E], E <: HasId]
extends BaseDAO[T, E] {
//line L1: this implicit val is needed to execute query.filter(_.id === id)
// what can be done in order to save the user from the necessity
// to override this value?
implicit val mappingId: BaseColumnType[E#Id]
def findById(id: E#Id)(implicit session: Session): Option[E] =
query.filter(_.id === id).firstOption
...
}
}
I apply this SlickExtensions as follows:
case class Entity(id: Option[Long] = None, value: String) extends HasId {
type Id = Long }
trait EntityComponent extends SlickExtensions {
import driver.simple._
class EntitiesTable(tag: Tag) extends Table[Entity](tag, "entities")
with HasIdColumn[Entity] {
def id = column[Long]("id", O.PrimaryKey, O.AutoInc)
def value = column[String]("value", O.NotNull)
def * = (id.?, value) <>(Entity.tupled, Entity.unapply)
}
object Entities extends HasIdActions[EntitiesTable, Entity] {
val query = TableQuery[EntitiesTable]
/* line L2: from slick library: ImplicitColumnTypes */
override implicit val mappingId = driver.simple.longColumnType
}
}
End point to execute queries:
val c = new EntityComponent {
lazy val driver = play.api.db.slick.Config.driver
}
db.withSession { implicit session =>
c.Entities.findById(1) foreach println
}
The main question is how to get rid of "implicit val mappingId" overriding in line L2?
I tried to create a class:
abstract class IdImplicits[E<:HasId](implicit val mappingId:BaseColumnType[E#Id])
and inherited it as follows:
object Entities extends IdImplicits[EntitiesTable, Entity]
with HasIdActions[EntitiesTable, Entity] {
val query = TableQuery[EntitiesTable]
//override implicit val mappingId: driver.simple.longColumnType
}
However it seems to me that such approach is redundant.
It would be great if I could hide "implicit val mappingId" inside SlickExtensions.
Here is the link to the same question
UPD:
In my project, I'd like to add HasName, HasValue[V] and some other mixins to construct the following DAOs:
object EntitiesDAO extends HasIdActions
with HasNameActions
with HasValueActions with NameToIdActions with ValueToIdActions {
...
override def nameToId(name:String):Option[E#Id]
override def valueToId(value:E#ValueType):Option[E#Id]
...
}
It leads to the following problems:
1) implicits for BaseColumnTypes, mentioned in my topic, should be taken into consideration for HasId, HasValue mixins
2) If implicits BaseColumnTypes are used as parameters of constructor of abstract classes then these classes can't be mixed in one EntityDAO object (the problem is described here).
3) If one abstract class is used for each variant of EntityDAO, then we get ugly-looking combinations, for example:
abstract class IdValueNameImplicits[E <: HasId with HasValue with HasName]
(implicit val idMapper:BaseColumnType[E#Id],
implicit val valueMapper:BaseColumnType[E#ValueType])
You can't do that because you are inside a trait and E#Id is only defined when you have a concrete implementation of it.
As you already discovered, you have to define your BaseColumnType when your trait is implemented because only then you have a defined type for E#Id.
Another option is not to have a trait but an abstract class where you can have a implicit BaseColumnType passed to the constructor.
I have a small project that does exactly what you are looking for. You can find it here: https://github.com/strongtyped/active-slick
There is also an Activator template.
http://typesafe.com/activator/template/slick-active-record
You can use it as is or as inspiration for your own.
Have fun!