Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

redirect-generics etc. only work on (some) structs #4934

Open
LiberalArtist opened this issue Feb 17, 2024 · 0 comments
Open

redirect-generics etc. only work on (some) structs #4934

LiberalArtist opened this issue Feb 17, 2024 · 0 comments

Comments

@LiberalArtist
Copy link
Contributor

This program:

#lang racket
(require racket/generic)
(chaperone-generics gen:dict #hash()
  [dict-ref (λ (super)
              super)])

produces the following error:

901a31301a/collects/racket/generic.rkt:202:9: gen:dict: contract violation
  expected: gen:dict?
  given: '#hash()

The error message seems to be coming from the internal struct-type property: in particular, note that (object-name dict?) is 'dict (there is no gen:dict?) and #hash() satisfies dict?.

Strictly speaking, getting some error here is consistent with the docs for impersonate-generics, which state that the supplied value "must be a structure that implements the generic interface", but I did not realize that meant the value "must be a structure" specifically. In fact, AFAICT from the implementation, "must be a structure" even more specifically means that the structure type must be created with the internal property attached, either via #:methods or make-struct-type-property/generic/make-generic-struct-type-property: structures handled via #:defaults or #:fast-defaults are not supported. There doesn't seem to be any public API to test for this requirement short of catching and trying to recognize exceptions.

At a minimum, the error message should be fixed, and I think the docs should be clarified.

I can also see at least two reasons to consider changing the behavior:

  1. In Racket in general, conceptually "everything is a struct" under some sufficiently-powerful inspector. Treating structs differently than non-structs is unusual.
  2. A programmer who wants to interpose on generic methods and doesn't want to hard-code special cases for the currently-supported non-structs can currently do so by creating some wrapper struct that implements the interface by simply bouncing each method through the generic version with define/generic. Even if it used essentially that implementation strategy, an implementation in racket/generic would be much more ergonomic, since racket/generic already knows the complete list of methods (including optional methods that may be added over time), the arity of each method, and which is the "this" argument to each.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant