News for hackers. Stuff that matters.
Re:Alan Kay on the Meaning of “Object-Oriented Programming” ... by boomlinde on Monday March 18, 2019 @10:33AM (#19421326)
> Making calls and sometimes they get picked up and sometimes not?!?

It's the basis of mainstream OOP as well. When you make a method call, you only know by loose protocol what effect it has, which objects it has an effect on or even whether it has an effect at all, as opposed to manipulating the data structure directly. It is the recipient of the message that decides what effect it has. This doesn't preclude having some mechanism to tell whether the message was accepted or not.

IMO the significant difference between something like Smalltalk-style message passing and Java-style method calling is that an unknown message in Smalltalk is a run-time "error"—which is passed as a #doesNotUnderstand message to the object that invoked the original message—while in Java it can be checked statically because the object definition specifies what messages it somehow handles.

A simple one-way message passing OO architecture in C, using a global set of messages:

    #define SEND(_objp, _msgp) (((struct Object *)(_objp))->dispatch((struct Object*)(_objp), (struct Message*)(_msgp)))

    enum MsgStatus list_dispatch(struct Object *self, struct Message *message)
    {
        switch (message->method) {
        case MSG_INSERT:
            insert_into_list((*struct List)self,
                             ((*struct InsertMessage)message)->index,
                             ((*struct InsertMessage)message)->value);
            return STATUS_OK;
        case MSG_DELETE:
            // ...
            return STATUS_OK;
        default:
            // Maybe the parent implements the message
            return SEND(((*struct List)self)->parent, message);

            // or we decide that this isn't a valid message for this object
            return STATUS_NOTUNDERSTAND;
        }
    }

    // ...

    // Construct and send an INSERT message to someList
    createInsertMessage(&insertMessage, 0, "hello");
    status = SEND(somelist, &insertMessage);
Now, every object is encoded by a struct starting with an Object struct which contains a generic dispatch function pointer, so that each object can encode their own dispatch logic and handle whatever messages they receive as they see fit. In this case, the ListMessage struct also has a parent field, which it defers unknown method calls to. If it did not, it could just return a method-not-found status code. It doesn't have to know whether the parent implements the message.

Likewise, every message starts with a Message struct which contains the message type/method name. Depending on the type it can be cast into more specific messages.

An interesting aspect of this architecture is that it doesn't explicitly implement any kind of inheritance logic. You let the objects handle that themselves. A possible benefit of having any object accept any kind of message is that you decide whether it's an error that an object could not receive a message or not. Maybe you don't care that the object couldn't receive e.g. a NOTIFY_CHANGE message.

Re:Alan Kay on the Meaning of “Object-Oriented Programming” ... by 0815test on Monday March 18, 2019 @10:49AM (#19421480)
There's just not much about this that's unique to OOP. It's just defunctionalization, combined with "add another layer of indirection" to implement dynamic dispatch and something like existential types. It can definitely be useful in some cases, but the way OOP proponents frame this does not seem very helpful. Always remember the YAGNI!
Re:Alan Kay on the Meaning of “Object-Oriented Programming” ... by boomlinde on Monday March 18, 2019 @04:48PM (#19425125)
It's true that there is not much about it that's unique to OOP, but that can be said of most high level programming concepts. They're just the cobbling-together of lower level abstractions.

I just wanted to demonstrate why message passing via dynamic dispatch isn't so fundamentally different from static dispatch, conceptually, and to which extent it really is "making calls and sometimes they get picked up or not" compared to any other dispatch mechanism.

Kay might disagree with this on the basis that late binding is important and that an object should not need to know what messages it will be passed at run-time; that the message is just that, a message rather than a contract. The only contract that exists is that an object should be able to receive a message, any message. But even with checked method calls like in Java I think the fundamental idea that you shouldn't have to consider what effect a method has on an object remains. What a language like Java adds is contracts like abstract classes or interfaces, essentially a way to tell the type checker what messages may be passed to an object.

I agree that this approach can be useful in some cases and also think that you most likely not only AGNI, but that it will cause serious headaches and existential dread when applied to the wrong problem. So will Java. IMO OOP is suffering a bit of a backlash not because it's a particularly bad, but because like a Swiss army knife it looks deceptively applicable to a wider range of problems than it really is.

Re:Alan Kay on the Meaning of “Object-Oriented Programming” ... by jimbokun on Monday March 18, 2019 @07:17PM (#19426327)
"It's just defunctionalization, combined with "add another layer of indirection" to implement dynamic dispatch and something like existential types."

But isn't this a pretty good working definition of "Object Oriented Programming"?

Re:Alan Kay on the Meaning of “Object-Oriented Programming” ... by hota_mazi on Monday March 18, 2019 @07:33PM (#19426448)
> It's the basis of mainstream OOP as well.

Not at all!

If I call a.foo(), I know for a fact foo() will be called. That statement is not just going to be ignored and dropped on the floor.

What it will do, now nobody has any idea, whether the call is local or remote.

Re:Alan Kay on the Meaning of “Object-Oriented Programming” ... by boomlinde on Tuesday March 19, 2019 @08:52AM (#19430259)
> If I call a.foo(), I know for a fact foo() will be called.

Likewise, when you send the message foo to a, you know it will be received. In both cases, the only way you'll ever have an idea of its effect, if any, is by knowing the state and implementation of a at the point of sending the message or calling the method.

What is different is how you communicate that a method might have had some effect. In Java I'll know at build time whether a method definitely wasn't considered because of its type system. It won't compile if I have not defined the method being called. In a dynamic language like Python, calling a method that is not defined results in an exception. In Smalltalk, an Object receiving a message with an unhandled method will send a #doesNotUnderstand message back to the sender. The default behavior of an Object receiving the #doesNotUnderstand message is to raise an exception. Unless you explicitly override the #doesNotUnderstand method, this becomes an implementation detail and really isn't much different, especially compared to dynamically typed languages with OOP facilities.

So as I said before, the message passing mechanism doesn't preclude communicating whether it was handled. Messages get ignored if that's what you want. Java IMO really has the same potential for run-time uncertainty thanks to exceptions.