DenseAxisArray in JuMP

I wonder why is the y below so complicated, unlike x.

julia> using JuMP

julia> model = Model();

julia> @variable(model, x[1:3]); x
3-element Vector{VariableRef}:
 x[1]
 x[2]
 x[3]

julia> R = 1:3
1:3

julia> @variable(model, y[R]); y
1-dimensional DenseAxisArray{VariableRef,1,...} with index sets:
    Dimension 1, 1:3
And data, a 3-element Vector{VariableRef}:
 y[1]
 y[2]
 y[3]

julia> typeof(y)
JuMP.Containers.DenseAxisArray{VariableRef, 1, Tuple{UnitRange{Int64}}, Tuple{JuMP.Containers._AxisLookup{Tuple{Int64, Int64}}}}

Moreover, if I want an x-like outcome for y, what code should I write?
Maybe something like @variable(model, y[$R])? (is there a correct style?)

See Variables · JuMP

Reuse this topic to ask a new question—as follows—why can’t I do this

julia> using JuMP

julia> model = Model();

julia> c = @constraint(model, [i in [2]], 0 == 1);

julia> delete.(model, c)
1-dimensional DenseAxisArray{Nothing,1,...} with index sets:
    Dimension 1, [2]
And data, a 1-element Vector{Nothing}:
 nothing

julia> c .= @constraint(model, [i in [2]], 0 == 2) # `.=` reuses the container `c`
ERROR: DenseAxisArray does not support this operation.
Stacktrace:
  [1] error(s::String)
    @ Base .\error.jl:35
  [2] LinearIndices(::JuMP.Containers.DenseAxisArray{ConstraintRef{…}, 1, Tuple{…}, Tuple{…}})
    @ JuMP.Containers K:\judepot1115\packages\JuMP\RGIK3\src\Containers\DenseAxisArray.jl:304
  [3] copyto_unaliased!
    @ .\abstractarray.jl:1072 [inlined]
  [4] copyto!
    @ .\abstractarray.jl:1061 [inlined]
  [5] copyto!
    @ .\broadcast.jl:966 [inlined]
  [6] copyto!
    @ .\broadcast.jl:925 [inlined]
  [7] materialize!
    @ .\broadcast.jl:883 [inlined]
  [8] materialize!
    @ .\broadcast.jl:880 [inlined]
  [9] materialize!(dest::JuMP.Containers.DenseAxisArray{…}, x::JuMP.Containers.DenseAxisArray{…})
    @ Base.Broadcast .\broadcast.jl:876
 [10] top-level scope
    @ REPL[5]:1
Some type information was truncated. Use `show(err)` to see complete types.

(So this is perhaps the reason why we should only use normal Arrays in JuMP.)

And a further question is, is there a more efficient in-place method that refill a container with new constraints (without allocating new container)?

julia> c = @constraint(model, [i in 1:3], 0 == 1);

julia> delete.(model, c);

julia> c
3-element Vector{ConstraintRef{Model, MathOptInterface.ConstraintIndex{MathOptInterface.ScalarAffineFunction{Float64}, MathOptInterface.EqualTo{Float64}}, ScalarShape}}:
 InvalidConstraintRef
 InvalidConstraintRef
 InvalidConstraintRef

julia> c .= @constraint(model, [i in 1:3], 0 == 2) # What is the most efficient way to do this?
3-element Vector{ConstraintRef{Model, MathOptInterface.ConstraintIndex{MathOptInterface.ScalarAffineFunction{Float64}, MathOptInterface.EqualTo{Float64}}, ScalarShape}}:
 0 == 2
 0 == 2
 0 == 2

Why would you want to do that?

This is another Julia interface issue: the set of methods to implement to support all possible behaviors is not well defined. In this case, we’re just missing some methods. But I’m also not really sure I want to support this.

I think needless. Basic julia Array for containing variables and constraints are enough. We don’t need Dense or SparseAxisArray, they are hard to use Although they are not supported well, they can be used sometimes with minor modification, e.g.

julia> model = JuMP.Model(); v = [4, 2];

julia> JuMP.@variable(model, x[s = 1:2, c = 1:v[s]]);

julia> x[2, :]
JuMP.Containers.SparseAxisArray{JuMP.VariableRef, 1, Tuple{Int64}} with 2 entries:
  [1]  =  x[2,1]
  [2]  =  x[2,2]

julia> ans' # ERROR: `Base.size` is not implemented

julia> [i for i in x[2, :]]
2-element Vector{JuMP.VariableRef}:
 x[2,1]
 x[2,2]

julia> ans'
1×2 adjoint(::Vector{JuMP.VariableRef}) with eltype JuMP.VariableRef:
 x[2,1]  x[2,2]