Why is objectid not foldable for type arguments?

For some types, objectid now folds in Julia 1.10-alpha1:

julia> f() = objectid(1); @code_typed f()
1 ─     return 0x5bca7c69b0d0ebca
) => UInt64

However, it doesn’t fold with a type as argument:

julia> f() = objectid(Int); @code_typed f()
1 ─ %1 = Main.Int::Type{Int64}
│   %2 = $(Expr(:foreigncall, :(:jl_object_id), UInt64, svec(Any), 0, :(:ccall), :(%1)))::UInt64
└──      return %2
) => UInt64

(The reason is that the folding behavior is determined by Base.isidentityfree, which returns false for types.)

I haven’t gone through the code of jl_object_id in detail, but from playing around with objectid I get the impression that it is consistent for types, even across different sessions and different machines. (For Int I always get 0x0000000007441304, for instance.) Is this impression wrong, or is there any other reason that objectid should not fold for types?

this is a very annoying one in that all well formed types have consistent objectids, but it is possible to make horrible abstract types that are not instantiable that don’t have consistent object ids


Are there some easily identifiable types for which one could make objectid fold? Your answer sounds as if at least concrete types would qualify.

I came across this in the context of writing (my own macro for generating) hash functions. For a type

struct A{T}

one could use any one of

hash(a::A, h::UInt) = hash(a.x, h)
hash(a::A, h::UInt) = hash(a.x, hash(A, h))
hash(a::A{T}, h::UInt) where T = hash(a.x, hash(A{T}, h))

depending on how much of the type information one wants to see in the hash. Now hash of a type is computed via objectid. In the cases above where the type does enter the hash, one either has a concrete type or a very specific UnionAll type. From a performance point of view, it would be great if objectid could fold in these cases.

Yeah we probably need to make this smarter It’s just one that’s mildly annoying and no one has bothered to fix it yet.