Addind Options to Function

Hi everyone.
I think this is really simple but I am not getting around it.

I have this function Rps that does some computation. Now, to the final results I can add some corrections. I would like to be able to do:

Rps(all arguments) → Standard output
Rps(all aguments, ‘Flat’) → Standard Output
Rps(all aguments, ‘Sphere’) → Apply spherical correction
Rps(all aguments, ‘Anaelastic’) → Apply anaelastic correction
Rps(all aguments,‘Sphere’, ‘Anaelastic’) → Apply both corrections

How can I get these keywords working inside the functions body?

You can use Julia’s multiple dispatch for this purposes. There is one of possible solutions:

struct Flat end
struct Sphere end
struct Anaelastic end

function Rps(all_arguments) 
    return Rps(all_arguments, Flat())
end

# type declaration :: in function argument without a name indicates that 
# the actual value of Flat object is unused, it only used for dispatch
# it is the same as 'unused::Flat'

function Rps(all_arguments, ::Flat) 
    ...
end

function Rps(all_arguments, ::Sphere) 
    ...
end

function Rps(all_arguments, ::Anaelastic) 
    ...
end

function Rps(all_arguments, ::Sphere, ::Anaelastic) 
    ...
end

Later on you can use your function as:

Rps(all_arguments)
Rps(all_arguments, Flat())
Rps(all_arguments, Sphere())
Rps(all_arguments, Sphere(), Anaelastic())

Structure with no fields creates a singleton object. It is completely fine to create this objects to dispatch on different implementations of your code. In many cases compiler will inline and eliminate Flat() or Sphere() objects creation at all. Unless you do it dynamically, e.g.

method = rand() > .5 ? Flat() : Sphere()
Rps(all_arguments, method)

What you can also do is to use Val built-in object to pass string-like compile-time values to your functions. For example

function Rps(all_arguments, ::Val{ :Flat })
    ...
end

and use it as

Rps(all_arguments, Val(:Flat))

Val is a powerful mechanism, but has to be used carefully and with caution. In some cases it may worsen the performance of your program.

3 Likes

Another more pedestrian alternative is:

julia> function f(x,args...)
         for arg in args
           if arg == "One"
             x += 1
           elseif arg == "Two"
             x += 2
           end
         end
         x
       end
f (generic function with 1 method)

julia> f(1)
1

julia> f(1,"One")
2

julia> f(1,"Two")
3

julia> f(1,"One","Two")
4


1 Like

From the sound of it, I would just have something like function Rps(args...; corrections=()) and then call it as Rps(args...; corrections=(Sphere, Anaelastic)) where you’ve defined e.g. an @enum of correction options (or maybe they are some other type… depends on how you perform this processing and how flexible you want to be). Then in the body of your function you can loop over the corrections.