Types as Function Parameters

I feel like this is probably somewhere easily found in the documentation, but I haven’t figured out where, so I think I just don’t know the right vocabulary here.

Suppose I wanted to write the following silly function:

function parsestring(T::Type, s::AbstractString)
  v::Union{Nothing,T} = tryparse(T,s)

  return v
end

parsestring(Int, "3")
parsestring(Float64, "3.4")

I’ve found the above is slow. Alternatively I could write:

function parsestringFloat64(s::AbstractString)
  v::Union{Nothing,Float64} = tryparse(Float64,s)

  return v
end

function parsestringInt(s::AbstractString)
  v::Union{Nothing,Int} = tryparse(Int,s)

  return v
end

parsestringInt("3")
parsestringFloat64("3.4")

which is predictably fast. The question is if there is a more idiomatic way of writing and calling functions in the second case? Do I need to dispatch on values?

I should add that dispatching on values is very fast, although I still feel like I am missing a more idiomatic way to do this:

function parsestring(s::AbstractString, ::Val{T}) where T
  v::Union{Nothing,T} = tryparse(T,s)

  return v
end

parsestring("3", Val(Int))
parsestring("3.4", Val(Float64))

Hi Clinton!

You can try the following:

function parsestring(::Type{T}, s::AbstractString) where {T}
    v::Union{Nothing,T} = tryparse(T, s)
    return v
end

parsestring(Int, "3")
parsestring(Float64, "3.4")

This is a pattern that shows up fairly often in Julia code.

4 Likes

Thanks! That was exactly what I was looking for.

1 Like

alternatively:

#general case
function parsestring(::Type{T},s::AbstractString) where T
  v::Union{Nothing,T} = tryparse(T,s) #the return is't necessary
end

#optimized case, for int64 and float64
function parsestring(::Type{Int64},s::AbstractString) 
  v::Union{Nothing,Int64} = tryparse(Int64,s) 
end

function parsestring(::Type{Float64},s::AbstractString) 
  v::Union{Nothing,Float64} = tryparse(Float64,s) 
end
1 Like

The “optimized case” should not be necessary and does not actually affect performance, so there’s no need to go beyond the nice generic where T form:

julia> using BenchmarkTools

julia> function parsestring(::Type{T},s::AbstractString) where T
         v::Union{Nothing,T} = tryparse(T,s) #the return is't necessary
       end
parsestring (generic function with 1 method)

julia> @btime parsestring($Int64, $("1"))
  18.972 ns (0 allocations: 0 bytes)
1

julia> function parsestring(::Type{Int64},s::AbstractString) 
         v::Union{Nothing,Int64} = tryparse(Int64,s) 
       end
parsestring (generic function with 2 methods)

julia> @btime parsestring($Int64, $("1"))
  18.974 ns (0 allocations: 0 bytes)
1
4 Likes

Lol, I forgot the interpolation when measuring :sweat_smile: