this is a great paper; explains several different approaches to compiling record access in as close to constant time as possible: @INPROCEEDINGS{Leijen:scopedlabels, author = {Leijen, Daan}, title = {Extensible records with scoped labels}, booktitle = {Proceedings of the 2005 Symposium on Trends in Functional Programming (TFP'05)}, location = {{T}allin, {E}stonia}, month = sep, year = 2005 } http://legacy.cs.uu.nl/daan/pubs.html#scopedlabels I'm going to use their suggested 'partial evaluation/constant folding' approach... whenever accessing a field, you first call a 'lookup' function that will return the index of that field in that particular record. A good compiler will do partial evaluation on that and inline the lookup whenever accessing a known/closed record. Rather than making Irken a good compiler, I'll just emit a small C function to do that, and count on the C compiler to do it. [I know gcc can do stuff like that because I've seen it inline lexical variable lookup loops when given a constant address] Each unique record will need a unique run-time tag though, how do I collect the set of 'realized' record layouts from the typed program? i.e., how do I distinguish realized layouts from the partially-typed ones generated by functions like this: (define (thing x) (+ x.left 1)) Here is the type of thing: [forall (x,) product(rlabel('left', pre(int,), x),)->int] While here is the type of a 'realized' record: product(rlabel('right', pre(char,), rlabel('left', pre(int,), rdefault(abs(),))),) So it seems like the answer is straightforward - each unique record type that has no row variables left in it. On top of that we'll just order the fields alphabetically. Now. Do we care what type is stored in each field? I don't think so (at least not yet). We only care about their order. So a record is uniquely identified by the set of labels attached to it. ----------------------- What I did: I ended up doing something very close to this. When the typer can get a closed record at compile-time, it will just emit the constant lookup via index. When it can't, it calls a lookup_field() function to do the lookup at runtime. Most lookups seem to be known ones, so I think this approach gets the best of both worlds.