Is `(unsafe-struct*-ref s -1)` a stable way to get type descriptors in Racket?

By stable I mean that the location of struct type descriptors within struct instances is, within reason, a permanent feature of the language.

Obviously on it's own that code is both unsafe and useless on impersonators, but it is a lot faster than using the struct-info procedure and if it's stable I could implement a different kind of struct type properties that may be more suited to one of my projects.

Just to clarify, I'm using Racket CS. It may be that the code doesn't work with Racket BC.

I'm not sure about the implementation details. Do you get the same result or just an opaque value that is good enough for what you need? Does that bypass the current-inspector?

I'm worried than in the future some internal part of the compiler like cptypes may be smart enough to detect that -1 is wrong and assume that the operation will raise an error of have an undefined behavior and then make an unpredictable optimization (like cutting all the code that follows it).

(My guess is that unsafe-struct*-ref is currently not expanded to Chez Scheme code, so the optimizations can't see the problem. But this kind of implementation details may change in the future.)

@mflatt: Does it make sense to add something like struct-info* to fix the problem?

It returns a result eq? to the struct type descriptor defined by the relevant struct form outside of the code, which is what I need.
It accesses the -1 index as fast as any other index, so I assume it does bypass the current-inspector. In my case that should be okay, as struct instances would have to first pass a type check: anything that doesn't satisfy the check would not have it's opacity breached.

I'm just exploring some options for implementing my class library. Being able to manually implement my own struct type properties using the code in question could give a large speed boost to dynamic dispatch of methods.

An unsafe-struct*-ref call is inlined as $record-ref at the Chez Scheme level, which means that the cptypes possibility is relevant.

Adding unsafe-struct*-type would make sense, and that seems like the right thing to do. An unsafe operation more like struct-info does not seem as useful, since determining whether the structure type is transparent is probably too much overhead.

(An unsafe-struct*-type would be inlined as $record-type-descriptor. So, another option to get the same functionality is to use ffi/unsafe/vm to get $record-type-descriptor, and then call that on the structure. But since the operation would not be inlined, that's probably not useful here.)

1 Like

If unsafe-struct*-type would be at least 85% as fast as using unsafe-struct*-ref then I think it would be worth it for a custom struct type properties implementation. It may be worth adding for other reasons.

Otherwise, I'm satisfied that using (unsafe-struct*-ref s -1) is not a stable option for extracting type descriptors. I'll explore other options for now. Thanks to both you and @gus-massa for the discussion!

Yes, (unsafe-struct*-type s) would generate the same machine code that (unsafe-struct*-ref s -1) currently does. I'll plan to add it soon, pending further discussion here. Meanwhile, you could rely on (unsafe-struct*-ref s -1) working until unsafe-struct*-type is added.

Oh awesome. I'll go ahead and use it for now.