Can I _really_ not add Decodeable conformance in an extension?

I have a class which provides a ThreadsafeDictionary

public class ThreadsafeDict<Key:Hashable,Value>{
    
    private var dict:[Key:Value]
    private let queue:DispatchQueue
 
    public init(_ newDict:[Key:Value]) {
        dict = newDict
        
        queue = DispatchQueue(label: "com.hobbyistsoftware.threadsafe.dict",
                              qos: DispatchQoS.userInitiated,
                              attributes: .concurrent)
    }

//Snip
}

it's seems like it would be easy to make this decodable if the key/value allow
(just encoding/decoding to the 'raw' dictionary)

extension ThreadsafeDict:Decodable where Key:Decodable,Value:Decodable {
    required public init(from decoder: Decoder) throws {
        let dict = try Dictionary<Key,Value>.init(from: decoder)
        self.init(dict)
    }
}

however this hits a couple of errors:

Designated initializer cannot be declared in an extension of 'ThreadsafeDict'; did you mean this to be a convenience initializer?

Initializer requirement 'init(from:)' can only be satisfied by a 'required' initializer in the definition of non-final class 'ThreadsafeDict<Key, Value>'

Of course - I can't provide the initialiser within the class because Key & Value are not necessarily Decodable

Am I missing something?

You have a couple options here. You could define the init(from:) in the body of the class with the where clause attached to the declaration itself:

required public init(from decoder: Decoder) throws 
  where Key: Decodable, Value: Decodable
{
  dict = try Dictionary<Key,Value>.init(from: decoder)

  queue = DispatchQueue(label: "com.hobbyistsoftware.threadsafe.dict",
                        qos: DispatchQoS.userInitiated,
                        attributes: .concurrent)
}

extension ThreadsafeDict:Decodable where Key: Decodable, Value: Decodable {}

Also, if you don't need clients to be able to inherit from ThreadsafeDict (which I'm guessing you don't since it is public and not open?), you can just make it final and use the convenience init:

public class ThreadsafeDict<Key: Hashable, Value> { ... }

extension ThreadsafeDict:Decodable where Key: Decodable, Value: Decodable {
  convenience public init(from decoder: Decoder) throws {
    let dict = try Dictionary<Key,Value>.init(from: decoder)
    self.init(dict)
  }
}
2 Likes

I had no idea you could put a where in a function definition!

I have only ever seen them in extension declarations.

Thank you - that's perfect.

1 Like

It's relatively new.

Terms of Service

Privacy Policy

Cookie Policy