Base.@kwdef

I know it’s been discussed before.

Can this be made the way structs work?

  • default values in the struct definition;
  • constructors can use keyword arguments.

And, of course, constructors can continue to use positional arguments, which is fine when there are only a few fields.

We all use the “secret” macro so why not get rid of the macro and have this be part of how structs are implemented? Is there a technical, safety, performance or compatibility obstacle? And, yes, one can create an outer constructor that does it.

It’s not a huge feature to be sure, but a lot of things that are not huge are beneficial and do get implemented. Without claiming to know, it must not be that much work as the macro as well as a couple of packages provide this (or similar) capability.

If the existence of the macro makes it an even lower priority to do the work (because it’s done already), then why not document the macro and “allow” it. (of course, it is already allowed)

2 Likes

I’m not sure if I want to do away with the current struct implementation.

  1. Not every field would have an explicit default value, and it would be unfeasible to make implicit defaults (for example, a “zero” would be the obvious choice, but you would need to define zero for every type beforehand).
  2. With structs with relatively few or no defaults, the positional constructors would be easier and more consistent to write, so the keyword constructors would just waste memory.
  3. Keyword arguments don’t participate with method dispatch, so it’s easy to overwrite the keyword constructor with a method with 0 positional arguments. That’s not nearly as much an issue with positional constructors.
  4. It’s also not clearly documented how keyword arguments are specialized/inferred (and @code_warntype isn’t entirely accurate, it errs toward overspecializing), so keyword arguments are still auxiliary to the positional ones.

The current struct implementation prods you toward positional arguments, away from those issues. As for why kwdef is not documented, exported, compiler-detected (triggered by a default argument), etc, I’m not sure.

Somewhat related, something I think would be cool as “standard issue” is Setfield.jl, or something like it. Keyword constructors specify specific fields’ values and uses defaults for the rest; creating an instance by “setting” fields is basically that but using an existing instance for defaults. And if reassigning an immutable instance to a variable, the compiler can perhaps optimize by just changing the fields under the hood instead of constructing a new instance; using a mutable instance for setting fields uses an allocation to allow sharing the instance and its mutations among several variables or references, which isn’t always necessary.

1 Like

Let’s focus on making it less secret then or perhaps coming up with a better name. See below.

https://github.com/JuliaLang/julia/issues/33192

https://github.com/JuliaLang/julia/issues/32659

4 Likes

Seems like the language core devs agree. Built in behavior would be better than a macro. Seems like it’s a matter of prioritization and someone who can do the work.

  • Lewis
1 Like

Yes, each to their own.

You may be assuming a more radical change than anyone proposes.

  • Positional arguments would work. Today that’s true even when you use @kwdef. Julia is about multiple methods. So you get another method with keyword arguments AND the method with positional arguments exists, too.
  • If you don’t supply a default for one or more fields, then there aren’t any. You have to provide values for the fields when you call the constructor.

The one tricky thing is I doubt it would be possible to mix some positional arguments and some keyword arguments. You can already write your own constructor method, inner or outer, to do this. It seems like this would be uncommon. For a given struct, one probably prefers all keyword arguments or none. Of course, having created the keyword method with the macro—you still have the positional method. Presumably (?) that would continue to work with a new implementation.

So, this request has been around a while and is mostly meant to take away the obscurity around @kwdef without taking away amy other feature.

  • Lewis

I’m not under the impression that there wouldn’t be a positional constructor anymore, just that a keyword constructor only sometimes makes writing code easier, so I don’t think it’s justified to make one for every struct by default or encourage people to use them by default.

1 Like

Fair enough.

I usually use keyword arguments if there are more than 4 fields and never when there are only 2.

If no default value is provided, couldn’t the parser just interpret the structure as it does now?

1 Like

Yeah that’s what I meant by this. I’m wary of @kwdef being easier to do and run into its limitations, but then again, it’s also easy to give fields abstract types (no annotation defaults to Any), and it’s not hard to inform people of the downsides.

1 Like