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)
}
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)
I need to access a companion class with a specified trait -- from a trait intended for case classes. I am almost certain that the Scala reflection library can accomplish this but I haven't quite been able to piece it together.
I created test code below that requires one section of ??? be filled in with some reflection magic. The code compiles and runs as is -- with a notification due to the missing functionality.
Some related answers that I have seen on StackOverflow were from 2.10. Scala 2.12 compatible please.
import scala.reflect.{ClassTag, classTag}
//for companion object
//accesses Fields of the associated case class to ensure the correctness
//note: abstract class -- not a trait due to issues using ClassTag on a trait
abstract class SupportsField1Companion[T: ClassTag] {
//gets the names of all Fields on the associated case class
val fieldNamesOfInstancedClass: Array[String] =
classTag[T].runtimeClass.getDeclaredFields.map(_.getName)
//prints the name and fields of the associated case class -- plus extra on success
def printFieldNames(extra: String = ""): Unit = {
val name = classTag[T].runtimeClass.getCanonicalName
val fields = fieldNamesOfInstancedClass.reduceLeft(_ + ", " + _)
println(s"Fields of $name: $fields" + extra)
}
}
//for case classes
//IMPORTANT -- please do not parameterize this if possible
trait SupportsField1 {
//some data for printing
val field1: String = this.getClass.getCanonicalName + ": field1"
//should get a reference to the associated companion object as instance of SupportsFieldsCompanion
def getSupportsFieldsCompanion: SupportsField1Companion[this.type] = //this.type may be wrong
??? //TODO reflection magic required -- need functionality to retrieve companion object cast as type
//calls a function on the associated Companion class
def callPrintFuncOnCompanion(): Unit =
getSupportsFieldsCompanion.printFieldNames(s" -- from ${this.getClass.getCanonicalName}")
}
//two case classes with the SupportsFieldsCompanion trait to ensure data is accessed correctly
object ExampleA extends SupportsField1Companion[ExampleA] {}
case class ExampleA() extends SupportsField1 {
val fieldA: String = "ExampleA: fieldA"
}
object ExampleB extends SupportsField1Companion[ExampleB] {}
case class ExampleB() extends SupportsField1 {
val fieldB: String = "ExampleB: fieldB"
}
object Run extends App {
//create instanced classes and print some test data
val exampleA = ExampleA()
println(exampleA.field1) //prints "ExampleA: field1" due to trait SupportsFields
println(exampleA.fieldA) //prints "ExampleA: fieldA" due to being of class ExampleA
val exampleB = ExampleB()
println(exampleB.field1) //prints "ExampleB: field1" due to trait SupportsFields
println(exampleB.fieldB) //prints "ExampleB: fieldB" due to being of class ExampleB
//via the SupportsFieldsCompanion trait on the companion objects,
//call a function on each companion object to show that each companion is associated with the correct case class
ExampleA.printFieldNames() //prints "Fields of ExampleA: fieldA, field1"
ExampleB.printFieldNames() //prints "Fields of ExampleB: fieldB, field1"
//test access of printFieldNames on companion object from instanced class
try {
exampleA.callPrintFuncOnCompanion() //on success, prints "Fields of ExampleA: fieldA, field1 -- from ExampleA"
exampleB.callPrintFuncOnCompanion() //on success, prints "Fields of ExampleB: fieldB, field1 -- from ExampleB"
} catch {
case _: NotImplementedError => println("!!! Calling function on companion(s) failed.")
}
}
There are lots of ways you can do this, but the following is probably one of the simplest that doesn't involve making assumptions about how Scala's companion object class name mangling works:
def getSupportsFieldsCompanion: SupportsField1Companion[this.type] =
scala.reflect.runtime.ReflectionUtils.staticSingletonInstance(
this.getClass.getClassLoader,
this.getClass.getCanonicalName
).asInstanceOf[SupportsField1Companion[this.type]]
This works as desired, but I'd probably type it as SupportsField1Companion[_], and ideally I'd probably avoid having public methods on SupportsField1 that refer to SupportsField1Companion—actually ideally I'd probably avoid this approach altogether, but if you're committed I think the ReflectionUtil solution above is probably reasonable.
I have multiple case classes representing values in DB for ex User which saves user based properties like name / age / address and CallLog which saves timestamp / status_of_call
What i want to achieve
I want to have a helper function which accepts list of models and checks if the list is empty then returns "error" otherwise should return json array of the list.
My Approach
I want to have a trait which groups certain models in it and the helper method will accept either the trait or List of it in order to check or may be have a generic which implements the trait.
Problem
Since implicit writes are tightly coupled with the model class, compiler throws the error on the line Json.toJson(list)
Things i have tried
Kept implicit in trait and got recursive type error
I am scala noob pardon me if this sounds silly
Thanks in advance
Since User, CallLog, etc. will be serialized differently, Each Writes[T] will be different for each implementation of your Model trait, so a Writes[Model] has to know about the implementation it is trying to serialize.
It is therefore not possible to have it part of the Model trait, because this information isn't known yet when you define it.
A workaround in your case would be to define your Writes[Model] in the scope of your helper function instead.
An implementation of your helper function could be like this :
import play.api.libs.json.{JsValue, Json, Writes}
sealed trait Model
case class User(name: String, age: String, address: String) extends Model
object User {
implicit val userWrites = Json.writes[User]
}
case class CallLog(timestamp: String, status_of_call: String) extends Model
object CallLog {
implicit val callLogWrites = Json.writes[CallLog]
}
implicit val modelWrites = new Writes[Model] {
override def writes(o: Model): JsValue = o match {
case u: User => Json.toJson(u)
case cl: CallLog => Json.toJson(cl)
}
}
def helper(models: Model*): Either[JsValue, String] = models match {
case Nil => Right("Error")
case _ => Left(Json.toJson(models))
}
helper(User("John", "32", "..."))
helper(User("John", "32", "..."), CallLog("now", "In progress"))
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.