
Is there a way to add generic methods to a struct dynamically after it has been define? Specifically I want to add a gen:custom-write method to a struct from a different library.

You might be able to use super struct? But instances of the original struct won’t get gen:custom-write
. Only ones you create with the new struct will.

I remember that there was a way to redefine the printer used in the REPL. I think it was a parameter. Anybody remember what that was called? They was I could define a function calls a different printer on my-struct? and pass through to the default printer in all other cases.

current-print
?

That is the one, thanks!

I think it only handles top-level values, though. So your strategy might fail on values like (list <your-struct>)
.

One possibility, I think, is to use current-print
along with racket/pretty
. I remember there are various parameters for configuring recursive printing.

Is it possible to write a function that works the same way with different vectors, without using a chain of cond
conditions like vector?
, u32vector?
etc. For example, how could I write this function to work with different vector types? ; Increment `vec` at `pos` by 1.
(define (vector-inc! vec pos)
; Determine `ref` and `set!`
; ...
(set! vec pos (add1 (ref vec pos))))

(I guess this is somewhat similar to samd’s questions, but theirs seems more specific.)

Do you need it to be extensible? If you just want something quick and hacky for your own use, you can always
(define (collection-set! c pos v)
(cond
[(vector? c) (vector-set! c pos v)]
[... ...]))
and then use it.
For a way that is extensible, you can use generics. There’s also https://docs.racket-lang.org/collections, but it doesn’t support mutable data structures IIRC.

Yes, I used the “quick and hacky” way. :wink: Or rather, I used it and then saw that I need to support only one vector type.
Generics seem to assume that types define the generic methods in advance, don’t they? So vector
etc. already would have needed to specify such generic methods. So if I’m dealing with vectors, this approach wouldn’t work.
I didn’t know about data/collections
. This might be interesting at some point.

When you use define-generics
, you can have a #:defaults
clause to take care of stuff already defined, like vectors.

See an example at https://docs.racket-lang.org/reference/struct-generics.html

If I understand this correctly, this however would mean that the default method would need to implement the “quick and hacky” approach for various vector types? So, ok, I would have a common interface, but it would be somewhat messy to implement.
I think I’m looking for something like generics in C++ or duck typing in Python. :slightly_smiling_face:

Probably the problem isn’t so serious in Racket because vector
s themselves can contain arbitrary data types, so the generic access for vectors is at least agnostic of the data stored in the vectors.

My intuition is that this some rather basic feature missing from Racket, but at the same time, it might not really be that important for how Racket is typically used. :slightly_smiling_face:

I think the more frequent problem isn’t supporting different types at the same time, but changing the underlying type of a struct and then having to change all functions that work on this underlying type.

It’s an oft-requested feature


Interesting, so I’m not the only one (or one of few) who think along these lines. :slightly_smiling_face:

Vectors are part of the gen:dict
interface, but I don’t know if the other vector types you are using are.

Also it would be a bit hacky to use the gen:dict
interface for indexed access.

> Vectors are part of the gen:dict
interface, Very interesting. I didn’t know.
> but I don’t know if the other vector types you are using are. It seems they aren’t: > (dict? (vector 1 2 3))
#t
> (dict? (u32vector 1 2 3))
#f

Yes, something like that.

Though, personally, I would strongly avoid a mutable data structure. From what you said earlier, it sounds like you don’t actually want to mutate the slots, just to append new data—could you just use a list, but define that it’s in reversed order? That can often work out, especially because pairs are aggressively optimized.

Similarly, if I were storing triplets, I’d be more inclined to use something like (struct triplet (a b c))
that a u8vector
/byte-string. Mostly, I like that the struct is more correct by construction, but I wouldn’t be shocked if it could also give better performance on access, since it should be able to avoid bounds checks. (But of course you’d want to benchmark if this is truly performance-critical, and the struct would presumably use very slightly more space.)

> I think the more frequent problem isn’t supporting different types at the same time, but changing the underlying type of a struct and then having to change all functions that work on this underlying type. One alternative would be to simply shadow the vector bindings, either manually like (define vector u32vector)
or by using renaming features of require
: aside from rename-in
, you could use filtered-in
to programmatically transform all bindings at compile time.

This can also be a good use-case for units, but that’s a much more intrusive change.

@a.c.clunn has joined the channel