Scala passing varargs to another function that takes varargs - scala

Why varargs can't be passed as another varargs without :_* ?
object Main {
def main(s: Array[String]): Unit = {
def someFunction(varars: String*) = {
someOtherFunction(varars) // Compilation ERRRO
someOtherFunction(varars:_*) // Works, but why ?
}
def someOtherFunction(someOtherVarars: String*): Unit = {
}
}
}

It's because varars is a single argument - an array of strings (note, that I'm not writing Array[String], because it is not the java Array, more details here), whereas by looking at the signature def someOtherFunction(someOtherVarars: String*): Unit, we can tell, that someOtherFunction takes multiple arguments of type String each. You cannot simply pass an array as the parameter to someOtherFunction, you need to "unfold" it first.
In other words an argument can be passed to someOtherFunction it has to be marked as a sequence argument. It would not make much sense to be able to pass varargs and varargs(1) to the single function. It's described in SLS ยง4.6.2.

"varargs"parameter means it can take any number of strings as an argument(i.e., a varargs field).
def someFunction(varars: String*): Seq[String] = {
varars }
if you define the above method and check for type of "varars" it has now become Seq[String] when you are using it. But when you pass it to another method which is expecting variableArgs type. It mismatch as it has become Seq[String] which should be converted to variable arguments using (someOtherVarars: _*).
_* operator tells the compiler to pass each element of the sequence as a separate argument, instead of passing it as a single argument.

Related

Why spark varargs function countDistinct receive a single String/Column firstly?

The declaration of spark org.apache.spark.sql.functions.countDistinct is:
def countDistinct(columnName: String, columnNames: String*): Column
def countDistinct(expr: Column, exprs: Column*): Column
The declaration receives variable arguments, but with a single String/Column firstly. So I cannot write code like this:
val id1sArr = id1.split(",").map(col(_))
df.agg(countDistinct(id1sArr: _*))
So my questions are:
Why varargs function countDistinct receive a single String/Column firstly? What is the advantage and disadvantage of this type of declaration?
How to adapt this declaration if I want to pass variable arguments?
The answer to why the declaration have a single string/column as the first argument is that
countDistinct requires at least one argument. If a declaration such as countDistinct(columnNames: String*) is used, zero arguments would be allowed.
As to how to pass a list of arguments, simply write:
df.agg(countDistinct(id1sArr.head, id1sArr.tail: _*))

Understanding Scala Syntax

I have code below and I wanted to know what does Seq[String] = List() mean?
Does it mean it takes sequence of strings and converts it into List()?
def somefuncname(input: Seq[String] = List()): Unit = {
//Some Code
}
First try to understand the below function signature.
def somefuncname(input: Seq[String]): Unit = {
//Some Code
}
The above code is a function declaration. Its a function which takes 1 argument called input which is of type Seq[String]. That means it takes sequence or list of strings as input and returns nothing Unit
Now, what does = mean?
= after the input argument of the function means default value for the function argument. If you are not interested in passing a custom "sequence of strings" then you can rely on the default argument of already passed.
Now, what does List() mean?
List() returns sequence of 0 elements or empty sequence. That means function is taking empty elements as default argument
alternatively you can also pass Seq() as default argument. It also means empty sequence
def somefuncname(input: Seq[String] = Seq()): Unit = {
//Some Code
}
Now to use the function in any of the following ways
somefuncname() // Now input is empty sequence of strings
somefuncname(Seq("apple", "cat"))
somefuncname(List("apple", "cat"))
input is of type Seq[String] and it has a default value of empty list (List()).
Having a default value means so that if you call the function without passing an argument it would get the default value

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 variable arguments :_*

could someone bring more shed on following piece of scala code which is not fully clear to me? I have following function defined
def ids(ids: String*) = {
_builder.ids(ids: _*)
this
}
Then I am trying to pass variable argument list to this function as follows:
def searchIds(kind: KindOfThing, adIds:String*) = {
...
ids(adIds)
}
Firstly, ids(adIds) piece doesn't work which is a bit odd at first as error message says: Type mismatch, expected: String, actual: Seq[String]. This means that variable arguments lists are not typed as collections or sequences.
In order to fix this use the trick ids(adIds: _*).
I am not 100% sure how :_* works, could someone put some shed on it?
If I remember correctly : means that operation is applied to right argument instead to left, _ means "apply" to passed element, ...
I checked String and Sequence scaladoc but wasn't able to find :_* method.
Could someone explain this?
Thx
You should look at your method definitions:
def ids(ids: String*)
Here you're saying that this method takes a variable number of strings, eg:
def ids(id1: String, id2: String, id3: String, ...)
Then the second method:
def searchIds(kind: KindOfThing, adIds:String*)
This also takes a variable number of string, which are packaged into a Seq[String], so adIds is actually a Seq, but your first method ids doesn't take a Seq, it takes N strings, that's why ids(adIds: _*) works.
: _* this is called the splat operator, what that's doing is splatting the Seq into N strings.

When is a scala partial function not a partial function?

While creating a map of String to partial functions I ran into unexpected behavior. When I create a partial function as a map element it works fine. When I allocate to a val it invokes instead. Trying to invoke the check generates an error. Is this expected? Am I doing something dumb? Comment out the check() to see the invocation. I am using scala 2.7.7
def PartialFunctionProblem() = {
def dream()() = {
println("~Dream~");
new Exception().printStackTrace()
}
val map = scala.collection.mutable.HashMap[String,()=>Unit]()
map("dream") = dream() // partial function
map("dream")() // invokes as expected
val check = dream() // unexpected invocation
check() // error: check of type Unit does not take parameters
}
For convenience, Scala lets you omit empty parens when calling a method, but it's clever enough to see that the expected type in the first case is ()=>Unit, so it doesn't remove all the parens for you; instead, it converts the method into a function for you.
In the val check case, however, it looks just like a function call result getting assigned to a variable. In fact, all three of these do the exact same thing:
val check = dream
val check = dream()
val check = dream()()
If you want to turn the method into a function, you place _ after the method in place of the argument list(s). Thus,
val check = dream() _
will do what you want.
Well, the problem is that you got it all wrong. :-)
Here are some conceptual mistakes:
def dream()() = {
println("~Dream~");
new Exception().printStackTrace()
}
This is not a partial function. This is a curried method with two empty parameter lists which returns Unit.
val map = scala.collection.mutable.HashMap[String,()=>Unit]()
The type of the values in this map is not partial function, but function. Specifically, Function0[Unit]. A partial function would have type PartialFunction[T, R].
map("dream") = dream() // partial function
What happens here is that Scala converts the partially applied method into a function. This is not a simple assignment. Scala does the conversion because the type inferencer can guess the correct type.
val check = dream() // unexpected invocation
Here there's no expected type to help the type inferencer. However, empty parameter lists can be ommitted, so this is just a method call.