I didn’t know how to word the title. But this object makes Juno throw errors.
For context. I have some objects which are located all over the place (memory-wise). I want to query them and pass them to Optim
. But before that I want to place the query results in vectors in order to obtain better memory locality, as Optim
will be accessing the results over and over, probably sequentially. I don’t know the size of the results (I know an upper bound at startup) and I also don’t want to allocate these vectors every time I query these objects. So I created a struct called MaterializedStuff
which on creation allocates these vectors with a size larger than the known bound, and define a materialize!(ms::MaterializedStuff, stuff)
function which collects the query results, writes them to vectors, and stores the vector size. Then I never access the vectors directly, I only access views. This is ok, because Optim
will only be reading. Here’s my implementation:
mutable struct MaterializedStuff
l::Int
arr::Vector{Float64}
MaterializedStuff(n::Int) = new(n, Vector{Float64}(undef, l))
end
Base.length(ms::MaterializedStuff) = getfield(ms, :l)
Base.getproperty(ms::MaterializedStuff, f::Symbol) = view(getfield(ms, f), 1:length(ms))
and the materialize!
function is schematically
function materialize!(ms::MaterializedStuff, stuff)
counter = 1
for i in stuff
if condition
write to ms.arr
counter += 1
end
ms.l = counter
end
end
The two important points are that A) materialize!
sets ms.l
which is only known at runtime (not to be confused with MaterializedStuff(n::Int)
, which is the upper bound known at startup time), and B) getproperty
returns a view with a size equal to ms.l
I like this because as a user I can type ms.arr
and be sure that it will have a variable size and won’t cause any allocations.
In Juno, this code:
ms = MaterializedStuff(100)
ms.
The moment I type the last dot .
I get a Juno error:
Julia Client – Internal Error
MethodError: no method matching view(::Int64, ::UnitRange{Int64})
Closest candidates are:
view(!Matched::AbstractUnitRange, ::AbstractUnitRange{var"#s91"} where var"#s91"<:Integer) at subarray.jl:167
view(!Matched::StepRange, ::AbstractRange{var"#s91"} where var"#s91"<:Integer) at subarray.jl:175
view(!Matched::StepRangeLen, ::OrdinalRange{var"#s91",S} where S where var"#s91"<:Integer) at subarray.jl:179
...
getproperty(::MaterializedStuff, ::Symbol) at replayer.jl:143
completionreturntype(::FuzzyCompletions.PropertyCompletion) at completions.jl:269
completion(::Module, ::FuzzyCompletions.PropertyCompletion, ::String) at completions.jl:179
_broadcast_getindex_evalf at broadcast.jl:648 [inlined]
_broadcast_getindex at broadcast.jl:621 [inlined]
getindex at broadcast.jl:575 [inlined]
macro expansion at broadcast.jl:932 [inlined]
macro expansion at simdloop.jl:77 [inlined]
copyto! at broadcast.jl:931 [inlined]
copyto! at broadcast.jl:886 [inlined]
copy at broadcast.jl:862 [inlined]
materialize at broadcast.jl:837 [inlined]
fuzzycompletionadapter(::String, ::String, ::String, ::Int64, ::Int64, ::Bool) at completions.jl:158
(::Atom.var"#275#276")(::Dict{String,Any}) at completions.jl:54
handlemsg(::Dict{String,Any}, ::Dict{String,Any}) at comm.jl:169
(::Atom.var"#31#33"{Array{Any,1}})() at task.jl:356
As a user I never access ms.l
, but I guess Juno struct inspection call getproperty(ms, l)
which acts with a view on an int.
So my question is: What is the good way of implementing this idea?