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)
.
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.
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.
=> 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 .
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
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.
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.”
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.
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.
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?
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With