Scala optional parameter of a Case class - scala

implicit val formats = DefaultFormats
val p = each_rsvp.extract[RSVPData]
p.venue.getOrElse(default = None)
I have done the extraction using case classes. RSVPData is a case class defined as follows:
case class RSVPData(
venue: Option[VenueDetails] = None,
visibility: String,
response: String,
guests: Int,
member: MemberDetails,
rsvp_id: Long,
mtime: Long,
event: EventDetails,
group: GroupDetails
)
As shown above, parameter 'venue' is an optional field of type VenueDetails which is also a case class.
case class VenueDetails(venue_name: String, lon: Double, lat: Double, venue_id: Int)
When I do:
p.venue.getOrElse(Default=None)
I get the output as :
VenueDetails(Waller Creek Pub House,-97.73584,30.266438,24179503)
The above is returned as 'Product with Serializable'. How to extract data from VenueDetails case class separately as venue name, latitude, longitude, venue id, from this output .

I'm going to assume that p is an RSVPData item. Correct? (
When you use .getOrElse on an Option, you are attempting to provide a default value in the case where no value is defined (that is, when the value is None). In other words, getOrElse gives you an opportunity to provide default venue details when none are available, so that you can handle both cases in a consistent manner. In your case, this argument should be an instance of VenueDetails.
By passing None as the argument to getOrElse you're saying that you want None if the Option's value is None - which makes very little sense. Even worse, getOrElse now returns two types of value: a VenueDetails or None. So Scala determines the return type as those traits that are common to both of these types, which it has determined to be Product with Serializable. As a result, you can't treat the return value as a VenueDetails, and so you cannot access its members.
General rule of thumb: NEVER pass None to Option.getOrElse! ;-)
(As an aside, specifying the argument name in the call is unnecessary; p.venue.getOrElse(None) is simpler and equivalent to p.venue.getOrElse(default = None).)
So, now it depends upon what you're trying to do, which isn't clear from your question. I'll try to provide a few examples...
This first example is more imperative than functional. It attempts to print out details of the venue:
// Is the venue defined? (If None, then it's undefined.)
if (p.venue.isDefined) {
// Retrieve the defined details. Note that get throws an exception if p.venue is None.
// BTW, detail's type is inferred to be VenueDetails.
val details = p.venue.get
println(s"Venue: ${details.venue_name}, loc: (${details.lon}, ${details.lat}), id: ${details.venue_id}")
}
// Handle the case where the venue details are undefined.
else {
println("Venue details are unknown")
}
Here's a slightly more functional version:
val desc = p.venue.fold {
// This argument is evaluated only if p.venue is None.
"Venue details are unknown"
} {
// This argument is executed only if p.venue is defined (not None).
// Again, details is inferred to have type VenueDetails
details =>
s"Venue: ${details.venue_name}, loc: (${details.lon}, ${details.lat}), id: ${details.venue_id}"
}
println(desc)
This version uses a default VenueDetails instance for cases where the venue details are unknown:
// Default details for case where p.venue is None.
val defaultDetails = VenueDetails("Unknown", 0.0, 0.0, -1)
// Here, details will have type VenueDetails.
val details = p.venue.getOrElse(defaultDetails)
val desc = s"Venue: ${details.venue_name}, loc: (${details.lon}, ${details.lat}), id: ${details.venue_id}"
println(desc)
In this latter case, if p.venue is None, then the following will be printed:
Venue: Unknown, loc: (0.0, 0.0), id: -1
However, if p.venue is defined as per your example, then the following will be printed:
Venue: Waller Creek Pub House, loc: (-97.73584, 30.266438), id: 24179503

I hope this would work:
p.venue.map(_.venue_name).getOrElse(None)

Related

Pattern matching on a Scala case class with `type` as a field

I have a case class defined for JSON parsing using the Circe library:
final case class Event(
source: Option[String],
nonce: Option[Int],
`type`: Option[Any],
tag: Option[String],
payload: Option[Any],
blockOrder: Option[Int] = None,
metadata: ResultMetadata[OperationResult.Event]
) extends Operation
Note that one of the fields is called type and I can only use the name using backticks or I get a compiler error. I don't have any choice over the schema used by the source system supplying the data.
Later on, when I try to pattern match on the case class in order to write some information to a database...
private val convertEvent: PartialFunction[
(Block, OperationHash, Operation),
Tables.OperationsRow
] = {
case (
block,
groupHash,
Event(source, nonce, `type`, tag, payload, blockOrder, metadata)
) =>
...
...I get the following error:
not found: value type
Event(source, nonce, `type`, tag, payload, blockOrder, metadata).
Is there any way I can still use Circe and case classes in general when a field has the same name as a reserved keyword?
In 2.13.8 the error is
not found: value type
Identifiers enclosed in backticks are not pattern variables but match the value in scope.
Event(source, nonce, `type`, tag, payload, blockOrder, metadata)
so just use something different from type in pattern matching as a pattern variable.
For example
case (
block,
groupHash,
Event(source, nonce, typ, tag, payload, blockOrder, metadata)
) =>
That's because backticks in pattern matching mean to use an already-existing value accessible in the scope, to check the equity of a pattern variable, like this:
case class Person(name: String, age: Int)
val johnName = "John"
val john = Person(johnName, 99)
val alice = Person("Alice", 128)
john match {
case Person(`johnName`, someAge) =>
// this will be matched, sine johnName = "John"
}
alice match {
case Person(`johnName`, someAge) =>
// won't match, "Alice" != "John"
case Person(johnName, someAge) =>
// this one matches, since johnName in the pattern is only some alias,
// and will shadow the variable defined above
}
The solution/workaround is already mentioned in the other anwer.

Why is the parameter type of a generic function not inferred?

In Scala 2.11.7, having the following case class and an additional apply method:
case class FieldValidator[T](key: String, isValid: T => Boolean,
errorMessage: Option[String] = None)
object FieldValidator {
def apply[T](key: String, isValid: T => Boolean,
errorMessage: String): FieldValidator[T] = ???
}
when I try to use:
FieldValidator[String](key, v => !required || v.nonEmpty, "xxx")
I'm getting a "missing parameter type" compilation error pointing at v.
When I explicitly specify the type of v, it compiles fine, and I can even skip the generic type of the apply method, i.e.
FieldValidator(key, (v: String) => !required || v.nonEmpty, "xxx")
Why isn't the type of v inferred when just the generic type of apply is provided?
It's not so much about generics, it's rather a problem with overloading and default parameters.
First, recall that since FieldValidator is a case-class, a synthetic factory method
def apply(
key: String,
isValid: T => Boolean,
errorMessage: Option[String] = None
)
is automatically added to the companion object FieldValidator. This results in Field validator having two generic methods with default parameters and same name.
Here is a shorter example that behaves in roughly the same way:
def foo[A](f: A => Boolean, x: Int = 0): Unit = {}
def foo[A](f: A => Boolean, x: String): Unit = {}
foo[String](_.isEmpty)
It results in:
error: missing parameter type for expanded function ((x$1: ) =>
x$1.isEmpty)
foo[String](_.isEmpty)
^
I can't pinpoint what exactly goes wrong, but essentially, you have confused the compiler with too much ambiguity by throwing three different sorts of polymorphism at it:
Overloading: you have two methods with name apply
Generics: your methods have a generic type parameter [A]
Default arguments: your errorMessage (x in my shorter example) can be omitted.
Together, this leaves the compiler with the choice between two equally named methods with unclear types and unclear number of expected type arguments. While flexibility is good, too much flexibility is simply too much, and the compiler gives up trying to figure out what you wanted, and forces you to specify all types of every single argument explicitly, without relying on inference.
Theoretically, it could have figured it out in this particular case, but this would require much more complex inference algorithms and much more backtracking and trial-and-error (which would slow down the compilation in the general case). You don't want the compiler to spend half a day playing typesystem-sudoku, even if it theoretically could figure out a unique solution. Exiting quickly with an error message is a reasonable alternative.
Workaround
As a simple work-around, consider reordering the arguments in a way that allows the compiler to eliminate ambiguity as fast as possible. For example, splitting the arguments into two argument lists, with two Strings coming first, would make it unambiguous:
case class FieldValidator[T](
key: String,
isValid: T => Boolean,
errorMessage: Option[String] = None
)
object FieldValidator {
def apply[T]
(key: String, errorMessage: String)
(isValid: T => Boolean)
: FieldValidator[T] = {
???
}
}
val f = FieldValidator[String]("key", "err"){
s => s.nonEmpty
}

scala named parameter in function-as-params?

I'm quite used to Typescript's function-with-param-names as function-params:
function doHello(
helloFunc: (lastName: string, firstName: string) => void,
...
) { ... }
Here, helloFunc describes a function-as-param with 'named' params (lastName, firstName)
but I could only find examples without param-names, such as:
case class HelloWoot(
helloFunc: (String, String) => Unit,
...
)
which omits some info about helloFunc signature.
So, how do I get the following code to compile in Scala?
case class HelloWoot(
helloFunc: (lastName: String, firstName: String) => Unit,
// Error
)
It's not possible to provide named parameters in a higher order function. If you are worried about people mixing up the String parameters you could introduce a new type like this:
// New object with firstName and lastName
case class NamesObject(firstName: String, lastName: String)
// Higher order function now takes the new type as input
case class HelloWoot(helloFunc: (NamesObject) => Unit)
// You can now safely access the correct variable without having to rely on their order in the Tuple2
HelloWoot(a => println(a.firstName, a.lastName))

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.

Getting Scala 2.10 annotation values at runtime

So I have a documentation annotation that looks like this:
case class DocProp(name: String = "", dataType: Class[_] = classOf[Object])
The idea is that by default we'll introspect the field and look at the ID and return type, but in some cases that needs overriding.
I want to put it on the fields of my model case classes, so I redeclare it as a type with #field:
type DocProperty = DocProp #field
And then use it in the following different scenarios:
case class MyModel(
// 1. use reflection to inspect the property
#DocProperty
prop1: Int,
// 2. override the name
#DocProperty(name = "myProp")
prop2: String,
// 3. override the return type
#DocProperty(dataType = classOf[String])
prop3: Option[String],
// 4. override everything
#DocProperty("myOtherProp", classOf[Number])
prop4: Float,
// 5. don't document this one at all
hiddenProp: String
)
I've finally managed to dig through layers of runtimeMirrors and whatnot to get down to the Symbols for the values and their associated annotations, and dig out just the DocProp annotations:
// val mc = classOf[MyModel] // passed in
import scala.reflect.runtime.{universe => ru}
val mirror = ru.runtimeMirror(mc.getClassLoader)
val members = mirror.classSymbol(mc).asType.typeSignature.members
val allProps = (for (m <- members) yield {
val a8ns = m.annotations
val a8n = a8ns.find(a => a.tpe <:< ru.typeOf[DocProp])
a8n match {
case Some(found) => Some((m, found))
case _ => None
}
}).flatten
This gets me an iterable of (Symbol, Annotation) for just the annotated properties (I still need the Symbols for the reflective cases).
But I'm now deep in a thicket of reflect.runtime.universe.Trees, and it's not obvious to me how to get out. How do I get from
reflect.runtime.universe.Tree = classOf[java.lang.Number]
to an actual Class[Number] value? How do I get from
reflect.runtime.universe.Tree = doc.this.DocProp.<init>$default$1
to the empty string, or even to 1?
So far there's no easy way of achieving that. Utilizing ToolBox.eval is the workaround that comes to mind. There's also a similar issue in our JIRA that talks about getting values of Java annotations: https://issues.scala-lang.org/browse/SI-6423.