Binarian
Binarian

Reputation: 12446

Initializer avoiding an empty array as argument

I have an initializer, it needs one value.

internal init(value pValue: T) { ... }

Now I have a convenience initializer, to convert an array to my type. But that array may not be empty (because it needs a value to make sense, therefore there is the designated initializer ahead).

internal convenience init(array pArray: [T]) {
    guard !pArray.isEmpty else {
        // it is not correct to init without at least one value
        return // or assert
    } // compiler error because there is no init call

    .. // init with non-empty array
}

What would be the a solution to this, so that someone who uses the interface wouldn't be surprised and still had good usability?

The hurdle here is, that in an initializer, every path need to call an initializer.

The solution, I think would make sense is, when the initializer gets an empty array as an argument, is to create the type with an arbitrary value of that type T.

self.init(T())

But I can not create T, because I do not know the initializers for T.

And I can not simply use

self.init(0)

because the compiler wants an initializer with type T.


I did implement it as a static method and it works (because I can just opt out to use init), but I want it as a non static method

I also did implement it as an variadic parameter and it works, but then this is very inconvenient with many parameters

Upvotes: 1

Views: 357

Answers (2)

Grimxn
Grimxn

Reputation: 22507

A failable init is the answer, but you need to declare <T>, and you need to call the main init -

class A { // or class A<T> 
    var count = 0

    init() {            
    }

    internal convenience init?<T>(array pArray: [T]) { // <T> not needed if declared at Class level
        guard !pArray.isEmpty else {
            // it is not correct to init without at least one value
            return nil
        }

        // init with non-empty array
        self.init()
        self.count = pArray.count
    }
}

let n:[String] = ["a"]
if let a = A(array: n) {
    print("\(a.count)")
} else {
    print("nil")
}

Upvotes: 2

Kirsteins
Kirsteins

Reputation: 27345

Perhaps you can use fail-able initialiser that will return nil if array is empty:

class Type<T> {
    init?(array pArray: [T]) {
        guard !pArray.isEmpty else {
            return nil
        }

        // ...
    }

    init(value pValue: T) {
        // ...
    }
}

Upvotes: 1

Related Questions