atheorist (atheorist) wrote,

dataflow / class diagram duality

Class diagrams in UML (for my purposes) have boxes, two kinds of arrows (isa and hasa) between boxes, and methods, which are essentially strings, inside the boxes. Class diagrams correspond to object-oriented code in that each box probably has a section of code corresponding to it, each method probably has a section of code corresponding to it, and each arrow leaving a box indicates a collaborator that will need to be considered.

Objects can be encoded into functional languages like ML or Haskell by an object-closure correspondence. Where the object-oriented code creates a new object, the functional code would define a new functional value, using a lambda. Where the object-oriented code invokes a method on an object, the functional code calls a function value. In order to model method dispatch, the functional code might call a function value representing the object as a whole, passing a known-at-compile-time value of an enumerated type as an argument, and then call the returned (function) value with the arguments of the method, something like this:

  v(PRINT)('hello %s', {'world'});

If you have functional code, but you need object-oriented code, then you can go the other way. (This is called defunctionalization, and the experts to google and read are Danvy and Reynolds.) For each function value constructed in the source code, you need a constructor, and usually a class. (Multiple constructors on the same class is possible, but dubious if you're shoehorning, and unlikely if you're not shoehorning.) The lexically-scoped variables Then you need to study the dataflow, and find out where the function value will be consumed (applied). That will give you your method name. Generally the dataflow looks like a river - several tributaries coming together to one port where the river ends. In statically typed object-oriented languages like C++ or Java, that means that you will need an interface (or pure virtual abstract class, same difference), corresponding to the consumption point. Then each of the origin points will need to declare that they implement that interface.

tl;dr - you can recognize "wannabe-functional" code in an OO language from the class diagram - it has a bunch of one-method classes, often in little groups (an interface and its several concrete implementations).
  • Post a new comment


    default userpic

    Your IP address will be recorded 

I'm toying with maybe preparing a talk for Hacker School about functional and OO programming. "The lambda calculus: the first object-oriented language." The link I was thinking of emphasizing was, in LC, the only thing you can do with a function is to call it; while in OO, I mean the really pure version of it like Actors, all you can do with an object is send it a message. For the 'things' in either system, you are what you do.

So in either, it's natural to use polymorphism instead of if-thens. To use transparent forwarders and adaptors. They both profit from tail-call optimization. They should encourage a design style distributing knowledge and responsibility, with clarity about who does what ('trained animals' do the jobs). (OTOH Steve Yegge wrote this missive "Execution in the Kingdom of Nouns" blaming Java's bureacratic doubletalk style on object orientation, just what I'm claiming should nudge writers toward clarity, so I'm not sure. I think he misdiagnosed the problem, but then I don't read much Java and I'm not even sure how bad the problem is.)

OTOH, both formalisms in their really pure form get awkward on problems that get easier when you can look inside a thing, like with pattern matching, or any of a bunch of other language features that do exist for reasons.

I like the point about looking for one-method classes, and sketching algorithms for compiling either way. (Actually I'm leaning towards just focusing mainly on how to compile call-by-value lambda calculus and not trying to make the above parallels power a whole talk.)
P.S. writing that out prodded me to read which turns out to say practically all of what I had in mind, down even to the title (section 5.4 ends "the untyped lambda-calculus was the first object-oriented language.")