Everything about floating point is difficult and fiddly and resists a one-size-fits-all treatment.  Joe recently did some work to characterize the various ways floats can be compared -- representational equivalence, bitwise equivalence, and the traditional `==`, and put these in the spec of Float/Double, so we would have a vocabulary to discuss them.

The main differences between these treatments are the treatment of NaN and signed zeroes.  (And for $REASONS, there are multiple NaN bit patterns.)

Representational equality means "same number", where all NaN values are the same.  Float::equals uses representational equality.

Bitwise equality means "same bit pattern".

The `==` operator says that 0 == -0 and that NaN is equal to nothing, not even itself.

For comparing a variable to a constant, representational equality is the obvious interpretation; `case nnn` means "is it the number nnn".  This allows you to say `case NaN` and `case -0` and get the right answer (all of these relations agree on what to do about 1.0).

For Valhalla's `==`, which we've decided means "substitutible" or "indistinguishable from", then bitwise equality is the obvious answer.  Its sad that these are all different, and each case requires getting experts in a room to hash it out, but that's life with floating point.

Your claim about refactoring anomalies is not right; the refactoring you offer will work for your example which uses 3.14, because `==` agrees with r.e. at the "regular" floating point values.  Where it will fail is for NaN, as `==` has its own weird opinions about NaN.  But `== NaN` is intrinsically useless anyway, since it folds to false, and anyone who knows what NaN is already knows this (probably by having been bitten by it).

On 1/26/2023 9:25 AM, [email protected] wrote:


------------------------------------------------------------------------

    *From: *"Angelos Bimpoudis" <[email protected]>
    *To: *"Remi Forax" <[email protected]>
    *Cc: *"amber-spec-experts" <[email protected]>
    *Sent: *Thursday, January 26, 2023 2:55:31 PM
    *Subject: *Re: Draft JEP on Primitive types in patterns,
    instanceof, and switch

    Thanks for the quick reply.

    I think there is one important factor here. By quickly inspecting
    the issues in the links, IIUC, the semantics of floating-point
    constants there follow the semantics of |==|​. So -0 and 0 compare
    equal there (e.g.,
    https://github.com/rust-lang/rust/issues/41620#issuecomment-300587182).


    The JEP follows the road of "representation equivalence" as
    described in
    
https://download.java.net/java/early_access/jdk20/docs/api/java.base/java/lang/Double.html#fpNumericalEq
    
<https://download.java.net/java/early_access/jdk20/docs/api/java.base/java/lang/Double.html#fpNumericalEq>


In terms of semantics Double::equals may be better than double == double, this seems to be the direction that Java is choosing (Valhhalla also used Double::equals for value types containing a double).

But it means that introducing a "when" is not a valid refactoring
  case double 3.14 -> ...
can not be refactored to
  case double x when x == 3.14 -> ...

Most of my students thinks in terms of equivalence, breaking this kind of refactoring make the proposed semantics not intuitive.

That's why i think it's better to not allow double/float constants, so people have to be explicit about the semantics they want.

regards,
Rémi



    ------------------------------------------------------------------------
    *From:* Remi Forax <[email protected]>
    *Sent:* 26 January 2023 14:16
    *To:* Angelos Bimpoudis <[email protected]>
    *Cc:* amber-spec-experts <[email protected]>
    *Subject:* [External] : Re: Draft JEP on Primitive types in
    patterns, instanceof, and switch
    > From: "Angelos Bimpoudis" <[email protected]>
    > To: "amber-dev" <[email protected]>
    > Sent: Thursday, January 26, 2023 10:48:47 AM
    > Subject: Draft JEP on Primitive types in patterns, instanceof,
    and switch

    > Hello all,

    > I would like to share this draft JEP with you about primitive
    types in patterns,
    > instanceof, and switch:

    > https://openjdk.org/jeps/8288476

    > "Enhance pattern matching by allowing primitive types to appear
    anywhere in
    > patterns. Extend instanceof to support primitive types, and
    extend switch to
    > allow primitive constants as case labels."

    > Comments very much welcomed!

    > Many thanks,
    > Angelos

    I still think that the semantics proposed for pattern matching on
    primitive types is useless complexity with the perverse side
    effect of normalizing the usage of "default" in pattern matching
    (too many examples of this JEP are using "default") but we already
    discussed that.

    Allowing switching on double and float constants is just wrong.
    Rust is actually trying to remove that feature
    [
    
https://urldefense.com/v3/__https://github.com/rust-lang/rust/issues/41255__;!!ACWV5N9M2RV99hQ!NfJ7KspB447oMGi0NoEyXC6s_w3vD1N-SBu5hiD4kMVAkmwDWPNbymH83iOnrkakPoayD6vwGwuB5NvedJfjH9LU$
    |
    
https://urldefense.com/v3/__https://github.com/rust-lang/rust/issues/41255__;!!ACWV5N9M2RV99hQ!NfJ7KspB447oMGi0NoEyXC6s_w3vD1N-SBu5hiD4kMVAkmwDWPNbymH83iOnrkakPoayD6vwGwuB5NvedJfjH9LU$
    ]

    I see no point to make the same mistake.

    Otherwise, the rest is fine.

    Rémi

Reply via email to