Constructor with default values for mutables which allows undefined values

I’m looking for something like Base.@kwdef or Parameters.@with_kw but which leaves unspecified arguments for mutables as #undef, i.e. it should do,

@new_kwdef mutable struct Foo
   x = 1
   y
end

Foo() # should return Foo(1, #undef)
Foo(y=2) # should return Foo(1, 2)

Does anything like this already exist? Both of the aforementioned macros error on Foo() because y doesn’t have a default and isn’t defined.

Oh, funnily enough I see now this was already asked about in https://github.com/JuliaLang/julia/pull/27987, by me :slight_smile:

I’m not sure if anyone has anything new to add to what is said there, fwiw I do still think it’s useful functionality.

1 Like

The comments made there are also relevant: it is special-casing mutable structs, and it is also at odds with the common behavior of functions just erroring when a keyword argument is not provided, eg

julia> f(; kw) = 1
julia> f()
ERROR: UndefKeywordError: keyword argument kw not assigned

That said, you can just write a macro for this, using Base.@kwdef as a starting point.

That argument I don’t totally get tbh, mutable structs are already special in that they can have #undef fields.

Certainly I can write a macro, although its not quite that easy because @kwdef creates an outer construction with keywords matching the struct fields, but its not as if I can give these keyword arguments a default value of #undef in the outer construction since that doesn’t exist in Julia.

I guess the argument I can understand is that non-keyword outer constructors already can’t create #undef fields, e.g.

mutable struct Foo
    x
end
Foo() # this does not currently create F(#undef)

and so keyword constructors shouldn’t be able to either.

So do (immutable) structs, eg try

struct Foo
    x
    Foo() = new()
end
Foo()

(possible? yes; useful? not really.)

For your original issue: various extensions of constructors are possible, but IMO most of these should be addressed (and experimented with) in packages, not Base.