In principle, chaperones could update a chaperoned
hasheq so that get-chaperoned
returns the chaperoned value, and get-top-chaperoned
is like get-chaperoned
but applied recursively. Then the test would reduce to (eq? (get-top-chaperoned h2) (get-top-chaperoned h3))
which would be symmetric and transitive. Of course, that probably requires changing the way chaperones currently work—for your own data, you could make a wrapper at least.
Regarding mutability, I guess you’d have to test for type-specific mutability (immutable?
, pair?
, number?
, symbol?
, …). Is there a way to check if a struct has any mutable field?
The (get-top-chaperoned h2)
idea wouldn’t be great because contracts and chaperones are sometimes used to enforce security and safety properties, especially in Typed Racket, where you can get segfaults if untyped-code calls the un-chaperoned value. Though I suppose if get-chaperoned
and get-top-chaperoned
were internal functions only usable by equal?
(or a new equal-always?
) itself, that no one else could get at… it’s a level of privilege equality would have to have over user code, and then I start wondering whether gen:equal+hash
could be exploited to break Typed Racket’s boundaries… I guess this is more complicated than I thought
(Re: Regarding mutability, struct han any mutable field?) Rackjure’s egal?
function uses struct-info to tell if a struct is immutable https://github.com/greghendershott/rackjure/blob/9422246972705cfa55c773c39383a33b531507d9/rackjure/egal.rkt#L149-L167 When any struct-info is missing, it conservatively assumes the struct is not immutable. The skipped?
result-values of struct-info
and struct-type-info
must be false, the immutable-k-list
result-value of struct-type-info
must contain every init-field and auto-field, and the parent struct-type must be immutable.
It’s strange that racket doesn’t seem to know whether a struct is immutable. I suppose some optimizations should be possible with this info.
check-syntax doesn’t seem to know that aa1 is mutated in #lang racket/base
(struct aa (a) #:mutable)
(define aa1 (aa 3))
(set-aa-a! aa1 2)
aa1
(no mutated variable
tooltip)
Sometimes I wish (expanded) syntax objects would be annotated with pure-functional?
One difficulty is to figure that some procedures can be used as pure function, despite mutating internal variables.
No, I think Racket can tell that that struct is mutable, especially at compile time when aa
is bound with define-syntax
to a struct-info. But mutable-data-structures are not mutable-variables
why make a new function for this instead of making the mutable struct you’re trying to use it on implement gen:equal+hash
the way you want it to?
Why make a new function? Because (equal? a b)
at one time doesn’t imply (equal? a b)
at any other time when a and b can contain mutable data
(equal? a b)
doesn’t imply a lot of things, since it does whatever gen:equal+hash
does, which can include side effects.
in general, if you’re using mutation, I worry it might be a good idea install continuation guards around each of your equal?
calls (and all other generic calls) so someone’s gen:equal+hash
implementation doesn’t capture the continuation and replay half your mutation behavior
. But the usefulness of a lot of generic interfaces in Racket relies on the good-faith assumption that everyone else’s generic implementations aren’t doing shenanigans like that.
I think the current design of (equal? a b)
succeeds to the same extent: As long as you have the faith that your two mutable containers aren’t actually being mutated, then comparing their contents is useful.
So I guess what I want is (equal-always? a b)
, and if it’s extensible at all the extension mechanism should be documented so that mutable data structures aren’t supposed to be traversed for it
@nabacg has joined the channel
The Chez Sheme level does analyze to find which part of the code is pure
Not sure if it will be easy to lift that up to Racket level
Oh that’s cool!