[Proposal] Set literals

Does "understanding" mean also knowing what the above expression actually does, re. operator precedence? Because I for one have no idea whether that expression means:

let x = (a ? y : b) ? z : t

…or:

let x = a ? y : (b ? z : t)

I wouldn't expect anyone, not even an author of the language, to have operator precedence memorised to that level of detail.

Personally I'd be fine if Swift flat-out rejected that code as ambiguous, and required explicitly parenthesis. Doing so would be completely in line with Swift's language goals of clarity over brevity.

Many places I've worked have required parenthesis for cases like that, specifically because it's considered dangerously easy to misinterpret. Terse to a potentially literal fault. I can say with confidence it would be broadly rejected at Google & LinkedIn, for example (it's explicitly banned by their style guides).

Maybe accepted at Apple, but then I wouldn't use them as a role model on this specific topic. :confused:

3 Likes

Well if you are new to the language you google before you use it ;) Most languages inherit the precedence of the ternary operator from C, though there's at least one exception, PHP.

If you are a seasoned developer of the X language, you are just expected to know. Corporations that hire people in bulk, conveyor-belt style, should protect themselves from dumb mistakes, that's understandable. It's why I've been avoiding big co.'s for many years now.

1 Like

This is (one of the reasons) why we now have if expressions!

// look ma, no precedence!
let x = if a { y } else { if b { z } else { t } }
2 Likes

For what it’s worth, the ternary operator is right-associative. I assume that was intentional in C (or wherever C took it from) so that you can use it as a simple sort of case expression. It can be hard to read on a single line, but it “iterates” quite nicely on multiple lines:

let x = cond1 ? result1 :
        cond2 ? result2 :
        cond3 ? result3 :
        otherwise

Anyway, this thread is about set literals.

14 Likes

What about using curly braces for Set literals?

let digits: Set = {1, 2, 3, 4, 5}

Are there any reasons why curly braces haven't been suggested or mentioned yet?

I think it was suggested in the 2016 thread, it causes ambiguity if you omit the type (is it code or a set?). On the other hand, if you are required to specify the type then what's the point of set literals?

1 Like

What about this:

let u = \{1, 2, 3}
print (u)
// {1, 2, 3} 

print (type (of: u))
// Set <Int>

The idea of curly braces isn't bad because it's closer to the math notation of sets, but the backslash kind of ruins it for me for aesthetical reasons :slight_smile:

The syntax isn't the problem. The whole idea of a "set literal" conflicts with the concept of literal overloading (expressible by) in Swift.

@crontab - I genuinely don't mean to condescend (I'm learning Swift still too), but you should take the time to understand how literals work in Swift (and how they differ from literals in other languages). As it stands, you're bike-shedding syntax for a feature that makes no sense conceptually.

Even if Swift had found no use for parens, so we could use (1, 2, 3) for "set literals", you would still have all the issues @James_Dempsey raised earlier.

Hmm, which one is "correct" behaviour? Or are they both?

let x: Set<Int> = [1, 1] // ✅
let y: [Int: Void] = [1:(), 1:()] // 🛑 Fatal error: Dictionary literal contains duplicate keys

ditto for variables instead of const expressions.

Shouldn't they both be crashing or both non-crashing?

IMO the existing behavior is justifiable on the grounds that the result of inserting two different values under the same key in a dictionary will result in one value being dropped (which would probably be undesirable to do silently), but inserting a duplicate element into a set is usually a no-op (except in the rare cases where you care to distinguish set elements for some reason).

3 Likes

Even though the dictionary version should only trap on non-equal elements only and be silent on duplicating equal elements, right? Otherwise we have an inconsistency here... ok, I take this back (dictionary elements could be non equatable to begin with, so this is more complicated than I thought initially).

1 Like

There's no Equatable constraint on a dictionary's Value type so whether two elements are 'duplicate' can't really be determined in the general case.

1 Like

Interestingly this was different in Obj-C, where duplicate dictionary entries were silent:

void objc(void) {
    //NSString* key = @"key";
    NSString* key = @"long key xxxxxxxxxxxxxxxxxxxxxxxxx";
    NSDictionary<NSString*, NSString*>* x = @{key : @"value", key : @"value"}; // ✅
    NSLog(@"x: %@", x); 
}

I do not think there is any need for Swift to introduce new literal syntax specifically for set types.

The current ExpressibleByArrayLiteral functionality is good enough. Set types such as Set, OrderedSet, TreeSet or BitSet already conform to it. These types are already quite easy to initialize with pleasant-enough syntax:

let a: Set = [1, 2, 3]
let b: TreeSet = ["one", "two", "three"]
let c: OrderedSet = [1.0, 2.0, 3.0]
let d: BitSet = [2, 4, 6]
// Coming soon, I hope:
let e: SortedSet = ["Dorothy", "Rose", "Blanche", "Sophia"]

I think it would be especially bad to choose syntax that isn't easily searchable, or one that is only applicable to some restricted subset of these types.

I don't think set types are different enough from other one-dimensional containers (arrays, deques, heaps, lists, etc) to be worthy of their own syntax.

(Rather than inventing unnecessary new syntax, I believe it would be more productive to think about how we could generalize ExpressibleByArrayLiteral to support noncopyable element types. How will we efficiently initialize a noncopyable array of noncopyable elements? We will need to come up with a reasonable way to directly feed an arbitrary number of items into a newly initialized construct, preferably without any allocations of temporary storage.)

21 Likes

Parameter packs?

6 Likes

Yes, I hope! We need to prototype such an API, to validate the idea (and to figure out how much work it will take to make it usable on heavily resource-limited platforms).

2 Likes

I don't see a need for Set Literal syntax. If anything it makes the language a bit more confusing to learn and I don't see a lot to gain by it to make it worth it.

5 Likes