Forwarding an `ExpressibleByDictionaryLiteral` conformance?

in today’s episode of things that really ought to work in swift, but simply don’t:

struct MyApplicationSpecificDictionary
{
    private
    var table:[Key: [Element]]
    private
    init(table:[Key: [Element]])
    {
        self.table = table
    }
}
extension MyApplicationSpecificDictionary
{
    subscript(key:Key) -> [Element]
    {
        _read
        {
            yield  self.table[key, default: []]
        }
        _modify
        {
            yield &self.table[key, default: []]
        }
    }
}
extension MyApplicationSpecificDictionary:ExpressibleByDictionaryLiteral
{
    init(dictionaryLiteral:(Key, [Element])...)
    {
        self.init(table: .init(dictionaryLiteral: dictionaryLiteral))
    }
}
error: cannot pass array of type '(Key, [Element])...' as variadic
       arguments of type '(Key, [Element])'

arghh!!!!

so for now, i really only need empty dictionary literals, so i can get away with

extension MyApplicationSpecificDictionary:ExpressibleByDictionaryLiteral
{
    init(dictionaryLiteral:(Key, Never)...)
    {
        self.init(table: [:])
    }
}

but, it really should be easier to define these sorts of specializations for Array and Dictionary without giving up on literal syntax. surely there must be a better way?

1 Like

For Dictionary specifically there’s init(_:uniquingKeysWith:) and init(uniqueKeysWithValues:), but in the general case there’s no way to forward this.

yeah, but unlike with Array-oids, you can’t just use the argument as-is, you have to define what happens if there are duplicate keys, which is something the compiler can check and warn about with a regular Dictionary.

The duplicate key diagnoses is for the literal, not the dictionary. If you pass your dictionary literal elements to Dictionary(uniqueKeysWithValues:), I believe you'll have the same diagnoses and behavior as the standard lib dictionary

i don’t think this is true. for one, there are some types like KeyValuePairs that explicitly allow duplicate keys and can be written with duplicate keys.

i tried this with a custom type:

let x:InlineDictionary<Int, Int> = [0: 1, 0: 2]

and it did not produce a diagnostic. :frowning:

1 Like

Ah, you're right; I'm wrong :frowning:. Looks like the warning is in fact special cased to just dictionaries: swift/lib/Sema/MiscDiagnostics.cpp at f9abb026e6a47eb6b2265812587ebedbe284d68e · apple/swift · GitHub

2 Likes