In the following code, is it possible to reformulate without using asInstanceOf? I found some styleguide suggestions that asInstanceOf/isInstanceOf should be avoided, and I managed to clean up my code except for the usage shown below.
I did find a duplicate question here, but it didn't really help me for this particular case, or I'm just too much of a beginner to translate it to my own use case.
trait pet {}
class dog extends pet {
def bark: String = {
"WOOF"
}
}
def test(what: pet) : String =
{
what match {
case _:dog =>
val x = what.asInstanceOf[dog]
x.bark
}
}
test(new dog())
I tried for example:
val x = what : dog
but that doesn't seem to work.
You can just specify in case section that you expect dog object:
case x: dog => x.bark
But now you might receive scala.MatchError if non-dog object will be passed to your method. So you need to add default case with desirable behavior like this:
case _ => "unknown pet"
Related
What is the FP idiomatic way for this: let's say I have this
trait Name
object Name{
def apply(name: String): Name = {
if (name.trim.isEmpty || name.trim.length < 3)
InvalidName
else
ValidName(name.trim)
}
}
case object InvalidName extends Name
case class ValidName(name:String) extends AnyVal with Name
Now I have some helper functions such as
def split = name.splitAt(" ")
//some more functions
which way is more idiomatic:
Put them in the case class it self but that some how makes the case class to contain some logic however I can do something like :
val n = ValidName("john smith")
val (first, last) = n.split
Put them in dedicated object but then the method will look like
def split(n: ValidName) = n.name.splitAt(" ")
Create an object with implicit class that will accept Name and will call the methods
What do you think ?
There is no major issue with adding logic to a case class, especially when it is just extracting the data in a different format. (It becomes problematic when you add data members to a case class).
So I would do option 1 and not worry about it!
In response to the comments, case class is actually just a shortcut for creating a class with a whole bunch of useful pre-implemented methods. In particular, the unapply method allows a case class to be used in pattern matching, and equals does an element-wise comparison of the fields of two instances.
And there are a bunch of other methods to extract the data from the case class in different ways. The most obvious are toString and copy, but there are others like hashCode and all the stuff inherited from Product, such as productIterator.
Since a case class already has methods to extract the data in useful ways, I see no objection to adding your split method as another way of extracting data from the case class.
More idiomatic:
case class Name private (name: String) {
lazy val first :: last :: Nil = name.split(" ").toList
}
object Name {
def fromString (name: String): Either[String, Name] = {
if (name.trim.isEmpty || name.trim.length < 3) Left("Invalid name")
else Right(new Name(name.trim))
}
}
Or maybe this:
case class Name (first: String, last: String) {
lazy val fullName = s"$first $last"
}
object Name {
def fromString (name: String): Either[String, Name] = {
if (name.trim.isEmpty || name.trim.length < 3) Left("Invalid name")
else {
val first :: last :: Nil = name.split(" ").toList
Right(new Name(first, last))
}
}
}
In scala it's more idiomatic to represent failure cases through the use of Either than through inheritance. If you have an instance of N, you can't call any functions on it, you'll probably have to pattern match it. But a type like Either already comes with functions like map, fold, etc. that makes it easier to work with.
Having a private constructor helps ensure that you can only create a valid Name because the only way to create one is through the fromString method.
DO NOT use implicits for this. There's no need and would only make for confusing code. Not really what implicits are for.
I think it depends on context. In this case, if most of the methods you are using are just slight tweaks to String methods, you might want to consider a fourth option:
case class Name(name: String)
implicit def NameToString(n: Name) = n.name
Name("Iron Man").split(" ") // Array(Iron, Man)
Because I'll get String's from my websocket, I must convert the String to an actual type. Is it possible to do something like that?:
def createThing(cls: String) = {
List[cls.getClass]() // or create actors or something like that
}
createThing("Int") // should produce List[Int]
createThing("Double") // should produce List[Double]
Is it possible to achieve this? I'm new to with reflection, therefore I could not find a solution.
No. The static type can't depend on runtime data in the way you want. E.g. should
createThing("Foo")
fail to compile if class Foo is not defined? However, you can do a lot of things without this. If you specify your problem better in a separate question, you may get answers.
You can solve this without mucking about with reflection. A minimalist class hierarchy can solve the problem quite effectively. Here is an example:
trait Message
case class StringList(strings: List[String]) extends Message
case class IntList(ints: List[Int]) extends Message
object Create {
def createThing(cls: String): Option[Message] = cls match {
case "strings" => Some(StringList(List[String]("a","b")))
case "ints" => Some(IntList(List[Int](3,4,5)))
case _ => None
}
}
object Main extends App {
val thing = Create.createThing("ints")
thing match {
case Some(a: StringList) => println(s"It was a StringList containing ${a.strings}")
case Some(b: IntList) => println(s"It was an IntList containing ${b.ints}")
case _ => println("Nothing we know about")
}
}
I'm using ScalaFX and JavaFX, and have this code:
import scalafx.Includes._
class Type1(anInt: Int, ...)
class Type2(aString: String, ...)
class ListItem[T](internalValue:T, ...)
object Worker
{
val list1 = FXCollections.observableArrayList[ListItem[Type1]]()
val list2 = FXCollections.observableArrayList[ListItem[Type2]]()
def workWithList(list:ObservableList[ListItemType]) {
list.foreach(i => workWithItem(i))
}
def workWithItem(item:ListItem) {
item match {
case i:ListItem[Type1] => do something
case i:ListItem[Type2] => do something else
}
}
workWithList(list1)
workWithList(list2)
}
My problem is that this code doesn't compile; it says that I can't use ObservableList[ListItem[Type1]] for the workWithList method, which expects ObservableList[ListItem].
As I've been playing with this, some variations of this code says that there are unchecked warnings, and that pattern matching won't work due to type erasure.
Ideally:
there would be just a single list that could hold objects of type ListItem[Type1] and ListItem[Type2]
I could do pattern matching when working with the items to do different things depending on what kind of item is being worked with
workWithItem could work with either type of item. In my current code I've had to change the signature to workWithItem(item:ListItem[_]) and then do workWithItem(someItem.asInstanceOf[ListItem[_]]). Probably not the correct thing to do!
Thanks!
The method signature for workWithList looks wrong - where does the ListItemType type come from? Should this be def workWithList(list: ObservableList[ListItem[_]]) { ...?
If so, then the problem you will run up against in the match cases is that due to type erasure, the JVM can't tell the difference at runtime between the type signatures of the cases. This can be worked around by, for example, turning the Type1, Type2 and ListItem into case classes (or manually generating unapply methods for them), then deconstructing the item in the match cases, like so:
case class Type1(anInt: Int)
case class Type2(aString: String)
case class ListItem[T](internalValue:T)
object Worker
{
val list1 = FXCollections.observableArrayList[ListItem[Type1]]()
val list2 = FXCollections.observableArrayList[ListItem[Type2]]()
def workWithList(list: ObservableList[ListItem[_]]) {
list.foreach(i => workWithItem(i))
}
def workWithItem(item: ListItem[_]) {
item match {
case ListItem(i: Type1) => println(s"Have type 1: ${i.anInt}") //do something
case ListItem(i: Type2) => println(s"Have type 2: ${i.aString}") //do something else
case anythingElse => println(s"Unknown type: $anythingElse") //just as a safe default for now
}
}
workWithList(list1)
workWithList(list2)
}
Note that I am working here without specific knowledge of the FX libraries (I tried this using straight scala Lists rather than ObservableList or FXCollections.observableArrayList), so they may affect the applicability of this solution (and might be where ListItemType is defined).
The method signature for workWithItem is fine, but the asInstanceOf cast you tried shouldn't be required.
You are attacking mosquito with a shotgun. This example can be solved without parametric polymorphism, with plain old inheritance:
import scalafx.Includes._
import javafx.collections.{FXCollections,ObservableList}
class ListItemType
class Type1(anInt: Int) extends ListItemType
class Type2(aString: String) extends ListItemType
class ListItem(val internalValue:ListItemType)
object Worker
{
val list1 = FXCollections.observableArrayList[ListItem]()
val list2 = FXCollections.observableArrayList[ListItem]()
def workWithList(list:ObservableList[ListItem]) {
list.foreach(i => workWithItem(i))
}
def workWithItem(item:ListItem) {
item.internalValue match {
case i:Type1 => println("do something")
case i:Type2 => println("do something else")
}
}
workWithList(list1)
workWithList(list2)
}
No errors, no warnings, and you can mix both types of objects in the same list.
I'd like to read a string as an instance of a case class. For example, if the function were named "read" it would let me do the following:
case class Person(name: String, age: Int)
val personString: String = "Person(Bob,42)"
val person: Person = read(personString)
This is the same behavior as the read typeclass in Haskell.
dflemstr answered more towards setting up the actual read method- I'll answer more for the actual parsing method.
My approach has two objects that can be used in scala's pattern matching blocks. AsInt lets you match against strings that represent Ints, and PersonString is the actual implementation for Person deserialization.
object AsInt {
def unapply(s: String) = try{ Some(s.toInt) } catch {
case e: NumberFormatException => None
}
}
val PersonRegex = "Person\\((.*),(\\d+)\\)".r
object PersonString {
def unapply(str: String): Option[Person] = str match {
case PersonRegex(name, AsInt(age)) => Some(Person(name, age))
case _ => None
}
}
The magic is in the unapply method, which scala has syntax sugar for. So using the PersonString object, you could do
val person = PersonString.unapply("Person(Bob,42)")
// person will be Some(Person("Bob", 42))
or you could use a pattern matching block to do stuff with the person:
"Person(Bob,42)" match {
case PersonString(person) => println(person.name + " " + person.age)
case _ => println("Didn't get a person")
}
Scala does not have type classes, and in this case, you cannot even simulate the type class with a trait that is inherited from, because traits only express methods on an object, meaning that they have to be "owned" by a class, so you cannot put the definition of a "constructor that takes a string as the only argument" (which is what "read" might be called in OOP languages) in a trait.
Instead, you have to simulate type classes yourself. This is done like so (equivalent Haskell code in comments):
// class Read a where read :: String -> a
trait Read[A] { def read(s: String): A }
// instance Read Person where read = ... parser for Person ...
implicit object ReadPerson extends Read[Person] {
def read(s: String): Person = ... parser for Person ...
}
Then, when you have a method that depends on the type class, you have to specify it as an implicit context:
// readList :: Read a => [String] -> [a]
// readList ss = map read ss
def readList[A: Read] (ss: List[String]): List[A] = {
val r = implicitly[Read[A]] // Get the class instance of Read for type A
ss.map(r.read _)
}
The user would probably like a polymorphic method like this for ease of use:
object read {
def apply[A: Read](s: String): A = implicitly[Read[A]].read(s)
}
Then one can just write:
val person: Person = read[Person]("Person(Bob,42)")
I am not aware of any standard implementation(s) for this type class, in particular.
Also, a disclaimer: I don't have a Scala compiler and haven't used the language for years, so I can't guarantee that this code compiles.
Starting Scala 2.13, it's possible to pattern match a Strings by unapplying a string interpolator:
// case class Person(name: String, age: Int)
"Person(Bob,42)" match { case s"Person($name,$age)" => Person(name, age.toInt) }
// Person("Bob", 42)
Note that you can also use regexes within the extractor.
Which in this case, helps for instance to match on "Person(Bob, 42)" (age with a leading space) and to force age to be an integer:
val Age = "[ ?*](\\d+)".r
"Person(Bob, 42)" match {
case s"Person($name,${Age(age)})" => Some(Person(name, age.toInt))
case _ => None
}
// Person = Some(Person(Bob,42))
The answers on this question are somewhat outdated. Scala has picked up some new features, notably typeclasses and macros, to make this more easily possible.
Using the Scala Pickling library, you can serialize/deserialize arbitrary classes to and from various serialization formats:
import scala.pickling._
import json._
case class Person(name: String, age: Int)
val person1 = Person("Bob", 42)
val str = person1.pickle.value // { tpe: "Person", name: "Bob", age: 42 }
val person2 = JSONPickle(str).unpickle[Person]
assert(person1 == person2) // Works!
The serializers/deserializers are automatically generated at compile time, so no reflection! If you need to parse case classes using a specific format (such as the case class toString format), you can extend this system with your own formats.
The uPickle library offers a solution for this problem.
Scala uses Java's serialization stuff, with no String representation.
I think it would be easier to describe a problem with concrete example. Suppose I have have Fruit class hierarchy and Show type class:
trait Fruit
case class Apple extends Fruit
case class Orange extends Fruit
trait Show[T] {
def show(target: T): String
}
object Show {
implicit object AppleShow extends Show[Apple] {
def show(apple: Apple) = "Standard apple"
}
implicit object OrangeShow extends Show[Orange] {
def show(orange: Orange) = "Standard orange"
}
}
def getAsString[T](target: T)(implicit s: Show[T]) = s show target
I also have list of fruits that I would like to show to the user using Show (this is my main goal in this question):
val basket = List[Fruit](Apple(), Orange())
def printList[T](list: List[T])(implicit s: Show[T]) =
list foreach (f => println(s show f))
printList(basket)
This will not compile because List is parametrized with Fruit and I have not defined any Show[Fruit]. What is the best way to achieve my goal using type classes?
I tried to find solution for this problem, but unfortunately have not found any nice one yet. It's not enough to know s in printList function - somehow it needs to know Show[T] for each element of the list. This means, that in order to be able to make this, we need some run-time mechanism in addition to the compile-time one. This gave me an idea of some kind of run-time dictionary, that knows, how to find correspondent Show[T] at run-time.
Implementation of implicit Show[Fruit]can serve as such dictionary:
implicit object FruitShow extends Show[Fruit] {
def show(f: Fruit) = f match {
case a: Apple => getAsString(a)
case o: Orange => getAsString(o)
}
}
And actually very similar approach can be found in haskell. As an example, we can look at Eq implementation for Maybe:
instance (Eq m) => Eq (Maybe m) where
Just x == Just y = x == y
Nothing == Nothing = True
_ == _ = False
The big problem with this solution, is that if I will add new subclass of Fruit like this:
case class Banana extends Fruit
object Banana {
implicit object BananaShow extends Show[Banana] {
def show(banana: Banana) = "New banana"
}
}
and will try to print my basket:
val basket = List[Fruit](Apple(), Orange(), Banana())
printList(basket)
then scala.MatchError would be thrown because my dictionary does not know anything about bananas yet. Of course, I can provide updated dictionary in some context that knows about bananas:
implicit object NewFruitShow extends Show[Fruit] {
def show(f: Fruit) = f match {
case b: Banana => getAsString(b)
case otherFruit => Show.FruitShow.show(otherFruit)
}
}
But this solution is far from perfect. Just imagine that some other library provides another fruit with it's own version of dictionary. It will just conflict with NewFruitShow if I try to use them together.
Maybe I'm missing something obvious?
Update
As #Eric noticed, there is one more solution described here: forall in Scala . It's really looks very interesting. But I see one problem with this solution.
If I use ShowBox, then it will remember concrete type class during it's creation time. So I generally building list with objects and correspondent type classes (so dictionary in present in the list). From the other hand, scala has very nice feature: I can drop new implicits in the current scope and they will override defaults. So I can define alternative string representation for the classes like:
object CompactShow {
implicit object AppleCompactShow extends Show[Apple] {
def show(apple: Apple) = "SA"
}
implicit object OrangeCompactShow extends Show[Orange] {
def show(orange: Orange) = "SO"
}
}
and then just import it in current scope with import CompactShow._. In this case AppleCompactShow and OrangeCompactShow object would be implicitly used instead of defaults defined in the companion object of Show. And as you can guess, list creation and printing happens in different places. If I will use ShowBox, than most probably I will capture default instances of type class. I would like to capture them at the last possible moment - the moment when I call printList, because I even don't know, whether my List[Fruit] will ever be shown or how it would be shown, in the code that creates it.
The most obvious answer is to use a sealed trait Fruit and a Show[Fruit]. That way your pattern matches will complain at compile time when the match is not exhaustive. Of course, adding a new kind of Fruit in an external library will not be possible, but this is inherent in the nature of things. This is the "expression problem".
You could also stick the Show instance on the Fruit trait:
trait Fruit { self =>
def show: Show[self.type]
}
case class Apple() extends Fruit { self =>
def show: Show[self.type] = showA
}
Or, you know, stop subtyping and use type classes instead.