Trouble with types when porting old Compose.jl code to v0.6


#1

I’m in the process of updating Compose.jl to work with Julia 0.6 and I got a MethodError thrown when accessing the new constructor via a typealias: (this was originally posted over here: https://github.com/JuliaLang/julia/issues/20774

Changes made on my part

I added @compat and {P} and where {P} do the following object definition:

immutable Form{P <: FormPrimitive} <: ComposeNode
    primitives::Vector{P}
    tag::Symbol

    @compat function Form{P}(prim, tag::Symbol=empty_tag) where {P <: FormPrimitive}
        new(prim, tag)
    end
end

and updated a typealias:

old:

immutable SimplePolygonPrimitive{P <: Vec} <: FormPrimitive
    points::Vector{P}
end

typealias SimplePolygon{P<:SimplePolygonPrimitive} Form{P}

typealias Polygon SimplePolygon
typealias PolygonPrimitive SimplePolygonPrimitive

new:

immutable SimplePolygonPrimitive{P <: Vec} <: FormPrimitive
    points::Vector{P}
end

const SimplePolygon{P<:SimplePolygonPrimitive} = Form{P}

const Polygon = SimplePolygon
const PolygonPrimitive = SimplePolygonPrimitive

Differences in behavior

OLD:

julia> using Compose

julia> x = [Compose.PolygonPrimitive(Tuple{Measure, Measure}[(Compose.x_measure(point[1]), Compose.y_measure(point[2]))
                                  for point in [(0.1, 0.2), (0.3, 0.4), (0.5, 0.6)]])]
1-element Array{Compose.SimplePolygonPrimitive{Tuple{Measures.Measure,Measures.Measure}},1}:
 Compose.SimplePolygonPrimitive{Tuple{Measures.Measure,Measures.Measure}}(Tuple{Measures.Measure,Measures.Measure}[(0.1cx,0.2cy),(0.3cx,0.4cy),(0.5cx,0.6cy)])

julia> Compose.Form(x, Compose.empty_tag)
Compose.Form{Compose.SimplePolygonPrimitive{Tuple{Measures.Measure,Measures.Measure}}}(Compose.SimplePolygonPrimitive{Tuple{Measures.Measure,Measures.Measure}}[Compose.SimplePolygonPrimitive{Tuple{Measures.Measure,Measures.Measure}}(Tuple{Measures.Measure,Measures.Measure}[(0.1cx,0.2cy),(0.3cx,0.4cy),(0.5cx,0.6cy)])],Symbol(""))

julia> Compose.Polygon(x, Compose.empty_tag)
Compose.Form{Compose.SimplePolygonPrimitive{Tuple{Measures.Measure,Measures.Measure}}}(Compose.SimplePolygonPrimitive{Tuple{Measures.Measure,Measures.Measure}}[Compose.SimplePolygonPrimitive{Tuple{Measures.Measure,Measures.Measure}}(Tuple{Measures.Measure,Measures.Measure}[(0.1cx,0.2cy),(0.3cx,0.4cy),(0.5cx,0.6cy)])],Symbol(""))

NEW:

julia> using Compose

julia> x = [Compose.PolygonPrimitive(Tuple{Measure, Measure}[(Compose.x_measure(point[1]), Compose.y_measure(point[2]))
                                  for point in [(0.1, 0.2), (0.3, 0.4), (0.5, 0.6)]])]
1-element Array{Compose.SimplePolygonPrimitive{Tuple{Measures.Measure,Measures.Measure}},1}:
 Compose.SimplePolygonPrimitive{Tuple{Measures.Measure,Measures.Measure}}(Tuple{Measures.Measure,Measures.Measure}[(0.1cx, 0.2cy), (0.3cx, 0.4cy), (0.5cx, 0.6cy)])

julia> Compose.Form(x, Compose.empty_tag)
Compose.Form{Compose.SimplePolygonPrimitive{Tuple{Measures.Measure,Measures.Measure}}}(Compose.SimplePolygonPrimitive{Tuple{Measures.Measure,Measures.Measure}}[Compose.SimplePolygonPrimitive{Tuple{Measures.Measure,Measures.Measure}}(Tuple{Measures.Measure,Measures.Measure}[(0.1cx, 0.2cy), (0.3cx, 0.4cy), (0.5cx, 0.6cy)])], Symbol(""))

julia> Compose.Polygon(x, Compose.empty_tag)
ERROR: MethodError: no method matching Compose.Form{P} where P<:Compose.SimplePolygonPrimitive(::Array{Compose.SimplePolygonPrimitive{Tuple{Measures.Measure,Measures.Measure}},1}, ::Symbol)
Closest candidates are:
  Compose.Form{P} where P<:Compose.SimplePolygonPrimitive(::Any) where T at sysimg.jl:24

Do you all have any suggestions on what I’m doing wrong? I’m not sure why this code broke on v0.5.


#2

For 0.5, I don’t think @compat can handle this.

For the constructor method error, it’s a bug on 0.5 if it doesn’t rase an error there.


#3

For 0.5, I don’t think @compat can handle this.

Then what’s the recommended way of preserving backwards compatability?

For the constructor method error, it’s a bug on 0.5 if it doesn’t rase an error there.

This is 3 year old code and has worked on every previous version of Julia. I didn’t write it and I don’t fully understand how it works.


#4

I mean it’s a base julia bug that it worked on 0.5, it was never supposed to work. You don’t need to understand why it worked to fix it (though you do need to understand how it is supposed to behave/what is supposed to work). Jeff have already clearly pointed out the correct way to make it work, have you tried it already?


#5

see https://github.com/JuliaLang/Compat.jl/issues/332 for the otherwise insufficiently documented way to make inner constructors work for both julia 0.5 and 0.6