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?

Dominique Makowski
  • 1,511
  • 1
  • 13
  • 30
  • 3
    union{} is the perfect fit for your problem: `function bigfunction(x::Union{Vector,Number}, y::Float64=0.5)` should do what you want – Picaud Vincent Aug 27 '18 at 19:41
  • It works perfectly thanks a lot! – Dominique Makowski Aug 27 '18 at 20:01
  • 7
    Alternatively, change the last line to `bigfunction(x::Number) = bigfunction([x])`. This style may prove cleaner. – Robert Hönig Aug 27 '18 at 21:47
  • 2
    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). – Colin T Bowers Aug 27 '18 at 23:13
  • 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. – DNF Aug 28 '18 at 06:16
  • @DominiqueMakowski That's a great question for someone like myself coming new to Julia. – Julia Learner Sep 18 '18 at 21:13

2 Answers2

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
Julia Learner
  • 2,754
  • 15
  • 35
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.

Chris Rackauckas
  • 18,645
  • 3
  • 50
  • 81