This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Why Option[T] ?
I am a newbie on Scala and I can't really feel that sensation of that difference between null on java and Option on Scala .
I know that none is an object and if I write smth like that on Scala , it will go safe :
val map = Map("koko" -> "is a cat")
val string:Option[String] =map.get("other")
println(string.map(a=>println(a.toString)) )
I well get None as a result instead of throwing an exception .
It's interesting .
However if I need the returning value not to be wrapped by Some . I will use .get to return the value .
In our example , it will throw an exceoption:
map.get("other").get.map(a=>println(a.toString))
I know I can handle this issue by using "match" .
I am taking here that I need to learn what's that booming on option on Scala vs null on java !
What I still couldn't get is that how could I use the advantages of Option but in case there are values existed into my variable , return the value not Some(value)
def testOption(): String = {
val map = Map("koko" -> "is a cat")
val string: Option[String] = map.get("koko")
string
}
I mean is there any way to make this code works instead of updating the return value to be Option[String] !
Imagine that I have to return a String in order to be set into my bean variable that is of type String not Option[String]
How could I make that works without any kind of match !!
I guess if there smth that makes it works , that will make me understand well the power of Option.
Options are actually quite useful. In Java, it's tough to document whether or not something can be null. In Scala, you can often assume all variables are not null.
This gets really useful when you have some computation that can fail or may not be defined. A good instance would be if you have a webapp and there's some user data that isn't filled out, so the computation can't run. If you had the user data in a map, you could do something like
val myData = map.get(userId).map(doFunction).map(toHtml)
println(myData.getOrElse(noDataHtml))
So clearly here we never have to worry about null. If the user data is in the map, we proceed with the computation and then turn that into html. Otherwise, we'll just print out a default html. In Java, at each stage we'd have to do a null check, but in Scala we can just chain functions.
Related
I'm currently working on my functional programming - I am fairly new to it. Am i using Options correctly here? I feel pretty insecure on my skills currently. I want my code to be as safe as possible - Can any one point out what am I doing wrong here or is it not that bad? My code is pretty straight forward here:
def main(args: Array[String]): Unit =
{
val file = "myFile.txt"
val myGame = Game(file) //I have my game that returns an Option here
if(myGame.isDefined) //Check if I indeed past a .txt file
{
val solutions = myGame.get.getAllSolutions() //This returns options as well
if(solutions.isDefined) //Is it possible to solve the puzzle(crossword)
{
for(i <- solutions.get){ //print all solutions to the crossword
i.solvedCrossword foreach println
}
}
}
}
-Thanks!! ^^
When using Option, it is recommended to use match case instead of calling 'isDefined' and 'get'
Instead of the java style for loop, use higher-order function:
myGame match {
case Some(allSolutions) =>
val solutions = allSolutions.getAllSolutions
solutions.foreach(_.solvedCrossword.foreach(println))
case None =>
}
As a rule of thumb, you can think of Option as a replacement for Java's null pointer. That is, in cases where you might want to use null in Java, it often makes sense to use Option in Scala.
Your Game() function uses None to represent errors. So you're not really using it as a replacement for null (at least I'd consider it poor practice for an equivalent Java method to return null there instead of throwing an exception), but as a replacement for exceptions. That's not a good use of Option because it loses error information: you can no longer differentiate between the file not existing, the file being in the wrong format or other types of errors.
Instead you should use Either. Either consists of the cases Left and Right where Right is like Option's Some, but Left differs from None in that it also takes an argument. Here that argument can be used to store information about the error. So you can create a case class containing the possible types of errors and use that as an argument to Left. Or, if you never need to handle the errors differently, but just present them to the user, you can use a string with the error message as the argument to Left instead of case classes.
In getAllSolutions you're just using None as a replacement for the empty list. That's unnecessary because the empty list needs no replacement. It's perfectly fine to just return an empty list when there are no solutions.
When it comes to interacting with the Options, you're using isDefined + get, which is a bit of an anti pattern. get can be used as a shortcut if you know that the option you have is never None, but should generally be avoided. isDefined should generally only be used in situations where you need to know whether an option contains a value, but don't need to know the value.
In cases where you need to know both whether there is a value and what that value is, you should either use pattern matching or one of Option's higher-order functions, such as map, flatMap, getOrElse (which is kind of a higher-order function if you squint a bit and consider by-name arguments as kind-of like functions). For cases where you want to do something with the value if there is one and do nothing otherwise, you can use foreach (or equivalently a for loop), but note that you really shouldn't do nothing in the error case here. You should tell the user about the error instead.
If all you need here is to print it in case all is good, you can use for-comprehension which is considered quite idiomatic Scala way
for {
myGame <- Game("mFile.txt")
solutions <- myGame.getAllSolutions()
solution <- solutions
crossword <- solution.solvedCrossword
} println(crossword)
I'm admittedly very new to Scala, and I'm having trouble with the syntactical sugar I see in many Scala examples.
It often results in a very concise statement, but honestly so far (for me) a bit unreadable.
So I wish to take a typical use of the Option class, safe-dereferencing, as a good place to start for understanding, for example, the use of the underscore in a particular example I've seen.
I found a really nice article showing examples of the use of Option to avoid the case of null.
https://medium.com/#sinisalouc/demystifying-the-monad-in-scala-cc716bb6f534#.fhrljf7nl
He describes a use as so:
trait User {
val child: Option[User]
}
By the way, you can also write those functions as in-place lambda
functions instead of defining them a priori. Then the code becomes
this:
val result = UserService.loadUser("mike")
.flatMap(user => user.child)
.flatMap(user => user.child)
That looks great! Maybe not as concise as one can do in groovy, but not bad.
So I thought I'd try to apply it to a case I am trying to solve.
I have a type Person where the existence of a Person is optional, but if we have a person, his attributes are guaranteed. For that reason, there are no use of the Option type within the Person type itself.
The Person has an PID which is of type Id. The Id type consists of two String types; the Id-Type and the Id-Value.
I've used the Scala console to test the following:
class Id(val idCode : String, val idVal : String)
class Person(val pid : Id, val name : String)
val anId: Id = new Id("Passport_number", "12345")
val person: Person = new Person(anId, "Sean")
val operson : Option[Person] = Some(person)
OK. That setup my person and it's optional instance.
I learned from the above linked article that I could get the Persons Id-Val by using flatMap; Like this:
val result = operson.flatMap(person => Some(person.pid)).flatMap(pid => Some(pid.idVal)).getOrElse("NoValue")
Great! That works. And if I infact have no person, my result is "NoValue".
I used flatMap (and not Map) because, unless I misunderstand (and my tests with Map were incorrect) if I use Map I have to provide an alternate or default Person instance. That I didn't want to have to do.
OK, so, flatMap is the way to go.
However, that is really not a very concise statement.
If I were writing that in more of a groovy style, I guess i'd be able to do something like this:
val result = person?.pid.idVal
Wow, that's a bit nicer!
Surely Scala has a means to provide something at least nearly as nice as Groovy?
In the above linked example, he was able to make his statement more concise using some of that syntactical sugar I mentioned before. The underscore:
or even more concise:
val result = UserService.loadUser("mike")
.flatMap(_.child)
.flatMap(_.child)
So, it seems in this case the underscore character allows you to skip specifying the type (as the type is inferred) and replace it with underscore.
However, when I try the same thing with my example:
val result = operson.flatMap(Some(_.pid)).flatMap(Some(_.idVal)).getOrElse("NoValue")
Scala complains.
<console>:15: error: missing parameter type for expanded function ((x$2) => x$2.idVal)
val result = operson.flatMap(Some(_.pid)).flatMap(Some(_.idVal)).getOrElse("NoValue")
Can someone help me along here?
How am I misunderstanding this?
Is there a short-hand method of writing my above lengthy statement?
Is flatMap the best way to achieve what I am after? Or is there a better more concise and/or readable way to do it ?
thanks in advance!
Why do you insist on using flatMap? I'd just use map for your example instead:
val result = operson.map(_.pid).map(_.idVal).getOrElse("NoValue")
or even shorter:
val result = operson.map(_.pid.idVal).getOrElse("NoValue")
You should only use flatMap with functions that return Options. Your pid and idVals are not Options, so just map them instead.
You said
I have a type Person where the existence of a Person is optional, but if we have a person, his attributes are guaranteed. For that reason, there are no use of the Option type within the Person type itself.
This is the essential difference between your example and the User example. In the User example, both the existence of a User instance, and its child field are options. This is why, to get a child, you need to flatMap. However, since in your example, only the existence of a Person is not guaranteed, after you've retrieved an Option[Person], you can safely map to any of its fields.
Think of flatMap as a map, followed by a flatten (hence its name). If I mapped on child:
val ouser = Some(new User())
val child: Option[Option[User]] = ouser.map(_.child)
I would end up with an Option[Option[User]]. I need to flatten that to a single Option level, that's why I use flatMap in the first place.
If you looking for the most concise solution, consider this:
val result = operson.fold("NoValue")(_.pid.idVal)
Though one could find it not clear or confusing
Im trying to map a JSONObject instance into an actual instance through Play Combinators. I am able to get the desrialization work correctly. The question is on the behavior of how map() works on an Option[JSONObject].
Option1:
jsonVal: Option[JSONObject] = getAsJson(input)
jsonVal.map(JSONUtil.fromJsonString(_.toString(), Blah.jsonReads))
Doesnt work, fails to compile as the _ is not resolved correctly. Compiler couldnt find the toString() on the object.
Option2:
jsonVal: Option[JSONObject] = getAsJson(input)
jsonVal.map(_.toString()).map(JSONUtil.fromJsonString(_, Blah.jsonReads))
Works !!. Can some one tell me why the Type of the default variable is not propagated when transformation is done as part of function argument?
It isn't behavior of map, it's behavior of _. It's just a shortcut for the normal function expression (in this case). In the first case you have
jsonVal.map(JSONUtil.fromJsonString(x => x.toString(), Blah.jsonReads))
which obviously doesn't work, and need to write the full version
jsonVal.map(x => JSONUtil.fromJsonString(x.toString(), Blah.jsonReads))
I've been learning Scala and decided to play with JSON parsing using json4s. I decided to use XPath syntax for deserializing and came across this strange bit of syntax I've never seen before.
val json = JsonMethods.parse("""{"meaningOfLife": 42}""")
val JInt(x) = json\"meaningOfLife"
The part confusing me is this bit right here
val JInt(x) = ...
I can't wrap my mind around what's happening there, I don't even know how to search this syntax or what it's called. Can anyone help me out? Scala is an amazing language with a lot of neat features that I'm not used to in other languages like C++ and Java.
Edit
To clarify, I'm confused because x isn't defined, but it's somehow being passed into a function or constructor then being assigned to the result of json\"meaningOfLife" which returns a JValue.
Edit 2
After some research and playing around, I figured out that this has something to do with case classes. I was able to run the following code.
case class MyCaseClass (x: Int)
val MyCaseClass(x) = new MyCaseClass(5)
println(x, x.getClass) // prints (5,int)
Which, after looking at some of the code, gives me a good understanding at what's happening.
val MyCaseClass(x) = MyCaseClass(5)
Is extracting (for lack of a better term) the Int value 5 from the instantiated MyCaseClass and storing that into x, meaning x will be of type Int.
In the code for json4s a JInt is a JValue which the \ operator returns. So the JInt(x) is taking out a BigInt (stored in the class JInt) and putting that into the value x from what I gather.
But I still have a question. What is this process called? Is there any documentation on it?
It's called "irrefutable pattern matching" and it's essentially equivalent to this bit of code:
val json = JsonMethods.parse("""{"meaningOfLife": 42}""")
val x = json match {
case JInt(xMatched) => xMatched
}
In other words, any case class or any extractor that fits the pattern of the declaration's left-hand-side can be used in this way.
Addendum:
The "irrefutable" means that a MatchError will be thrown if the pattern cannot be satisfied.
How do I test and see if a variable is set in Scala. In PHP you would use isset()
I am looking for a way to see if a key is set in an array.
First, Array in Scala does not have keys. They have indices, and all indices have values in them. See the edit below about how those values might be initialized, though.
You probably mean Map, which has keys. You can check whether a key is present (and, therefore, a value) by using isDefinedAt or contains:
map isDefinedAt key
map contains key
There's no practical difference between the two. Now, you see in the edit that Scala favors the use of Option, and there's just such a method when dealing with maps. If you do this:
map get key
You'll receive an Option back, which will be None if the key (and, therefore, the value) is not present.
EDIT
This is the original answer. I've noticed now that the question is not exactly about this.
As a practical matter, all fields on the JVM are pre-initialized by the JVM itself, which zeroes it. In practice, all reference fields end up pointing to null, booleans are initialized with false and all other primitives are initialized with their version of zero.
There's no such thing in Scala as an "undefined" field -- you cannot even write such a thing. You can write var x: Type = _, but that simply results in the JVM initialization value. You can use null to stand for uninitialized where it makes sense, but idiomatic Scala code tries to avoid doing so.
The usual way of indicating the possibility that a value is not present is using Option. If you have a value, then you get Some(value). If you don't, you get None. See other Stack Overflow questions about various ways of using Option, since you don't use it like variable.isDefined in idiomatic code either (though that works).
Finally, note that idiomatic Scala code don't use var much, preferring val. That means you won't set things, but, instead, produce a new copy of the thing with that value set to something else.
PHP and Scala are so different that there is no direct equivalent. First of all Scala promotes immutable variables (final in Java world) so typically we strive for variables that are always set.
You can check for null:
var person: Person = null
//...
if(person == null) {//not set
//...
}
person = new Person()
if(person == null) {//set
//...
}
But it is a poor practice. The most idiomatic way would be to use Option:
var person: Option[Person] = None
//...
if(person.isDefined) {//not set
//...
}
person = Some(new Person())
if(person.isDefined) {//set
//...
}
Again, using isDefined isn't the most idiomatic ways. Consider map and pattern matching.