Automatic keyword argument constructor

Is there a way to have Julia automatically defining a constructor using keywords arguments?

# the composite type
struct Person
  name::String
  age::Int
end
# generates automatically this constructor:
me = Person("Hugo", 24)
# is there a way to define automatically
# this constructor using only keyword arguments
# corresponding to fields names?
me = Person(;name="Hugo", age=24)

I think this could be achieved using macros, but I’m not good at it and do not know how to do. Now, I’m forced to implement it manually:

struct Person
  name::String
  age::Int
  Person(;name::String,age::Int) = new(name,age)
end

It’s a bit cumbersome.

I believe Parameters.jl is exactly what you’re looking for

3 Likes

Thanks, it does the trick!

import Parameters.with_kw

@with_kw struct Person
   name::String
   age::Int
end

julia> Person(name="Hugo", age=24)
Person
  name: String "Hugo"
  age: Int64 24

note: it also changes the way the structure prints itself, without Parameters.jl, it was

julia> Person(name="Hugo", age=24)
Person("Hugo", 24)

There’s also Base.@kwdef. It’s very poorly advertised, though. It should probably be mentioned in the Constructors chapter in the manual.

6 Likes

perhaps Base.@kwdef is not documented because it is not exported, is hence considered an internal function, and might be removed in future? seems very useful though. definitely a keeper!

Parameters.jl also export @unpack, which is very useful.

1 Like

For the reference, since Julia 1.9 (release April 2023), the @kwdef macro is exported, see Julia 1.9 release NEWS: Standard library changes.

This was implemented in PR

3 Likes

I am only adding this here for context (since the @kwdef only appears documented in Base - so people reading the manual might not easily encounter it).

Please note that by using @kwdef, you can also set some defaults for your fields:

@kwdef struct Person
  name::String="World"
  age::Int=42
end

By defining your struct as above, you are also provided with Person() constructor (obviously - there are not good defaults for a person, but this can come in handy when defining some configuration or you just have reasonable default values).

1 Like

Yes, I opened an issue on this topic (add at-kwdef to the manual · Issue #32659 · JuliaLang/julia · GitHub) but didn’t went to the next level of submitting a PR to add @kwdef to the manual.

1 Like

my_func(; a, b, other... )
This syntax allows my_func to be called with additional arguments that are ignored.

I know you could write a similar constructor for a struct.
It would be nicie if there was a flag that did it automatically. e.g. allow:

@kwdef  @allow_other_args  struct X  
    x::Int
    y::Int    
end

To be created with

X(x=1, y=2,   w=10,  z=100,   a="something_else" )

Use case: I convert a database table to a vector of structs of different types (each row becomes a struct). I currently have to filter the fields of each row to match the struct.
It would be nice to just use AsTable(:) to feed each row in as a named tuple and have the requried fields selected automatically.