Is there such a thing as an implicit conversion from a matrix view?

I am trying to construct a struct that refers to a view of a vector. However, there appears to be an implicit conversion, and I end up with a copy of the “view”.

mutable struct A{
    IT,
    MBT, # matrix-entry buffer type
    IJT, # index buffer type
} 
    buffer_length::IT
    matbuffer::MBT
    rowbuffer::IJT
end


function _task_local_assembler(a::AT, buffer_range) where {AT}
    buffer_length = maximum(buffer_range) - minimum(buffer_range) + 1
    matbuffer = view(a.matbuffer, buffer_range)
    rowbuffer = view(a.rowbuffer, buffer_range)
    @show typeof(matbuffer)
    _a =  AT(
        buffer_length,
        matbuffer,
        rowbuffer
    )
    @show typeof(_a)
    return _a
end

a  = A(1, zeros(Float64, 10), zeros(Int, 10))

_a = _task_local_assembler(a, 1:5)

a.matbuffer .= -1
@show a 
@show _a

On Windows 11, Julia 1.10, I end up with:

julia> include(raw"playo.jl")
typeof(matbuffer) = SubArray{Float64, 1, Vector{Float64}, Tuple{UnitRange{Int64}}, true}
typeof(_a) = A{Int64, Vector{Float64}, Vector{Int64}}
a = A{Int64, Vector{Float64}, Vector{Int64}}(1, [-1.00000e+00, -1.00000e+00, -1.00000e+00, -1.00000e+00, -1.00000e+00, -1.00000e+00, -1.00000e+00, -1.00000e+00, -1.00000e+00, -1.00000e+00], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0])   
_a = A{Int64, Vector{Float64}, Vector{Int64}}(5, [0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00], [0, 0, 0, 0, 0])
A{Int64, Vector{Float64}, Vector{Int64}}(5, [0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00], [0, 0, 0, 0, 0])

Your AT constructor is based on the type of a — parameters and all. And the parameters of a are Vectors. And the default constructors do a convert to the field types for you — even for parameterized fields, when they are given. And there is a conversion defined from SubArray to Vector.

So, yes.

Thanks. Can I prevent that from happening?

Many ways. One simple one is to just use A directly instead of the captured and fully parameterized AT.

I do not know what the actual type is. I only know the a that is passed in. The function should create an object of type similar to typeof(a), but with those views.

@mbauman is suggesting to replace _a = AT(...) with _a = A(...). Is this not doing what you need?

The thing is: I do not know at the call site what A is. I only know a, and hence typeof(a)

You’re looking for something like constructorof from ConstructionBase.jl, e.g. the default method will give you A from a:

@generated function constructorof(::Type{T}) where T
    getfield(parentmodule(T), nameof(T))
end

You can also overload this function for your own types.

1 Like

Nice!!!

1 Like