Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unwrapping a list or map as function arguments in Scala

Tags:

python

scala

Is it possible to dynamically unwrap a list/tuple/map items as arguments to a function in Scala? I am looking for a Scala equivalent of Python's args/kwargs.

For instance, in Python if a function is defined as def foo(bar1, bar2, bar3=None, bar4=1) then given a list x=[1,7] and a dictionary y={'bar3':True, 'bar4':9} you can call foo as foo(*x, **y).

like image 687
Abraham Yusuf Avatar asked Dec 22 '13 15:12

Abraham Yusuf


People also ask

How do I unpack a list in Scala?

The unzip function is applicable to both Scala's Mutable and Immutable collection data structures. The unzip method will unzip and un-merge a collection consisting of element pairs or Tuple2 into two separate collections. The unzip method is a member of GenericTraversableTemplate trait.

What is Scala map function?

Advertisements. map() method is a member of TraversableLike trait, it is used to run a predicate method on each elements of a collection. It returns a new collection.

What does => mean in Scala?

=> is syntactic sugar for creating instances of functions. Recall that every function in scala is an instance of a class. For example, the type Int => String , is equivalent to the type Function1[Int,String] i.e. a function that takes an argument of type Int and returns a String .

What is a map in Scala?

The map is a higher-order function, which takes some function as a parameter and applies the function to every element of the source collection. The return type is the same as that of the source type of collection. 1. Immutable Map 2. Mutable Map:- By using scala.collection.mutable.Map

Is it possible to get arguments from another method in Scala?

runtime. But it never accepts parameters from any other method in the program. For accessing our Scala command-line arguments using the args array, which is made available to us implicitly when we extend App.

How can I reuse control patterns in Scala?

Here’s what Martin Odersky wrote about this in his book, Programming in Scala (#ad): “You can use functions within your code to factor out common control patterns, and you can take advantage of higher-order functions in the Scala library to reuse control patterns that are common across all programmers’ code.”

Is Scala easier to learn than imperative programming?

In many situations Scala/FP code can be easier to understand than imperative code. That’s because a great benefit of Scala/FP is that methods like filter, map, head, tail, etc., are all standard, built-in functions, so once you learn them you don’t have to write custom for loops any more.


1 Answers

Just to be clear, the following is valid Python code:

def foo(bar1, bar2, bar3=None, bar4=1): print("bar1="+str(bar1)+" bar2="+str(bar2)+" bar3="+str(bar3)+" bar4="+str(bar4))
x=[1,7]
y={'bar3':True, 'bar4':9}
foo(*x,**y)

However, there is no analogous Scala syntax. There are some similar things, but the main reason this is never going to be possible is that it would violate the compile-time type checking that Scala requires. Let's look more closely.

The reasons

First, think about the varargs portion. Here you want to be able to pass in an arbitrary-length list of arguments and have it fill in the relevant function parameters. This will never work in Scala because the type checker requires that the parameters passed into a function be valid. In your scenario, foo() can accept a parameter list x of length two, but no less. But since any Seq can have an arbitrary number of parameters, how would the type checker know that the x being pass it is valid at compile time?

Second, think about the keywword arguments. Here you are asking for the function to accept an arbitrary Map of arguments and values. But you get the same problem: How can the compile-time type checker know that you are passing in all of the necessary arguments? Or, further, that they are the right types? After all, they example you give is a Map containing both a Boolean and an Int, which would have the type Map[String, Any], so how would the type checker know that this would match your parameter types?

Some solutions

Scala's varargs

You can do some similar things, but not this exactly. For example, if you defined your function to explicitly use varargs, you can pass in a Seq:

def foo(bar1: Int*) = println(f"bar1=$bar1")
val x = Seq(1, 2)
foo(x:_*)

This works because Scala knows that it only needs a sequence of zero or more arguments, and a Seq will always contain zero or more items, so it matches. Further, it only works if the types match as well; here it's expecting a sequence of Ints, and gets it.

tupled

The other thing you can do is to pass in a tuple of arguments:

def foo(bar1: Int, bar2: Int, bar3: Boolean = false, bar4: Int = 1) = println(f"bar1=$bar1 bar2=$bar2 bar3=$bar3 bar4=$bar4")
val x = (1, 2, true, 9)
(foo _).tupled(x)

Again, this works because Scala's type checker can verify that the arguments are valid. The function requires four arguments, of types Int, Int, Boolean, and Int, and since a tuple in Scala has a fixed length and known (and possibly different) types for each position, the type-checker can verify that the arguments match the expected parameters.

like image 89
dhg Avatar answered Oct 04 '22 21:10

dhg