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")
}
}
Related
I am creating a command-line app where it reads what the user puts in and then makes a POST request with that data (I've just started).
My problem is I've never seen a class extended like this before and it's throwing me off. How do I get the values from CommandApp so that I can use it in my Main Object?
import cats.implicits._
import com.monovore.decline._
object Main extends CommandApp(name = "hello-world",
header = "Says hello!",
main = {
val userOpt = Opts.option[String]("target", help = "Person to greet.").withDefault("world")
val quietOpt = Opts.flag("quiet", help = "Whether to be quiet.").orFalse
(userOpt, quietOpt).mapN { (user, quiet) =>
if (quiet) println("...")
else println(s"Hello $user!")
}
}) {
// How do I get the value from user into here.
// Eventually I will want to use that user data variable for a POST request.
}
If I understood you correctly you want to pattern match the case class Parameters of CommandApp from the main Object?
In Scala this isn't directly possible since Main is a child of CommandApp and not the other way round (you can only pattern match to child case classes). But you can use traits:
Declare a new Trait that has no direct function
CommandApp has to inherit that trait
Convert your main Object to that trait type
Pattern matching
Since i don't have your class definitions, i wrote a small example. Let's say your class looks like this:
case class Test(str:String)
class MainTest extends Test("Hello World!")
and you want to access the str value of Test like this:
val t = new MainTest()
t match{
case Test(str) => println(str)
case _ => println("Could not match")
}
This would not work since MainTest is not a case class and therefore cannot be pattern matched. But if you declare a new trait which Test inherits:
trait InheritanceTrait
case class Test(str:String) extends InheritanceTrait
class MainTest extends Test("Hello World!")
You can pattern match a MainTest object by casting it to a InheritanceTrait, which has a pattern-matching child class (therefore can be pattern matched):
val t = new MainTest()
t.asInstanceOf[InheritanceTrait] match{
case Test(str) => println(str)
case _ => println("Could not match")
} //prints "Hello World!"
If you don't want to or simply can't declare a super class of CommandApp you could use a dirty alternative by converting t to the Any type, since every class inherits from Any. Would work just as fine.
My example then would like this:
object Main{
case class Test(str:String)
class MainTest extends Test("Hello World!")
def main(args:Array[String]){
val t = new MainTest()
t.asInstanceOf[Any] match{
case Test(str) => println(str)
case _ => println("Could not match")
}
}
}
I hope this solved your problem!
It should be noted that CommandApp isn't a case class, it's a regular abstract class.
The intended use of CommandApp appears to be that your entire program goes into main and when main completes, your program is done. This is evidenced by the class having a name ending in App (c.f. IOApp) and has main.
So what you would do is define a function elsewhere which takes whatever values you've validated that you want to use (e.g user in this case) as arguments and does stuff with them, e.g.
// Disclaimer: I'm guessing from the code that userOpt is Option[String]
def sendUserAsPostRequest(user: String): Unit = {
// sending the user as a POST is left as an exercise for the reader
}
You can place that function in Main or in a different object (or in a different class as long as your main constructs an instance of that class). You're main would then look like (I'm assuming that for this, you're not interested in quiet):
main = {
val userOpt = Opts.option[String]("target", help = "Person to greet.").withDefault("world")
userOpt.map(sendUserAsPostRequest)
}
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)
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"
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.