Attached macros using the peer
, member
, and accessor
roles currently require a names:
argument to declare the names of symbols that the macro will generate. The supported options for this argument are:
named(<#name#>)
overloaded
prefixed(<#prefix#>)
suffixed(<#suffix#>)
arbitrary
(prohibited for peer macros)
Ignoring arbitrary
since this option is prohibited in peer macros, only prefixed
and suffixed
offer dynamic name generation derived from the attached type. However, because they strictly prepend or append to the type name, the generated names must:
- Be longer than the original type name
- Contain the full attached type name as a substring
This limitation can be problematic in scenarios where naming conventions are semantically inverted. For example:
A Limiting Use Case
Imagine a macro @GenerateProtocol
that reads the public interface of the attached type and emits a corresponding protocol. Suppose a project adopts the convention of:
- Generalized names for protocols (e.g.
Database
) - Specialized names for concrete implementations (e.g.
ProductionDatabase
)
If I attach @GenerateProtocol
to ProductionDatabase
, there is currently no way to dynamically derive the name Database
using existing names:
options. The only solution is to hard-code the target name using named(Database)
, which:
- Is brittle and unsustainable at scale
- Requires the macro definition to be aware of client-specific types
- Defeats the purpose of automatic naming
Proposed Solution: unprefixed(...)
and unsuffixed(...)
To improve ergonomic, semantically meaningful naming, I propose two new options for the names:
argument:
unprefixed(<#prefix#>)
: Strips the given prefix from the attached type nameunsuffixed(<#suffix#>)
: Strips the given suffix from the attached type name
These options allow for type-name derivation based on naming patterns without requiring hardcoded values.
Example:
// Macro module
@attached(peer, names: unprefixed(Production))
public macro GenerateProtocol() = #externalMacro(...)
// App module
@GenerateProtocol
class ProductionDatabase: Database { ... }
// Generated code:
protocol Database { ... }
This supports a clean and maintainable relationship between generated code and client types, especially in large codebases.
Benefits
- Enables more expressive and flexible naming patterns
- Preserves peer macro constraints (avoids
arbitrary
names) - Encourages scalable naming conventions
- Requires no knowledge of client-specific naming in macro libraries
Alternative Names Considered
If unprefixed
/unsuffixed
feel too unconventional, other viable names include:
dropPrefix(...)
/dropSuffix(...)
trimPrefix(...)
/trimSuffix(...)
stripPrefix(...)
/stripSuffix(...)
I'm looking forward to hearing your feedback.