Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Order of type parameters is somewhat problematic #170

Open
Keno opened this issue Jul 10, 2021 · 3 comments
Open

Order of type parameters is somewhat problematic #170

Keno opened this issue Jul 10, 2021 · 3 comments
Labels

Comments

@Keno
Copy link

Keno commented Jul 10, 2021

Some of methods in this package are inconsistent about the order
of the type parameters being used. E.g. in

typeof(Interval{Closed, Open}(1, 2))

In the constructor, you technically have T===Closed, L===Open, R<:Any.
This isn't really a technical problem, since the package does not
defined any bounds on these type parameters, and as long as the package
doesn't do any other operations on these types, it's probably fine.
That said, there is certainly some tooling that expects that constructors
of the form (::T)(args...) where T<:Type actually return something that's
a subtype of T, which this violates, since:

julia> Interval{Int64, Closed, Open} <: Interval{Closed, Open}
false

I would recommend reordering the parameters, so the type comes last.
If the concern is needing to write a bunch of extra parameters
that usually are not dispatched on, this can be handled via alias
as in Base.Vararg vs NTuple. E.g. in this case, you might have:

const IntervalT{T, L, R} = Interval{L, R, T}

and use IntervalT in method signatures.

@omus omus added the breaking label Jul 12, 2021
@omus
Copy link
Collaborator

omus commented Jul 12, 2021

There seem to be three main ways the Interval type is used:

Interval{T}
Interval{L,R}
Interval{T,L,R}

The Intervals.jl package uses Interval{T} and Interval{T,L,R} for dispatch often but Interval{L,R} is only used during construction (in fact it can't be used for dispatch but I've also found I've never really wanted it). Going back to the original change I can see I made a similar comment about this:

I should also point out that IntervalSets.jl uses Interval{L,R,T} where L and R are symbols. I think Interval{T,L,R} is a better ordering as I expect Interval{T} will be used more often when it comes to dispatch. Additionally this order happens to be non-breaking for Intervals.jl but it is still good to discuss our ideal parametric ordering.

#102 (comment)

If Julia allowed us to define the behaviour of specific number of type parameters we could end with something consistent but not currently possible:

struct Interval{T, L <: Bound, R <: Bound} end
const Interval{T} = Interval{T,L,R} where T, L <: Bound, R <: Bound
const Interval{L,R} = Interval{T,L,R} where T, L <: Bound, R <: Bound

I would recommend reordering the parameters, so the type comes last.

Could you share any additional examples you have for why you thing the type should be last instead of first? I'm not opposed to making such a change we just need to justify the churn.

@omus
Copy link
Collaborator

omus commented Jul 13, 2021

Possibly this may be nice path forward:

julia> using Intervals

julia> Intervals.Interval(::Type{L}, ::Type{R}) where {L <: Bound, R <: Bound} = Interval{T,L,R} where T

julia> Interval(Closed, Open)
Interval{T, Closed, Open} where T

julia> (::Type{Interval{T,L,R} where T})(a::S, b::S) where {S,L<:Bound,R<:Bound} = Interval{S,L,R}(a, b)

julia> Interval(Closed, Open)(1,2)
Interval{Int64, Closed, Open}(1, 2)

@rofinn
Copy link
Member

rofinn commented Apr 4, 2023

I think my preferred path forward would be to just drop the bound parameters completely and just store them as symbols in the type. See #208

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants