Eyad
Eyad

Reputation: 11

Why the swift compiler cannot use my subscript?

I have code that resembles this

I created custom subscript to do the unwrapping for me to make things easier.

enum MyEnum {
   case one
   case two
   case three
}

struct MyStruct {
   static var empty: Self {
       return .init()
   }

   //Some Variables Here
}

class MyClass {
   var index = 0

   var data: [MyEnum: MyStruct] = [
       .two: .empty,
       .three: .empty,
       .one: .empty
   ]

   var allTypes: [MyEnum] {
       switch Bool.random() {
           case true:
               return [.two, .three]
           case false:
               return [.one]
       }
   }

   var currentSelectedType: MyEnum {
       return allTypes[index]
   }

   func myMethod(type: MyEnum) {
       let one: MyStruct = data[type]!
       let two: MyStruct = data[currentSelectedType]!
       let three: MyStruct = data[allTypes[index]]
       let four: MyStruct = data[.one]

   }
}

fileprivate extension Dictionary {
   subscript(_ key: Key) -> Value where Key == MyEnum, Value == MyStruct {
       get {
           return self[key]!
       }
       set {
           self[key] = newValue
       }
   }
}

in my MyClass myMethod why I have to forcely unwrapp one and two but not three and four otherwise I get a compile time error

       let one: MyStruct = data[type] // Error Value of optional type 'MyStruct?' must be unwrapped to a value of type 'MyStruct'
       let two: MyStruct = data[currentSelectedType] //Error Value of optional type 'MyStruct?' must be unwrapped to a value of type 'MyStruct'

Is there something I'm missing here?

Upvotes: 0

Views: 100

Answers (1)

Tarun Tyagi
Tarun Tyagi

Reputation: 10102

I don't have an answer on why compiler isn't picking the expected overload in this situation.

I would recommend clarifying the overload you wish to use at call site, like following.

fileprivate extension Dictionary {
    subscript(safe key: Key, defaultValue: Value = .empty) -> Value where Key == MyEnum, Value == MyStruct {
        get { return self[key, default: defaultValue] }
        set { self[key] = newValue }
    }
}

With above, you can tell compiler explicitly to use your preferred overload.

func myMethod(type: MyEnum) {
    let one: MyStruct = data[safe: type]
    let two: MyStruct = data[safe: currentSelectedType]
    let three: MyStruct = data[safe: allTypes[index]]
    let four: MyStruct = data[safe: .one]
}

Upvotes: 1

Related Questions