Lambda the Ultimate

inactiveTopic Programming OOP Pattern Libraries
started 1/26/2004; 7:49:49 AM - last post 1/31/2004; 10:17:19 AM
Eray Ozkural (exa)) - Programming OOP Pattern Libraries  blueArrow
1/26/2004; 7:49:49 AM (reads: 326, responses: 8)
One of my favorite extensions to an object oriented language would be a means to specify classes of class hierarchies, effectively implementing OO design patterns in the language itself.

Although not a great discovery, I realized that such a thing could be done using ocaml's module system. Ocaml allows one to define "functors" which are 'functions' from structures to structures. (ocaml modules are called structures) I think it's easy to see that "functor" terminology actually makes a lot of sense in the category theoretical sense ;) Maybe more so than Arrow libraries in Haskell.

From the manual, a functor implements a "a structure A parameterized by a structure B".

Combining the object system in objective caml and the use of functors, it is easy to realize generic class hierarchies one could start from to implement a design pattern.

Here the functor would realize a class hierarchy P parametrized by an input module X.

Do you think this makes any sense?

Patrick Logan - Re: Programming OOP Pattern Libraries  blueArrow
1/26/2004; 9:19:25 AM (reads: 316, responses: 0)
One of my favorite extensions to an object oriented language would be a means to specify classes of class hierarchies, effectively implementing OO design patterns in the language itself... Do you think this makes any sense?

I have trouble saying without seeing an example. The question on my mind about any "implement patterns in a language" approach is:

How is this different from implementing a "framework" of classes in an OO language?

Neel Krishnaswami - Re: Programming OOP Pattern Libraries  blueArrow
1/27/2004; 11:08:39 AM (reads: 260, responses: 1)
Hi Patrick,

What you can do in OCaml, which you can't easily do in conventional OO languages, is to use parameterized modules to write classes with "abstract superclasses". For example, suppose that you have the following interface:

module type FOO =
  sig
    class t :
      object
        method get : string
        method set : string -> unit
      end
  end

That is, you've got an interface with two methods, get and set, which return a string and let you update the returned string. Now, suppose that you want to write a "subclass function" that will take any class supporting the FOO interface, and return a new class that adds undo functionality to the class. You can write that using a parameterized module:

module Add_Undo(Base : FOO) =
  struct
    class t =
      object
        inherit Base.t as super

        val mutable undos = []

        method set s =
          begin
            undos <- super#get :: undos;
            super#set s;
          end

        method undo =
          match undos with
            | [] -> ()
            | x :: xs -> (super#set x; undos <- xs)
      end
  end

So now Add_Undo can be run on any class that supports the FOO interface, and it will automagically produce a new class with undo support -- and we only needed to write the undo code once. It also has excellent readability properties, in that it's extremely clear to the code reader what the dependencies in the subclassing are, and in which direction they run.

Ehud Lamm - Re: Programming OOP Pattern Libraries  blueArrow
1/27/2004; 11:27:57 AM (reads: 256, responses: 0)
Sure. You can do this with generic units in Ada as well. This is the standard way to produce mixin inheritance, given that the language doesn't support multiple inheritance. See here for a discussion.

Neel Krishnaswami - Re: Programming OOP Pattern Libraries  blueArrow
1/27/2004; 1:46:32 PM (reads: 240, responses: 1)
I count that a mark in Ada's favor, then. :)

As a programmer, I prefer mixin-like constructs not just to multiple inheritance, but to ordinary single inheritance, too. The reason is that constructs like traits and mixins make everything they depend on explicit, and so interface boundaries can be more consistently respected.

Ehud Lamm - Re: Programming OOP Pattern Libraries  blueArrow
1/27/2004; 1:54:04 PM (reads: 240, responses: 0)
Well put.

Avdi - Re: Programming OOP Pattern Libraries  blueArrow
1/29/2004; 10:16:55 AM (reads: 168, responses: 0)
I don't know if C++ counts as a "conventional OO language", but here's the C++ analog to the OCaml example given above:

template <typename SUPER> class Undoable : SUPER {
public:
    void undo(void) {
        if( !history_.empty() ) {
            set(history_.top());
            history_.pop();
        }
    }
    void set(string s) {
        history_.push(s);
        SUPER::set(s);
    }
private:
    stack<string> history_;
};

Given a class "Foo" with get and set methods, creating an "Undoable Foo" object would look like this:

    Undoable<Foo> myFoo;

This limits the ways in which Undoable can be used; A more flexible solution might be to code Undoable as a mixin class and create a little helper metafunction to combine it with an arbitrary class:

template <typename T> struct make_undoable {
    class type : T, Undoable {};
};

// Create an Undoable Foo: make_undoable<Foo>::type myFoo;

Neel Krishnaswami - Re: Programming OOP Pattern Libraries  blueArrow
1/29/2004; 3:49:31 PM (reads: 163, responses: 0)
Hi Avdi, thanks for the example. I don't see an interface for the SUPER class; does the compiler check if the Undoable has a get method, too? Also, can you explain how the template metafunction thing works? I can't figure that part out.

Avdi - Re: Programming OOP Pattern Libraries  blueArrow
1/31/2004; 10:17:19 AM (reads: 106, responses: 0)
In the example given, the compiler will only check that SUPER has the methods that are needed by Undoable, which in most cases is the best way to do things. If you wanted for some reason to assert that SUPER supports both get() and set() explicitly, there are ways to do so. The Boost libraries contain a template library for making arbitrary compile-time assertions about template parameters.

A template metafunction is simply a structure definition which when parameterized returns a type, rather than a value, as it's result. By convention the type result is a nested type named 'type'. In this case the type "returned" by instantiating make_undoable fo Foo is a new class which derives from both Foo and Undoable. It's just a shortcut for explicitly deriving a new class from Foo and Undoable.