In my example I meant to nest two property wrapper types and the wrapped property to be of type Value.
// both are equivalent
@A<B, Int, String> var property: Value
@A<B<Value>, Int, String> var property: Value
// the above forms allow us to avoid the following composition form.
@A<B, Int, String>
@B
var property: Value
@A<B<Value>, Int, String>
@B<Value>
var property: Value
FWIW, I'm opposed to changing the grammar of attributes to introduce commas. It won't be at all clear when commas are needed or significant, and I don't think it clarifies this code at all.
I've put my thoughts into the proposal draft, so I won't repeat them at length here, but I feel like commutative composition is a non-goal for property wrappers.
Right, that'd work. We can even add $$foo, $$$foo, etc. in the future to access inner wrappedValue should the need arise, though quite frankly I don't even see the need myself.
I just started playing around with property wrappers and I immediately tried to find a concise way to do the same thing that @Avi outlined. I think that it is pretty important that the initialValue initializer have a flexible number of additional arguments after it.
There's a subtle difference between your two examples:
// the former is
var val: Omittable<String?>?
// the latter is desugared as
var val: Omittable<String?>
Notice that the former is an optional omittable, whereas the latter is a non-optional omittable. Decoding a type with optional fields, will work with missing keys. In fact, you could just declare it as var val: String? and it would work just the same. In the second example, where you use the type as a property wrapper, decoding will fail because the key is missing.
I have experimented with creating a more specific overload of decode(_:forKey:) on KeyedDecodingContainer like so:
As long as String conforms to ZeroInitializable which is a custom protocol which defines a static "zero" value for a given type, eg. empty string, empty array, zero numeral, false, etc.
Spot on. I thought that my problem was there was no syntax to indicate that Decodable should treat @Omittable var val: String? as if it desugared to var val: Omittable<String?>?.
However, I'm really intrigued by your solution using an extension on KeyedDecodingContainer. I think that is workable, at least in my use-case. For my actual "omittable" type I will build in a Bool indicating whether the value it wraps was omitted and use your extension (although I do not even need ZeroInitializable because I can set Omittable's wrapped value to nil and its omittedBool to true in Omittable.init()).
Sure! In my own experiments with this, I've used "omittable" as a kind of "default value decodable", in that it can decode if present, and fall back to a default "zero" value.
I would like to be able to use:
@Omittable(default: "some default") var val: String
But that doesn't really work when decoded, as the initializer on declaration isn't called in that case, and there's no way of getting at the parameter. In the current design it must be entirely type-based. It is, however, possible to wrap a value as a static member of a phantom type, like so:
protocol ZeroInitializable {
associatedType ZeroType
static var zeroValue: ZeroType { get }
}
enum False: ZeroInitializable {
static let zeroValue = false
}
enum True: ZeroInitializable {
static let zeroValue = true
}
enum Zero<N: ExpressibleByIntegerLiteral>: ZeroInitializable {
static var zeroValue: N { return 0 }
}
extension String: ZeroInitializable {
static let zeroValue = ""
}
extension Array: ZeroInitializable {
static var zeroValue: [Element] { [] }
}
And then using it like so:
struct SomeDecodable: Decodable {
@Omittable(False.self) var isEnabled: Bool
@Omittable(True.self) var hasContent: Bool
@Omittable() var name: String
@Omittable(Zero<Int>.self) var count: Int
}
Where the initialiser used on the declaration site, is only used to infer the type, and where the actual value used as a default value, is available through the phantom type on the wrapper.
I do a lot of phantom type trickery of a similar nature in a JSON:API library I wrote (not adapted to use property wrappers yet, but that’s the basis for my current experimentation). This is exactly the motivation for my suggested future direction in the new proposal thread for this feature.
Xcode versions that did land had a very early and buggy versions of the proposed feature. Some things have changed ever since including some details about access control.
When the proposal hopefully is accepted soon, the implementations will be updated for Xcode toolchains as well.
Swift Property Wrappers vs TypeScript Decorators is there any difference between thease two
TypeScript Decorators:
A Decorator is a special kind of declaration that can be attached to a class declaration, method, accessor, property, or parameter. Decorators use the form @expression , where expression must evaluate to a function that will be called at runtime with information about the decorated declaration.
Not feeling like wading through 200+ posts to see if this question is already answered.
If I make a MyWrapper around an Int property, and the property satisfies a protocol requirement, is the associatedtype tracking Int or MyWrapper? And how can I switch which one it tracks?