12

I'd like to extend Optional, where Wrapped is an array (with elements of any type). In other words, I want to add a function to [Any]?. I'm just not sure how to declare that. I've tried:

1.

extension Optional where Wrapped: Array

results in:

error: reference to generic type 'Array' requires arguments in <...>

2.

extension Optional where Wrapped: Array<Any>

results in:

type 'Wrapped' constrained to non-protocol type 'Array<Any>'

and various other similar declarations. Help is appreciated.

5
  • 2
    What would this extension be, exactly? In other words, what functionality would it be that you would wish to add only to [Any]? Commented Nov 4, 2016 at 16:31
  • 1
    I'd like to add a convenience function that 1) appends an element if the array is non-nil and 2) initializes the array with just the element if the array is nil. Commented Nov 4, 2016 at 17:18
  • 2
    @ConnorNeville You mean array = (array ?? []) + [element]? IMO that's not really worth an extension (considering the workarounds you'd have to go through in order to make it work). Commented Nov 4, 2016 at 17:21
  • Doh. That's a much more concise way of doing it than what I was repeatedly writing. I'll just do that, thanks. Commented Nov 4, 2016 at 17:22
  • @ConnorNeville No problem :) Although I do feel the need to question the use of an optional array, is it not possible for it just to be a non-optional empty array? Commented Nov 4, 2016 at 17:30

4 Answers 4

17

I am kinda late, but maybe I can help.

In swift 4, you can do this

extension Optional where Wrapped: Collection {

If you need to access the Element type of the array you can do:

Wrapped.Iterator.Element

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for pointing me to the Collection protocol, this is what I needed actually
4

A bit late to the party but it still might help future readers. Using Wrapped RangeReplaceableCollection to support strings as well:


extension Optional where Wrapped: RangeReplaceableCollection {
    mutating func append(_ element: Wrapped.Element) {
        self = (self ?? .init()) + CollectionOfOne(element)
    }
    mutating func append<S: Sequence>(contentsOf sequence: S) where S.Element == Wrapped.Element {
        self = (self ?? .init()) + sequence
    }
}

var optionalString: String?
optionalString.append("a")
optionalString  //  "a"
optionalString.append(contentsOf: "bc")
optionalString  //  "abc"
optionalString.append(contentsOf: ["d", "e"])
optionalString  //  "abcde"
var optionalArray: [Int]?
optionalArray.append(1)
optionalArray  //  [1]
optionalArray.append(contentsOf: [2,3])
optionalArray  //  [2,3]

Comments

2

Yes the problem here is that in this line,

extension Optional where Wrapped: Array<Any>

the 'Array' should be a protocol, in a more general way :

extension Type where Element: Protocol 

The solution I got is ugly but works, consider this:

protocol ArrayOfAny {}
struct ArrayAny<Element: Any>: ArrayOfAny {
    let array: [Element]
    init(_ array: [Element]) {
        self.array = array
    }
}    

Because this:

extension Array: ArrayOfAny where Element: Any {}

is not supported...

then you can just do this:

extension Optional where Wrapped: ArrayOfAny

Hope it helps :)

Comments

0

A better solution for this problem is using generic functions on Optional like this (here you are only adding functions to Optional if it really is an Array):

extension Optional {
    mutating func appendAndSetIfNil<E>(_ element: Wrapped.Element) where Wrapped == [E] {
        self = (self ?? []) + [element]
    }

    mutating func appendAndSetIfNil<S>(contentsOf newElements: S) where S: Sequence, Wrapped == [S.Element] {
        self = (self ?? []) + newElements
    }
}

This is just an example where the append function basically has been added conditionally to Optional if its Wrapped Type is an Array. In this case here the value is changed from nil to [] before appending.

But you can do anything here!

Be aware that this approach does not work in all circumstances, but in this one, it works!

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.