Object-oriented – Can objects be implemented in terms of higher order functions

functional programmingobject-oriented

Martin Odersky finished one online course on Scala with an unanswered question:

Can we implement one concept in terms of other ?

  • Objects in terms of higher order functions?
  • Higher order functions in terms of objects?

It is clear that high order functions can be implemented using objects but I am not sure if it works the other way round or at least while using static types.

Suppose that closure can contain encapsulated data as object does but it still has only one 'method' in its interface – applying itself. In dynamic languages (or in static ones if we use some broad type like Object or Any) we can pass and return anything from this function but is this really an object ?

Best Answer

With dynamic typing, it is fairly straightforward to implement an object-oriented system in terms of closures. I've written about this in my answer to “Modelling Objects as Functions” and expanded on that on my blog. There are some details about open recursion that are necessary to get certain OOP features such as subclassing right, but it's doable. In short, invoking the closure representing an object maps a method name to a method bound to that object, which can then be invoked as an ordinary function. Usage might look like result = object("methodName")(otherObject).

However, OOP and static typing are fundamentally at odds. There are various interpretations of OOP, such as OOP-as-message-passing or OOP-as-virtual-dispatch, but a central theme is that we do not statically know the exact runtime type of an expression such as x. However, many statically typed OOP languages do assign type bounds to an expression (such as x is a subtype of Iterable). When implementing objects in terms of closures in a statically typed language, we quickly run into the problem – when specifying the required method as an argument to the dispatch function, we can't statically know the required signature of the function. In the above example, how do I know that the result of object("methodName") should be a function accepting exactly one parameter?

The common solution when implementing objects is to make the object-system unityped (aka. untyped). That is, all method signatures would have the same type regardless of their arity (number of arguments) or of the types of arguments. This also requires that all our objects have the same type in the host language.

Some languages might be able to do better. E.g. in C++, we could pass the requested method type as a template parameter to the dispatch function: auto result = object<ResultType(ArgumentType)>("methodName")(otherObject). A clever implementation could then use different lookup tables to dispatch int() or int(int) method types etc. However, we cannot statically guarantee that the requested method exists since it is provided as a string. Another possibility would be to pass in a (visitor-like?) Message object rather than a string name to the dispatch function, which might allow more type safety in statically typed host languages, but I do not have sufficient experience with implementing OOP in static languages to describe this in more detail.

Related Topic