aberdysh
aberdysh

Reputation: 1664

Parametric return types

I'm trying to understand how parametric types work in Julia.

Suppose I have a function foo, which takes an Integer (i.e. non-parametric type), and I want to assert this function to return a vector, whose elements are subtypes of Real. From documentation I deduced that it should be implemented as follows:

function foo{T<:Real}(n::Integer)

    # come code to generate variable vec

    return vec::Vector{T}

end

But it is not working. What am I doing wrong?

Upvotes: 2

Views: 1325

Answers (3)

raythurnevoid
raythurnevoid

Reputation: 2824

Now you can do this:

function with_parametric_output(::Type{T}, cb::Function)::T where {T <: Any}
    return cb()
end
    
with_parametric_output(Int, () -> 3)

Upvotes: 0

Reza Afzalan
Reza Afzalan

Reputation: 5746

A parametric method or a constructor of a parametric type

A function is called using the traditional parenthesis syntax:

julia> f(2,3)
5

The above rule is true for both parametric and non-parametric methods.
So, one should not try to call a parametric method like: f{atype}(2,3). I think the source of this mall-usage could be the syntax of calling a parametric type constructor:

julia> typeof(Array{Int})
DataType

julia> Array{Int}(2)
2-element Array{Int32,1}:
 57943068
 72474848 

But in the case of a parametric method:

julia> same_type{T}(x::T, y::T) = true;

julia> typeof(same_type)
Function

julia> same_type{Int}
ERROR: TypeError: Type{...} expression: expected Type{T}, got Function

So with this introduction it has become clear that something like:

function foo{T<:Real}(n::Integer)
  .....
end

would be useless, because the value of T won't be determined from caller the arguments.

Make benefit of parametric methods

julia> same_type{T}(x::T, y::T) = true;
julia> same_type(x,y) = false;

julia> same_type(1, 2)
true
julia> same_type(1, 2.0)
false

The main purpose of parametric methods is to let dispatch find the right method to call with respect to argument types when calling a function, but also it has the following idiomatic side effect:

Method type parameters are not restricted to being used as the types of parameters: they can be used anywhere a value would be in the signature of the function or body of the function.

julia> mytypeof{T}(x::T) = T
mytypeof (generic function with 1 method)

julia> mytypeof(1)
Int64

Now, let's go back to the main problem of:

How to write a method with Parametric return types?

If your method is already parametric, you could use the parameter value as return type as in the above mytypeof sample or e.g:

julia> newoftype{T}(x::T,n) = T(n)
newoftype (generic function with 1 methods)

julia> newoftype([1,2],4)
4-element Array{Int32,1}:
   57943296
   72475184
  141142104
 1970365810

But making return type of a method, a function of arguments value is a straightforward functionality and could be simply done without need to a parametric method. really many of typical methods do this job e.g:

julia> Array(Int,4)
4-element Array{Int32,1}:
 126515600
  72368848
  72474944
         0
julia> Array(Float64,4)
4-element Array{Float64,1}:
 -2.122e-314
  0.0
  5.12099e-292
  5.81876e-292

It could be done using a argument type of Type e.g:

julia> myarray(T::Type,n::Int)=Array(T,n); 

Upvotes: 0

Colin T Bowers
Colin T Bowers

Reputation: 18560

Parametric types are used to parameterise the inputs to a function, not the outputs. If your function is type-stable (read about what that means in the performance tips), then the output of the function can be automatically inferred by the compiler based on the input types, so there should be no need to specify it.

So your function might look something like this:

function foo{T<:Real}(n::T)
     #some code to generate vec
     return(vec)
end

For example, you can generate a vector of the appropriate type within the body of your function, e.g. something like this:

function f1{T<:Number}(x::T)
    y = Array(T, 0)
    #some code to fill out y
    return(y)
end

But note that T must appear in the argument definitions of the inputs to the function, because this is the purpose of parametric types. You'll get an error if T does not appear in the description of the inputs. Something like this doesn't work:

f{T<:Number}(x::Vector) = x

WARNING: static parameter T does not occur in signature for f at none:1.
The method will not be callable.
f (generic function with 1 method)

But this does, and is type stable, since if the input types are known, then so are the outputs

f{T<:Number}(x::Vector{T}) = x

Upvotes: 2

Related Questions