Parametric constructor


#1

I am defining the data structure below, which contains a string and a parameterized type array. I’m having trouble defining the corresponding parameterized constructor that initializes a zero-length array of the requested type. see below

type mydata{T}
    name::String
    data::Array{T,1}
end

function mydata{T}(name::String)
     mydata{T}(name, T[])
end

mydata{Int64}("myIntdata")

I am getting a warning “WARNING: static parameter T does not occur in signature for Type”, and consequently a call to the constructor is ignored with an error message.
I am clearly defining the constructor in a wrong way…


#2
mutable struct MyData{T}
    name::String
    data::Vector{T}
    MyData{T}(obj::AbstractString) where T = new(obj, Vector{T}())
end
MyData{Int64}("X")

#3

Like this you lose the other constructor though: MyData("a", [1,2]) no longer works.

I think it should be:

mutable struct MyData{T}
    name::String
    data::Vector{T}
end

(::Type{MyData{T}})(s::String) where {T} = MyData(s, T[])

MyData("a", [1,2])

MyData{Int64}("a")


#4

Use the newer syntax where T:

function mydata{T}(name::String) where T
     mydata{T}(name, T[])
end

The old syntax function mydata{T}(name::String) is equivalent to the new syntax function mydata(name::String) where T, and both correctly give an error.

There isn’t a consistent way to express what you want using the old syntax, and this was one of the motivating reasons for introducing the new syntax: https://stackoverflow.com/questions/41931289/where-in-function-definitions-in-julia-0-6


#5

Thanks! this one works. I am still confused about the syntax though. Is there a difference between

(::Type{MyData{T}})

as opposed to just

MyData{T}

#6

@greg_plowman has a cleaner solution. I somehow got convinced that the Type trick was necessary, but it’s not, so you should go with the where syntax as he explains above.

In Julia you can overload the function call operator: telling Julia that whenever there is a “function call” (something of the type a(b)) if a is of a given type, it should call a specific method. For example (don’t do this in your code!):

julia> (a::String)(x) = println("I can call strings!")

julia> "aa"(2)
I can call strings!

This is very powerful: for example if you have defined say a struct representing a polynomial, you could overload the function call so that (p::Polynomial)(x::Number) would compute the value of the polynomial at that number (see this example from the docs).

I used an extra trick to say that I wanted to overload the function call only when my object is MyData{T} for some T. To do that, you can dispatch on Type{MyData{T}} (MyData{T} are the only objects of type Type{MyData{T}} ).

As @greg_plowman points out, this is completely redundant and you may simply define your function with the where syntax, but at least you’ve learned one new trick :slight_smile: