# Array hashing is complicated

**URL:** <https://discourse.julialang.org/t/array-hashing-is-complicated/8567>\
**Category:** Internals & Design\
**Created:** [January 24, 2018, 11:09am UTC](https://discourse.julialang.org/t/array-hashing-is-complicated/8567 "2018-01-24T11:09:52Z")\
**Posts on this page:** 20\
**Page:** 2

<div class="post-metadata">

**Author:** ![foobar\_lv2](https://avatars.discourse-cdn.com/v4/letter/f/ee59a6/32.png) [@foobar\_lv2](https://discourse.julialang.org/u/foobar_lv2)\
**Post date:** [January 24, 2018, 11:59pm UTC](https://discourse.julialang.org/t/array-hashing-is-complicated/8567/21 "2018-01-24T23:59:43Z")

</div>

> [@StefanKarpinski](#):
>
> It applies to Julia only in as much as it applies to any language with user-extensible equality and it does not apply to ===

…if equality always checked types first, then it would not apply (but people could still break symmetry, transitivity or reflexivity for their types).

> [@StefanKarpinski](#):
>
> Comparing equality in Julia to equality in PHP or Javascript is uncharitable and way off the mark – few languages have put as much thought into equality as we have.

I agree; it is uncharitable and the situation in julia is somewhat better, due to the awesomeness of multiple dispatch and the thought that has been put into it (and at least none of the type-wrong equalities are as nonsensical as string to number).

Type-unsafe equality is scary and the road to hell (also I’m not sure how much inference loses due to branches like `if x==1` not giving type information about `x`. Of course you can argue that it should be `if x===1`, but at least base tends to use `==` in cases where `===` would also work).

Regardless, I apologize for being too negative. Julia is way, way better than php or javascript, I am thankful that the core devs like you, jeff, keno, yuichao, etc, comment and explain here, and am even more thankful for you developing julia.

---

<div class="post-metadata">

**Author:** ![ScottPJones](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/scottpjones/32/146_2.png) [@ScottPJones](https://discourse.julialang.org/u/ScottPJones)\
**Post date:** [January 25, 2018, 12:55am UTC](https://discourse.julialang.org/t/array-hashing-is-complicated/8567/22 "2018-01-25T00:55:56Z")

</div>

> [@foobar\_lv2](#):
>
> and at least none of the type-wrong equalities are as nonsensical as string to number

That really is not nonsensical, it just depends on the architecture of the language.  
In a language where semantically everything is a string, it makes perfect since for “0” == 0, or  
1E5 == “100000”. (That’s the way the most used language for healthcare systems, at least in the US, which was the 3rd ANSI standard language, does things).

---

<div class="post-metadata">

**Author:** ![StefanKarpinski](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stefankarpinski/32/24_2.png) [@StefanKarpinski](https://discourse.julialang.org/u/StefanKarpinski)\
**Post date:** [January 25, 2018, 1:06am UTC](https://discourse.julialang.org/t/array-hashing-is-complicated/8567/23 "2018-01-25T01:06:19Z")

</div>

> [@foobar\_lv2](#):
>
> …if equality always checked types first, then it would not apply

The problem with an object being equal to 1, 2 and 3 at the same time is that it’s a violation of transitivity, not that objects shouldn’t be equal to integers. Saying that `==` should check types doesn’t solve this in any meaningful way since a user can define `==` to violate that recommendation just as easily as they can violate the current rule that equality should be pure and transitive. If people follow the rule then `a == 1 && a == 2` cannot happen.

We _tried_ having `==` and `isequal` check types first and it had serious problems – it does not work well in a dynamic languages like Julia. The history: [in 0.2 we made values of different types unequal](https://github.com/JuliaLang/julia/blob/release-0.2/NEWS.md#library-improvements) and then [in 0.3 we went back to making equal values of different types equal](https://github.com/JuliaLang/julia/blob/release-0.3/NEWS.md#library-improvements-1) with a much more disciplined approach.

It may not immediately obvious why having `1 != 1.0` is a problem in Julia, but it interacts really badly with other features of the language. One issue is the interaction with auto-conversion of values upon assignment to typed locations. For example, you can do something like this:

```julia
julia> d = Dict{Float64,Bool}()
Dict{Float64,Bool} with 0 entries

julia> d[1] = true
true

julia> d
Dict{Float64,Bool} with 1 entry:
  1.0 => true

```

The integer 1 is automatically converted to `1.0` because the key type of the dict is `Float64`. But now consider what would happen if you had `isequal(1, 1.0) == false` . Immediately after doing that assignment, you’d get a key error upon doing `d[1]` – even though that’s the exact the key you just put into the dictionary. This is because you can’t find `1.0` in a dict with a value that’s not `isequal` to it. Now consider a potentially more loosely type dictionary:

```julia
d[1] = true
d[1.0] = true

```

How many entries does the dictionary have now? Depends on its key type! If it’s `Float64` or `Int` then you only have one; if it’s `Real` or `Any` then you have two. Fun.

There are other potential ways to solve these problems than making `1 == 1.0`. We could get rid of conversion on assignment to typed locations, for example. Then you would simply get an error when doing `d[1] = true` for a dict with `Float64` key type. But that starts to make the language feel very strict and fussy. Instead, the design we have makes this work in a coherent way and does – basically universally – what people feel like it should. A _lot_ of thought and work has gone into making it that way.

> Type-unsafe equality is scary and the road to hell

Calling what we do now “type-unsafe equality” is scaremongering and also just incorrect terminology – type safety is a real thing and has nothing to do with this. Our equality has worked this way since Julia 0.3 and it doesn’t have any obvious issues. What _actual_ problems have you found with it?

---

<div class="post-metadata">

**Author:** ![StefanKarpinski](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stefankarpinski/32/24_2.png) [@StefanKarpinski](https://discourse.julialang.org/u/StefanKarpinski)\
**Post date:** [January 25, 2018, 1:08am UTC](https://discourse.julialang.org/t/array-hashing-is-complicated/8567/24 "2018-01-25T01:08:39Z")

</div>

> [@ScottPJones](#):
>
> it makes perfect since for “0” == 0, or 1E5 == “100000”

If `"00" == 0` then this causes a fairly major transitivity problem since presumably you do not want to have `"0" == "00"`.

---

<div class="post-metadata">

**Author:** ![ScottPJones](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/scottpjones/32/146_2.png) [@ScottPJones](https://discourse.julialang.org/u/ScottPJones)\
**Post date:** [January 25, 2018, 1:26am UTC](https://discourse.julialang.org/t/array-hashing-is-complicated/8567/25 "2018-01-25T01:26:45Z")

</div>

No, `"00"` is not a “canonic numeric” string, and hence is not equivalent.  
Applying a numeric operator, or the unary `+`, will convert a non-canonic string to a canonic number  
(and internally, there are numeric types, but they are just an optimization).  
All arithmetic is done as decimal floating point, so that there are no conversion issues between numeric strings and internal numeric type values.

---

<div class="post-metadata">

**Author:** ![ScottPJones](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/scottpjones/32/146_2.png) [@ScottPJones](https://discourse.julialang.org/u/ScottPJones)\
**Post date:** [January 25, 2018, 1:37am UTC](https://discourse.julialang.org/t/array-hashing-is-complicated/8567/26 "2018-01-25T01:37:23Z")

</div>

> [@StefanKarpinski](#):
>
> What actual problems have you found with it?

We ran into a problem with `Dict{Any,Any}`, where Bool keys ended up as `0` and `1` instead of staying as separate entries as `false` and `true`. (We were trying to keep track of the values found in a JSON file, with `null`, `true`, `false`, being considered distinct from numbers and strings).

If `Bool` weren’t `<: Number`, then it wouldn’t have been a problem.

---

<div class="post-metadata">

**Author:** ![StefanKarpinski](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stefankarpinski/32/24_2.png) [@StefanKarpinski](https://discourse.julialang.org/u/StefanKarpinski)\
**Post date:** [January 25, 2018, 3:13am UTC](https://discourse.julialang.org/t/array-hashing-is-complicated/8567/27 "2018-01-25T03:13:21Z")

</div>

The problem there is that `Bool <: Number` which we discussed changing but decided it was a bit too disruptive this late in the game. For that sort of application you should probably be using an `IdDict` instead.

---

<div class="post-metadata">

**Author:** ![mauro3](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mauro3/32/292_2.png) [@mauro3](https://discourse.julialang.org/u/mauro3)\
**Post date:** [January 25, 2018, 8:03am UTC](https://discourse.julialang.org/t/array-hashing-is-complicated/8567/28 "2018-01-25T08:03:17Z")

</div>

There is some interesting reading related to equality in this (closed) pull-request: [https://github.com/JuliaLang/julia/pull/18856](https://github.com/JuliaLang/julia/pull/18856).

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [January 25, 2018, 9:13am UTC](https://discourse.julialang.org/t/array-hashing-is-complicated/8567/29 "2018-01-25T09:13:12Z")

</div>

and of course the [timeless classic of Kent M. Pitman](http://www.nhplace.com/kent/PS/EQUAL.html), with the conclusion

> in occasional bug reports that vendors receive, arguing that an incorrect choice has ``clearly’’ been made for how objects of a given type are compared, rather than acknowledging that the choice is really quite arbitrary. When urged to write their own equality predicate to suit their particular needs, they sometimes react as if we are putting them off, rather than realizing that any function they could write is just as valid as any one the language provides. Were the language changed to accommodate such bug reports, different users would probably complain.

I think that the best a language can do is to

1. provide various commonly used notions of equality with a clear conceptual model, so that the programmer can pick what’s best for each case,
2. make the semantics of functions that rely on some concept of equality as extensible as possible.

Ideally, hash tables like `Dict` could be customizable for different concepts of equality and corresponding hashes, and various trade-offs with hashing sophistication and collision, but that is something that could live in a package when someone gets around to implementing it.

---

<div class="post-metadata">

**Author:** ![ScottPJones](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/scottpjones/32/146_2.png) [@ScottPJones](https://discourse.julialang.org/u/ScottPJones)\
**Post date:** [January 25, 2018, 11:49am UTC](https://discourse.julialang.org/t/array-hashing-is-complicated/8567/30 "2018-01-25T11:49:34Z")

</div>

> [@StefanKarpinski](#):
>
> For that sort of application you should probably be using an IdDict instead.

No, not at all, because we need numbers, even of different types, to be compared by their value, same with strings.

> [@StefanKarpinski](#):
>
> The problem there is that Bool \<: Number which we discussed changing but decided it was a bit too disruptive this late in the game.

Would it really be that disruptive, if it weren’t \<: Number, but appropriate conversions and operators with Number types were defined?  
This would be the time to do it, along with all the other disruptive changes.

Edit: To clarify, I am _not_ opposed to the disruptive changes, as painful as they might be at the moment,  
I think that the work done now to improve the consistency and ease of use of the APIs, as well as moving stuff out of what is the “core” language, is the best thing possible for Julia in the long run.

---

<div class="post-metadata">

**Author:** ![foobar\_lv2](https://avatars.discourse-cdn.com/v4/letter/f/ee59a6/32.png) [@foobar\_lv2](https://discourse.julialang.org/u/foobar_lv2)\
**Post date:** [January 25, 2018, 12:00pm UTC](https://discourse.julialang.org/t/array-hashing-is-complicated/8567/31 "2018-01-25T12:00:03Z")

</div>

> [@StefanKarpinski](#):
>
> We tried having == and isequal check types first and it had serious problems – it does not work well in a dynamic languages like Julia.

Thanks for the explanation of the history! Just leaving this here…

```julia
Float32(e)==Float64(Float32(e))
true
Float32(pi)+Float32(e)==Float32(pi) + Float64(Float32(e))
false

```

`Ptr{Int}(1)==Ptr{UInt8}(1)`  
…so pointers need to be checked with === before you deref them. I have a feeling that bugs due to type-wrong equality are much, much harder to spot than bugs due to same-value-for-my-purpose-different-type (if you want to compare addresses, reinterpret).

So some built-in types have a very… relaxed notion of equality. OTOH, default equality apparently means === on user types.

Now, in 07, === sometimes checks for identity (in the intensional sense of machine-representation) and sometimes not:

```julia
BigInt(1)===BigInt(1)
false
"foo"==="foo"
true #false on 0.6
pointer("foo")==pointer("foo")
false

```

This whole DWIM equality/identity makes me very nervous.

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [January 25, 2018, 12:44pm UTC](https://discourse.julialang.org/t/array-hashing-is-complicated/8567/33 "2018-01-25T12:44:34Z")

</div>

> [@foobar\_lv2](#):
>
> ```julia
> Float32(pi)+Float32(e)==Float32(pi) + Float64(Float32(e))
> false
> 
> ```

I am curious what you expected here, since

```julia
julia> (Float32(pi)+Float32(e))-(Float32(pi) + Float64(Float32(e)))
2.384185791015625e-7

```

---

<div class="post-metadata">

**Author:** ![StefanKarpinski](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stefankarpinski/32/24_2.png) [@StefanKarpinski](https://discourse.julialang.org/u/StefanKarpinski)\
**Post date:** [January 25, 2018, 1:38pm UTC](https://discourse.julialang.org/t/array-hashing-is-complicated/8567/34 "2018-01-25T13:38:43Z")

</div>

> [@Tamas\_Papp](#):
>
> I am curious what you expected here, since
> 
> ```julia
> julia> (Float32(pi)+Float32(e))-(Float32(pi) + Float64(Float32(e)))
> 2.384185791015625e-7
> 
> ```

Indeed, if anything, given the context of the thread, this shows that Julia is very careful to make sure that `==` is an equivalence relation. If this comparison was done by converting to `Float32` then it would violate transitivity. Here’s another fun one:

```julia
julia> 2^53+1 == 2.0^53
false

julia> Float64(2^53+1) == 2.0^53
true

```

Why doesn’t `==` just convert to `Float64` and then compare? Do you see the problem? Other fun tricks:

```julia
julia> 1/10
0.1

julia> 1/10 == 1//10
false

```

What?! One tenth is not representable exactly as a `Float64`, so `1/10` – i.e. the closest `Float64` to one tenth – cannot be exactly equal to `1//10` which represents one tenth exactly. Sure, we get the occasional bug report about this, but if we didn’t do this, then we’d rapidly get PHP/JavaScript-esque violations of basic properties that `==` should obey (namely transitivity). There is a coherent philosophy here, and it is very strictly obeyed.

> [@foobar\_lv2](#):
>
> ```julia
> Ptr{Int}(1)==Ptr{UInt8}(1)
> 
> ```
> 
> …so pointers need to be checked with === before you deref them. I have a feeling that bugs due to type-wrong equality are much, much harder to spot than bugs due to same-value-for-my-purpose-different-type (if you want to compare addresses, reinterpret).

This is a judgement, but we treat the type of a pointer as an essential part of its identity unlike numbers which represents some mathematical value which is independent of their type or representation. The number 1 is the same no matter whether it’s represented as an `Int` or a `Float64` or a `Complex{UInt8}`. We do not, however, treat `1` with a unit the same as `1`:

```julia
julia> using Unitful: m

julia> 1 == 1m
false

julia> 1m == 1m^2
false

```

Pointers are a bit like united quantities – a pointer to an `Int64` is different than a pointer to a `Float64` even if they point at the same location. You get different things if you load from those pointers, for example.

> So some built-in types have a very… relaxed notion of equality. OTOH, default equality apparently means `===` on user types.

There is a quite old [open 1.0 issue](https://github.com/JuliaLang/julia/issues/4648) to change the default `==` fallbcack. I am in favor of changing it to something a bit more intuitive and commonly wanted. The current choice of `===` is basically the most conservative choice possible since it will never consider two things equal unless they are programmatically indistinguishable. Unfortunately, this is often stricter than what one wants.

> [@](#):
>
> Now, in 07, `===` sometimes checks for identity (in the intensional sense of machine-representation) and sometimes not:
> 
> ```julia
> BigInt(1)===BigInt(1)
> false
> "foo"==="foo"
> true #false on 0.6
> pointer("foo")==pointer("foo")
> false
> 
> ```
> 
> This whole DWIM equality/identity makes me very nervous.

There’s not really any wiggle room for `===`: it implements Henry Baker’s “egal” predicate, which is very well-defined. The predicate is true if two values are programmatically indistinguishable from within a language. Changing `String` `===` went hand in hand with changing its representation so that you can no longer programmatically distinguish two different `String` objects _except_ by doing unsafe operations like taking pointers and writing through them. A `pointer(str)` call will always give you a pointer to _some_ memory that holds bytes equal to the string you passed it, but it’s not guaranteed to give you a pointer to the exact memory of the string you passed it. In other words, the impurity here belongs to the `pointer` function, not the `String` type.

Two different `BigInt` values representing the same value are programmatically distinguishable because this is the representation of a `BigInt`:

```julia
julia> dump(big(1))
BigInt
  alloc: Int32 1
  size: Int32 1
  d: Ptr{UInt64} Ptr{UInt64} @0x00007fd3d56caff0

julia> dump(big(1))
BigInt
  alloc: Int32 1
  size: Int32 1
  d: Ptr{UInt64} Ptr{UInt64} @0x00007fd3d7b28b80

```

These two instances of `big(1)` have different pointers, therefore they are not `===`. They are, of course `==` because they represent the same value. In a future version of Julia, we might integrate `BigInts` more deeply into the language and garbage collection and make `big(1)` an immutable value without any exposed pointers (and use a hybrid immediate representation for small integers), but we don’t do that yet and `===` does not lie.

So far all of these examples have been good ones, but imo, they actually show that there is a well-considered and thorough policy for equality in Julia, rather than the opposite. The `===` operator is not user-extensible because it has a well-defined meaning which should cannot be changed by the user: it checks programmatic indistinguishability. The `==` operator implements value comparison independent of representation. If you want to know if `x == y` should be true, consider if they represent the same abstract value or not. There is some interpretation involved for user-defined types, but if you’re implementing a number type, for example, it’s pretty clear. If you have some other kind of type, you will have to decide what it represents and think carefully on what an equivalence relation on that abstraction should look like.

---

<div class="post-metadata">

**Author:** ![ScottPJones](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/scottpjones/32/146_2.png) [@ScottPJones](https://discourse.julialang.org/u/ScottPJones)\
**Post date:** [January 25, 2018, 2:01pm UTC](https://discourse.julialang.org/t/array-hashing-is-complicated/8567/35 "2018-01-25T14:01:18Z")

</div>

The only place I’ve found that I don’t think works well, and seems to go against not allowing things like:  
`5 ? 1 : 0`, is that `1 == true` and `0 == false` both return true (really same issue as the dict issue with Bool vs. numbers)

Edit: to clarify, I _do_ think (with this one exception) that Julia’s concepts of `==` vs. `===` are rather well thought out, more so than I’ve seen in most other places (well, MUMPS was also well thought out, equality was always based the string representation, no matter any internal optimizations for numbers)

---

<div class="post-metadata">

**Author:** ![foobar\_lv2](https://avatars.discourse-cdn.com/v4/letter/f/ee59a6/32.png) [@foobar\_lv2](https://discourse.julialang.org/u/foobar_lv2)\
**Post date:** [January 25, 2018, 2:08pm UTC](https://discourse.julialang.org/t/array-hashing-is-complicated/8567/36 "2018-01-25T14:08:39Z")

</div>

> [@Tamas\_Papp](#):
>
> I am curious what you expected here, since…

```julia
Float32(pi)+Float32(e)==Float32(pi) + Float64(Float32(e))
false

```

is correct. Automatic promotion on addition is expected. Automatic promotion on comparison is a nightmare, and I am happy that julia does not do this.

Naively one would expect `isequal(a,b)` to imply `isequal(a+x, b+x)`. This does not hold, because `typeof(a) != typeof(b)`, and hence we get different dispatches / promotions for `+(a,x)` and `+(b,x)`. DWIM equality is nice for productivity in throw-away code (just compare type-vomited objects); it is dangerous with respect to weird bugs (the above extends to all numeric types like int, uint of various types, and all vectors holding such types) and makes the language “specification” extremely complex, i.e. makes actual behavior hard to predict.

I apologize for bringing up a topic that surely was discussed to death at the time. This shows how inexperienced I am in julia (I wrongly used isequal in all my code, even though I wanted typed isequal; typical mistake like people using `==` when they should use `===` in e.g. javascript or php.) Base is not very helpful here (as a source of example code to emulate), because it mostly uses `==` as default, and one needs to look at the `code_typed` in order to see whether this is a bug.

> [@StefanKarpinski](#):
>
> Pointers are a bit like united quantities – a pointer to an Int64 is different than a pointer to a Float64 even if they point at the same location.

I get the following:

```julia
Ptr{Int}(1)==Ptr{Float32}(1)
true

```

I agree that pointers should carry their type! I was complaining that they do not!

> [@StefanKarpinski](#):
>
> A pointer(str) call will always give you a pointer to some memory that holds bytes equal to the string you passed it, but it’s not guaranteed to give you a pointer to the exact memory of the string you passed it.

So passing strings-pointers to mutating C libraries is not allowed?

> [@StefanKarpinski](#):
>
> So far all of these examples have been good ones, but imo, they actually show that there is a well-considered and through policy for equality in Julia, rather than the opposite.

I agree; the DWIM-equality policy is well-considered and looks surprisingly good (few weird corners I’ve seen so far) and the fact that you managed fast DWIM-hashing is impressive. I think I am not whining about the way equality works (except for pointer types) but rather about the general decision that two objects of different types can be equal at all.

---

<div class="post-metadata">

**Author:** ![ScottPJones](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/scottpjones/32/146_2.png) [@ScottPJones](https://discourse.julialang.org/u/ScottPJones)\
**Post date:** [January 25, 2018, 2:16pm UTC](https://discourse.julialang.org/t/array-hashing-is-complicated/8567/37 "2018-01-25T14:16:33Z")

</div>

> [@foobar\_lv2](#):
>
> So passing strings-pointers to mutating C libraries is not allowed?

Strings in Julia are immutable. You could do it, but it’s not at all supported, and probably would break something.

---

<div class="post-metadata">

**Author:** ![StefanKarpinski](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stefankarpinski/32/24_2.png) [@StefanKarpinski](https://discourse.julialang.org/u/StefanKarpinski)\
**Post date:** [January 25, 2018, 4:00pm UTC](https://discourse.julialang.org/t/array-hashing-is-complicated/8567/38 "2018-01-25T16:00:09Z")

</div>

> [@foobar\_lv2](#):
>
> I agree that pointers should carry their type! I was complaining that they do not!

I thought they were, perhaps we should change that. Then again, I’m not sure how important this really is. We don’t exactly encourage programming with pointers in Julia.

> So passing strings-pointers to mutating C libraries is not allowed?

All things are mutable in computers. If you sneak around behind the language’s back to mutate things that are supposed to be immutable, you’re on your own.

> the DWIM-equality policy is well-considered and looks surprisingly good

Calling it “DWIM” seems to suggest that it has some kind of arbitrary “do what I mean” behavior. It does not: it is abstract-value-based equality, which is not DWIM at all (as shown by many of the surprising corner cases). The only judgement call is what “abstract value” something represents, but as long as you’re consistent about that, `==` will always be an equivalence relation since identity of abstract values is an equivalence relation.

> the fact that you managed fast DWIM-hashing is impressive

Yes, that was quite tricky.

---

<div class="post-metadata">

**Author:** ![Keno](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/keno/32/285_2.png) [@Keno](https://discourse.julialang.org/u/Keno)\
**Post date:** [January 25, 2018, 10:44pm UTC](https://discourse.julialang.org/t/array-hashing-is-complicated/8567/39 "2018-01-25T22:44:47Z")

</div>

> [@StefanKarpinski](#):
>
> I thought they were, perhaps we should change that. Then again, I’m not sure how important this really is. We don’t exactly encourage programming with pointers in Julia.

The type on pointers is more of a suggestion to the `unsafe_load/store` functions than objective reality. In particular arithmetic is intentionally always bytewise and deliberately excluded from TBAA, so arbitrary pointer type-casting is legal (and happens implicitly via convert). It would be bit odd for the implicit conversion to be allowed, but for them to not be considered equal. Pointers are basically in the language to interface with native code.

If you want stronger notions of pointer, that’s fine, but `Ptr` is not it.

---

<div class="post-metadata">

**Author:** ![jeff.bezanson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeff.bezanson/32/48_2.png) [@jeff.bezanson](https://discourse.julialang.org/u/jeff.bezanson)\
**Post date:** [January 26, 2018, 2:20am UTC](https://discourse.julialang.org/t/array-hashing-is-complicated/8567/40 "2018-01-26T02:20:43Z")

</div>

You want to avoid involving object addresses in equality as much as possible, because it exposes implementation details. It means implementing an optimization (e.g. storing all strings equal to `"foo"` at the same address) or an unintentional change can break people’s programs. See for example the `eq` function in common lisp and python (v2?) which is totally unreliable for certain arguments because of this.

---

<div class="post-metadata">

**Author:** ![jameson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jameson/32/23_2.png) [@jameson](https://discourse.julialang.org/u/jameson)\
**Post date:** [January 26, 2018, 2:22am UTC](https://discourse.julialang.org/t/array-hashing-is-complicated/8567/41 "2018-01-26T02:22:49Z")

</div>

> [@Keno](#):
>
> It would be bit odd for the implicit conversion to be allowed,

I don’t think we should allow pointer-conversions as freely as we do, it has just never managed to be high on my priority list. But it’s just weird to be more permissive than C.

> [@foobar\_lv2](#):
>
> I’m not sure how much inference loses due to branches like if x==1 not giving type information about x

Basically nothing. Having `x == 1` mean `x::Int == 1` adds vanishingly little information in a non-Hindley–Milner type-system.

> [@ScottPJones](#):
>
> well, MUMPS was also well thought out, equality was always based the string representation, no matter any internal optimizations for numbers

Sounds somewhat logical on the surface, but wouldn’t that be terribly slow, and susceptible to changes in the string representation of an object (e.g., if I decide to change the printing of `1.0` to `1` or `1.0e0`)? It feels like that definition is recursive when you want to go actually implement it.

[Previous page](https://discourse.julialang.org/t/array-hashing-is-complicated/8567.md?page=1)

[Next page](https://discourse.julialang.org/t/array-hashing-is-complicated/8567.md?page=3)
