Change construction type parameters for a type in a vector?

I have an abstract type:

abstract type Pickle end

I have a sub-type

mutable struct Dill <: Pickle
    rating::Integer
end

If I construct a Vector{Dill}:

[Dill(5), Dill(6,)]

The type of this is Vector{Dill}. What I would like for this to do instead is return a Vector{Pickle}. Instead of the sub-type, I want my supertype in the parameters.
I do not want my users to have to call a method that groups the pickles, like pickles(pickles::Pickle ...) or something, instead i’d rather them do

# vv insert method with this argument here.
[pickles ...] = 

Does anybody have more info on this?
thanks friends :slight_smile:

You need to specialize Base.vect

julia> Base.vect(X::Pickle...) = Pickle[X[i] for i in eachindex(X)]

julia> [Dill(3), Dill(4)]
2-element Vector{Pickle}:
 Dill(3)
 Dill(4)
1 Like

Hi!
All it takes is to do a = Pickle[Dill(5), Dill(6)], or to create a = Vector{Pickle}(undef, 2) and fill it afterwards. However, I’m not sure I understood why you want to do that, since it will probably result in a performance loss.
As a side note, you probably want to give the rating field a concrete type such as Int instead of the abstract type Integer, so that the compiler knows its memory layout and can perform better optimizations. If you don’t need mutability, you may also ditch the mutable keyword to further speed things up.

2 Likes

Even though this isn’t technically type piracy, it does profoundly change a pretty fundamental behavior in Julia: one expects [] to always return the narrowest typed vector. Changing this behavior risks confusing your users badly, @emmettgb.

Being explicit here by doing

seems much preferable.

The part below is a bit confusing. What does it mean?

3 Likes

What are the adverse consequences of this, other than possibly hitting suboptimal fallback methods? Can this break anything?

1 Like

No, as I said, it’s not type piracy, so I’m not sure if there are bad consequences. But, psychologically, I think it would be very confusing. I could very well imagine myself spending an hour in total disbelief, trying to figure out why [] stopped working.

2 Likes

I think perhaps it violates the description in the documentation of vect:

Create a Vector with element type computed from the promote_typeof of the argument, containing the argument list.

1 Like

Ok, in that case, extending Base.vect in this way is unwarranted. Perhaps the docstring needs to be refined though, as promote_typeof is not a part of the API (it’s not documented, and doesn’t have a docstring either), so defining the element type of vect in terms of this seems a bit iffy.

1 Like

That was a concern, of course yes, but sometimes you might want to dispatch a collection of abstract types, like a Vector{Number} which contains Int64's and Float64’s instead of being a Vector{Any}.
Doubtful it would detract from anything else in Base, or suddenly break Vectors, but I definitely see your point on how it might confuse people. However, all of my methods which work with collections in my package use them from the top of the heirarchy. In other words, a Vector{Dill} has no methods, but a Vector{Pickle} has a surplus.
Still, I agree this is somewhat implicit, especially when it comes to Julia, however I think this will be what I go with. Also the pickles(p ...) thing that I was referring to is something like:

pickles(p::Pickle ...) = Vector{Pickle}(p)

Thanks for your reply!

Thanks, but I do not think this will work for what I want to do, as I want all collections of any Pickle subtype to become a Dill.

Thank you, master kenobi, these were the Base methods I was looking for

Also – don’t worry the real code I am applying this to has nothing to do with this little example and nothing to do with Pickles. I figured this would be a lot more interpretable than placing all of this type information into the post!

promote_typeof and promotion in general is what I was trying before, I could not get it to work for this application – and as you touched on, the documentation in that portion of Base was not my favorite, but I kind of figured there had to be a method that does this, which I now know to be Base.vect, and I think this option will be what I go with – at least for now, thanks!

So you have methods taking Vector{Pickle}, and therefore want your users to create vectors of this type? It’s probably better to change the argument type to Vector{<:Pickle}, or better yet AbstractVector{<:Pickle}, so you can pass in Vector{Dill} as well.

What will you do if someone creates a Vector{Dill}, and start push!ing to it?

I fear this will make things both really hard and very confusing for your users. Why not try to stick with consistency and predictability, values that are very central to the language?