Fact: Sets are the Jan Brady of Swift Collections

Swift can infer array types:

let myArray = ["a", "b", "c", "d"]

Swift can infer dictionary types:

let myDictionary = ["key1": "value1", "key2": "value2"]

But what about sets?

let mySet = ["a", "b", "c", "d"] as Set // or
let mySet: Set = ["a", "b", "c", "d"]

These johnny-come-lately collections offer no automatic inferencing. Don’t sets deserve love too?

Parentheses are already taken by tuples. Angle brackets are protocol/generic specific No one wants to type 《》. Face it. Sets are Swift’s Jan Brady collections.

Swift playgrounds use braces to show sets in the results sidebar:

Screen Shot 2015-11-19 at 10.34.41 AM

But of course, braces mean closures:

Screen Shot 2015-11-19 at 10.36.50 AM

And even if Swift could infer a set from comma-delineated braced items, should it?

let mySet = {"a", "b", "c", "d", "e"} // wrong, bad, wrong 
let mySet = {members | "a", "b", "c", "d", "e"} // nope

You could do a lot worse.

let mySet = ~1, 2, 3~ // The "mustache" delimiter
let mySet = ¯\_(ツ)_/¯ 1,2,3, ¯\_(ツ)_/¯
let mySet = •< 1, 2, 3 >•
// ...etc...

Even if there were a way to infer sets, Swift still wouldn’t be able to infer option sets, bags, ordered sets, ordered dictionaries, counted sets, fashionable totes, shopping satchels, and unique arrays.

let myTotes = [(Gucci, Prada, Louis Vuitton)]

You could try (or try! or try?) but you’re just (ahem) setting yourself up for failure.

So what should Swift do? You tell me.

Thank you everyone in #swift-lang IRC for your suggestions.

3 Comments

  • My first thought was Swift should use the vertical bar: |”a”, “b”, “c”|. The problem comes in with an empty set being the same as a logical OR. Maybe a vertical bar / square bracket combo: |[“a”, “b”, “c”]|?

  • You can use prefix (or postfix) operators that just return their input to get the type inference to recognise a set:

    prefix operator | {}
    public prefix func |
    (x: Set) -> Set {
    return x
    }

    let set = |[1, 2, 3]

    But that’s probably a bad idea.

  • You’ve tacitly acknowledged that Set is ArrayLiteralConvertible; the generic type system infers the array literal’s Element type:

    let stringSet: Set = [“a”, “b”, “c”]
    // {“b”, “a”, “c”}
    // Opt-click → let stringSet = Set

    … so the issue is braces versus a type annotation that’s only _mostly_ inferred? You have to draw the line on syntactic sugar somewhere (Swift may already have more than is good for it), but I can respect the argument that Set should be common enough to earn its sugar.

    Identifying a Set, as such, isn’t where the programmer’s cognitive load is. Inferring the Element type from a collection that may not be so obviously homogeneous, or may change Element type as the code is revised, is 90% of the work (weighted by the potential for programmer error). Next to that, I’ll pay the five characters (I’m on the colon-space team).

    And I’ll be 60 in two weeks. Please don’t make it critical that I distinguish braces, brackets, and parentheses without context.