Search code examples
arraysswiftoption-typeproperty-wrapper

How to force non-optional type (for array element) on compile time in Swift?


struct MyStruct {
    @ArrayOfNonOptionalElements var arr: [SomeNonOptionalType]
}

where @ArrayOfNonOptionalElements is a propertyWrapper.
So, how to force non-optionality for the type inside? Is it even possible? 🙄
I mean, how to implement the property wrapper in such a way, that it forces the array element type to be non-optional.

Update:
Well, looks like nobody understood my question 😣
I want the compiler to prevent putting a question mark inside the square brackets 😃

Update2:
Will copy/paste here one of my comments from under the post, so everyone could easily see it:

I'm writing "@Compact" propertyWrapper for safe array decoding. So the result will be guaranteed not to contain any nils. This property wrapper can operate with any array types. So it's rather just a kind of perfectionist challenge 🙂


Solution

  • So, how to force non-optionality for the type inside? Is it even possible? 🙄

    No. Swift does not have a way to express "not" in the type system. (There is a new ~Copyable coming, but it does not mean "not Copyable." It means "removes the implicit assumption of Copyable.")

    I'm writing "@Compact" propertyWrapper for safe array decoding. So the result will be guaranteed not to contain any nils. This property wrapper can operate with any array types.

    This isn't really accurate. Optionals are Decodable if their Wrapped is Decodable. So the following is valid:

    try JSONDecoder().decode([Int?].self, from: Data("[1]".utf8)) // [Optional(1)]
    

    This suggests your @Compact could still return an array of Optionals. And if it can return Optionals, it can return nil. The type system has to be able to prove at compile time that this is impossible, and from what you've described, it is possible, you just "promise" it won't happen. And the type system isn't letting you get away with that, as is its job.

    But even if you could really promise what you're promising, the Swift type system has no way to express it.