Julep: Efficient Hierarchical Mutable Data

I had some time this morning to try my hand at a macro-based solution.

This is indeed impressive macro work!

I used

mutable struct Part
    a::Float32
end

@with_inline_types mutable struct Whole 
    b::Int32
    part::@inline(Part) 
end

w = Whole(Int32(42), Part(42.0f0))

to stay compatible with the rest of the discussion (but great that the solution is tested with nested structs)

Note that I have only a limited understanding of the macro implementation, so please correct points I haven’t evaluated correctly, so I can correct the list.

These are the pros and cons I see :

pros:

  • clearly defined constructor semantics
  • seems to have ideal memory behavior (only one alloc, clear GC story)
  • field access works with nested structs
  • preserves user defined getproperty for Whole:
    Base.getproperty(w::Whole, s::Symbol) = s === :c ? true : getfield(w, s)
    julia> w.c
    true
  • Preserves object identity (although I do not understand why)
    w1 = Whole(Int32(1), Part(1.0))
    w2 = Whole(Int32(1), Part(1.0))
    julia> w1.part === w1.part !== w2.part === w2.part
    true
  • methods involving Part can be called (using a Union or subtyping):

cons:

  • constructor no longer supports type conversion (Whole(42, Part(42.0) does not work)
  • definition syntax more complicated as macro needed both before struct definition and inside field definition
  • returns “wrong” fieldnames:
    julia> Whole |> fieldnames
    (:b, :part__a)
  • returns “wrong” type for substructs: w.part |> typeof
    julia> w.part
    PartView{:part, Whole}(Whole(42, 42.0f0))
  • Part’s methods needs to accept a Union or an abstract type (then Part needs to use that, too) to work
  • Does not support getting the memory address
    julia> w1.part |> pointer_from_objref
    ERROR: pointer_from_objref cannot be used on immutable objects
  • Returns different types for multiple fields of the same type

So while it does work for the simplest of cases, it seems to be too limited (but I might be using it incorrectly).

Edit: corrections due to additional input (see below)
Edit 2: added foobar_lv2’s limitation