Live data from Hacker News

Weird Python Integers

kate.io

141–150 of 150 posts

Re: Weird Python Integers

#141

Earlier quoted context omitted.

The point is that equality of identity is objectively more fundamental than equality by any other metric. You can easily observe this by noting that any two objects which are equal in identity are necessarily equal in all other possible ways. There is no argument to be made that "comparison by value is just as fundamental a concept as comparison by identity", or that this is just a matter of opinion. The fact that it…

> any two objects which are equal in identity are necessarily equal in all other possible ways Two NaNs are equal in identity but not in value, according to the IEEE spec.

I wasn't aware that IEEE floating point provided for two different kinds of equality checking? How would you invoke one or the other?

A NaN value does not compare equal to itself, because NaN is not thought of as a value at all but rather an error signal ("Not a Number"). You can check whether something is NaN, but that's not a distinction between comparing by identity and comparing by value -- it's a distinction between comparing values and checking for the presence of errors. The analogous operations to (1) comparing NaN to itself (unequal) and (2) checking whether NaN is NaN (yes), for another value such as -0, are (1b) comparing -0 to itself (equal) and (2b) checking whether -0 is NaN (no). They aren't (1c) comparing -0 to itself and (2c) checking whether -0 has the same "identity" as -0.

Re: Weird Python Integers

#143

Earlier quoted context omitted.

Yeah, a "fun" thing to do was to change the value of built-in constants such as pi.

That feature was required by the Indiana General Assembly. https://en.wikipedia.org/wiki/Indiana_Pi_Bill

More like ridiculed than required.

I was going to mention Indiana but was more hoping that it wouldn't be mentioned at all.

Re: Weird Python Integers

#144
post #104

Earlier quoted context omitted.

Because "foo" is an instance of String, aka subclass of Object, while 45L is a value for the primitive type long. I fail to see the confusion, other than for newbies.

That's pretty much saying "it is the way it is", which a) is not even true, see floating point numbers and b) will be obsolete with value types. Needless to say, there is pointless confusion created by Java's design, and there are better approaches available. All you have to do is to adapt the semantic model from reference equality vs. value equality to identity vs. equality. Identity checks whether the "bits" are id…

Better yet, allow identity checks for reference types only. Value types don't have identity, per se, so the operation should be meaningless for them.

Re: Weird Python Integers

#145

Earlier quoted context omitted.

That's pretty much saying "it is the way it is", which a) is not even true, see floating point numbers and b) will be obsolete with value types. Needless to say, there is pointless confusion created by Java's design, and there are better approaches available. All you have to do is to adapt the semantic model from reference equality vs. value equality to identity vs. equality. Identity checks whether the "bits" are id…

Better yet, allow identity checks for reference types only. Value types don't have identity, per se, so the operation should be meaningless for them.

I don't think you can get away with that for theoretical and practical reasons:

1.

There is a ton of code out there which does something like

    def contains(that: Thing): Boolean =
      this.value identity that || this.value equality that
Pretty much every single collection implementation would be broken if this stopped working with value types. Additionally, you would run into issues with floating point numbers which would not be found/retrieved anymore if identity were removed.

2.

The idea to define a _sane_ definition of identity/equality across all types is there to avoid the "next-best" option: boxing primitives to wrapper classes which is both slow and has terrible semantics.

3.

I don't really think restricting identity to e.g. reference types makes sense given that equality is defined for every type. Either none of them should be available by default, or both should be.

There _are_ multiple valid ways to compare to things (consider floating point numbers for a second) and making one more privileged than the other feels wrong.

Re: Weird Python Integers

#146
post #59

Earlier quoted context omitted.

That's only the case if you specifically treat them as full-blown objects. If you treat them as primitives they stay as primitives. Note that the type of these local variables is `Integer` rather than `int`.

Although you are technically correct (the best kind of correct), it is still a shortcoming of objects (or maybe just their implementation in Java). It is just a bad idea to implement the '==' operator using comparison on addresses instead of on values and I consider languages pretty low-level that do that. In a sane language == is always a function adhering the attributes of an equivalence relation (reflexivity, symm…

I don't think that it was a specific design decision to make '==' be a pointer comparison instead of value comparison. It's simply a consequence of the much more general design decision that operators cannot be overloaded.

`a==b` is always an analog for the C code `a==b`, not `* a==*b` and certainly not C++'s `operator==(a, b)`

Re: Weird Python Integers

#147

Earlier quoted context omitted.

Better yet, allow identity checks for reference types only. Value types don't have identity, per se, so the operation should be meaningless for them.

I don't think you can get away with that for theoretical and practical reasons: 1. There is a ton of code out there which does something like def contains(that: Thing): Boolean = this.value identity that || this.value equality that Pretty much every single collection implementation would be broken if this stopped working with value types. Additionally, you would run into issues with floating point numbers which would…

> Pretty much every single collection implementation would be broken if this stopped working with value types.

Maybe collections of values should be different from collections of references. The sensible use cases for the two are quite different.

> Additionally, you would run into issues with floating point numbers which would not be found/retrieved anymore if identity were removed.

Meh, just allow NaN to compare equal to itself. Equality is supposed to be reflexive.

> The idea to define a _sane_ definition of identity/equality across all types is there to avoid the "next-best" option: boxing primitives to wrapper classes which is both slow and has terrible semantics.

Unboxed primitives don't have identity, only value equality. They align well with what's being proposed.

> I don't really think restricting identity to e.g. reference types makes sense given that equality is defined for every type. Either none of them should be available by default, or both should be.

We could build the distinction into the language, so for every type you define you explicitly choose whether it's value or reference. Scala's already halfway there with the class/case class distinction.

> There _are_ multiple valid ways to compare to things (consider floating point numbers for a second)

Disagree; comparison is so fundamental to most types that it's worth privileging. Using the wrong kind of comparison is a very common source of bugs.

Re: Weird Python Integers

#148
post #147

Earlier quoted context omitted.

I don't think you can get away with that for theoretical and practical reasons: 1. There is a ton of code out there which does something like def contains(that: Thing): Boolean = this.value identity that || this.value equality that Pretty much every single collection implementation would be broken if this stopped working with value types. Additionally, you would run into issues with floating point numbers which would…

> Pretty much every single collection implementation would be broken if this stopped working with value types. Maybe collections of values should be different from collections of references. The sensible use cases for the two are quite different. > Additionally, you would run into issues with floating point numbers which would not be found/retrieved anymore if identity were removed. Meh, just allow NaN to compare equ…

> Maybe collections of values should be different from collections of references. The sensible use cases for the two are quite different.

I think all existing code disagrees with that. There has been great value derived from being able to abstract over element types.

What you are proposing would double the required number of collection classes and all of its traits, because it would require separate ones for Collection[E There is literally no reason for introducing this complexity. Go has demonstrated how poorly this idea has worked out in practice.

Additionally, this approach would make it nearly impossible to migrate reference types to value types, because it would break all users of the code.

> Meh, just allow NaN to compare equal to itself. Equality is supposed to be reflexive.

That's a complete non-option. You might not like the IEEEs definition of equality, but this is what it is. Messing with it would break all existing code using floating point numbers.

> Unboxed primitives don't have identity, only value equality.

Their identity is the bits they consist of, just like identity on references is the bits of the reference.

> They align well with what's being proposed.

What is being proposed?

> We could build the distinction into the language, so for every type you define you explicitly choose whether it's value or reference.

We already have that: AnyRef and AnyVal.

> Scala's already halfway there with the class/case class distinction.

That doesn't make any sense. The case keyword is basically just a compiler built-in macro to generate some code. It is already doing way to much, and overloading it with even more semantics is not the way to go.

> Disagree; comparison is so fundamental to most types that it's worth privileging. Using the wrong kind of comparison is a very common source of bugs.

What I'm proposing improves the consistency across value and reference types so that it's always obvious which kind of comparison happens:

- identity: Low-level comparison of the bits at hand. Built into the JVM and not overridable.

- equality: High-level comparison defined by the author of the type.

Re: Weird Python Integers

#149
post #147

Earlier quoted context omitted.

> Pretty much every single collection implementation would be broken if this stopped working with value types. Maybe collections of values should be different from collections of references. The sensible use cases for the two are quite different. > Additionally, you would run into issues with floating point numbers which would not be found/retrieved anymore if identity were removed. Meh, just allow NaN to compare equ…

> Maybe collections of values should be different from collections of references. The sensible use cases for the two are quite different. I think all existing code disagrees with that. There has been great value derived from being able to abstract over element types. What you are proposing would double the required number of collection classes and all of its traits, because it would require separate ones for Collecti…

> What you are proposing would double the required number of collection classes and all of its traits, because it would require separate ones for Collection[E Less than double, because not all collections make sense for both - e.g. a sorted set or sorted map only makes sense if the keys are values.

> There is literally no reason for introducing this complexity. Go has demonstrated how poorly this idea has worked out in practice.

It eliminates a common class of errors. All type-level distinctions add a bit of complexity, but we often consider them worthwhile to make.

> Additionally, this approach would make it nearly impossible to migrate reference types to value types, because it would break all users of the code.

Changing from one to the other is a radical change that should force the user to reexamine code that deals with them.

> That's a complete non-option. You might not like the IEEEs definition of equality, but this is what it is. Messing with it would break all existing code using floating point numbers.

Java already deviated from the IEEE definition with Float and Double. The sky didn't fall. Maybe strict IEEE semantics could be offered in their own type where needed, and that type would neither be value or identity-is-meaningful. (This would mean the type system wouldn't allow you to use the strict-IEEE type in any standard collection, which I think is correct behaviour; compare e.g. Haskell where for a long time you could corrupt the standard sorted set structure by inserting two NaNs).

> Their identity is the bits they consist of, just like identity on references is the bits of the reference.

That's a low-level implementation detail that may not even be true on all platforms. The language semantics should make sense.

> We already have that: AnyRef and AnyVal.

No, those are just implementation details of how they're passed around. Many AnyRef types have value semantics.

> That doesn't make any sense. The case keyword is basically just a compiler built-in macro to generate some code. It is already doing way to much, and overloading it with even more semantics is not the way to go.

Well, what I'd like in an ideal language is: no universal equality, opt-in value equality with derivation for product/coproduct types. As for references... I'm not really convinced there's a legitimate use case for comparing references, especially the implicit invisible references that the language uses to implement user classes. If we need reference comparison at all I'd rather something a bit more explicit - either an opt-in "the identity of this class is meaningful", or a notion of explicit references that were much more visible in the code (something a bit like ActorRef), or both.

> What I'm proposing improves the consistency across value and reference types so that it's always obvious which kind of comparison happens: > - identity: Low-level comparison of the bits at hand. Built into the JVM and not overridable. > - equality: High-level comparison defined by the author of the type.

That's very inconsistent at the language-semantics level; which things are "the bits at hand" are a low-level implementation detail that should probably be left up to the runtime to represent as best suits a particular code path. At the language level, "does 2L + 2L equal 4L?" is the same kind of question as "does "a" + "b" equal "ab"?", and both those questions are quite different from any question to which reference comparison would be the answer.

Re: Weird Python Integers

#150
post #149

Earlier quoted context omitted.

> Maybe collections of values should be different from collections of references. The sensible use cases for the two are quite different. I think all existing code disagrees with that. There has been great value derived from being able to abstract over element types. What you are proposing would double the required number of collection classes and all of its traits, because it would require separate ones for Collecti…

> What you are proposing would double the required number of collection classes and all of its traits, because it would require separate ones for Collection[E Less than double, because not all collections make sense for both - e.g. a sorted set or sorted map only makes sense if the keys are values. > There is literally no reason for introducing this complexity. Go has demonstrated how poorly this idea has worked out…

This hardly makes any sense, is not practical to implement and theoretically questionable.

It makes decisions that break existing code and introduce pointless complexity, while failing to offer any tangible benefits in return.

Post reply on HN