Read the example more carefully; you don’t need to specify default values (missing values will just error).
julia> Base.@kwdef struct Foo
a
b
end
Foo
julia> Foo(a = 1, b = 2)
Foo(1, 2)
julia> Foo()
ERROR: UndefKeywordError: keyword argument a not assigned
Stacktrace:
[1] Foo() at ./util.jl:673
[2] top-level scope at none:0
I see, I think this is what I was looking for, I’ll try it! Thx!
Another question, I’m trying to understand Julia more and I usually try to see similarities with other languages. With @kwdef I clearly see a similarity with Javascript:
Not sure what the question is. But named keyword arguments exist in most modern languages. The macro is just a way to define them quickly, you can also make an outer constructor
I also struggled with this.
Not so much that the constructor looked ugly, but rather that maintaining the code, especially calling the constructor, was easy to get wrong when rearranging, adding and deleting fields (which I do often).
So I wrote a macro to make this a bit easier.
macro CompositeFieldConstructor(T)
dataType = eval(current_module(), T)
esc(Expr(:call, T, fieldnames(dataType)...))
end
(Note: macro works on v0.6, probably need modifying to work with v1.0)
Essentially, the constructor needs to define a local variable with the same name for each field in the struct.
Order of variable definitions doesn’t matter.
So your constructor becomes:
function Scene(fieldPath::String)::Scene
field = open(fieldPath) do file
read(file, String)
end
shader = genFieldComputeShader(field)
renderer = GLShader("MeshRenderer", "./vertex.glsl", "./fragment.glsl", ["\$df" => field])
pointcloud, cmdBuffer, pointcloudVAO = computePointCloud(computer)
errorComputer = GLShader("MeshDistanceErrorComputer", "./computeMeshError.glsl", ["\$df" => field])
mesh, normals, meshBuffer = computeMeshFromPointCloud(cmdBuffer, pointcloud)
return @CompositeFieldConstructor(Scene)
end
Note I had to change local variable computer to shader to match the field name.
I always do this for a constructor. I found it more convenient about the ordering. Seems this is no longer in the new documentation?
mutable struct Foo
a::int
b::Float64
...
function Foo(a::Int, ...)
this = new()
this.b = 3.0 * a # order does not matter
this.a = a
......
this
end
end
Inner constructors should be used sparingly cf the docs
It is considered good form to provide as few inner constructor methods as possible: only those taking all arguments explicitly and enforcing essential error checking and transformation. Additional convenience constructor methods, supplying default values or auxiliary transformations, should be provided as outer constructors that call the inner constructors to do the heavy lifting.