camoy
2022-7-24 13:33:06

Is there any unsafe way to determine if a value is an opaque struct?


soegaard2
2022-7-24 13:38:25

Back in the Scheme days without a portable gensym and with no structs, it was popular to write (define none (list 'none)) to produce a unique value that printed nicely.


mflatt
2022-7-24 13:59:41

It depends on what you mean by “opaque struct”.

I assume you want to recognize instances of something like (struct s ()) and not, say, a number or a primitive like cons. But various core datatypes are represented with opaque structures, including some forms of procedures and most chaperoned values. It’s not clear that drawing a line between those after-the-fact makes sense, and I’m not immediately sure what operation would make sense if you don’t draw a line.

The intended way of distinguishing layers is to set an inspector so that anything created as opaque afterward is not opaque to you, but I don’t know whether that’s an option in your case.


camoy
2022-7-24 14:23:24

I’d like to recognize non-primitives, what would be record? at the chez level


camoy
2022-7-24 14:25:43

(If that includes core data structures that happen to be structs that’s ok.)


mflatt
2022-7-24 14:35:22

I think record? will capture everything you want, but possibly more. “Primitive” versus “not primitive” just isn’t a reliable concept.


camoy
2022-7-24 14:42:02

I can provide a bit more context. I’m just doing some extremely experimental code and I’d like to be able to chaperone values that I reasonably shouldn’t be able to chaperone. Generally, I know that you can retrieve the struct type of an arbitrary opaque struct unsafely via unsafe-struct-ref and -1 but I obviously don’t want to do that for primitives.


mflatt
2022-7-24 14:43:50

Ok. Since you’re going to Chez Scheme for record?, I recommend also using record-rtd instead of unsafe-struct-ref with -1.


camoy
2022-7-24 14:44:58

Right, but I’m interested in doing this at the Racket level. Of course I can hack my version of Racket to expose these things, but I’d prefer not to do that :stuck_out_tongue:


camoy
2022-7-24 14:45:28

But maybe that’s the only thing to do here


camoy
2022-7-24 14:49:25

Or the other option I suppose is to just have a predicate that checks for every primitive and just hope that I don’t miss any.


mflatt
2022-7-24 14:58:37

In case it helps, it’s possible at the Rumble level to determine whether a record type was created with make-struct-type: use inspector-ref and check that the result is not none.


camoy
2022-7-24 15:01:06

Ah, that is useful. Thanks!


sschwarzer
2022-7-24 18:44:47

Wow. Not having gensym is understandable, but having no structs/records sounds quite limiting for abstraction. Would people then use lists to store records? (Wait, records would be nicer, I suppose, if you have them.) Given that Scheme is Scheme, I’d expect people roll their own record/struct types, though. :wink: Along these lines, I saw there’s nowadays an <https://srfi.schemers.org/srfi–9/srfi–9.html|SRFI for records>.


soegaard2
2022-7-24 19:17:23

It wasn’t unusual to see: (define foo-tag (list 'foo)) (define (make-foo a b) (vector foo-tag a b)) (define (foo? x) (and (vector? x) (eq? (vector-ref x 0) foo-tag)) (define (foo-a x) (cond [(foo? x) (vector-ref x 1)] [else (error 'foo-a "expected a foo")])) etc However, this was only necessary when writing portable Scheme. Most implementations had their own records/structures.


soegaard2
2022-7-24 19:18:02

I believe portable records/structures first appeared in R6RS.