Parametric Types with struct constructors

Hello! I’m new to julia and trying to get a grasp on parametric types / use it like a geric type.

Here’s the code:

struct Interval{T}
    start::Int
    stop::Int 
    val::T 
end

struct ScAIList{T}
    interval_list::Vector{Interval{T}}
    other_stuff::Int 
end

function ScAIList{T}(inputs::Vector{Interval{T}})::ScAIList{T} where T
    input_len = length(inputs)
    return DataStructure(inputs, input_len)
end 

function main()
    inputs = [Interval(3, 5, true), Interval(4, 10, false)]
    container = ScAIList{Bool}(inputs)
end

main()

Error message:

ERROR: MethodError: no method matching ScAIList{Bool}(::Array{Interval{Bool},1}, ::Int64)
Closest candidates are:
  ScAIList{Bool}(::Any, ::Any, ::Any, ::Any, ::Any) where T at /home/me/.julia/dev/scailist/src/scailist.jl:15
  ScAIList{Bool}(::Array{Interval{T},1}) where T at /home/me/.julia/dev/scailist/src/scailist.jl:23
  ScAIList{Bool}(::Array{Interval{T},1}, ::UInt64) where T at /home/me/.julia/dev/scailist/src/scailist.jl:23
Stacktrace:
 [1] ScAIList{Bool}(::Array{Interval{Bool},1}) at /home/me/.julia/dev/scailist/src/scailist.jl:23
 [2] top-level scope at REPL[7]:1 

My outer constructor doesn’t appear to apply ‘T’ to the Interval it contains?

Please provide self containing code. Here, DataStructure is not defined.

2 Likes

To stress Kris’ point, if you change that to ScAIList the code works. But probably that is not what you need :slight_smile:

julia> main()
ERROR: UndefVarError: DataStructure not defined
Stacktrace:
 [1] ScAIList{Bool}(::Array{Interval{Bool},1}) at ./REPL[3]:3
 [2] main() at ./REPL[4]:3
 [3] top-level scope at none:0

julia> function ScAIList{T}(inputs::Vector{Interval{T}})::ScAIList{T} where T
           input_len = length(inputs)
           return ScAIList(inputs, input_len)
       end

julia> main()
ScAIList{Bool}(Interval{Bool}[Interval{Bool}(3, 5, true), Interval{Bool}(4, 10, false)], 2)

Cheers!

Well, I feel foolish. In getting a working example together, I think I figured it out. I had a default argument to ScAIList that was the wrong type, so nothing was working. The parametric types were working as expected the whole time!

Working example code:

struct Interval{T}
    start::Int
    stop::Int 
    val::T 
end

struct ScAIList{T}
        intervals::Vector{Interval{T}}
        num_comps::Int
        comp_lens::Vector{Int}
        comp_idxs::Vector{Int}
        max_ends::Vector{Int}
end

function ScAIList{T}(input_intervals::Vector{Interval{T}}, min_cov_len::Int = 20)::ScAIList{T} where T
        max_comps = floor(Int, log2(float(length(input_intervals)))) + 1
        min_cov = div(min_cov_len, 2)

        # A compoenet is essentially a sublist
        num_comps = nothing # number of components
        comp_lens = Vector{Int}() # lengths of each component
        comp_idxs = Vector{Int}() # start positions of each component
        max_ends = Vector{Int}() # list of the max end positions

        min_comp_len = max(64, min_cov_len) # min length of a component

        input_len = length(input_intervals)
        sort!(input_intervals, by  = iv -> iv.start)

        decomposed = Vector{Interval{T}}()

        # if input_len <= min_comp_len
                num_comps = 1
                push!(comp_lens, input_len)
                push!(comp_idxs, 1)
                append!(decomposed, input_intervals)
        # end

        # Augment with maxend
        for j in 1:num_comps
                comp_start = comp_idxs[j]
                comp_end = comp_start + comp_lens[j] - 1
                max_end = decomposed[comp_start].stop
                push!(max_ends, max_end)
                for iv in decomposed[comp_start:comp_end]
                        if iv.stop > max_end
                                max_end = iv.stop
                        end
                        push!(max_ends, max_end)
                end
        end

        return ScAIList{T}(decomposed, num_comps,comp_lens, comp_idxs, max_ends)
end

in repl

ScAIList{Bool}([Interval(3, 5, true), Interval(4, 10, false)])