Tuesday 19 March 2024

Named Arguments Differences

In 2 previous posts [1] and [2] we saw that Python, JavaScript and Kotlin have some differences (python limitations we can say) in how they deal with Default arguments. I was wondering if there are any differences in how they handle Named Arguments.

As for JavaScript, given that it does not support named arguments (which is rather surprising), there's not much to say.

The main difference between Python and Kotlin Named Arguments (also knows as Keyword Arguments in Python) has to do with mixing positional and named arguments in the same call. In Python the named arguments can be provided in any order, but you can not use a not-named argument (positional) after a named argument. In Kotlin, you can also provide named arguments in any order when you are not providing not-named arguments after them. So yes, that "when" means that you are also allowed to provide not-named arguments after named arguments, but if you do this, all the arguments (positional ones and named ones) have to be provided in just the same order they were defined in the function signature.

Let's see some examples in Python:


def format(w1, w2, txt):
    return f"{w1}{w2}{txt}{w2}{w1}"

print(format("-", "|", "Bonjour"))

print(format("-", "|", txt="Bonjour"))

print(format("-", w2="|", txt="Bonjour"))

print(format("-", txt="Bonjour", w2="|"))

# Positional argument cannot appear after keyword arguments
#print(format("-", txt="Bonjour", "|"))
#print(format("-", l2="|", "Bonjour"))


And in Kotlin:


package namedParameters


fun format(w1: String, w2: String, txt: String): String {
    return "$w1$w2$txt$w2$w1"
}


fun main() {
    println(format("-", "|", "Bonjour"))

    println(format("-", "|", txt = "Bonjour"))
    
    println(format("-", w2 = "|", txt = "Bonjour"))
    
    println(format("-", txt = "Bonjour", w2 = "|"))

    //error: Mixing named and positioned arguments is not allowed
    //println(format("-", txt="Bonjour", "|"))
    
    //If I'm going to provide an unnamed parameter after a named one (not available in Python), all the parameters in the call have to be passed in order
    
    println(format("-", w2 = "|", "Bonjour"))

}

From what I've read here named arguments in C# have the same behaviour as in Kotlin (you can provide not-named arguments after named ones, but this forces you to provide all of them in order). At first sight this feature seemed of little use to me. Once you provide some named argument, why would you skip the name of an ensuing argument if that's going to force you to provide all the arguments in the order defined in the signature? Well, indeed it makes sense, let me explain. When we have variables that have the same names as function parameters it can seem a bit redundant to use named arguments, so let's say we are passing as arguments some "inline values" and some variables with a different name from the parameter. This is a case where even if we are keeping the same order as in the function signature, using named arguments for those "inline values" and variables will do our code more clear. But if after those arguments we are going to pass a variable that has the same name as the parameter, using a named argument is redundant, so it's nice not to be forced to name it.

A bit related to this it has come to my mind a discussion in Python (there's a recently created PEP draft for it) about a syntax for shortening the use of named arguments when a variable and a parameter have the same name. The idea seems to be inspired by ruby and would look like this:


#For example, the function invocation:

my_function(my_first_variable=, my_second_variable=, my_third_variable=)

#Will be interpreted exactly equivalently to following in existing syntax:

my_function(
  my_first_variable=my_first_variable,
  my_second_variable=my_second_variable,
  my_third_variable=my_third_variable,
)


This looks like an excellent idea to me that would make unnecessary implementing the Kotlin/C# feature that we've been discussing.

There's one feature of named arguments in Python that I mentioned in my previous post. In Python a function can force us to provide certain (or all) arguments as named ones by means of "*", you can read more here and here. It seems there's been some discussion about adding this to Kotlin, but nothing has been done so far.

No comments:

Post a Comment