The last time I was hoping for macros, I was reading the documentation for SwiftUI EnvironmentValues
. Here is a snippet of this documentation:
Create custom environment values by defining a type that conforms to the
EnvironmentKey
protocol, and then extending the environment values structure with a new property. Use your key to get and set the value, and provide a dedicated modifier for clients to use when setting the value:private struct MyEnvironmentKey: EnvironmentKey { static let defaultValue: String = "Default value" } extension EnvironmentValues { var myCustomValue: String { get { self[MyEnvironmentKey.self] } set { self[MyEnvironmentKey.self] = newValue } } } extension View { func myCustomValue(_ myCustomValue: String) -> some View { environment(\.myCustomValue, myCustomValue) } }
The above code snippet is what every developer is supposed to write in their application in order to use custom environment keys in SwiftUI.
This code has no intrinsic problem. Yet, it is highly repetitive and contains very little information that is related to the very user's needs.
What the user needs is:
-
myCustomValue
: the identifier that makes it possible to set and read the environment key. The user wants to be able to write:@Environment(\.myCustomValue) var value: String myView.environment(\.myCustomValue, "Custom value")
-
String
: the type of the environment value. -
"Default value"
: the default value for the environment key -
(Optional)
myCustomValue
: a convenience View extension method, so that the user can write:myView.myCustomValue(...)
And yet, the user has to define a MyEnvironmentKey
type that is never used (with the added difficulty to find a unique name for this unused type), and to write extensions with a fixed pattern. In this boilerplate, the relative amount of useful information, considering the use case, is very low.
To me, this sounds like one of the interesting use cases for a macro system.