Julia: Same function for multiple types?
Asked Answered
G

2

5

I have this big function that I defined on a vector, but I'd like it to work also with a single value. I'd like the type of the first argument to be either a vector or a number.

I triend the following:

function bigfunction(x::Vector, y::Float64=0.5)

  # lots of stuff
  z = x .+ y
  return z
end


bigfunction(x::Number) = bigfunction()

The function works on a vector, but not on the number.

bigfunction([0, 1, 3])
bigfunction(2)

Should I do something with Union{} as I've seen sometimes? Or redefining the method in a different way?

Gaelan answered 27/8, 2018 at 19:11 Comment(6)
union{} is the perfect fit for your problem: function bigfunction(x::Union{Vector,Number}, y::Float64=0.5) should do what you wantSmutchy
It works perfectly thanks a lot!Gaelan
Alternatively, change the last line to bigfunction(x::Number) = bigfunction([x]). This style may prove cleaner.Doorstone
I'd second Robert's approach. Some operations work quite differently for vectors versus numbers, and although it may work fine now, small changes to bigfunction in the future could easily break it if the author is not careful to make sure each new line is compatible with both a vector or number input. Robert's approach sidesteps this very neatly (I use idiom's like it a lot in my code).Yazzie
Do you really need to restrict y to be a Float64? Now the function will not work if y is an integer, a complex, a single precision float, etc. Consider y::Number or y::Real. I don't know what bigfunction is supposed to do, but consider whether you can define it for (x::Number, y::Number=0.5), and then use broadcasting, that is, call bigfunction.(x, y) (with a dot) when x is an array.Maeda
@DominiqueMakowski That's a great question for someone like myself coming new to Julia.Dorsett
D
4

This question and the responses help illustrate for me the points made at the great blog post by Chris Rackauckas on type dispatch in Julia.

I have collated the responses into the following code:

# I ran this only in Julia 1.0.0.

## ========== Original function ==========
## function bigfunction(x::Vector, y::Float64=0.5)
##     # lots of stuff
##     z = x .+ y
##     return z
## end
## bigfunction(x::Number) = bigfunction()
## println(bigfunction([0, 1, 3]))
## println(bigfunction(2))
## ---------- Output has ERROR ----------
## [0.5, 1.5, 3.5]
## ERROR: LoadError: MethodError: no method matching bigfunction()


# ========== Answer Suggested by Picaud Vincent in comments ==========
# Note use of Union in function signature.
function bigfunction(x::Union{Vector, Number}, y::Float64=0.5)
    # lots of stuff
    z = x .+ y
    return z
end
println(bigfunction([0, 1, 3]))
println(bigfunction(2))
## ---------- Output Okay ----------
## [0.5, 1.5, 3.5]
## 2.5


# ========== Answer Suggested by Robert Hönig in comments ==========
# Note change in line right after function definition.
function bigfunction(x::Vector, y::Float64=0.5)
    # lots of stuff
    z = x .+ y
    return z
end
bigfunction(x::Number) = bigfunction([x])
println(bigfunction([0, 1, 3]))
println(bigfunction(2))
## ---------- Output Okay ----------
## [0.5, 1.5, 3.5]
## 2.5


# ========== Answer Suggested by Chris Rackauckas ==========
# Note change in function signature using duct typing--no type for x.
function bigfunction(x, y=0.5)
    # lots of stuff
    z = x .+ y
    return z
end
println(bigfunction([0, 1, 3]))
println(bigfunction(2))
## ---------- Output Okay ----------
## [0.5, 1.5, 3.5]
## 2.5
Dorsett answered 18/9, 2018 at 21:24 Comment(0)
O
3

Or duck type. Remember that functions always auto-specialize so choosing restrained dispatches does not impact the performance at all.

function bigfunction(x, y=0.5)

  # lots of stuff
  z = x .+ y
  return z
end

This will be just as performant yet will work on many more types. See this blog post on type-dispatch designs for more information.

Octodecillion answered 28/8, 2018 at 14:10 Comment(1)
That's interesting, with all this dispatching talk going out I thought it was more efficient indeed, thanksGaelan

© 2022 - 2025 — McMap. All rights reserved.