Reputation: 1851
I have a situation where I'd like to set a function with a parametric return type - a simplified example below. It seems like this is not currently possible - what is the logical idiom to use instead? It is not obvious to me how to achieve reasonable code re-use.
struct Output{T <: Number}
other_details::String # lots of stuff here
numeric_output::T
end
function get_output{T <: Number}(input)::Output{T}
transformed_input = input
# Do stuff to transformed_input
Output{T}(
"lots of data",
transformed_input
)
end
input = 1::Int64
get_output{Float64}(input)
Any thoughts appreciated.
Upvotes: 3
Views: 216
Reputation: 7704
As you might have noticed, parametrically defined functions, e.g. functions like foo{T}(x)
, can only be defined if they are constructors for a type (which has already been defined). What you can do instead is take the desired output type as a function argument, like this:
struct Output{T <: Number}
other_details::String
numeric_output::T
end
function get_output(::Type{T}, input) where {T <: Number}
Output("lots of data", T(input))
end
julia> get_output(Float64, 1)
Output{Float64}("lots of data", 1.0)
Note that a literal 1
is already an integer. There's no need to write 1::Int64
.
Also note the use of a singleton type in the function signature. This only serves to restrict the dispatch. You could write get_output
like this and it would work fine:
get_output(T, input) = Output("lots of data", T(input))
By the way, I would strongly recommend against doing this, but it is possible to cheat, since the Julia compiler does not enforce that constructors actually return instances of the types that they are supposed to construct:
struct Output{T <: Number}
other_details::String
numeric_output::T
end
struct get_output{T} end
function get_output{T}(input) where {T <: Number}
Output("lots of data", T(input))
end
julia> get_output{Float64}(1)
Output{Float64}("lots of data", 1.0)
Upvotes: 5