Apple: procedural -> OO -> AOP -> advanced procedural

"... go back to the starting point of procedural programming languages and extend them into a different direction in order to create advanced procedural languages which are significantly simpler than aspect-oriented languages while offering comparable expressiveness and flexibility."

APPLE: Advanced Procedural Programming Language Elements pdf

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

Yet another doc about OO having failed.

...and since OOP have failed, some people are thinking about going back to the drawing board, starting from simple procedural languages and see from there what can be done in order to make a programming language for the 21st century.

Basically there are three things that are needed for the 100th year programming language:

1) an open syntax, so as that domain-specific languages can be built.

2) a type system that can incorporate all possible constraints. Aspects, non-nullable pointers, interfaces, inheritance etc are all about expressing constraints of the code. The type system should be algorithmic (i.e. built out of algorithms) and expressed with the open syntax described above. Even assignment can be allowed in a constrained environment, thus making purely functional programming languages 'obsolete'.

3) component-oriented programming: each block of code or data should expose certain requirements that must be filled in by users of the component. Software must be built out of components; subtyping is not the proper way, because it projects the requirements of the subtype on the interface of the supertype.

An interesting statement

subtyping is not the proper way, because it projects the requirements of the subtype on the interface of the supertype

Um, what do you mean by that? An example would help even more than an explanation.

Algorithimic type system ?

Sounds a bit complex for me. I mean, I like the idea of extending the type system (who doesn't ?), but I don't like the idea of having to prove subject reduction each time I change a line of the aforementioned code.

Well, perhaps it doesn't matter for most people.

the problem with constraint s

the problem with constraint solving as a genderalized form of type checking is that only some constraint domains / constraint problems are decidable. Witness Hongwei Xi's ATS language, which has a decision procedure for solving linear arithmatic constraints but requires the user to do some theorem proving if you wish to use nonlinear constraints.

I guess it comes down to what sort of end user you wish the language to accessible to. I can't imagine ( at this point in time ) the typical programmer being willing to learn about the curry howard isomorphism and theorem proving just in order to get their extra verified algorithm to type check. Somewhere down the line, one would hope that languages like epigram or ATS will eventually garner widespread industrial use in situations where verification is important.

... I can't imagine ( at this

... I can't imagine ( at this point in time ) the typical programmer being willing to learn about the curry howard isomorphism and theorem proving just in order to get their extra verified algorithm to type check. ...

ATS is less imposing than it might seem. You can use it just as you would SML or Ocaml if you elide the kinding operations and propositions (Propositions are sort of a static analog to types used in its theorem proving).

Verification is done in a pay-as-you-go manner, so there's no additional programmer burdon work unless you want to verify a property.

ATS is an exceedlying cool research language, but the current implementation feels pretty rough. E.g. the parsing and error messages are usually undecipherable, and its difficult to figure out how to actually use the theorem proving portion of it.

Um, what do you mean by that?

Um, what do you mean by that? An example would help even more than an explanation.

GUI libraries are good examples for what I said. The most usual approach is for the base Widget class to contain methods (virtual methods for C++) for mouse, keyboard and paint events. But this approach is wrong: not all widgets need to handle mouse up/down/enter/move/leave, key up/down and paint. Furthermore, if new events are added to the library (for example, focus in/out) then widgets must be re-engineered. The problems are created because a subtype that needs to handle focus in/out projects its requirement (focus handling) on the interface of its super-type, i.e. the widget must have an interface for managing focus in/out.

A better way for truly componentized software would be for a component to declare a connection of one or more of its input signals with another component's output signal either as part of its type (so as that the connection is static) or in run-time...then each time one component emits an output signal, another component catches it and acts accordingly. Overloading could be specified as re-declaring the connection with a different target. This mechanism would allow for building software like hardware: components inputs would be connected to other components' outputs. One could go even further and use the continuation style exclusively so as that execution is always continued from an emitted signal, just like in hardware.

Here is some code from an imaginative component-based programming language. Initially there are 3 components; a widget, a button, and an event manager:

(* a widget component; its purpose of existence is to provide the painting interface and
   widget geometry *)
component Widget
    (* widget dimensions *)
    int x
    int y
    int width
    int height
    
    (* window handle *)
    Window window

    (* output signal *)
    output draw(Window window, GraphicsDevice gd)
end component

(* button component *)
component Button
    (* button includes widget as a component;
       the widget's draw signal is connected to
       the button's draw signal. Interfaces
       must match between output and input signals.
     *)
    Widget widget with 
        widget.draw => draw

    (* paint signal *)
    input draw(Window window, GraphicsDevice gd)
    end input
end component

(* event manager component *)
component EventManager
    (* emitted when some window must be painted *)
    output paintEvent(Window wnd, GraphicsDevice gd)
  
    (* handles events *)
    input doEvent(Event event)
        switch event.type
            case EventPaint do
                paintEvent(event.window, new GraphicsDevice(event))
            end case
        end switch
    end input
end component

(* main application; creates a button window (supposing that no window frame is needed)
   then redirects paint events to the button window.
 *)
component Main
    (* our button *)
    Button btn = new Button
    
    (* our event manager; the paint event is sent to the button *)
    EventManager eventManager =>
       eventManager.paintEvent => btn.widget.draw

    (* just do events *)
    input main(string[] args)
        eventManager.doEvents
    end input
end component

Now let's say that we would like to extend our program with focus capabilities. Instead of declaring interfaces, overloading the interfaces for specific classes, providing concrete implementations etc, we simply provide a new event manager that knows how to handle focus events, and a new component that knows when focus changes or not:

(* focus component *)
component FocusObject
    boolean isFocused = false
    
    output focusChanged(Window window, boolean isFocused)
    
    input focusIn(Window window)
        isFocused = true
        focusChanged(window, isFocused)
    end input
    
    input focusOut(Window window)
        isFocused = false
        focusChanged(window, isFocused)
    end input
end component

(* focus event manager *)
component FocusEventManager
    output focusInEvent(Window window)
    output focusOutEvent(Window window)

    EventManager eventManager with
        eventManager.doEvent => doEvent

    
    input doEvent(Event event)
        switch event.type
            case EventFocusIn do
                focusInEvent(event.window)
            end case
            case EventFocusOut do
                focusOutEvent(event.window)
            end case
            default
                eventManager.doEvent(event)
            end default
        end switch
    end input
end component

Now all we have to do is create a new button component that knows how to draw itself according to focus and a new Main component that instantiates a focus event manager:

component FocusButton
    Button button with
        button.widget.draw => draw
        
    (* connections may also be closures, not methods! the following piece of code
       shows how to connect an object with a non-compatible signal through a closure *)    
    FocusObject focus with
        focus.focusChanged => 
           closure (boolean isFocused)
               button.widget.redraw()
           end closure
end component

(* new main application that can handle focusing *)
component Main
    (* our new focus button *)
    FocusButton btn = new FocusButton
    
    (* our new focus event manager *)
    FocusEventManager eventManager =>
       eventManager.eventManager.paintEvent => btn.button.widget.draw,
       eventManager.focusInEvent => btn.focus.FocusIn,
       eventManager.focusOutEvent => btn.focus.FocusOut

    (* just do events *)
    input main(string[] args)
        eventManager.doEvents
    end input
end component

The cool thing with all the above is that all components are independent and can be reused on a need basis without recompiling. There is no need for littering the code with interfaces, and message passing takes constant time since no run-time lookup is needed (ok, maybe some pointer adjustment); the compiler shall compile each component with special space for inserting ,replacing and deleting compile-time and run-time signals.

I apologise for the lengthy post, but I wanted to show a good example.

Sounds like occam

A better way for truly componentized software would be for a component to declare a connection of one or more of its input signals with another component's output signal either as part of its type (so as that the connection is static) or in run-time...then each time one component emits an output signal, another component catches it and acts accordingly.

This sounds suspiciously like channel communications model that is used in the occam language. The ability to reconfigure channel connections at runtime sounds very much like the mobile channels that Peter Welch and Fred Barnes have implemented in occam-pi.
Unfortunately, for some reason neither language has really taken off. Perhaps because people don't like the syntax (or because occam has an unfortunate association with the now-defunct Transputer). Welch has also implemented a similar programming model for Java in the JCSP library. Unfortunately, since JCSP is just a library its somewhat more cumbersome to use than occam-pi.

...or Concurrent C.

The nice thing about component-based programming with signals is that the abstraction can be carried over from static connections (i.e. inheritance) to distributed computing either for a CPU cluster or a network. Concurrent C also used typed channels for communication between threads.

Indeed. Concurrent C appears

Indeed. Concurrent C appears (from the papers I have glanced at) to have been heavily influenced by occam and Hoare's work on CSP, although they don't acknowledge this influence in the papers I've seen. However, Concurrent C doesn't appear to support the kind of fine-grained parallelism that is possible in occam, such as nested PAR constructs.

That said, I agree that the signal abstraction makes component-based programming much easier, and provides a nice, transparent way to migrate to a distributed system. In fact, when programming in occam on the Transputer it was extremely easy to add additional Transputers to a system, and reconfigure the occam process network to execute across the newly added Transputers.

Hmm, “output signals” in

Hmm, “output signals” in my mind are reminiscent of C# delegates. I thought I would approximate your example using C# for better understanding. But now I am puzzled by the Widget’s draw signal. Why is it declared as output and why does it become input in the Button component?

The widget's draw signal is o

The widget's draw signal is output because, when the widget must be drawn, it outputs a draw signal, i.e. it notifies the world that it needs to be drawn. In the Button component, the 'draw' signal is input, because it is not an overloaded method, but an input to the Widget's draw signal. It goes like this:

Widget.draw (output) => Button.draw (input).

The Button.draw signal could be named 'Button.paintMySelf' for example. An output signal is a like a C# event: it can have multiple dispatch targets. An input signal is a simple procedure. It can not have attached delegates to it.

An input signal can be wired to anything the programmer wants, as long as the called routine has the same interface. For example, one could rewire the Widget.draw signal to write a debug message each time is called, and then call the rest of the attached procedures.

Somebody better tell these guys...

...not to give their project the same name as one of the worlds' most lawsuit-happy companies. (Who themselves have to defend against numerous lawsuits from the record label with the same name, every time they do anything music-related--the most recent example being iTunes and the iPod).

At any rate, interesting. Hasn't CL's multi-methods worked (for or less) in a similar fashion for years? Or is there some nuance I'm missing here?

CLOS and Dylan

The procedure dispatch did immediately remind me of what I've read about CLOS, and Dylan as well (created by the same company Scott mentioned.)

Doesn't sound so great

The author's point appears to be that AOP constructs can be reduced to idioms in a language with fewer constructs. How, exactly, does replacing language constructs with idioms make learning the language easier? You've still got the same conceptual load; it's just that you no longer have language support for some of the concepts.

I thought that...

simulating language constructs in one language A with idioms in another language B was known as "greenspunning".

Especially if A is a dialect of Lisp. :P

Found an implementation of component-based programming.

This is an old topic, but if anyone is interested, I found an implementation of component-based programming here:

CompC++

I think that component-based programming deserves more attention, as I think it would solve many problems of OOP.

Seems a bit... superfluous.

C++ TR1 contains function objects and flexible binders to allow callbacks in much the same way CompC++ does without any syntax changes.

If you cannot wait for compiler vendors to support TR1, Boost have an implementation:

I disagree.

1) you are comparing apples and oranges:

a) Boost.bind is for binding parameters; i.e. currying, not for callbacks.

b) Boost.function is simple function wrappers, i.e. it does not allow pointers to delegates (i.e. to object + method).

c) Boost.lambda is anonymous local functions.

2) the syntax is far from elegant. Maybe that's personal, but I really dislike _1, _2 etc.

3) the library is based on various preprocessor tricks to offer a wide number of possible parameters...which means a very slow compilation.

My opinion is that such tricks like callbacks either belong to the language or the language must provide enough support so they can be elegantly expressed.

For example, if C++ had variable template arguments, it would be much easier to declare callbacks. Variable arguments are necessary, and that is why the C99 preprocessor defines macros with varargs.

Huh?

Boost.Function in combination with Boost.Bind (or Boost.Lambda) allows delegates. I've actually used this stuff to do component-based programming!

The reason I cited Boost.Lambda for advanced uses is that it contains a binder like Boost.Bind (but slightly different) and anonymous functions.

So with that out of the way most of your points are irrelevant or just plain wrong.

You are right about template varargs though... which is why Douglas Gregor has tried to implement them: See this.

Another problem which is even more critical to better binders is the lack of so-called "perfect forwarding" in C++. Without perfect forwarding you have to resort to tricks like boost::ref() to work around the fact that there are is no distinction between lvalue and rvalue references in the language. I should note, that the problem of differentiating between lvalue/rvalue references is theoretically solvable using only currently standard C++, but it requires an exponential (in the number of binder arguments) number of overloads.

EDIT: Spelink misteaeks

So with that out of the way

So with that out of the way most of your points are irrelevant or just plain wrong.

Indeed, you can make delegates out of boost.bind/function. But the result is ugly, to say the least, and too many preprocessor tricks are needed to reach the goal.

Another problem which is

Another problem which is even more critical to better binders is the lack of so-called "perfect forwarding" in C++. Without perfect forwarding you have to resort to tricks like boost::ref() to work around the fact that there are is no distinction between lvalue and rvalue references in the language.

take comfort in knowing that bjarne et al is actively pursuing the problem.

recent proposal: A Brief Introduction to Rvalue References

You should actually try boost


a) Boost.bind is for binding parameters; i.e. currying, not for callbacks.

b) Boost.function is simple function wrappers, i.e. it does not allow pointers to delegates (i.e. to object + method).

Actually, you can use boost.bind to make boost.function objects. And a member function is just a special case of a function that takes an inivisible this pointer as its first parameter:

// Make a function object that returns void and takes an int
boost::function<void (int)> f;

// Now make the function object be a pointer to an object + method
f = boost::bind(&MyObjectClass::MyMethod, myThisPointer, _1);

Now f will be a function that when passed an int, will call MyMethod on the myThisPointer object.


2) the syntax is far from elegant. Maybe that's personal, but I really dislike _1, _2 etc.

_1, _2, etc. are tools, not clunky syntax:

boost::function<int (int)> square;
f = boost::bind(&Calculator::Multiply, myCalculator, _1, _1);

// Same result!
int x = square(4);
int y = myCalculator->Multiply(4, 4);


3) the library is based on various preprocessor tricks to offer a wide number of possible parameters...which means a very slow compilation.

I would like to actually see some evidence of this. My project's compilation didn't seem slowed at all, but I didn't use boost::bind/function all over the place. I'm not even sure preprocessor tricks are really necessary, although I do believe boost implements _1, _2, etc. that way.


For example, if C++ had variable template arguments ...

How would that work? You'd need some way of iterating over the variable number of types... I suspect what you're thinking of may be possible with some non-obvious template tricks rather than a language extension. Class templates support default arguments, so to some extent you can define a variable number of types simply by defining a template with a lot of parameters that default to an empty class type.

In fact, you could make those empty classes not even take up any additional space with some clever trickery (inherit from them rather than instantiating them, the standard doesn't require parent classes to take up any space, even though it mandates that empty classes created as standalone objects take up 1 byte so all objects occupy a unique address).

/me starts getting implementation ideas...

well, yes, but...

_1, _2, etc. are tools, not clunky syntax

They are tools, no doubt about that. But the syntax is ugly. Especially when looking at the code a few days later and trying to quickly browse through it.

I would like to actually see some evidence of this. My project's compilation didn't seem slowed at all, but I didn't use boost::bind/function all over the place. I'm not even sure preprocessor tricks are really necessary, although I do believe boost implements _1, _2, etc. that way.

Boost uses the preprocessor to introduce function1, function2, ...functionN implementations of function. The actual macro used is BOOST_PP_REPEAT or something. The actual definition of the code is burried deep inside macros.

All the preprocessor processing certainly makes the compiler slower than it ought to be. Solutions like precompiled headers help solve the problem, but I have no idea how precompiled headers play with BOOST_PP_REPEAT macros.

How would that work?

It's not that difficult:

template <...> class Delegate {
    virtual void operator ()(__TEMPLATE_VAR_PARAMS__);
};

template <...> class Function : 
public Delegate<__TEMPLATE_VAR_TYPES__> {
public:
    typedef void (*FPtr)(__TEMPLATE_VAR_PARAMS__);

    Delegate(FPtr fn) : m_function(fn) {
    }

    virtual void operator ()(__TEMPLATE_VAR_PARAMS__) {
        for(int i = 0; i < sizeof(__TEMPLATE_VAR_ARGS__); ++i) {
            cout << typeid(__TEMPLATE_VAR_PARAMS__[i]).name();
            cout << __TEMPLATE_VAR_ARGS__[i];
        }
        m_function(__TEMPLATE_VAR_ARGS__);
    }

private:
    FPtr m_function;
};

Explanation:

  • ... is used for declaring variable template arguments.
  • predefined macro __TEMPLATE_VAR_TYPES__ expands to a comma separated list of the template parameters: T1, T2, T3, ... TN.
  • predefined macro __TEMPLATE_VAR_PARAMS__ expands to a comma separated list of parameters with the same types and order as the template parameters.

  • predefined macro __TEMPLATE_VAR_ARGS__ expands to a comma separated list of variables defined as template parameters.

  • both macros above can be used as pseudo-arrays for addressing individual elements.

Lets not mix up

Lets not mix up currying with partial application, no mattter how subtle the difference. Boost.Bind gives you partial application not currying.

complicated

This looks pretty complicated compared to just using classes, not to mention verbose. Is a solution to the expression problem the only thing this has over OOP?

It allows for greater reuse of components.

Personally I find it easier to make aggregates of objects than to use inheritance. The reason is that component-based programming unifies virtual methods, callbacks, single/multiple inheritance and mixins in one easy-to-understand mechanism; additionally, it allows for various types of connections not possible with classic OO.

If component-based programming is coupled with structural subtyping, then suddently object-oriented programming becomes a whole lot easier.

The reason is that

The reason is that component-based programming unifies virtual methods, callbacks, single/multiple inheritance and mixins in one easy-to-understand mechanism; additionally, it allows for various types of connections not possible with classic OO.

Could you expand on this? I'm having trouble figuring out your reasoning behind any of these.

Explanation.

Single/multiple inheritance, mixins and aggregation are methods of composition of objects out of other objects.

Virtual methods, callbacks, delegates, events, signals and slots, blocks/closures are methods of message passing.

The component-based approach unifies all these: it defines one type of message passing (the input/output ports), and one type of composition (aggregation) which covers all the others. A component has inputs and outputs, and components can be connected in arbitrary ways.

Just like functional programming proves the power of functional composition, so does component-based programming.

I would go as far as saying that functional composition and component composition is the same thing, provided that functions can enclose state.