I would like to define a new macro @publiclyInitiazable
that aliases to @MemberwiseInit(.public, _optionalsDefaultNil: true)
from this package.
How can I easily do this? I tried
@attached(member, names: named(init))
public macro publiclyInitializable(
_ accessLevel: AccessLevelConfig = .public,
_deunderscoreParameters: Bool? = nil,
_optionalsDefaultNil: Bool? = true
) =
#externalMacro(
module: "MemberwiseInitMacros",
type: "MemberwiseInitMacro"
)
but the parameters don't get applied:
It seems like you want the macro to have different default arguments. Currently, this is not possible unless you fork the macro's implementation.
The way macros read their arguments is different from how methods read their arguments. In particular, macro implementations read the AST nodes from the source code directly, instead of evaluating the argument expressions like when you call a method. The default parameter values you see in the macro's declaration doesn't affect how the macro expands at all. They serve as documentation, at best.
For this to work properly, you'd need to write your own macro that can expand to @MemberwiseInit
. However, as of Swift 6.0, this kind of macro is not supported. You are only able to add attributes to members of a declaration using a MemberAttributeMacro
. At best, you need an enclosing type, e.g.
@publiclyInitializable
public enum EnclosingType {
public struct AnyParams { ... }
}
// expands to
public enum EnclosingType {
@MemberwiseInit(.public, _optionalsDefaultNil: true)
public struct AnyParams { ... }
}
This enclosing type might be undesirable, but you can use a typealias
to somewhat overcome that.
Alternatively, you can fork the repository and change the macro implementation. This is where you need to change.
let configuredAccessLevel: AccessLevelModifier? = extractConfiguredAccessLevel(from: node)
// I have added "?? true" here, so that when this argument cannot be found, it is "true"
// when this argument does exist, and it is "nil", extractLabeledBoolArgument will actually return "false".
// See the implementation of extractLabeledBoolArgument for more details
let optionalsDefaultNil: Bool? =
extractLabeledBoolArgument("_optionalsDefaultNil", from: node) ?? true
let deunderscoreParameters: Bool =
extractLabeledBoolArgument("_deunderscoreParameters", from: node) ?? false
// I have changed this from "?? .internal" to "?? .public"
let accessLevel = configuredAccessLevel ?? .public