Outer constructor

My struct definition:

struct DiscreteField{T}
    time::Vector{Float64}
    data::Vector{T}   
end

I would like to create an outer constructor:

function DiscreteField(data::Base.Iterators.Zip{Tuple{Vector{Float64},Vector{}}})
    a = Float64[]
    b = []

    for (time, val) in data
        push!(a, time)
        push!(b, val)
    end
    return DiscreteField(a, b)
end

Then the initialization of object got error:

DiscreteField(data)

Error message:

MethodError: no method matching DiscreteField(::Base.Iterators.Zip{Tuple{Array{Float64,1},Array{Int64,1}}})
Closest candidates are:
  DiscreteField() at In[8]:7
  DiscreteField(!Matched::Array{Float64,1}, !Matched::Array{T,1}) where T at In[11]:4
  DiscreteField(!Matched::Base.Iterators.Zip{Tuple{Array{Float64,1},Array{T,1} where T}}) at In[15]:2

Stacktrace:
 [1] top-level scope at In[17]:100:

Why does this happens?

I have the other outer constructor which works well:

function DiscreteField{T}(data::Base.Iterators.Zip{Tuple{Vector{Float64}, Vector{T}}}) where {T}
    a = Float64[]
    b = []

    for (time, val) in data
        push!(a, time)
        push!(b, val)
    end
    return DiscreteField(a, b)
end

Would you mind telling me what was the error in the previous constructor?

Nothing per se, but you probably called it with a data it didn’t have a method for. Since you did not provide data, it’s hard to say what the problem was.

Generally, it is a very bad idea to specialize constructors like this. Base.Iterators.Zip is an implementation detail of zip, and could change any time. Just defining DiscreteField(data) would be fine, and it would work on any iterable that provides 2-tuples. See the last point in this recent blog post:

https://white.ucc.asn.au/2020/04/19/Julia-Antipatterns.html

2 Likes

Thank you for your advice! I got that idea and success with tuple.