Struct Embedding in Racket

Racket supports defining structures and interfaces to express a more seamless composition of types. This is similar to the concept of embedding in other languages.

#lang racket

(struct base (num))

(define (describe b)
  (format "base with num=~a" (base-num b)))

; A 'container' includes a 'base'. In Racket, we use inheritance to 
; achieve a similar effect to embedding.
(struct container base (str))

(define (main)
  ; When creating structs, we initialize all fields, including those from the parent struct.
  (define co (container 1 "some name"))
  
  ; We can access the base's fields directly on 'co'.
  (printf "co={num: ~a, str: ~a}\n" (base-num co) (container-str co))
  
  ; We can also access the fields using the full accessor functions.
  (printf "also num: ~a\n" (base-num co))
  
  ; Since 'container' inherits from 'base', we can use functions 
  ; that work on 'base' with a 'container'.
  (printf "describe: ~a\n" (describe co))
  
  ; In Racket, we don't need to explicitly define interfaces. 
  ; Instead, we can use generic functions or contracts to achieve 
  ; similar behavior.
  (define (use-describer d)
    (printf "describer: ~a\n" (describe d)))
  
  (use-describer co))

(main)

To run the program:

$ racket struct-inheritance.rkt
co={num: 1, str: some name}
also num: 1
describe: base with num=1
describer: base with num=1

In this Racket version, we use struct inheritance to achieve a similar effect to embedding in other languages. The container struct inherits from the base struct, allowing it to have all the fields and behavior of base plus its own additional field.

Racket doesn’t have a direct equivalent to interfaces, but we can achieve similar behavior using generic functions or contracts. In this example, we’ve used a function use-describer that can work with any value that has a describe function defined for it.

This example demonstrates how Racket can express complex relationships between data types, allowing for flexible and powerful programming paradigms.