Scala syntax to access property of an option inline and chain "OrElse"? - scala

Sometimes I want to return the value that is a property of an object wrapped in option, but I can't do that easily with getValue.orElse(otherValue).
For instance, I am mapping properties inline and I want to use a pattern like object.get.property.orElse(""). But the preceding doesn't compile. How can I access that property and still maintain an option-like syntax?

You can use map() to achieve this. It becomes obvious once you start to think about Option[T] like a container of type T that can hold 0 or 1 element:
case class Person(name: String, age: Int)
val optionalPerson = Some(Person("John", 29))
val name = optionalPerson map {_.name} getOrElse "?"
Furthermore if you have a nested structure of Options:
case class Person(name: String, age: Int, parent: Option[Person])
you can extract nested Option with flatMap:
val optionalPerson = Some(Person("John", 29, Some(Person("Mary", 55, None))))
val parentName = optionalPerson flatMap {_.parent} map {_.name} getOrElse "Unknown parent name" //Mary
Or you can use filter() to turn Some() into None when value wrapped in Some does not satisfy some criteria:
val nameIfAdult = optionalPerson filter {_.age >= 18} map {_.name}

Use map() to maintain the option-like pattern.
For instance you need to get the name property of a field object. But if field is actually None, you can return a blank string. Like this:
field.map(_.name).getOrElse("")
And using it in the bigger picture:
implicit def castDraftModel(drafts:List[Tuple2[models.ReportInstance,Option[models.Report]]]) = drafts.map{
(field) =>
List(Field(
field._1.id,
field._1.teamId,
field._2.map(_.name).getOrElse(""),
field._1.lastModifiedRelative,
field._2.map(_.id).getOrElse(0L),
field._2.map(_.reportType).getOrElse(""),
field._1.referenceId,
field._1.referenceName( draft._2.map(_.reportType).getOrElse("") ) ))
}.flatten.sortBy(_.id)

Related

Dealing with optional field with lihaoyi ujson

I want to use ujson of the upickle library to extract an optional string from a json document. In some documents the json field exists, in others not.
When acessing the field and the field does not exist I get a NoSuchElementException:
val json = ujson.read(jsonString)
json("attributename").str
results in: java.util.NoSuchElementException: key not found: attributename
What is the idiomatic way to deal with optional json attributes in ujson?
If you want to return default value in case of any exception you can use Try with getOrElse:
val result = Try(json("attributename").str).getOrElse("defaultValue")
The result will be value of attributename key or defaultValue string if there is no such key.
I think the idiomatic way is to have a case class instead of going against the JSON AST manually.
In your case class you could then have an Option[String] field.
case class MyModel( attributeName: Option[String] )
implicit val rw: ReadWriter[MyModel] = macroRW
read[MyModel](jsonString)
But from the looks of it, you could do
json.obj.value.get("attributename").map(_.str)
to get an Option[String] back.
Don't forget, a json is an object.
So we can check it like this:
val json = ujson.read(jsonString)
if (json.obj.get("attributename").nonEmpty) {
json("attributename").str
...
}
And btw, you can get the keySet like this:
json.obj.keySet
According to liahoy
the canonical way is to add None defaults
for example,
import upickle.default._
case class User(name: String, age: Option[Int] = None)
implicit val userRW: ReadWriter[User] = macroRW
read[User]("""{ "name": "Picard" }""")
outputs
res0: User = User(Picard,None)
I am not sure, but, I was looking the GitHub repo here
It seems at line 62 and from line 87 till line 99, it just call x.obj(i).
It doesn't perform any check, and just call it. This lead to a java.util.NoSuchElementException because trying to access without a check. I didn't see around any version to get the Option, or to even perform a check if this value exists.
I would suggest to go via a Try/Success/Failure idiom on scala
val tryAttr = Try{json("attributename").str}
tryAttr match {
case Success(_) => doYourThing
case Failure(t: NoSuchElementException) => DoSomethingElse
}

Underscore usage for eta expansion

scala> val names = List("Peter", "Paul", "Mary")
names: List[String] = List(Peter, Paul, Mary)
scala> names.map(_.toUpperCase)
res12: List[String] = List(PETER, PAUL, MARY)
In this case, the underscore represents the only input argument, which is the element of names. This string is implicitly converted to StringOps and toUpperCase is invoked.
However, this does not work:
scala> names.map(StringOps.toUpperCase _)
<console>:14: error: value toUpperCase is not a member of object scala.collection.immutable.StringOps
names.map(StringOps.toUpperCase _)
I thought that this syntax is how I would get a reference to the function from the toUpperCase method.
First of all, there is no implicit conversion for _.toUppercase that convert String to StringOps, Since toUppercase is belong to String type, it's unnecessary convert to StringOps.
so for _.toUppercase is actual expand to high order function: val a: String => String = (str: String) => str.toUpperCase.
and StringOps implicit conversion defined in Predef.scala: augmentString, and this conversion only will occur when used StringOps's method, like: slice, stripSuffix, stripPrefix etc, for Example:
"name".slice(0, 2) // convert "name" to new StringOps("name").slice(0,2)
"name".stringPrefix
StringOps is a class, hence to use its method you'll need to instantiate an instance:
names.map( x => (new StringOps(x)).toUpperCase )
Or
names.map( new StringOps(_) toUpperCase )
StringOps is a wrapper class of the String class which means that it "enriches" this class with additional methods like the one you are using.
When you want to call a method on a string instance, you simply do:
instanceName.methodName
This is exactly what you are doing in your first example.
However, in your second example you are doing the following:
methodName(instanceName)
toUpperCase does not take an argument, it is called on the instance of the string itself.

Scala: constructor with two paretneheses

I'm new to scala.
What does following syntax mean?
case class User(val id: Long)(val username: String)
I've read about currying in scala, but explain please how it related to construction above (if related).
Thanks.
Just like partially-applied functions, a constructor (which is a function from its arguments to the constructed type) can be partially applied, in this case:
scala> case class User(val id: Long)(val username: String)
defined class User
scala> val userBuilder = User(123L) _
userBuilder: String => User = <function1>
Note the type of the resulting userBuilder - it's a function from String (the remaining parameter) to User
Now, like partially applied functions, you can apply this result to a String and get a User instance:
scala> val user = userBuilder("a")
user: User = User(123)
scala> user.username
res1: String = a
When is this useful?
When you want to construct many instances with common values for a subset of the arguments, e.g.:
case class Person(lastName: String)(val firstName: String)
class Family(lastName: String, firstNames: List[String]) {
def getMembers: List[Person] = {
val creator = Person(lastName) _ // will be reused for each first name!
firstNames.map(creator)
}
}
When you want to use one argument as the default value of another one:
case class Measure(min: Int)(val max: Int = min*2)
Measure(5)() // max = 10
Measure(5)(12) // default overridden, max = 12
When you want to use implicit arguments, which must reside in a separate, last argument list of the function, as described int the Scala Language Specification (Chapter 7.2):
A method or constructor can have only one implicit
parameter list, and it must be the last parameter list given.
It allows you to construct the object in steps.
val user = User(123L) _ // user now has only the ID
// later on
val completeUser = user("moreo") // user now also has the username
This is generally useful when you want to have your object follow an interface, but need to pass additional parameters, so you first initialise your object with those parameters and then later you get a function that can follow the interface.

Get class fields by name

For example my case class is
case class Test(id: String, myValues: List[Item])
case class Item(id: Long, order: Long)
and I get string value like
val checkValue: String = "id"
I want sort Tests by items and I want it to look like
val test= Test("0", List(Item(0, 14), Item(1, 34))
val sortedItems = test.myValues.map(_.*checkValue*).sorted
Its about get field of class like someInstanceOfClass.checkValue
Scala is not an interpreted language, therefore you can't just use strings as variable names. The easiest way to solve your problem is to map the string value to the variable:
scala> def get(item: Items, str: String) = str match {
| case "id" => item.id
| case "order" => item.order
| }
get: (item: Items, str: String)Long
scala> test.myValues.map(get(_, checkValue)).sorted
res0: List[Long] = List(0, 1)
scala> test.myValues.map(get(_, "order")).sorted
res1: List[Long] = List(14, 34)
Of course there are more ways to solve the problem. You could use Reflection to read the name of the variable at runtime. In case you already know at compile time the name of the variable you want to read, you could also use macros to generate the code that is doing what you want. But these are both very specialized solutions, I would go with the runtime matching as shown above.
You may wish to rethink how you're going about this. What good does the string "id" actually do you? If you just need the capability to pull out a particular bit of data, why not use a function?
val f: Item => Long = _.id
Do you not want to have to type the function type over and over again? That's fine too; you can use a method to request the compiler's help filling in the type arguments:
def pick[A](x: Item => A) = x
val f = pick(_.id)
Now you can use f anywhere you would have used "id". (You can even name it id instead of f if that will help, or something that reminds you that it's actually a function that gets an id, not an id itself, like idF or getId.)

Understand how to use apply and unapply

I'm trying to get a better understanding of the correct usage of apply and unapply methods.
Considering an object that we want to serialize and deserialize, is this a correct usage (i.e. the Scala way) of using apply and unapply?
case class Foo
object Foo {
apply(json: JValue): Foo = json.extract[Foo]
unapply(f: Foo): JValue = //process to json
}
Firstly, apply and unapply are not necessarily opposites of each other. Indeed, if you define one on a class/object, you don't have to define the other.
apply
apply is probably the easier to explain. Essentially, when you treat your object like a function, apply is the method that is called, so, Scala turns:
obj(a, b, c) to obj.apply(a, b, c).
unapply
unapply is a bit more complicated. It is used in Scala's pattern matching mechanism and its most common use I've seen is in Extractor Objects.
For example, here's a toy extractor object:
object Foo {
def unapply(x : Int) : Option[String] =
if(x == 0) Some("Hello, World") else None
}
So now, if you use this is in a pattern match like so:
myInt match {
case Foo(str) => println(str)
}
Let's suppose myInt = 0. Then what happens? In this case Foo.unapply(0) gets called, and as you can see, will return Some("Hello, World"). The contents of the Option will get assigned to str so in the end, the above pattern match will print out "Hello, world".
But what if myInt = 1? Then Foo.unapply(1) returns None so the corresponding expression for that pattern does not get called.
In the case of assignments, like val Foo(str) = x this is syntactic sugar for:
val str : String = Foo.unapply(x) match {
case Some(s) => s
case None => throw new scala.MatchError(x)
}
The apply method is like a constructor which takes arguments and creates an object, whereas the unapply takes an object and tries to give back the arguments.
A simple example:
object Foo {
def apply(name: String, suffix: String) = name + "." + suffix
def unapply(name: String): Option[(String, String)] = {
//simple argument extractor
val parts = name.split("\\.")
if (parts.length == 2) Some(parts(0), parts(1)) else None
}
}
when you call
val file = Foo("test", "txt")
It actually calls Foo.apply("test", "txt") and returns test.txt
If you want to deconstruct, call
val Foo(name) = file
This essentially invokes val name = Foo.unapply(file).get and returns (test, txt) (normally use pattern matching instead)
You can also directly unpack the tuple with 2 variables, i.e.
scala> val Foo(name, suffix) = file
val name: String = test
val suffix: String = txt
BTW, the return type of unapply is Option by convention.
So apply and unapply are just defs that have extra syntax support.
Apply takes arguments and by convention will return a value related to the object's name. If we take Scala's case classes as "correct" usage then the object Foo's apply will construct a Foo instance without needing to add "new". You are free of course to make apply do whatever you wish (key to value in Map, set contains value in Set, and indexing in Seq come to mind).
Unapply, if returning an Option or Boolean can be used in match{} and pattern matching. Like apply it's just a def so can do whatever you dream up but the common usage is to extract value(s) from instances of the object's companion class.
From the libraries I've worked with serialization/deserialization defs tend to get named explicitly. E.g., write/read, show/read, toX/fromX, etc.
If you want to use apply/unapply for this purpose the only thing I'd suggest is changing to
def unapply(f: Foo): Option[JValue]
Then you could do something like:
val myFoo = Foo("""{name: "Whiskers", age: 7}""".asJson)
// use myFoo
val Foo(jval) = myFoo
// use jval