Help defining setindex! with a custom structure


I have a struct called Quaternion (which has 4 elements) and I want to make the following code work:

julia> v = zeros(10);

julia> q = Quaternion(1.0, 2.0, 3.0, 4.0);

julia> v[4:7] = q

It fails with the following error:

ERROR: ArgumentError: indexed assignment with a single value to possibly many locations is not supported; perhaps use broadcasting `.=` instead?

The operation with .= works, but I need the first.

Here is a bad, but working implementation

struct Quaternion; x; y; z; w; end
function Base.setindex!(a::Vector{Float64}, v::Quaternion, I::UnitRange)
       a[I] .= [v.x,v.y,v.z,v.w]

v = zeros(10)
q = Quaternion(1.0,2.0,3.0,4.0)
v[4:7] = q

So, you need to define setindex! for these types (with probably a better implementation than mine).

The problem of doing that is that I got a lot of problems due to ambiguous definition of setindex! from Base.

Shouldn’t Base support it out of the box if RHS is iterable?

Did you implement all the things from Interfaces · The Julia Language ?
(If yes and if it is easy: do you mind to share the code, than it’s easier to mess around with it.)

1 Like

I guess according to these lines is does the job only automatically if Quaternion is a instance of AbstractArray

1 Like

I will push the code and create a MWE. It is in ReferenceFrameRotations.jl.

Quaternion used to be <:AbstractArray, but I was getting a lot of problems in Zygote. In this case, we have an array in which the multiplication q1 * q2 (2 4x1 vectors) was leading to another 4x1 array. This was causing a lot of problems. Hence, I am dropping the supertype now and trying to fix things.

1 Like

Ah, I see. Given that Quaternion is not a subtype of anything, I guess Julia has no chance of figuring out at the point of setindex!(...) that your type could be iterable (since that would need to be encoded in the type either way)? I think I can’t help, it looks tricky. Maybe someone else has a good idea :slight_smile:

1 Like

Quaternion is iterable, it has all the API functions defined. I think Julia could verify if RHS is iterable and has the right size, and then make everything work.

I think I reached a good tradeoff by defining this function as you mentioned before:

@inline function setindex!(v::Vector{T}, q::Quaternion, I::UnitRange) where T
    # We can use all the funcion in static arrays.
    return setindex!(v, q[:], I)

My last attempt was using v::AbstractVector, and that’s why I was getting too many problems.

1 Like

Thanks for the help @SteffenPL ! I opened an issue to see what the devs say:

I really think this should work for iterable objects.