Constructor with a vector of parameters doesn't seem to be recognized?

Minimal working example:

struct PureComponentData{Q, T}

    ΔGf::T
    ΔHf::T
    ΔSf::T
    ΔGm::T
    ΔHm::T
    ΔSm::T 
    Tm::T
    Cp::Q
end 

struct CpData{T}
    Tmin::T
    Tmax::T
    a::T
    b::T
    c::T
    d::T
end

function PureComponentData{Q,T}(params::Vector{T}, Cp::Q) where {Q,T}
    if length(params) != 7
        throw(ArgumentError("Must supply the correct number of parameters for Component Data"))
    end
    return PureComponentData(params..., Cp)
end

function __main__()
    Cp = CpData(0,0,0,0,0,0)
    Compound = PureComponentData([1,1,1,1,1,1], Cp)
end

Running this file, I get:

julia> __main__()
ERROR: MethodError: no method matching PureComponentData(::Array{Int64,1}, ::CpData1{Int64})
Closest candidates are:
  PureComponentData(::T, ::T, ::T, ::T, ::T, ::T, ::T, ::Q) where {Q, T} at /path/to/file.jl:3
Stacktrace:
 [1] __main__() at /path/to/file.jl:31
 [2] top-level scope at none:0

Why isn’t Julia recognizing the alternate constructor? What should I do instead?

The constructor signature isn’t correct. Try this:

function PureComponentData(params::Vector{T}, Cp::CpData{Q}) where {Q,T}
    if length(params) != 7
        throw(ArgumentError("Must supply the correct number of parameters for Component Data"))
    end
    return PureComponentData(params..., Cp)
end
3 Likes

Thanks for your answer! I was hopeful, but the error persists after making that change. Did you test it? Any other ideas?

Yes. Perhaps you can restart REPL and try again? Just post your new findings here.

I’m still getting the same error. This is the file I’m running now:

struct PureComponentData{Q, T}

    ΔGf::T
    ΔHf::T
    ΔSf::T
    ΔGm::T
    ΔHm::T
    ΔSm::T 
    Tm::T
    Cp::Q
end 

struct CpData{T}
    Tmin::T
    Tmax::T
    a::T
    b::T
    c::T
    d::T
end

function PureComponentData(params::Vector{T}, Cp::CpData{Q}) where {Q,T}
    if length(params) != 7
        throw(ArgumentError("Must supply the correct number of parameters for Component Data"))
    end
    return PureComponentData(params..., Cp)
end
function __main__()
    Cp = CpData(0,0,0,0,0,0)
    Compound = PureComponentData([1,1,1,1,1,1], Cp)
end

And it gives the same error:

               _
   _       _ _(_)_     |  Documentation: https://docs.julialang.org
  (_)     | (_) (_)    |
   _ _   _| |_  __ _   |  Type "?" for help, "]?" for Pkg help.
  | | | | | | |/ _` |  |
  | | |_| | | | (_| |  |  Version 1.1.0 (2019-01-21)
 _/ |\__'_|_|_|\__'_|  |  Official https://julialang.org/ release
|__/                                                                                      `

julia> include("mwe.jl")
__main__ (generic function with 1 method)

julia> __main__()
ERROR: MethodError: no method matching PureComponentData(::Array{Int64,1}, ::CpData1{Int64})
Closest candidates are:
  PureComponentData(::T, ::T, ::T, ::T, ::T, ::T, ::T, ::Q) where {Q, T} at /path/to/mwe.jl:3
Stacktrace:
 [1] __main__() at /path/to/mwe.jl:3:31
 [2] top-level scope at none:0

I copied and paste your mwe.jl content and ran it without any problem. However, I’m curious why you have CpData1 instead of CpData in the error message?

… Well. D’Oh. I had the name CpData1 in the original code, which helped me figure out the reason the updated version wasn’t working correctly. I hadn’t actually saved the file after changing it. Now it does indeed work great!

I have one final question here. So in general then, for some type MyStruct{T, U}:

struct MyStruct{T,U}
    x::T 
    y::U 
end 

Is it true that you can’t define some outer constructor
MyStruct{T,U}(x::T, y::U) = MyStruct(x,y) and then call it with some y that is itself a parametric type? If so, why not?

No, whether or not y has a parametric type is of no significance. An outer constructor of the form:

Foo{T}(...) where {T} = ...

is only invoked if you actually call it with some {T} at the call site (as in f = Foo{Int}(...) not f = Foo(...)). That’s the only reason your initial code didn’t work. If you want an outer constructor that doesn’t require the {T} to be specified, then you would define it as

Foo(...) where {...} = ...
1 Like

Ooooooohhh. Thank you. I read through the docs on constructors and didn’t understand that at all. Perhaps that point should be added to the manual, or clarified.