Property-Wrapper style attached macros with dollar-sign prefix? Or underscore?

Hi! I'm experimenting with Swift Macros and having a lot of fun! One use case I've been looking at is a "property wrapper" style macro. The Swift Book has this to say:

As a special case, you can write prefixed($) for a[n attached] macro that behaves similar to a property wrapper.[1]

I'm actually not really clear on this. Can anyone help me understand how the swift-syntax repo treats the dollar-sign as a special case?

I'm also confused because it seems like Apple chose to use an underscore for the SwiftData.Query family of property-wrapper style macros:[2]

@attached(accessor) @attached(peer, names: prefixed(`_`))
macro Query()

Does anyone know more why the documentation goes out of its way to instruct engineers to use a dollar sign here instead of an underscore (or any other arbitrary character)?

Any advice about that would be great. Thanks!


  1. swift-book/TSPL.docc/ReferenceManual/Attributes.md at main · apple/swift-book · GitHub ↩︎

  2. Query() | Apple Developer Documentation ↩︎

@Alex_Martini did you remember anything more about that dollar sign documentation? Thanks!

That fact comes from the Swift Evolution proposal:

Declarations whose name is formed by adding a prefix to the name of the declaration to which the macro is attached: prefixed(_). As a special consideration, $ is permissible as a prefix, allowing macros to produce names with a leading $ that are derived from the name of the declaration to which the macro is attached. This carve-out enables macros that behavior similarly to property wrappers that introduce a projected value.

My reading is that, because of this special case in the naming rules, you're allowed to use a dollar sign in this way. Without this special case, macros that act like a property wrapper wouldn't be able to define an identifier that starts with $.

The "TODO TR" comment in the book's source marks a place where additional technical review (TR) is needed, but it looks like we ran out of time or the question got missed during the review process. We might have to follow up with one of the proposal authors to get more details.

In general, names that start with an underscore mean "treat this as private", as described in TSPL:

Treat identifiers that begin with an underscore, subscripts whose first argument label begins with an underscore, and initializers whose first argument label begins with an underscore, as internal, even if their declaration has the public access-level modifier. This convention lets framework authors mark part of an API that clients must not interact with or depend on, even though some limitation requires the declaration to be public. In addition, identifiers that begin with two underscores are reserved for the Swift compiler and standard library.

EDIT: For context, the $ prefix is used for projected values, which are documented in the Properties chapter.

1 Like

@Alex_Martini Ahh… interesting! Thanks for linking back to the proposal. I found this that might help explain more[1]:

A macro that emulated a property wrapper would specify the storage name via prefixed(_), meaning that _ will be added as a prefix to the name of the declaration to which that macro is attached.

And[2]:

$ is permissible as a prefix, allowing macros to produce names with a leading $ that are derived from the name of the declaration to which the macro is attached. This carve-out enables macros that behavior similarly to property wrappers that introduce a projected value.

I believe the thinking here I am trying to follow along with is that:

  • Property-Wrapper style macros should (by convention) specify storage with underscore prefix.
  • Property-Wrapper style macros may optionally expose a projected value.
  • Property-Wrapper style macros can define a dollar sign prefix to conform to the projected value convention.

My thinking here is it might be more clear in the documentation if we wrote that prefixed(_) is chosen for a "property wrapper" style macro. As an additional step, engineers might choose prefixed($) if their property wrapper style macro exposes a projected value. Does that sound like the right idea?


  1. swift-evolution/proposals/0389-attached-macros.md at main · apple/swift-evolution · GitHub ↩︎

  2. swift-evolution/proposals/0389-attached-macros.md at main · apple/swift-evolution · GitHub ↩︎