code
2021-4-17 13:47:54

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.


sorawee
2021-4-17 13:50:37

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.


code
2021-4-17 13:53:33

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.


sorawee
2021-4-17 13:53:59

current-print?


code
2021-4-17 13:55:49

That is the one, thanks!


sorawee
2021-4-17 13:56:01

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


sorawee
2021-4-17 13:57:01

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


sschwarzer
2021-4-17 15:17:01

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))))


sschwarzer
2021-4-17 15:18:10

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


sorawee
2021-4-17 15:24:18

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.


sschwarzer
2021-4-17 15:30:50

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.


sorawee
2021-4-17 15:33:19

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


sorawee
2021-4-17 15:33:24

sschwarzer
2021-4-17 15:38:16

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:


sschwarzer
2021-4-17 15:42:20

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


sschwarzer
2021-4-17 15:42:25

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:


sschwarzer
2021-4-17 15:44:43

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.


sorawee
2021-4-17 15:47:47

It’s an oft-requested feature


sorawee
2021-4-17 15:47:55

sschwarzer
2021-4-17 15:53:25

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


samdphillips
2021-4-17 18:52:39

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


samdphillips
2021-4-17 18:53:13

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


sschwarzer
2021-4-17 20:05:50

> 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


philip.mcgrath
2021-4-17 20:47:01

Yes, something like that.


philip.mcgrath
2021-4-17 20:52:19

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.


philip.mcgrath
2021-4-17 20:58:38

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.)


philip.mcgrath
2021-4-17 21:05:51

> 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.


philip.mcgrath
2021-4-17 21:06:26

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


a.c.clunn
2021-4-17 23:29:47

@a.c.clunn has joined the channel