When I attempt to apply partial construction of a case class through a series of other classes, I get an unexpected (at least to me) result.
This is scala 2.11.12
object PartiallyAppliedWeirdness {
case class Person(dob: String)(name: String)
class Born(dob: String) {
def namingFunction: String => Person = Person(dob)
}
class Naming(bornPerson: Born,name: String) {
def namingFunction: Person = bornPerson.namingFunction (name)
}
def main(args: Array[String]): Unit = {
val birth: Born = new Born("2010-01-01")
val somPerson: Person = new Naming(birth, "Dave").namingFunction
println(somPerson)
println(somPerson.getClass)
}
}
Result
Person(2010-01-01)
class PartiallyAppliedWeirdness$Person
How can this be! Can any one explain what is going on here?
Thanks
Related
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()
I have a lot of classes such as DataFrameFlow, TextFlow, RDDFlow. They all derive from base class Flow.
Now I want to write a function judgeFlow which can read from a path: String and return something representing exact Flow type from which I can create corresponding instance. The whole code seems like the following
def judgeFlow(path:String) = /*1*/ {
Flow.getStoreType(path) match {
case StoreType.tdw =>
DataFrameFlow
case StoreType.hdfs =>
TextFlow
}
}
def createFlow(typeInfo:/*2*/) = /*3*/{
new typeInfo()
}
However, I don't know how to write in place 1, 2 and 3.
EDIT
Knowing how to construct them is not enough here, because I also want the following:
pattern matching through typeInfo
some ways to do asInstanceOf
EDIT 2
Definition of Flow
abstract class Flow(var outputName: String) extends Serializable{
def this() = this("")
...
}
Definition of DataFrameFlow
class DataFrameFlow(d: DataFrame, path: String) extends Flow {
var data: DataFrame = d
def this(data: DataFrame) = this(data, "")
def this(path: String) = this(null, path)
def this() = this(null, "")
...
}
Pattern matching can't return different types from different cases. The type returned by pattern matching is the least upper bound of types returned in cases.
When someone wants to return different types, most probably he/she wants a type class.
sealed abstract class Flow
class DataFrameFlow extends Flow
class TextFlow extends Flow
class RDDFlow extends Flow
trait JudgeFlow[In] {
type Out <: Flow
def judgeFlow(in: In): Out
}
object JudgeFlow {
implicit val `case1`: JudgeFlow[???] { type Out = DataFrameFlow } = ???
implicit val `case2`: JudgeFlow[???] { type Out = TextFlow } = ???
implicit val `case3`: JudgeFlow[???] { type Out = RDDFlow } = ???
}
def judgeFlow[In](in: In)(implicit jf: JudgeFlow[In]): jf.Out = jf.judgeFlow(in)
But the trouble is that types are resolved at compile time. You seem to want to choose a case based on a value of string i.e. at runtime. So you can't return more specific types than just Flow at compile time.
flatMap with Shapeless yield FlatMapper not found
It's hard to guess your use case completely.
But using Scala reflection you can try
import scala.reflect.runtime.universe._
import scala.reflect.runtime.currentMirror
def judgeFlow(path:String): Type = {
Flow.getStoreType(path) match {
case StoreType.tdw =>
typeOf[DataFrameFlow]
case StoreType.hdfs =>
typeOf[TextFlow]
}
}
def createFlow(typeInfo: Type): Flow = {
val constructorSymbol = typeInfo.decl(termNames.CONSTRUCTOR).asMethod
val classSymbol = typeInfo.typeSymbol.asClass
val classMirror = currentMirror.reflectClass(classSymbol)
val constructorMirror = classMirror.reflectConstructor(constructorSymbol)
constructorMirror().asInstanceOf[Flow]
}
I´ve been watching some examples of monads transformers with Cats, and I was trying to reproduce those in Scalaz
Here I have a for comprehension where I first receive an optional which I flatMap with OptionalT, and the second function return a Future of Employee.
Here my code
//Attributes for this example
sealed trait Employee {
val id: String
}
final case class EmployeeWithoutDetails(id: String) extends Employee
final case class EmployeeWithDetails(id: String, name: String, city: String, age: Int) extends Employee
case class Company(companyName: String, employees: List[EmployeeWithoutDetails])
trait HybridDBOps {
protected def getDetails(employeeId: String): Future[EmployeeWithDetails]
protected def getCompany(companyName: String): Option[Company]
}
class DbHybrid extends HybridDBOps {
override def getDetails(employeeId: String): Future[EmployeeWithDetails] = Future {
EmployeeWithDetails("1", "name", "city", 36)
}
override def getCompany(companyName: String): Option[Company] = Some(Company(companyName, List(EmployeeWithoutDetails("1"))))
}
def getEmployeeAgeScalaZHybrid(employeeId: String, companyName: String): Future[Option[Int]] = {
val db = new DbHybrid
val eventualOption = (for {
company <- OptionT.fromOption(db.getCompany(companyName)) --> Wont compile
if company.employees map (_.id) contains employeeId
details <- OptionT.liftF(db.getDetails(employeeId)) --> Wont compile
} yield details.age).run
eventualOption
}
This code is from cats version, and in scalaz the OptionT.fromOption to wrap a Option does not exist, I notice that I can do OptionT(Some(db.getCompany(companyName)) and then compile but now the signature of the method says that I returning an Optional instead of a future.
Also how can use the OptionT.liftF in ScalaZ
Here the complete example https://github.com/politrons/reactiveScala/blob/master/scala_features/src/main/scala/app/impl/scalaz/MonadTransformer.scala
Regards.
These should work as substitutes:
import scalaz.std.future._
import scalaz.syntax.monad._
// instead of OptionT.fromOption(db.getCompany(companyName))
OptionT(db.getCompany(companyName).pure[Future])
// instead of OptionT.liftF(db.getDetails(employeeId))
db.getDetails(employeeId).liftM[OptionT]
However, it would be good to have both methods also on OptionT. You could add them and open a pull request.
I have a small Scala/Neo4j application that links people and topics through "skilledAt" and "interestedIn" relations. It has a REST/Json Api (using Scalatra) and I ran into a typical type-erasure problem when I wanted to add an "asJson" method to List[Person] and List[Topic]. I would like to implement different Json serialization behaviour for the different content types but of course the types get erased. The best I've been able to come up with so far is the following runtime trick:
implicit def topicsOrPeopleAsJson[T](list: List[T]) = new {
def asJson: String = {
list match {
case head :: tail if (head.isInstanceOf[Topic]) => topicsToJson(list.asInstanceOf[List[Topic]])
case head :: tail if (head.isInstanceOf[Person]) => peopleToJson(list.asInstanceOf[List[Person]])
case _ => "[]"
}
}
private def peopleToJson(people: List[Person]) = {
...
}
private def topicsToJson(topics: List[Topic]) = {
...
}
}
This works just fine but I was wondering whether there was a better solution, maybe something including type classes, a topic I'm not very familiar with (yet).
Use another level of implicit (this is typeclasses indeed):
trait ListToJsonConverter[T] {
def asJson(l: List[T]) : String
}
implicit object PeopleToJsonConverter extends ListToJsonConverter[Person] {...}
implicit object TopicToJsonConverter extends ListToJsonConverter[Topic] {...}
implicit object DefaultJsonConverter extends ListToJsonConverter[Any] {
def asJson(l: List[Any]) = "[]"
}
implicit def topicsOrPeopleAsJson[T](list: List[T])(implicit ev : ListToJsonConverter[T]) = new {
def asJson = ev.asJson(list)
}
This may not be exactly what you asked for however. The converter will be chosen at compile time. So if you call with a list of person which the compiler knows only as a List[Any], it will not work as expected.
Why not do it the OO way?
trait JSONable {
def toJSON:String
}
class Person
class Topics
implicit def persontoJSONable(p:Person) = new PersonSerializer(p)
implicit def topicToJSONable(t:Topic) = new PersonSerializer(t)
class PersonSerializer(p:Person) extends JSONable {
override def toJSON = {
//...
}
}
class TopicSerializer(t:Topic) extends JSONable {
override def toJSON = {
//...
}
}
def ListAsJSON[T <% JSONable](l:List[T]) = {
l.map(_.toJSON)
}
I am looking for a clean object-orientated way to model the following (in Scala):
A person can be:
A manager at some firm
A mathematician
A world-class tennis player
A hobbyist programmer
A volunteer at a local school
A creative painter
This suggests that we introduce a Person super-class and sub-classes:
class Manager
class Mathematician
class TennisPlayer
class HobbyistProgrammer
class Volunteer
class Painter
The Manager class has methods such as: getSalary(), workLongHours(), findNewJob(), etc. The TennisPlayer class has methods such as: getWorldRanking(), playGame(), strainAnkle(), etc. And so on. In addition there are methods in class Person such as becomeSick(). A sick manager loses his job and tennis player stops playing in the season.
Futhermore the classes are immutable. That is, for instance strainAnkle() returns a new TennisPlayer that that has a strained ankle, but where all other properties remain the same.
The question is now: How do we model the fact that a person can be both a Manager and a TennisPlayer?
It's important that the solution preserves both immutability and type-safety.
We could implement classes such as:
ManagerAndMathematician
ManagerAndTennisPlayerAndPainter
ManagerAndPainter
but this leads to a combinatorial explosion of classes.
We could also use traits (with state), but then how do we implement methods such as findNewJob(), which needs to return a new person with the same traits mixed in, but with a new state of the Manager trait. Similarly, how can we implement methods such as becomeSick()?
Question: How would you implement this in a clean OO-fashion in Scala? Remember: Immutability and type-safety are a must.
This does not look to me like an ideal case for inheritance. Maybe you're trying to force things into an inheritance pattern because it seems awkward to handle composition with immutable values. Here's one of several ways to do it.
object Example {
abstract class Person(val name: String) {
def occupation: Occupation
implicit val self = this
abstract class Occupation(implicit val practitioner: Person) {
def title: String
def advanceCareer: Person
}
class Programmer extends Occupation {
def title = "Code Monkey"
def advanceCareer = practitioner
}
class Student extends Occupation {
def title = "Undecided"
def advanceCareer = new Person(practitioner.name) {
def occupation = new Programmer
}
}
}
def main(args: Array[String]) {
val p = new Person("John Doe") { def occupation = new Student }
val q = p.occupation.advanceCareer
val r = q.occupation.advanceCareer
println(p.name + " is a " + p.occupation.title)
println(q.name + " is a " + q.occupation.title)
println(r.name + " is a " + r.occupation.title)
println("I am myself: " + (r eq r.occupation.practitioner))
}
}
Let's try it out:
scala> Example.main(Array())
John Doe is a Undecided
John Doe is a Code Monkey
John Doe is a Code Monkey
I am myself: true
So this works in a somewhat useful way.
The trick here is that you create anonymous subclasses of your person each time an occupation (which is an inner class) decides to change things up. Its job is to create a new person with the new roles intact; this is helped out by the implicit val self = this and the implicit constructor on Occupation which helpfully automatically loads the correct instance of the person.
You will probably want a list of occupations, and thus will probably want helper methods that will regenerate the list of professions. Something like
object Example {
abstract class Person(val name: String) {
def occupations: List[Occupation]
implicit val self = this
def withOccupations(others: List[Person#Occupation]) = new Person(self.name) {
def occupations = others.collect {
case p: Person#Programmer => new Programmer
case s: Person#Pirate => new Pirate
}
}
abstract class Occupation(implicit val practitioner: Person) {
def title: String
def addCareer: Person
override def toString = title
}
class Programmer extends Occupation {
def title = "Code Monkey"
def addCareer: Person = withOccupations( this :: self.occupations )
}
class Pirate extends Occupation {
def title = "Sea Monkey"
def addCareer: Person = withOccupations( this :: self.occupations )
}
}
def main(args: Array[String]) {
val p = new Person("John Doe") { def occupations = Nil }
val q = (new p.Programmer).addCareer
val r = (new q.Pirate).addCareer
println(p.name + " has jobs " + p.occupations)
println(q.name + " has jobs " + q.occupations)
println(r.name + " has jobs " + r.occupations)
println("I am myself: " + (r eq r.occupations.head.practitioner))
}
}
A clean object-oriented way of solving this does not have to be Scala-specific. One could adhere to the general object-oriented design principle of favoring composition over inheritance and use something like Strategy pattern, which is a standard way of avoiding class explosion.
I think this can be solved in a manner similar to type-safe builders.
The basic idea is to represent "state" through type parameters, and use implicits to control methods. For example:
sealed trait TBoolean
final class TTrue extends TBoolean
final class TFalse extends TBoolean
class Person[IsManager <: TBoolean, IsTennisPlayer <: TBoolean, IsSick <: TBoolean] private (val name: String) {
// Factories
def becomeSick = new Person[TFalse, IsTennisPlayer, TTrue](name)
def getBetter = new Person[IsManager, IsTennisPlayer, TFalse](name)
def getManagerJob(initialSalary: Int)(implicit restriction: IsSick =:= TFalse) = new Person[TTrue, IsTennisPlayer, IsSick](name) {
protected override val salary = initialSalary
}
def learnTennis = new Person[IsManager, TTrue, IsSick](name)
// Other methods
def playGame(implicit restriction: IsTennisPlayer =:= TTrue) { println("Playing game") }
def playSeason(implicit restriction1: IsSick =:= TFalse, restriction2: IsTennisPlayer =:= TTrue) { println("Playing season") }
def getSalary(implicit restriction: IsManager =:= TTrue) = salary
// Other stuff
protected val salary = 0
}
object Person {
def apply(name: String) = new Person[TFalse, TFalse, TFalse](name)
}
It can get very wordy, and if things get complex enough, you may need something like an HList. Here's another implementation, that separates concerns better:
class Person[IsManager <: TBoolean, IsTennisPlayer <: TBoolean, IsSick <: TBoolean] private (val name: String) {
// Factories
def becomeSick = new Person[TFalse, IsTennisPlayer, TTrue](name)
def getBetter = new Person[IsManager, IsTennisPlayer, TFalse](name)
def getManagerJob(initialSalary: Int)(implicit restriction: IsSick =:= TFalse) = new Person[TTrue, IsTennisPlayer, IsSick](name) {
protected override val salary = initialSalary
}
def learnTennis = new Person[IsManager, TTrue, IsSick](name)
// Other stuff
protected val salary = 0
}
object Person {
def apply(name: String) = new Person[TFalse, TFalse, TFalse](name)
// Helper types
type PTennisPlayer[IsSick <: TBoolean] = Person[_, TTrue, IsSick]
type PManager = Person[TTrue, _, _]
// Implicit conversions
implicit def toTennisPlayer[IsSick <: TBoolean](person: PTennisPlayer[IsSick]) = new TennisPlayer[IsSick]
implicit def toManager(person: PManager) = new Manager(person.salary)
}
class TennisPlayer[IsSick <: TBoolean] {
def playGame { println("Playing Game") }
def playSeason(implicit restriction: IsSick =:= TFalse) { println("Playing Season") }
}
class Manager(salary: Int) {
def getSalary = salary
}
To get better error messages you should use specialized versions of TBoolean (ie, HasManagerJob, PlaysTennis, etc), and the annotation implicitNotFound to go with it.