Abstract Types Convertion


#1

I am extending a current framework (Persa), and adding some new functionality. As a matter of fact, i need to use the same types to benefit from the framework.

This is my current structure:

struct ContextRating{T <: Number} <: Persa.AbstractRating{T}
    value::T
    context::Dict{Symbol,Any}
    ContextRating(x::T, preference::Persa.Preference{T}, context::Dict{Symbol,Any}) where T <: Number = new{T}(Persa.correct(x, preference), context)
end

struct DatasetContext{T <: Number} <: Persa.AbstractDataset{T}
	ratings::SparseMatrixCSC{Persa.AbstractRating{T}, Int}
        preference::Persa.Preference{T}
        users::Int
        items::Int
	metaContext::Dict{Symbol,DataType}
end

Relevant Persa Structures:

abstract type AbstractDataset{T <: Number}
end

abstract type AbstractRating{T <: Number}
end

struct Dataset{T <: Number} <: AbstractDataset{T}
    ratings::SparseMatrixCSC{AbstractRating{T}, Int}
    preference::Preference{T}
    users::Int
    items::Int
end

The problem is i cant convert

Array{ContextCF.ContextRating{Int64},1}

to:

Array{Persa.AbstractRating{Int64},1}

The log of the error:

ERROR: LoadError: MethodError: no method matching ContextCF.DatasetContext(::SparseArrays.SparseMatrixCSC{ContextCF.ContextRating{Int64},Int64}, ::Persa.Preference{Int64}, ::Int64, ::Int64, ::Dict{Symbol,DataType})
Closest candidates are:
  ContextCF.DatasetContext(::SparseArrays.SparseMatrixCSC{Persa.AbstractRating{T<:Number},Int64}, ::Persa.Preference{T<:Number}, ::Int64, ::Int64, ::Dict{Symbol,DataType}) where T<:Number at /Users/Equipe/.julia/dev/ContextCF/src/dataset.jl:2
Stacktrace:
 [1] ContextCF.DatasetContext(::DataFrames.DataFrame, ::Persa.Dataset{Int64}, ::Dict{Symbol,DataType}) at /Users/Equipe/.julia/dev/ContextCF/src/dataset.jl:70
 [2] ContextCF.DatasetContext(::DataFrames.DataFrame, ::Dict{Symbol,DataType}) at /Users/Equipe/.julia/dev/ContextCF/src/dataset.jl:21
 [3] ContextCF.DatasetContext(::DataFrames.DataFrame) at /Users/Equipe/.julia/dev/ContextCF/src/dataset.jl:18
 [4] top-level scope at none:0
 [5] include_string(::Module, ::String, ::String) at ./loading.jl:1005
 [6] (::getfield(Atom, Symbol("##129#135")){String,String,Module})() at /Users/Equipe/.julia/packages/Atom/7rQ1O/src/eval.jl:125
 [7] withpath(::getfield(Atom, Symbol("##129#135")){String,String,Module}, ::String) at /Users/Equipe/.julia/packages/CodeTools/hB4Hy/src/utils.jl:30
 [8] withpath at /Users/Equipe/.julia/packages/Atom/7rQ1O/src/eval.jl:46 [inlined]
 [9] #128 at /Users/Equipe/.julia/packages/Atom/7rQ1O/src/eval.jl:122 [inlined]
 [10] with_logstate(::getfield(Atom, Symbol("##128#134")){String,String,Module}, ::Base.CoreLogging.LogState) at ./logging.jl:397
 [11] with_logger at ./logging.jl:493 [inlined]
 [12] #127 at /Users/Equipe/.julia/packages/Atom/7rQ1O/src/eval.jl:121 [inlined]
 [13] hideprompt(::getfield(Atom, Symbol("##127#133")){String,String,Module}) at /Users/Equipe/.julia/packages/Atom/7rQ1O/src/repl.jl:85
 [14] macro expansion at /Users/Equipe/.julia/packages/Atom/7rQ1O/src/eval.jl:120 [inlined]
 [15] (::getfield(Atom, Symbol("##126#132")){Dict{String,Any}})() at ./task.jl:85
in expression starting at /Users/Equipe/playground.jl/src/playground.jl.jl:8```

Even though they come from the same type. Is there a way to solve this?

#2

Try this example here:

julia> abstract type S{T <: Number} end

julia> struct Foo{T <: Number} <: S{T}
       x::T
       end

julia> i = S{Int}[]
0-element Array{S{Int64},1}

julia> push!(i, Foo(10))
1-element Array{S{Int64},1}:
 Foo{Int64}(10)

#3

Tried. But it didnt work.

julia> v = Persa.AbstractRating{Number}[]
0-element Array{Persa.AbstractRating{Number},1}

julia> a = ContextCF.ContextRating{Number}
ContextCF.ContextRating{Number}

julia> push!(v,a)
ERROR: MethodError: Cannot `convert` an object of type Type{ContextCF.ContextRating{Number}} to an object of type Persa.AbstractRating{Number}
Closest candidates are:
  convert(::Type{S}, ::T<:(Union{CategoricalString{R}, CategoricalValue{T,R} where T} where R)) where {S, T<:(Union{CategoricalString{R}, CategoricalValue{T,R} where T} where R)} at /Users/pauloxavier/.julia/packages/CategoricalArrays/rQrLR/src/value.jl:86
  convert(::Type{T}, ::T) where T at essentials.jl:154
Stacktrace:
 [1] push!(::Array{Persa.AbstractRating{Number},1}, ::Type) at ./array.jl:855
 [2] top-level scope at none:0

#4

Your issue is a=ContextCF.ContextRating{Number} is not of type ContextCF.ContextRating{Number}, but rather of type DataType. You need something like a=ContextCF.ContextRating{Number}(5).


#5

Oh, sure. You’re right.

julia> rating
ContextCF.ContextRating{Int64}(2, Dict{Symbol,Any}(:isWeekend=>true,:notWeekend=>false))

julia> arr = Persa.AbstractRating{Int}[]
0-element Array{Persa.AbstractRating{Int64},1}

julia> push!(arr,rating)
1-element Array{Persa.AbstractRating{Int64},1}:
 ContextCF.ContextRating{Int64}(2, Dict{Symbol,Any}(:isWeekend=>true,:notWeekend=>false))

Sounds like i need to explicity pass the Type, even though Int is a subtype of number, i guess.


#6

In the end, that was the problem, i had to pass the type explicitly.

DatasetContext{eltype(df[:rating])}()

Thanks for the help.