What does a "?" symbol (question mark) mean in Scala? - scala

I meet some scala code with "?" but do not know what it mean in scala, could anyone explain it to me ? Thanks.
And here's one example
def getJobId(conf: Configuration): String =
?(conf.get("scoobi.jobid")).getOrElse(sys.error("Scoobi job id not set."))

For me it looks like the apply method of Option. Is there somewhere the following import statement in the code:
import Option.{apply => ?}
This means apply is imported as ?. From the doc of Option.apply:
An Option factory which creates Some(x) if the argument is not null,
and None if it is null.
The whole statement means then:
if conf.get("scoobi.jobid") is not equal null, assign this string,
otherwise assign the string sys.error("Scoobi job id not set.")
returns

It's just a legal character, just like "abcd..."
scala> def ?(i: Int) = i > 2
$qmark: (i: Int)Boolean
scala> val a_? = ?(3)
a_?: Boolean = true
UPD: See Valid identifier characters in Scala , Scala method and values names
UPD2: In the example "?" could be function, method of this or just some object with apply method. It probably returns Option[String].

Related

Read a tuple from a file in Scala

my Task is to read registrations from a file given like:
Keri,345246,2
Ingar,488058,2
Almeta,422016,1
and insert them into a list(Tuple of (String, Int, Int).
So far I wrote this:
The problem is that I don‘t understand why I can't try to cast value2 and value3 to Int even tho they should be Strings because they come from an Array of Strings. Could someone tell me, what my mistake is, I am relatively new to Scala
What is the point of using Scala if you are going to write Java code?
This is how you would properly read a file as a List of case classes.
import scala.io.Source
import scala.util.Using
// Use proper names for the fields.
final case class Registration(field1: String, field2: Int, field3: Int)
// You may change the error handling logic.
def readRegistrationsFromFile(fileName: String): List[Registration] =
Using(Source.fromFile(fileName)) { source =>
source.getLines().map(line => line.split(',').toList).flatMap {
case field1Raw :: field2Raw :: field3Raw :: Nil =>
for {
field2 <- field2Raw.toIntOption
field3 <- field3Raw.toIntOption
} yield Registration(field1 = field1Raw.trim, field2, field3)
case _ =>
None
}.toList
}.getOrElse(default = List.empty)
(feel free to ask any question you may have about this code)
In Scala, in order to convert a String to an Int you need explicit casting.
This can be achieved like this if you are sure the string can be parsed into a integer:
val values = values(1).toInt
If you cannot trust the input (and you probably should not), you can use .toIntOption which will give you a Option[Int] defined if the value was converted successfully or undefined if the string did not represent an integer.
The previous answers are correct. I would add a few more points.
saveContent is declared as a val. This is means it cannot be changed (assigned another value). You can use the Scala REPL (command-line) tool to check:
scala> val saveContent = Nil
val v: collection.immutable.Nil.type = List()
scala> saveContent = 3
^
error: reassignment to val
Instead, you could use a var, although it would be more idiomatic to have an overall pattern like the one provided by Luis Miguel's answer - with pattern-matching and a for-comprehension.
You can use the Scala REPL to check the types of the variables, too. Splitting a String will always lead to more Strings, not Ints, etc.
> val values = "a,2,3".split(",")
val values: Array[String] = Array(a, 2, 3)
> values(2)
val res3: String = 3
This is why a cast like Gael's is necessary.
Array-type access is done with parentheses and not square brackets, in Scala. See above, and http://scalatutorials.com/tour/interactive_tour_of_scala_lists for more details.

scala mutable.Map put/get handles null's in an unexpected way?

I know one is not supposed to use nulls in scala but sometimes when interoperating with Java it happens. The way a scala mutable map handles this seems off though:
scala> import scala.collection.mutable
import scala.collection.mutable
scala> val m: mutable.Map[String, String] = mutable.Map.empty
m: scala.collection.mutable.Map[String,String] = Map()
scala> m.put("Bogus", null)
res0: Option[String] = None
scala> m.get("Bogus")
res1: Option[String] = Some(null)
scala> m.getOrElse("Bogus", "default")
res2: String = null
I would have expected m.get to return None in this case. Almost seems like a bug, like somewhere in the code there was a Some(v) instead of Option(v)
Is there discussion w/r/t to changing this behavior?
I would have expected m.get to return None in this case.
Why? None would mean the key "Bogus" is not in the map, but you just put it in (with value null).
Java's Map API has problems distinguishing "the value for this key is null" from "this key is not in the map", but Scala's doesn't.
Null is subtype of String:
scala> implicitly[Null <:< String]
res3: Null <:< String = <function1>
Therefore null is a valid String value:
scala> val s: String = null
s: String = null
If you want to store a null as a String in a map, it's your good right.
Compared to Java's Map#get (let's call it javaLikeGet), the Scala's get behaves roughly as follows:
def get(k: K) = if (containsKey(k)) {
Some(this.javaLikeGet(k))
} else {
None
}
and not like what you have assumed:
def get(k: K) = Option(this.javaLikeGet(k))
The latter version (presumably what you thought) would get a null for an existing key, pass it to Option(...), and return None. But the former version (which imitates how the real implementation works) would notice that the key exists, and wrap the null returned by javaLikeGet into a Some.
The simple and consistent rule is:
If the key k exists, then get(k) returns Some[V], otherwise it returns None.
This is much less surprising than the strange behavior of Java's get that returns null in two entirely different situations.
This is the Billion-Dollar Mistake, but Scala is not the language that is likely to fix it, because it has to interop with Java. My guess is that there is and will be no discussion about changing this behavior, at least not until something fundamentally changes in the entire programming landscape.

Trying to skip implicit parameter list

I'd like to call a function returned by a function with an implicit parameter, simply and elegantly. This doesn't work:
def resolveA(implicit a: A): String => String = { prefix =>
s"$prefix a=$a"
}
case class A(n: Int)
implicit val a = A(1)
println(resolveA("-->")) // won't compile
I've figured out what's going on: Scala sees the ("-->") and thinks it's an attempt to explicitly fill in the implicit parameter list. I want to pass that as the prefix argument, but Scala sees it as the a argument.
I've tried some alternatives, like putting an empty parameter list () before the implicit one, but so far I've always been stopped by the fact that Scala thinks the argument to the returned function is an attempt to fill in the implicit parameter list of resolveA.
What's a nice way to do what I'm trying to do here, even if it's not as nice as the syntax I tried above?
Another option would be to use the apply method of the String => String function returned by resolveA. This way the compiler won't confuse the parameter lists, and is a little shorter than writing implicltly[A].
scala> resolveA[A].apply("-->")
res3: String = --> a=A(1)

Scala string.count('\t'==) Why does it work?

Suppose I have a string s, if I want to count the amount of tabs in the string I can do the following:
string.count('\t'==)
Any idea why this works?? I would've expected a predicate
Reference: Count all occurrences of a char within a string
The == is being used as a "postfix operator", so you are effectively passing in the function '\t'.== to string.count.
Note: if I do this in the REPL with -feature turned on, I get this output:
scala> "hello\tworld".count('\t'==)
<console>:8: warning: postfix operator == should be enabled
by making the implicit value language.postfixOps visible.
This can be achieved by adding the import clause 'import scala.language.postfixOps'
or by setting the compiler option -language:postfixOps.
See the Scala docs for value scala.language.postfixOps for a discussion
why the feature should be explicitly enabled.
"hello\tworld".count('\t'==)
^
> res0: Int = 1
Adding the dot removes the warning:
scala> "hello\tworld".count('\t'.==)
res1: Int = 1
Is your question
Does String have a function count(p: (Char) ⇒ Boolean): Int?
Is the == method on a char a boolean function on another char?
The answers: yes and yes.
In scala you can pass predicate this way:
def predicate(ch: Char) = { ... }
string.count(ch => predicate(ch))
or this way
string.count(predicate(_))
Also there is way to omit parameter placeholder, which looks actually nice
string.count(predicate)
And in your example you are actually calling method '==' of Char, so it's very similar to code above. Just far more unreadable.
string.count('\t'.==)

First parameter as default in Scala

Is there another way of making this work?
def b(first:String="hello",second:String) = println("first:"+first+" second:"+second)
b(second="geo")
If I call the method with just:
b("geo")
I get:
<console>:7: error: not enough arguments for method b: (first: String,second: String)Unit.
Unspecified value parameter second.
b("geo")
Here is one of the possible ways: you can use several argument lists and currying:
scala> def b(first:String="hello")(second:String) = println("first:"+first+" second:"+second)
b: (first: String)(second: String)Unit
scala> b()("Scala")
first:hello second:Scala
scala> val c = b() _
c: (String) => Unit = <function1>
scala> c("Scala")
first:hello second:Scala
See scala language specifications 6.6.1 (http://www.scala-lang.org/docu/files/ScalaReference.pdf):
"The named arguments form a suffix of the argument list e1, ..., em, i.e. no positional argument follows a named one."
Providing a single string parameter (without naming it) is too ambiguous for the compiler. Probably you meant the value for the non-default parameter, but... maybe not. So the compiler wants you to be more specific.
Generally you put all your default parameters at the end of the method signature (if you did in this case, b("geo") would work) so that they can be left out less ambiguously.