Fork me on GitHub
Joshua Suskalo15:08:53

What do people do about having records conform to specs? Since it's generally good practice to use namespaced keywords with specs, but records don't support namespaced keywords on the enumerated fields, the only ways I've seen is either to make a less extensible spec by not using namespaced keywords, or to just not spec the records and prevent them from crossing interface boundaries.

Alex Miller (Clojure team)15:08:43

I think those are the big ones

Joshua Suskalo15:08:58

Fair enough. Sometimes I wish I could just define namespaced record fields, but I can see why that'd be a challenge.


@suskeyhose What drives you to use records rather than hash maps?

Joshua Suskalo19:08:55

Performance. I write game engines in my spare time and things like field access time from entities can make the difference between being able to support hundreds of objects at 60 fps to being able to support thousands, which entirely changes the types of games you can make.

👍 1
Joshua Suskalo19:08:47

And in those sorts of systems, spec brings a lot of value since many of these systems have complex calling contracts that must be upheld and instrumentation and generative testing aid a lot in tracking down errors when you're able to encode those contracts via spec.


Ah, interesting niche. Yes, I can see performance being a good driver for that decision.

Joshua Suskalo19:08:14

I'll also say that yes, game engines is very niche for Clojure development, and for someone who wants to make a very performance-sensitive game they'll have better luck with Unity's new systems, or writing something from scratch in Rust or C++, I prefer Clojure because it makes it easy to write my game code, and I don't make highly performance-sensitive games, but at an engine level I'd like to be able to make as few concessions as possible so that the overhead of being in Clojure takes away the least creative freedom.

Joshua Suskalo19:08:18

And since I'm an engine developer by education and desire, I'm perfectly willing to take on lots of complexity in the engine if I can make writing something atop it simple and unconstrained.


Couldn’t you write a one-way conformer for records to be spec’d? Like (def ->map (s/conformer #(into {} %))), then use something like (s/and #(instance? MyRecord %) ->map (s/keys :req-un [….]))

Joshua Suskalo21:08:21

The problem I have with that is then I have to write code that doesn't follow the spec, but follows an implementation detail for performance. Ideally I'd still be able to do the keyword-based lookup.