I encountered this limitation before and could not figure out a way to automate the process. I think something along the lines of what you proposed would be a useful addition to the language.
I don’t think one can make it entirely automatic, consider eg
Base.@kwdef struct Foo{S,T} # NOTE ORDER
a::T
b::S
function Foo(a::T, b::S) where {T,S}
@assert a > 0 && b > 0
new{S,T}(a, b) # NOTE ORDER
end
end
What is missing is a nice way to compose
the outermost layer of keyword arguments, with defaults,
the default outer constructor which nicely promotes,
an inner constructor which can call an arbitrary block of code that has at least access to the fields (not necessarily transformations, generation, etc, even though that would be nice).
Currently Base provides an all-or-nothing approach. Which may be fine, this is a job for a package. Currently none of the options available provide a full solution. But the problem is quite complex and I need to think more about what I want exactly, and whether it can be generalized enough to be packaged.
The immediate question I don’t get though is why the Foo3 inner constructor code doesn’t work. Is it a bug?
I don’t know if it’s a bug, but it seems to be unsupported. Without @kwdef, I get this:
Julia-1.1.0> struct Foo3{T,S}
a::T
b::S
function Foo3(a, b)
@assert a > 0 && b > 0
args = (a, b)
new{map(typeof, args)...}(args...)
end
end
ERROR: syntax: ... is not supported inside "new"