Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift extension on RawRepresentable has no accessible initializer

I'm trying to create an extension for my FieldIdentifiable protocol only where the enum that implements it has a RawValue of Int. The only problem is that the return FieldIdItem(rawValue: newValue) line keeps showing this error:

'Self.FieldIdItem' cannot be constructed because it has no accessible initializers

Is this a Swift bug or am I missing something?

enum SignUpField: Int, FieldIdentifiable {
  case Email = 0, Password, Username

  typealias FieldIdItem = SignUpField
}

protocol FieldIdentifiable {
  typealias FieldIdItem

  func next() -> FieldIdItem?
  func previous() -> FieldIdItem?
}

extension FieldIdentifiable where Self: RawRepresentable, Self.RawValue == Int {

  func next() -> FieldIdItem? {
    let newValue: Int = self.rawValue+1
    return FieldIdItem(rawValue: newValue)
  }

  func previous() -> FieldIdItem? {
    return FieldIdItem(rawValue: self.rawValue-1)
  }
}
like image 848
programmerdave Avatar asked Dec 24 '22 08:12

programmerdave


1 Answers

In

extension FieldIdentifiable where Self: RawRepresentable, Self.RawValue == Int { ... }

the associated type FieldIdItem of Self is not (necessarily) RawRepresentable, and that's why

FieldIdItem(rawValue: newValue)

does not compile. You could fix that by adding additional constraints:

extension FieldIdentifiable where Self: RawRepresentable, Self.RawValue == Int,
Self.FieldIdItem : RawRepresentable, Self.FieldIdItem.RawValue == Int { ... }

However, if the next() and previous() methods actually should return instances of the same type then you don't need the associated type at all, and can use Self as return type in the protocol:

enum SignUpField: Int, FieldIdentifiable {
    case Email = 0, Password, Username
}

protocol FieldIdentifiable {

    func next() -> Self?
    func previous() -> Self?
}

extension FieldIdentifiable where Self: RawRepresentable, Self.RawValue == Int {

    func next() -> Self? {
        return Self(rawValue: self.rawValue + 1)
    }

    func previous() -> Self? {
        return Self(rawValue: self.rawValue - 1)
    }
}

Note also that the constraint

Self.RawValue == Int

can be relaxed slightly to

Self.RawValue : IntegerType
like image 138
Martin R Avatar answered Jan 01 '23 20:01

Martin R