essays and observations

How to make a record and a class mutally recursive in OCaml

This is harder than it ought to be. To declare mutually recursive record types is easy:

type shop = {
	name: string;
	sell: trinket -> unit }
and trinket = {
	price: int;
	purchase: shop -> unit }

Mutually recursive class types are also easy:

class type shop = object
	method name: string
	method sell: trinket -> unit
end
and trinket = object
	method purchase: shop -> unit
end

But because the syntax for declaring class types is distinct from the syntax for declaring all other types, to make a record and a class mutually recursive is a little trickier. You can either have the recursion happen in the record:

class type ['a] trinket = object
	method price: int
	method purchase: 'a -> unit
end

type shop = {
	name: string;
	sell: shop trinket -> unit }

class trinket (price: int) = object (self)
	method price = price
	method purchase location = location.sell (self :> trinket)
end

or in the class:

type 'a shop = {
	name: string;
	sell: 'a -> unit }

class trinket (price: int) = object (self)
	method price = price
	method purchase location = location.sell (self :> trinket)
end

One other way to do it is to declare the class type with the non-class type syntax:

type shop = {
	name: string;
	sell: trinket -> unit }
and trinket = <
	price: int;
	purchase: shop -> unit >

However with this method, trinket can't inherit from another class. You could add in every superclass's methods manually... If you could inherit with this syntax I think it would be superior.

Doing it in the class is simplest, except you're left with a parameterized record type. I'd rather have the parameterized class type, since I'm not going to actually use it for anything besides declaring the record type. I suspect most people deal with this issue by just making everything a class rather than a record.

The weird thing is that normally when you declare a class, you're declaring both a type and specifying the executable code that is used with the type. The type system in OCaml starts to seem annoying when you mix it with classes. I'm actually having a hard time understanding why the (self :> trinket) is necessary. Shouldn't the type inferer figure that out on its own?

2007/05/23 20:06