# \`objectid\` and reproducibility

**URL:** <https://discourse.julialang.org/t/objectid-and-reproducibility/126119>\
**Category:** General Usage\
**Created:** [February 20, 2025, 3:48pm UTC](https://discourse.julialang.org/t/objectid-and-reproducibility/126119 "2025-02-20T15:48:13Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![mhinsch](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mhinsch/32/26676_2.png) [@mhinsch](https://discourse.julialang.org/u/mhinsch)\
**Post date:** [February 20, 2025, 3:48pm UTC](https://discourse.julialang.org/t/objectid-and-reproducibility/126119/1 "2025-02-20T15:48:13Z")

</div>

I just spent half a day debugging very weird non-deterministic behaviour in my simulation. The culprit as it turns out was one little piece of code where I used sorting an array of objects by `objectid` as a way to make getting rid of duplicates more efficient. Apparently objectid is not derministic, though, so the order of objects varied between simulation runs leading to (numerically) different results even with the same random seed.

It’s not difficult to avoid the issue, once you know that it exists, but finding it was a bit of a hassle…

ETA: [issue](https://github.com/JuliaLang/julia/issues/57477)

---

<div class="post-metadata">

**Author:** ![matthias314](https://avatars.discourse-cdn.com/v4/letter/m/a88e4f/32.png) [@matthias314](https://discourse.julialang.org/u/matthias314)\
**Post date:** [February 20, 2025, 10:48pm UTC](https://discourse.julialang.org/t/objectid-and-reproducibility/126119/2 "2025-02-20T22:48:23Z")

</div>

I’ve run into a related issue: If you define `hash` for some new type `T` and that hash involves `objectid(T)`, then dictionaries with key type `T` are displayed non-deterministically. If such a dictionary shows up in Julia output inside some docstring, then Documenter.jl will complain all the time that the docstring is not accurate anymore.

---

<div class="post-metadata">

**Author:** ![cstjean](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cstjean/32/1444_2.png) [@cstjean](https://discourse.julialang.org/u/cstjean)\
**Post date:** [February 21, 2025, 4:26am UTC](https://discourse.julialang.org/t/objectid-and-reproducibility/126119/3 "2025-02-21T04:26:02Z")

</div>

Python switched its dicts to ordered dicts by default, and solving those non-determinacy problems is a major benefit. I use `OrderedDict` by default nowadays (from OrderedCollections.jl), unless I have a very good reason not to.

---

<div class="post-metadata">

**Author:** ![danielwe](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/danielwe/32/35657_2.png) [@danielwe](https://discourse.julialang.org/u/danielwe)\
**Post date:** [February 21, 2025, 5:35am UTC](https://discourse.julialang.org/t/objectid-and-reproducibility/126119/4 "2025-02-21T05:35:28Z")

</div>

> [@mhinsch](#):
>
> a way to make getting rid of duplicates more efficient

I’d try `Base.IdSet` for this. It lacks a convenient constructor, but you can do

```julia
set = union!(Base.IdSet(), arr)

```

Sets have undefined order, so for reproducibility you probably want something like

```julia
ordered_and_unique = sort!(collect(set); by=<something>)

```

* * *

Caveat: `Base.IdSet` isn’t documented. I don’t know why; it’s built on `IdDict` the same way `Set` is built on `Dict`, and `IdDict` is well-documented and exported.

---

<div class="post-metadata">

**Author:** ![Zentrik](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/zentrik/32/35409_2.png) [@Zentrik](https://discourse.julialang.org/u/Zentrik)\
**Post date:** [February 21, 2025, 8:02am UTC](https://discourse.julialang.org/t/objectid-and-reproducibility/126119/5 "2025-02-21T08:02:20Z")

</div>

Fwiw `IdSet` uses `objectid` as it’s hashing function.

---

<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:** [February 21, 2025, 10:51am UTC](https://discourse.julialang.org/t/objectid-and-reproducibility/126119/6 "2025-02-21T10:51:57Z")

</div>

As people pointed out, `objectid` is simply the (slightly mangled) address for addressable objects (i.e. for objects where `pointer_from_objref` is doesn’t throw).

This fact looks unlikely to go away soon. The current implementation implicitly guarantees the following very nice property:

> If you have two addressable objects that are not identical / egal, then their `objectid`s will be different.

This subtle undocumented fact is internally relied on. For example, the current implementation of ScopedValues uses a persistent dict / HAMT that just doesn’t handle hash-collisions. This is fine, because hash-collisions are fundamentally impossible as long as you remember never to feed in non-addressable objects (objectids can be re-used after the old object dies; that’s the responsibility of allocator/GC)!

So, I guess you should consider asking this question to your operating system / libc, because the exact addresses of virtual memory handed out there is probably the ultimate source of your non-reproducibility.

(yes, this is another complication in moving GC)

> [@cstjean](#):
>
> Python switched its dicts to ordered dicts by default, and solving those non-determinacy problems is a major benefit. I use `OrderedDict` by default nowadays (from [OrderedCollections.jl](https://juliaregistries.github.io/General/packages/redirect_to_repo/OrderedCollections)), unless I have a very good reason not to.

I very much second this recommendation. Introducing very-hard-to-reproduce unintentional randomization into a software project sucks _so_ hard!

At work we had one incident where somebody computed a checksum over some data by processing entries in the order they fell out of a java HashMap iterator, to be used for some caching. Later that was upgraded to a sha checksum, and another team thought “these don’t collide, let’s use that as a key/identity for our database”.

That bug laid dormant for years until it exploded into our face, and left us with years of subtly broken/inconsistent history that was impossible to clean up 😱. Upshot was a soft policy of “unordered collections are just as suspect as sun.misc.Unsafe – don’t do it without at least a paragraph of justifying source-code comment”.

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [February 21, 2025, 11:12am UTC](https://discourse.julialang.org/t/objectid-and-reproducibility/126119/7 "2025-02-21T11:12:49Z")

</div>

> [@matthias314](#):
>
> If such a dictionary shows up in Julia output inside some docstring, then [Documenter.jl](https://juliaregistries.github.io/General/packages/redirect_to_repo/Documenter) will complain all the time that the docstring is not accurate anymore.

That’s simply a doc test bug (your bug). Use `[...]` in the doc string where the dictionary is shown: [Writing Documentation](https://docs.julialang.org/en/v1/manual/documentation/#Writing-Documentation).

> [@cstjean](#):
>
> Python switched its dicts to ordered dicts by default, and solving those non-determinacy problems is a major benefit.

Another solution, adopted by the Go language, is to randomize the iteration order every time.

---

<div class="post-metadata">

**Author:** ![matthias314](https://avatars.discourse-cdn.com/v4/letter/m/a88e4f/32.png) [@matthias314](https://discourse.julialang.org/u/matthias314)\
**Post date:** [February 21, 2025, 1:23pm UTC](https://discourse.julialang.org/t/objectid-and-reproducibility/126119/8 "2025-02-21T13:23:06Z")

</div>

> [@nsajko](#):
>
> Use `[...]` in the doc string where the dictionary is shown

That doesn’t work if I want the output to appear in the docstring. Think of a function that returns a dictionary. If I want to illustrate what such a function does, then omitting the output doesn’t make sense.

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [February 21, 2025, 1:33pm UTC](https://discourse.julialang.org/t/objectid-and-reproducibility/126119/9 "2025-02-21T13:33:23Z")

</div>

Then use `julia-repl` instead of `jldoctest`, in addition to unit tests.

---

<div class="post-metadata">

**Author:** ![barucden](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/barucden/32/26154_2.png) [@barucden](https://discourse.julialang.org/u/barucden)\
**Post date:** [February 21, 2025, 1:58pm UTC](https://discourse.julialang.org/t/objectid-and-reproducibility/126119/10 "2025-02-21T13:58:16Z")

</div>

Following on Neven’s suggestion, you could also show the dictionary entries explicitly:

````julia
    """
        f(x)

    Returns a dict.

    # Examples
    ```jldoctest
    julia> d = f(1);

    julia> d["a"], d["b"]
    (1, 2)
    ```
    """
    function f(x)
        return Dict("a"=>x, "b"=>1+x)
    end

````

That way, you don’t (incorrectly) assume any ordering.
