I am wondering what people think of the idea of an actual elvis operator?
Right now we have a null coalescing operator which is nice for optionals. This however does not work with non-optional Bools. The reason I think this would be handy is that you could set a value of a Bool using functions that return Bool but allowing a backup if the first fails while not having to worry about side-effects.
Example:
let value = Func1() ? Func1() : Func2() // Potential side-effects and Func1 is called twice. (What if Func1 incremented a value somewhere).
This can be fixed with (of course)
let func1Result = Func1()
let value = func1Result ? func1Result : Func2()
But this kinda defeats the purpose of a ternary operator IMO and the code below is a lot nicer.
It seems they want to remove the ternary operator completely because it uses a "?" it seems and that there is a replacement using an operator overload. The conversation there also got to adding an operator that seems to return an optional if the value is false. I think that is a slightly different issue and I would love to keep the current null coalescing and the ternary operators as is.
Does this come up a lot? It sounds equivalent to short-circuiting logical OR to me, so I'm having trouble understanding why it is worth creating a new operator.
The Elvis operator has to be one of the following cases:
// In a typesafe language, ?: must construct the same type left and right T ?: T and not T ?: U
// The only way to have a test is Boolean:
Bool ? Bool : Bool
// which then is shortened to
Bool ?: Bool
If you use it like many people do in C-like languages, you can test against "0" instead of testing for a bool:
// How to construct it in Swift
intValue != 0 ? intValue : fallbackValue
// What an Elvis would look like
intValue ?: fallbackValue
This is, again, of very limited use.
Finally, you can test it against a false-like condition, for example, an optional:
value != nil ? value! : fallbackValue
// which is
value ?: fallbackValue
// exactly the same as
value ?? fallbackValue
The only other situation I can see is extending ?? and if let to other constructs with bias case loads
SomeEnum.caseName(value) ?? fallbackValue
But I wouldn't go Elvis on these. I'd rather use @stephencelis 's .isCaseName?.value (however that ends up being spelled.)
Yes. More generally, many other languages have a concept of "truthiness" such that 0 or NULL or an empty string can all qualify as false values for Boolean purposes. But since Swift allows only real Booleans in Boolean contexts, the utility of an Elvis operator seems much reduced.
It is easy enough to add Collection and hence String Elvis, this might be worth adding to the standard library since it is a common pattern in other languages:
You could write something similar for Integers, but I would be against added the int version because it is rarely used in GCC and because it is very un-Swift like since testing against zero instead of a Bool is weird in Swift.
You could write something similar for Integers, but I would be against added the int version because it is rarely used in GCC and because it is very un-Swift like since testing against zero instead of a Bool is weird in Swift.
I feel the same way about your extension to Collection here : if it's 'un-Swift like' to test an integer against zero instead of using a Bool, why would testing a Collection's count against zero would be better ?
If you view an Optional as a collection of up to 1 element it makes sense.
It is a common idium in other languages that use reference semantics to return nil for empty collections/strings and therefore code like this is common practice.
It is useful to signal an error with an empty collection and have an easy way to provide a default.
Optional formally isn't a collection and I don't see a way in which it resembles one.
Yes, but Swift, being a high-level language, doesn't use such semantics. An empty array in C is a NULL pointer. In Swift, an empty array is a full-fledged instance.
The nil-coalescing operator is unique and used only for optionals, and in my opinion it should be left as is.
I don't see the perspectives of introducing a new operator for that purpose - the core team isn't tolerant towards new operators of that sort, and neither am I. But you are free to try, of course.
You can always use the 'true-boolean' _?_:_ which is even more useful and isn't that bad of an alternative. It's just a bit longer.
Better use isEmpty, count can lead to writing inefficient code when using the operator.
Could be written in just a single line: return lhs.isEmpty ? try rhs() : lhs
Please start a new thread discussing the specific issue you raise here: I see no obvious reason we couldn't change 'throw' to be an expression returning Never.
That said, making that change wouldn't fix your code above, because ?? requires the left and right side to be the same base types, and Never is not an A.
…but “??” uses an autoclosure for its right-hand side, and the code works if you manually wrap the expression in a closure, so I’m not sure why it doesn’t work as-is:
let x = Optional(0)
let y = x ?? fatalError()
// error: cannot convert value of type 'Never' to expected argument type 'Int'
let z = x ?? { fatalError() }()
// no error