What behavior do you want the non-initialized fields to have? Presumably to throw an error for any operation using them? Or do you want the non-initialized values to propagate and return other non-initialized values after operations?
This is the difference between nothing and missing in Julia. Since Julia aims to have both more “programming” and more “data science” uses, we don’t want to require a single default behavior for non-initialized values.
The Union{Nothing, Int64} or Union{Missing, Int64} is the correct solution to your problem, and it has the benefit of being explicit about the behavior of your uninitialized values.
macro awesome(s)
if s.head !== :struct
error("Not a struct def")
end
ismutable = s.args[1]
if !ismutable
error("Not mutable")
end
name = s.args[2]
body = s.args[3]
ctor = :(function $(name)(;kwargs...)
K = new()
for (key, value) in kwargs
field_type_key = typeof(getfield(K,key))
setfield!(K, key, convert(field_type_key, value))
end
return K
end)
newbody = [body.args; ctor]
return Expr(s.head, ismutable, name, Expr(body.head, newbody...))
end
Now we can write:
@awesome mutable struct coly8
x :: Int32
y :: Float64
z :: Bool
t :: Int32
u :: Float32
v :: Bool
end
The next step would be parsing a expression in a struct with predefined constants or use the x::Int = 42 syntax like in Parameters.jl. Truly limitless set of options I would add also zeroing of not defined fields like most of languages do.
Sorry for reopening this thread, would you happen to know if one can get this to work for arrays? An example is taking your macro and struct and redefining v as such:
v :: Array{Float32,1}
Then afterwards if you try to use coly8(v=[2.f0;2.f0]), then the error becomes:
ERROR: UndefRefError: access to undefined reference
Stacktrace:
[1] coly8(; kwargs::Base.Iterators.Pairs{Symbol,Array{Float32,1},Tuple{Symbol},NamedTuple{(:v,),Tuple{Array{Float32,1}}}}) at ..
[2] top-level scope at none:1
Or maybe there is another way to do this in Julia today?