Renamed is a macro to ease the renaming of symbols. For example, say you have
struct MyType {
let propertyName: String
}
but you rename MyType.propertyName
to MyType.newName
. To avoid introducing a breaking change you can add a computed property named propertyName
decorated with @available(*, deprecated, renamed: "newName")
, but this can be cumbersome.
With Renamed this can be done with a single attribute.
struct MyType {
@Renamed(from: "propertyName")
let newProperty: String
}
This generates the Swift code:
struct MyType {
let newName: String
@available(*, deprecated, renamed: "newName")
var propertyName: String {
newName
}
}
(this isn't exactly how the macro gets expanded, but that's not important here).
Renamed
uses the same naming syntax as the renamed
parameter of the @available
attribute. For example, renaming a function is also supported.
@Renamed(from: "oldFunctionName(argument:_)")
func newFunctionName(_ variableName: String, argumentName: Int) -> Bool {}
produces:
func oldFunctionName(argument arg0: String, _ arg1: Int) -> Bool {
newFunctionName(arg0, argumentName: arg1)
}
Functions without parameters can omit the parentheses:
@Renamed(from: "oldFunctionName")
func newFunctionName() -> Bool {}
This works for:
- Structs
- Classes
- Enums
- Type aliases
- Immutable properties
- Mutable properties
- Functions
Q: How ready is this?
This is currently in beta, with support for the latest Swift 5.9 snapshot, specifically tested with the Xcode 15 beta. There are probably more cases that can be supported and most descriptive errors that could be thrown in some cases (e.g. rather than producing invalid code).
With all that said, all supported use-cases have associated tests that prove this works.
Q: I found something that doesn't work. What can I do?
A: Please open an issue or, better yet, a PR with a failing or implementation. I'm sure there are some edge cases I've not thought of!
Q: Will this be slow?
A: There is a small compile-time hit but it's minimal. The code produced is often identical to what would be written by hand. No runtime dependencies are added.
Q: Do I have to add a whole dependency just to save myself some typing?
A: Yes. Personally I would only consider using this project for a big refactor.
Q: Is this type-safe?
A: To a degree. Swift will check the code generated by this marco, so if you enter an invalid name, e.g. @Renamed(from: "1nvalid")
the compiler will throw an error. The macro will also produce a compile-time error when used on unsupported symbols, such as a variable without an explicit type. These errors are being worked on and some more situations will be supported.
Q: Where can I find more about macros?
A: Swift Macros Dashboard. CustomHashable.
To use macros you need to use a recent Swift toolchain. Because Xcode does not support building a package with a toolchain development is being done in Visual Studio Code. Check the settings.json file to see which snapshot the project is being developed against.