Can you avoid magic values when using default values in macro parameters?

Let's say you have a macro declaration like this:

public macro AddCompletionHandler(completionName: String = "onCompletion") = #externalMacro(...)

and you use it omitting the completionName parameter:

@AddCompletionHandler()
public func whatever(...

When this macro is tried to be expanded, the code in the macro receives an AttributeSyntax with no parameters, and of course with no reference to the default value defined in the macro declaration. I guess that in this case you must search for the parameter in the AttributeSyntax, and if not present, assume a default value...

But where do you define this default value??? I only see two options:

  • You create a magic value inside the macro implementation which is used as the default value of the parameter (I would call this magic even if defined as a constant anywhere, because it is totally unrelated to the value in the macro declaration, and a change in the macro declaration without a corresponding change in the macro implementation would cause the macro to have inconsistent behaviour)
  • Create a constant in the macro implementation that is used in the macro declaration. This feels unnatural because you would be using a constant defined elsewhere as a default value, and you would probably be forced to give access to the source code of the macro, something that you may not want to do

Am I missing anything here?

4 Likes

In my case, my macro parameter is enum that I defined in macro implementation and imported that module to macro definition to be able to use it as parameter. I also felt concerned about it. So I'm looking forward to watch this thread.

1 Like

This is still a good question. The Apple SwiftData Query family of Macros have some arguments with default parameters (like SortOrder). I'm guessing this question was brought up internally. I'm not sure if the external community has any consensus about a best practice… but I hope we can hear some more discussion on this.