[Amendment] SE-0368: StaticBigInt

Arguably this is a bug that’s worth a source-breaking change to fix. -0 as Float not producing a negative zero is just wrong.

2 Likes

Source-breaking - yes. Worth "fixing" - I'd also say yes.

let a: Double = -0
print(a.sign) // plus

let b: Double = -0.0
print(b.sign) // minus

let c: Double = -(0)
print(c.sign) // minus

let d: Double = -(0.0)
print(d.sign) // minus

let O: Double = 0

let e: Double = -O
print(e.sign) // minus

let f: Double = -(O)
print(f.sign) // minus
1 Like

from TSPL:

Grammar of a literal

literal → numeric-literal | string-literal | regular-expression-literal | boolean-literal | nil-literal

numeric-literal → - opt integer-literal | - opt floating-point-literal

the TSPL grammar has had mistakes in it in the past, but in this instance i think it (and the parser implementation) is correct, and consistent with how other literal grammars (e.g., JSON) handle prefix +/-.

in my view, that swift generates a function call out of prefix + is the aberration.

also, i think it is weird that swift considers + inside a floating point literal to be part of the float literal, but it does not consider + prefixed to an integer literal to be part of the integer literal.

floating-point-e → e | E

floating-point-p → p | P

sign → + | -

2 Likes

parsing -0 as (-)(0 as some ExpressibleByIntegerLiteral) breaks integer literal initializers. in particular, it will no longer be possible to express:

let min:Int8 = -128

because init(integerLiteral:) would receive (128 as Int8), and that would overflow the bit width.

EDIT: just saw that @John_McCall noticed the same thing.

1 Like

On the contrary, Swift language should be unaware of prefix minus or prefix plus or any other prefix operator. Plus on a custom type (which can be integer literal expressible among other things) can do arbitrary things instead of returning self unchanged, and prefix minus should be parsed as a proper operator to avoid the anomalies mentioned above or similar, IMHO.

Looks a lesser evil to me.

How often do you have to write "-2146483648" (or 2146483647 FTM) †? Perhaps you can do the same and use .min / .max instead of -128 / 127

(† - yes, there's a typo and that's to stress the point.)

Edit: IIRC (yep, e.g. here, search for SCHAR_MIN), C used the notion of INT_MIN / INT_MAX not only to account for different size in bits, but to be compatible with weird one's complement architectures where INT8_MIN is -127. Ok, ok, we'll probably never need to support that in Swift. Right?

Edit2: I used to ask this question (or rather its C equivalent) in the interviews
func isqrt(_ x: Int) -> Int {
    precondition(x >= 0)
    return Int(sqrt(Double(x)))
}

// 🐞 not so safe 🐞
func safeSqrt(_ x: Int) -> Int {
    var x = x
    if x < 0 { x = -x }
    return isqrt(x)
}

Edit3: another funny + / - asymmetry:

enum SpecialNumbers: Double {
    case negativeZero = -0.0
    case zero = 0.0
    case positiveZero = +0.0 // 🛑 Enum case must declare a raw value when the preceding raw value is not an integer
}

We are definitely not going to cause -128 as Int8 to fail compilation. That’s utterly out of the question; it’s also, incidentally, not something that is in the scope of this amendment review.

6 Likes

Actually, that's not the case, I think—not if we do deliberately something like what we are trying to undo here (which was done accidentally):

If static prefix func - (_: StaticBigInt) -> Int8 overloads are added that return values of each concrete fixed-width integer type, they ought to be favored and permit overflow checking to be deferred to the result of negation, allowing the full range of values to be expressed as literals without the need for special handling of - for literals.

(Some preliminary fiddling on a playground suggests the compiler doesn't like that too much at the moment for reasons unclear.)

Floating-point literals have the same issue as integer literals.

sign+ | -

The sign is only used in the grammar of a decimal-exponent or hexadecimal-exponent.

struct Number: ExpressibleByFloatLiteral {
  init(floatLiteral: Double) {}
  static prefix func + (_ rhs: Self) -> Self { rhs }
}

let a = -7e+2  //-> `-700 as Double`
let b = +6e-2  //-> `0.06 as Number`
let c = a * b
//          ^
// error: cannot convert value of type 'Number' to expected argument type 'Double'
3 Likes

Here's another interesting quirk from the way negative literals are handled in Swift: while the negative sign is sometimes considered part of the literal, it still retains the same precedence as the negation operator. This leads to interesting cases like the one below.

extension Numeric {
    func incremented() -> Self {
        return self + 1
    }
}

-13.incremented()   // -14
(-13).incremented() // -12
-(13.incremented()) // -14
4 Likes

I don’t think this is really a quirk. The right way to understand the behavior is as I described it above, that the operator behaves specially when directly applied to an integer literal. The grammar is wrong to say that it’s grammatically part of the literal.

2 Likes

That might be the right way to think about it, but I don't think most Swift programmers will think about it that way. This has led to confusion before. And not only does the grammar get this subtlety wrong — the syntax highlighters for the Swift Playgrounds app and Visual Studio Code also get it wrong, highlighting this expression incorrectly.

Personally, I'd be in favor of adding a warning to expressions like -13.incremented() that can be suppressed by adding parentheses around a subexpression e.g. -(13.incremented()) or (-13).incremented().

1 Like

Unless your argument is that -x.incremented() is crystal clear but -13.incremented() isn't, this isn't about literals and the special quirk here.

As was rightfully noted the scope of this review is the amendment to StaticBigInt (specifically removing the "+" operation from it). We should move all other discussions (e.g. those related to "prefix -" peculiarities) elsewhere (and yes, they deserve being discussed).

2 Likes

i cannot reproduce this on VSCode using the 5.8 toolchain and latest VSCode swift extension.

image

Thank you everyone for participating in this review! The amendment has been accepted:

Holly Borla
Review Manager

5 Likes