AnyObject on Linux may give different result for ObjectIdentifier.init()

Can you elaborate on why you find it useful to pass metatypes as AnyObject? Why not use generics?

  1. Such usage is some existing code porting from Apple platform to Linux platform. Changing the implementation here may break the ABI.

  2. I can accept we do not accept it on non-Objective platform. But IMO Swift should at least gives a consistent output behavior here.

Every time you call test2, a new temporary object is created and immediately discarded, so the memory may or may not be reclaimed by the allocator each time. This isn't specific to AnyObject bridging but can happen with any memory allocation.

For example, here is a plain C program that calls malloc and free in a loop, printing each allocation address; it just so happens to return the same address each time with the compiler and library configuration on godbolt.org's servers:

1 Like

On Linux, class metatypes are not objects, and as AnyObject just wraps the value in a generic object wrapper.

Got it. So the expected behavior on non-ObjectiveC platform is that we do not guarantee the result of ObjectIdentifier(X.self as AnyObject) to be the same.

I believe most people will not see the underlying issue here.

If X.self as AnyObject behave so different on ObjectiveC platform and non-ObjectiveC platform and we have no intend to unify them, can we at least ban such usage on non-ObjectiveC platform?

I did not see the value here and it only brings confusion and bugs IMO.

There's never a legitimate reason to write ObjectIdentifier(x as AnyObject) on any platform, because of the potential for as AnyObject to create a temporary bridging object. It should emit a warning if anything. ObjectIdentifier(x), without the conversion, works portably for values that are already objects or metatypes.

2 Likes

On Darwin platform, it is the same effect of ObjectIdentifier(X.self as AnyObject) and ObjectIdentifier(X.self) because X.self will be converted to AnyObject implicitly here.

And ObjectIdentifier(X.self) will give us identical result for every run.

I got the magic here. It works on Darwin just because the implementation detail for X.self as AnyObject use the stable ObjectiveC Runtime Class identity here.

So for platforms using temporary bridging object, the magic is gone.