# Ryan got me thinking about the Racket class system

**URL:** <https://racket.discourse.group/t/ryan-got-me-thinking-about-the-racket-class-system/107>\
**Category:** General\
**Tags:** object-oriented\
**Created:** [November 12, 2021, 7:25pm UTC](https://racket.discourse.group/t/ryan-got-me-thinking-about-the-racket-class-system/107 "2021-11-12T19:25:12Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![badkins](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/badkins/32/99_2.png) [@badkins](https://racket.discourse.group/u/badkins)\
**Post date:** [November 12, 2021, 7:25pm UTC](https://racket.discourse.group/t/ryan-got-me-thinking-about-the-racket-class-system/107/1 "2021-11-12T19:25:12Z")

</div>

Ryan mentioned something along the lines of Racket's class system being under appreciated in his RacketCon talk, so I've begun to look into it a bit more.

I spent three decades, one in each of C++, Java & Ruby, mostly focused on object oriented programming. Then my pendulum swung heavy into the functional world, and I didn't really look back.

The timing of Ryan's comment was perfect. I've just realized I've been creating "an ad hoc, informally-specified, [hopefully not] bug-ridden" implementation of some OO concepts for a recent project. Functional programming works really well for the vast majority of my code, but sometimes the nail really is an OO nail 🙂

I'm currently reading [Scheme with Classes, Mixins, and Traits](https://www.cs.utah.edu/plt/publications/aplas06-fff.pdf) which I found in the Racket Guide. Feel free to respond with any other sources of info on Racket OO.

---

<div class="post-metadata">

**Author:** ![spdegabrielle](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/spdegabrielle/32/95_2.png) [@spdegabrielle](https://racket.discourse.group/u/spdegabrielle)\
**Post date:** [November 12, 2021, 8:44pm UTC](https://racket.discourse.group/t/ryan-got-me-thinking-about-the-racket-class-system/107/2 "2021-11-12T20:44:20Z")

</div>

Probably a bit too tangential but I thought this was cool: [http://shivers.com/~shivers/scheme04/tmp/scheme04/article/06-java2scheme.pdf](http://shivers.com/~shivers/scheme04/tmp/scheme04/article/06-java2scheme.pdf)

---

<div class="post-metadata">

**Author:** ![badkins](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/badkins/32/99_2.png) [@badkins](https://racket.discourse.group/u/badkins)\
**Post date:** [November 14, 2021, 4:09pm UTC](https://racket.discourse.group/t/ryan-got-me-thinking-about-the-racket-class-system/107/3 "2021-11-14T16:09:55Z")

</div>

@soegaard passed on another paper:

[Super and Inner — Together at Last!](https://www.cs.utah.edu/plt/publications/oopsla04-gff.pdf)

---

<div class="post-metadata">

**Author:** ![greghendershott](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/greghendershott/32/98_2.png) [@greghendershott](https://racket.discourse.group/u/greghendershott)\
**Post date:** [November 14, 2021, 4:20pm UTC](https://racket.discourse.group/t/ryan-got-me-thinking-about-the-racket-class-system/107/4 "2021-11-14T16:20:10Z")

</div>

If you don't mind sharing, I'm curious what aspects of `racket/class` you found yourself to be [Greenspun-10th-ruling-ing](https://en.wikipedia.org/wiki/Greenspun%27s_tenth_rule)?

* * *

Why I ask:

Your history sounds very similar to mine. 🙂

For me the pendulum is still very much away from OO: I find `struct` (usually plain, sometimes with struct inheritance or generics) + modules to be sufficient and preferable.

But enough time has elapsed to make me wonder if that's justifiably due to the kinds of programs I'm writing (e.g. I haven't done something like the `db` package's support of various engines), or unjustifiable bias.

I'm not trying to "debate OO" or asking you to defend or persuade or anything like that! I just like to hear other people's experiences and think about them.

---

<div class="post-metadata">

**Author:** ![badkins](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/badkins/32/99_2.png) [@badkins](https://racket.discourse.group/u/badkins)\
**Post date:** [November 14, 2021, 4:57pm UTC](https://racket.discourse.group/t/ryan-got-me-thinking-about-the-racket-class-system/107/5 "2021-11-14T16:57:16Z")

</div>

I have a new application that is _mostly_ generic. Customers have Users. User's add Providers. The Providers are notified they have been requested to provide information. Providers either accept and submit a form of fields, or decline.

Although it's mostly generic, there is some specialization per Customer. For the most part, I was able to handle the specialization by parameterizing Customers with static data (e.g. a list of questions, field types, min/max number of providers per user, etc.); however, I also need some simple behavioral specialization.

I've always used structs for my database models, so to accomplish the latter, I had a struct that subtyped the Customer struct and added a number of functions. A factory function would create and populate this struct with functions specific to the customer. For example (we need to fix the code highlighter!):

```auto
(struct q customer (activate-user
                    get-user-data
                    display-link?
                    application-css
                    application-name
                    validate-provider-meta-data
                    validate-provider-customer-data
                    ...)
  #:transparent)

(define/contract (build-q customer-obj)
  (-> customer? q?)
  (match (customer-username customer-obj)
    ["tla" (build-q-tla customer-obj)]
    [_ (error "build-q: invalid customer")]))

(define (build-q-tla obj)
  (q (customer-id obj)
     ; other customer fields
     ...
     activate-user ; not quest specific
     get-user-data ; not quest specific
     display-link? ; not quest specific
     tla:application-css
     tla:application-name
     tla:validate-provider-meta-data
     tla:validate-provider-quest-data
     ...))

```

It was efficient (no dynamic method lookup), simple, and worked ok because it was a flat class hierarchy of just one level. A typical use:

```auto
((q-get-user-data obj) conn obj reference-key type)

```

Which is now:

```auto
(send obj get-user-data conn obj reference-key type)

```

And... as I typed that, I just realized I probably don't need the second `obj` now since `get-user-data` can refer to `this` 🙂

I'm pretty sure I'll need a deeper class hierarchy, and while I was contemplating this, I saw Ryan's talk 🙂 Adding method dispatch for a deeper hierarchy is where I saw I was re-inventing the wheel too much.

It was trivial to convert my code to use Racket classes. For the time being, I'm going to continue to use simple structs for my database records, and there was one small advantage of my previous approach - I could use a `q` where a `customer` was needed, but with my current approach, rather than `q` subtyping `customer` it _composes_ a `customer`.

Although Rails use of object orientation has some niceties, for the most part, I felt the magical implicit aspects went too far. I'll need further research to determine whether I want to use classes for database records vs. my current structs, but for the simple behavioral specialization I needed, classes make sense to me, and my code is now _much_ more maintainable.

Kudos to the folks who created Racket's class system! It's nice to have that tool for the cases where it fits well, and I love how it feels more Rackety than previous OO systems I've used.

Brian

---

<div class="post-metadata">

**Author:** ![Decabytes](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/decabytes/32/54_2.png) [@Decabytes](https://racket.discourse.group/u/Decabytes)\
**Post date:** [November 21, 2021, 9:45pm UTC](https://racket.discourse.group/t/ryan-got-me-thinking-about-the-racket-class-system/107/6 "2021-11-21T21:45:45Z")

</div>

I asked about the performance of Racket classes [in this post](https://www.reddit.com/r/Racket/comments/q9qenr/do_racket_classes_suffer_from_the_same/) on Reddit. One enlightening answer came from /u/ryan017

> A class is implemented as a struct type with a struct type property that holds the method tables, etc. An object is implemented as an instance of the class's struct type. The OO features add some overhead, so using structs directly and using functions instead of methods will generally be faster. The overhead is not huge, though, so don't avoid objects if an OO solution fits your problem.  
> More details:
> 
> - A call to a `public` method using `send` is slower than a function call. The method call (usually) turns into a struct property lookup, a hash table lookup, a vector access, and then a function call. The final function call is to a computed function, which is not optimized the same way that direct calls to known functions are.
> - A call to a `public` method within a class (on the same object, without using `send` ) is faster. It is equivalent to a vector access and then a function call.
> - A call to a `private` (or `public-final` , I think) method within a class is the same as a function call.
> - Object construction is more complicated than struct instance construction. IIRC simple struct constructors (ie, without guards) are especially optimized by Racket's compiler.
> - A field access using `get-field` is slower than call to a struct accessor. It is roughly the same as a public method call. Likewise for `set-field!` .
> - A field access within a class is the same as a struct accessor call. Likewise, a field assignment is a struct mutator call.
> - If contracts are involved, then read the paper soegaard mentioned to find out what happens.

The paper in question from the last point is the one linked by @badkins
