enum Direction: Double, CaseIteratable {
case north = #Eval(0.0 - 45) or #Eval(Angle.degrees(0.0 - 45).radians)
case east = #Eval(90.0 - 45)
case north = #Eval(180.0 - 45)
case north = #Eval(360.0 - 45)
}
Edit: it appears it's not possible to place anything but a real literal value for switch case value. Putting an expression macro there, even though the macro works standalone, the compiler error out with "Raw value for enum case must be a literal". Why the compiler so eager to reject this code, why not expand the macro first?
Hmm, I didn't realise you couldn't use trivial expressions (that are compile-time deterministic). I guess I'm not surprised per se, given how Swift feels in general about 'const' expressions. Still, this feels like something best solved (long-term) with language improvements, not macros.
If such overrides cannot be used at compile time, then the compiler must reject the expression: it would not be obvious at all if instead it just substituted some other disfavored overload.
Whether that the compiler does not reject this code (or complain otherwise) when "func -" is defined as a static function defined in an extension of Double is a bug or a feature – I don't know.
Presumably a feature, right? You can override methods (including static ones) on types from other modules (although the override is only visible in your current module, I believe?).
No, it should not be rejected. You're shadowing== with an unrelated static function that shares the same name, not changing the conformance of Double to Equatable. Swift doesn't offer you any way to make 0.0 equivalent to 1.0:
It doesn't matter what I am returning from it (it could be a fatalError("TODO") for that matter) as this code is not executed at compile time, just the compiler notices I have this shadowed and as a result allows the "let x: UInt8 = 255 + 1" expression to compile. However this line:
let y: UInt8 = 256 // 🛑 Error: Integer literal '256' overflows when stored into 'UInt8'
I can not "fix" by providing this shadowing initialiser:
What strikes me odd is that I can make the code compilable in one instance but not another. Which behaviour is correct? Or are they both correct, somehow?
They are both correct. Again, shadowing means that the implementation being shadowed is still there: you cannot change the way in which UInt8 conforms to ExpressibleByIntegerLiteral; you have only created another function that happens to share the same name, and thus will be invoked preferentially when you write exactly that function call.
In this case, the integer literal 256 is being used to create a value of type UInt8 using the implementation required by the protocol conformance, which overflows. You can call your shadowing implementation by writing UInt8(integerLiteral: 256) and the compiler won't complain. Remove your implementation and the compiler will complain again.
Thank you, now I see what you mean. Two further notes:
I don't see method shadowing being mentioned anywhere in the TSPL, is it there and I just missed it?
this method shadowing feature is on the edge of being a foot-gun: one would assume that, say, EQ was "overridden" entirely, whilst it is merely shadowed. A more honest approach would be to give a compilation error during an attempt to shadow: "you can't do that".
This wasn’t added to the language because it means upstream changes are more likely to break downstream code. Of course, it only goes so far, since conformances can’t shadow the same way, and since someone even further downstream could still be broken.
Having said that, at least when my code stops to compile I am aware of the issue and can fix it. This is different to a silent and potentially serious foot-gun I'm getting either by (1) incorrectly writing a method implementation which is in fact "shadowing", or (2) by writing a method implementation that is not shadowing today and that only becomes "shadowing" retrospectively because of the future change in the compiler / standard library.