Using Multiple Dispatch with Keyword Arguments

Hi all,
Still a new Julia user here, but hoping to find some help. I’m building an application that will take in user-provided information and process it. There are a few required arguments from the user, and some optional. Given we don’t know exactly what the user will upload, I thought Julia’s multiple dispatch would come in handy, but I’m having trouble with it. Here’s an example code:

using DataFrames
using Statistics
my_dataset=DataFrame(Number=(1:6), Gender=["M", "F", "F", "M","M","M"], State=["Texas","Oklahoma","Texas","Texas","Oklahoma","Texas"])

function my_function(;dataset,calc)
    println(mean(dataset[:,calc]))
end


function my_function(;dataset,calc,by_group)
    groups = unique(dataset[:,by_group])
    df1 = dataset
    for g in groups
        print("working on $g")
        dataset = filter(row->row[by_group]==g,df1)
        println(mean(dataset[:,calc]))
    end
end

At this point, I thought if I run the function:

run=my_function(
    dataset=my_dataset,
    calc="Number" #or add ,by_group=nothing
)

It would run the first method

I thought if I run:

run=my_function(
    dataset=my_dataset,
    calc="Number",
    by_group="Gender"
)

Multi-dispatch would call the second method.

What actually happens is I get an error if I only run my_function with dataset and calc defined:
ERROR: UndefKeywordError: keyword argument by_group not assigned

If I run my_function with dataset, calc, and by_group defined, I get the intended result (second method is called): working on M4.0 working on F2.5

Is there a way to have multidispatch work based on arguments? All the examples I’ve seen online are just for changing the argument types (e.g. x::Int vs x::String). I’ve tried playing around by setting the first function to have by_group as an optional argument, but still can’t seem to get the intended result.

Also, please note that this is just an example… I know there’s better ways to calc a mean of a group rather than looping through a dataframe :slight_smile:

Thanks for your help!
Snowy

This looks similar to How can kwargs be used in multiple dispatch. In short, multiple dispatch does not apply to keyword arguments (“kwargs”), but you can maybe work around it.

This would work as intended if you use positional arguments rather than keyword arguments. The “drawback” is that the order of the arguments has to be right…

For this example, you could define

function my_function(;dataset,calc, by_group = nothing)
    by_group === nothing && return println(mean(dataset[:,calc]))
    groups = unique(dataset[:,by_group])
    df1 = dataset
    for g in groups
        print("working on $g")
        dataset = filter(row->row[by_group]==g,df1)
        println(mean(dataset[:,calc]))
    end
end

Another option is to define

 my_function(;dataset,calc, by_group = nothing) =  my_function(dataset,calc, by_group)

function my_function(dataset, calc, ::Nothing)
    println(mean(dataset[:,calc]))
end

function my_function(dataset,calc,by_group)
    groups = unique(dataset[:,by_group])
    df1 = dataset
    for g in groups
        print("working on $g")
        dataset = filter(row->row[by_group]==g,df1)
        println(mean(dataset[:,calc]))
    end
end

i.e., use the keyword function only to move the arguments to positional arguments, which then use dispatch to call the correct method

3 Likes

FYI: I fixed your thread title, since this question is about keyword arguments, not optional arguments. Optional arguments are positional, but has a default value specified.

1 Like