So, can someone please explain me "some"?


#1

I had some fun with Scala. I practically just tried to transform my old Perl code in scala style and got this:

// Some und None

val countryCapitals = Map(
“Germany” -> “Berlin”,
“Russia” -> “Moscow”,
“Finland” -> “Helsinki”)

println( " Read capitals in Option-Objects:" )
println( "Germany: " + countryCapitals.get(“Germany”) )
println( "Russia: " + countryCapitals.get(“Russia”) )
println( "New York: " + countryCapitals.get(“New York”) )

I got this as an output:

 Read capitals in Option-Objects:
Germany: Some(Berlin)
Russia: Some(Moscow)
New York: None

Explain please in easy manner :slight_smile:
I got it that Scala identifies values such like “Unit” or “ArrayBuffer”, but the “some” in the output really confuses me. Scala apparantly tries to get rid of the “null-problem” by evaluating them either as some or none…


#3

The return value is of type Option, which can have a value of Some or None. If the key (country name) is not found, None is returned. If it is found, the capital city name is returned as Some value. The Option class is used for cases like this to avoid null when the output could be undefined.


#4

yeah, but the “some” is not really soemthing I want to have in my output. It doesnt look good :slight_smile:


#5

If you’re absolutely sure that the entry is there in the map, you can use countryCapitals("Germany") and you’ll get just "Berlin". But if you’re mistaken, then instead of None you will have to deal with java.util.NoSuchElementException.

Alternatively, you can call getOrElse on the Option returned by Map.get. For example countryCapitals.get(“New York”).getOrElse("No such place") will return the string "No such place".


#7

Blockquote
If you’re absolutely sure that the entry is there in the map, you can use countryCapitals(“Germany”) and you’ll get just “Berlin”. But if you’re mistaken, then instead of None you will have to deal with java.util.NoSuchElementException.
Alternatively, you can call getOrElse on the Option returned by Map.get. For example countryCapitals.get(“New York”).getOrElse(“No such place”) will return the string “No such place”.

ah… so the first get parameter just refers to the Option-type… and the second get… i don’t know how to describe it, just refers on the actual content of the Map-list? Has it something to do with the HindleyMilner inference type?
Thanks so far!


#8

No, no.
You just call methods on objects.
Your countryCapitals map is an object of the class Map[String, String]. Among methods of the class Map[K, V] (K - the type of the key, V - the type of the value; in this case they are both String) you have def get(key: K): Option[V], as well as def apply(key: K): V. The apply method is special in that you can use a short-hand to call it: instead of writing countryCapitals.apply("Germany") you can write countryCapitals("Germany") - you will call the apply method in both cases, and it will either return the value, or throw an exception. In case of the get method, you have to call it explicitely: countryCapitals.get("Germany") and it will return an Option[V] where V is the string "Berlin". There are two subtypes of Option[V]: Some[V], used when the value exists, and None when it does not. On top of that, the Option class has the method def getOrElse(defaultValue: V): V. You can use it to transform Option[V] into V. The defaultValue argument has to be of the same type as the value (the string in this case) and it will be used if Option[V] is actually None.


#9

Adding to @makingthematrix’s explanation of method calls, it may also help to understand the reason for using Option, which your example does not show, because it’s actually a special case.

Usually Option is used to mark on the type level, that something may not be there. This is usually an improvement over using nulls for “not there”, because it forces you to check the presence of the value before using it. You cannot use the value directly because it has a different type, e.g. an Option[Int] instead of an Int:

val number: Int = 1
val optionNumber: Option[Int] = Some(2)

number + optionNumber // => compile error,
                      // cannot add an Option[Int] to Int directly

The problem in your example is, that your value is a String, and Scala inherited Java’s way of converting everything to a String using its toString method automatically, when it is concatenated with a string. As the String you want is still wrapped in an Option, the toString method of Option is used, which adds the “Some()” around your value, or returns “None” as string for empty options.


#10
val countryCapitals = Map(
"Germany" -> "Berlin",
"Russia" -> "Moscow",
"Finland" -> "Helsinki")

def getCapitals(country: String): String =
  countryCapitals.get(country) match {
     case Some(capital) => capital
     case None => "unknown!"
     }

def getCapitals2(country: String): String =
  countryCapitals.getOrElse(country, "unknown!")

def getCapitals3(country: String): String =
  countryCapitals.get(country).fold( "unknown!")(c=>c)

val targets = List("Germany", "Russia", "New York")

println( " Read capitals:" )
targets.foreach(t => println(s"$t: ${getCapitals(t)}")

#11

thanks! It is an explicit way of handling things, I guess . I tried to find a way of just read the countries from the Map without knowing them.