Got it, thanks for explaining what you're trying to do. How would the scheme you've devised handle a situation like this?
@UserDefault(key: "c", defaultValue: "") var c: String?
print(c)
c = "<nil>"; print(c)
c = nil; print(c)
?
In general you're right that the UserDefaults API makes it somewhat problematic to distinguish between the "never set" and "explicitly set to nil" cases. Trying to represent the "explicitly set to nil" case in the 'space' of the underlying value, though, will require you to 'burn' one of the valid values to use as a sentinel for nil. Maybe that's okay for your use case, and you'll never set anything to nil.
But if you'd like to avoid that, you'll need to have a way for your "never set," "set to nil," and "set to non-nil value" representations to all be distinct. You could accomplish this by, for example, defining a protocol for use by your UserDefault type, e.g., UserDefaultStorable that has a couple requirements like:
func storeInUserDefaults(for key: String)
func extractFromUserDefaults(for key: String) -> Self?
The types that are directly representable (Int, String, etc.) could just forward to the corresponding methods on UserDefaults, and then Optional could have a conditional conformance to UserDefaultStorable whenever the wrapped type conforms to, say, Codable. You could encode the wrapped value to a JSON String if present and then encode .some(value) yourself as { "value": <value string> } and .none as {}, then store that string in the user defaults. When fetching from user defaults, you'd reverse this process. If the user default returns nil that means you never set any value and you should return nil (i.e. Optional<Optional<T>>.none) from the extractFromUserDedaults method. But if there is a String, then you can decode the Optional<T> value to either Optional<T>.nil or Optional<T>.some(...), and return that from the extract method (i.e., return Optional<Optional<T>>.some(Optional<T>.none) or Optional<Optional<T>>.some(Optional<T>.some(...)) respectively.
This extra layer of optionality is what allows you to keep the representations of "never set" and "explicitly set to nil" distinct, and then your UserDefaults wrapper can be agnostic to the underlying identity of the wrapped type. All it needs to know is that the type itself is able to produce a value when it has been set, and return nil if it hasn't been set.