https://github.com/wilhelmoks/modifiedcopymacro
A Swift macro for making inline copies of a struct by modifying a property.
https://github.com/wilhelmoks/modifiedcopymacro
copy inline macro struct swift value-types
Last synced: 2 months ago
JSON representation
A Swift macro for making inline copies of a struct by modifying a property.
- Host: GitHub
- URL: https://github.com/wilhelmoks/modifiedcopymacro
- Owner: WilhelmOks
- License: mit
- Created: 2023-07-03T14:40:26.000Z (over 2 years ago)
- Default Branch: main
- Last Pushed: 2025-07-21T08:28:28.000Z (5 months ago)
- Last Synced: 2025-09-18T19:31:21.664Z (3 months ago)
- Topics: copy, inline, macro, struct, swift, value-types
- Language: Swift
- Homepage:
- Size: 26.4 KB
- Stars: 33
- Watchers: 2
- Forks: 7
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# ModifiedCopyMacro
A Swift macro for making inline copies of a struct by modifying a property.
The syntax is similar to Kotlin's copy function for data classes: https://kotlinlang.org/docs/data-classes.html#copying
## Usage
Apply the `@Copyable` macro to a struct:
```swift
@Copyable
struct Person {
let name: String
var age: Int
}
```
and it will add a copy function for each stored property and constant:
```swift
struct Person {
let name: String
var age: Int
/// Returns a copy of the caller whose value for `name` is different.
func copy(name: String) -> Self {
.init(name: name, age: age)
}
/// Returns a copy of the caller whose value for `age` is different.
func copy(age: Int) -> Self {
.init(name: name, age: age)
}
}
```
## Capabilities, Limitations and Design Choices
### Chains for multiple changes
To make a copy of a struct and modify multiple properties, you can chain the `copy` calls like this:
`Person(name: "Walter White", age: 50).copy(age: 52).copy(name: "Heisenberg")`
This is different than Kotlin's version of `copy`, which allows multiple parameters to pass in a single call.
It's not possible to implement it like that in Swift because it's not possible to have default values for parameters which refer to the current values of the properties of the struct (or class).
And we also can't use nil as a marker for the old/current value, because nil might be a valid new value that we want the property to set to when we make a copy.
There might be a way that I'm not aware of, to still make it possible. So if you know how to do it, please let me know.
#### CopyableCombi
With version 2.1.0, the separate macro CopyableCombi was introduced, which generates copy functions with all combinations of parameters.
This solution has the disadvantage that the number of generated functions can become large quickly, but it provides an API which is more similar to Kotlin's copy function.
### Stored properties and constants
A copy function will be generated for each stored property (`var`) and each constant (`let`) of the struct.
The macro recognizes computed properties by checking if they have `get` or `set` accessors.
### Only for struct
This macro works only for structs.
It doesn't make sense for enums because enums can't have stored properties.
Classes and actors have reference semantics and I don't want this library to provide a copy function for reference types. I just want to augment the natural copy capability of structs with modified properties.
This macro emits a Diagnostic Message when you try to apply it to anything but a struct.
### Only with default init
The generated copy functions produce the copies by calling the synthesized default initializer.
So, if you provide a custom initializer, no default initializer will be synthesized and the copy functions won't work.
You can still have synthesized default initializers if you define your custom initializers in an extension.
### No struct extensions
You can't apply this macro on an extension of a struct.
This seems to be a limitation of the macro system.
If you know how to make it possible, please let me know :)
## Installation
Macros are a new language feature of Swift 5.9 and it will only work in Xcode 15 and later.
Add the url `https://github.com/WilhelmOks/ModifiedCopyMacro.git` as a Swift Package to your project.
When prompted, select the Package Product `ModifiedCopy` (Kind: Library) to add to your target.
Make a clean build.
`import ModifiedCopy` in the file where you want to attach the `@Copyable` macro.