Create a struct with uninitialized fields

Having a mutable struct, e.g.:

mutable struct Point
    x
    y
end

is it possible to construct its instance with uninitialized fields and set them later? E.g.:

p = create_uninitialized(Point)    # <-- anything like this?
p.x = 10.0
p.y =  20.0

Note: we can do it with arrays, e.g. Array{Float64,1}(10).


Alternatively, I’d be happy to hear about similar() for structs, i.e. a function that takes an instance of a struct and creates similar instance with dummy field values:

p = Point(8.0, 11.0)
p2 = similar_struct(p)    # <-- like this
p2.x = 10.0
p2.y = 20.0

Currently I use:

p = Point(8.0, 10.0)
p2 = deepcopy(p)
p2.x = 10.0
p2.y = 20.0

But deepcopy is expensive and doesn’t work for all types.

2 Likes

Like this?

julia> mutable struct Point
           x
           y
           Point() = new()
       end

julia> p = Point()
Point(#undef, #undef)

julia> p.x = 2
2

julia> p.y = 3
3

julia> p
Point(2, 3)

Or do you want to do it without having access to the inner constructor?

12 Likes

Yes, without any restrictions on a target type. I.e. user of this function should be able to use it for any mutable struct.

(However, thanks for the interesting trick - I didn’t know inner constructors may be used like this).

1 Like

What if I want to do this when I don’t have access to the inner constructor? Using Core is fine; the context here is I am trying to refactor a codebase that uses ccall to internal functions to be less fragile. So using Base functions would be best, but Core is still an improvement.

I ended up with the following implementation:

"""
    __new__(T, args...)
User-level version of the `new()` pseudofunction.
Can be used to construct most Julia types, including structs
without default constructors, closures, etc.
"""
@generated function __new__(T, args...)
    return Expr(:splatnew, :T, :args)
end

I did’t try it with undef initializer, but given actual arguments, it works pretty well for quite a wide range if use cases in Ghost.jl. One caution though is that since :new/:splatnew are quite low-level, Julia won’t validate this expression, so misuse may lead to segfault.

4 Likes