Racket seems to have two mechanisms for adding per-type information to structs: generics
and properties
. Unfortunately, the documentation doesn't seem to indicate when one is preferred over the other. The docs do say:
Generic Interfaces provide a high-level API on top of structure type properties.
But that doesn't seem to provide a good intuition when I should use one over the other. It does seem pretty clear that define-generic
provides a much higher level interface than make-struct-type-property
. But many struct types still only use properties, which seems to indicate that there are still cases where the low-level API is preferred.
So the question is, when is using the struct properties system better than using the generics one, or does the properties library only exist as a historic relic?
A structure, an instance of a structure type, is a first-class value that contains a value for each field of the structure type. A structure instance is created with a type-specific constructor procedure, and its field values are accessed and changed with type-specific accessor and mutator procedures.
A generic interface is primarily a normal interface like any other. It can be used to declare a variable but assigned the appropriate class. It can be returned from a method. It can be passed as argument. You pass a generic interface primarily the same way you would an interface.
In addition to generic classes, you can also create a generic struct. Like a class, the generic struct definition serves as a sort of template for a strongly-typed struct.
The general syntax to declare a generic interface is as follows: interface interface-name<T> { void method-name(T t); // public abstract method. } In the above syntax, <T> is called a generic type parameter that specifies any data type used in the interface.
The struct property system is the implementation strategy for the generic interface library, so it's not deprecated. It, or something like it, is necessary to make generic interfaces work. Not all uses of struct properties make sense as generic interfaces either.
That said, for many typical use cases the define-generic
form is preferred. As the #:methods
form for structs suggests, it is useful for code that is organized in an object-oriented fashion with interface-based dispatch. Examples of this include sequences (gen:sequence
from data/collection
) and dictionaries (gen:dict
).
Plain struct properties in the Racket codebase are typically used when some data just needs to be stored in a struct as metadata, or when there is only one "method" and it's needlessly complicated to use define-generic
, or when the interface is more complicated than "just put a procedure in here". Examples include prop:procedure
or prop:evt
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With