Alan Kay on the Meaning of “Object-Oriented Programming” (2003)
purl.org
purl.org
In fact, the origins of OOP are basically what we would now call microservice architecture (CSP-inspired languages like Go being a specialisation of this). Each service can be as stateless or as stateful as it needs to be (without shared state) and services should be loosely coupled.
That's quite different to most large-scale OOP architectures, but it is possible to code in that style in any OOP language.
Heavy reliance on inheritance for code reuse is a whole problem class in itself that again has little to do with OOP and lots to do with the influence of C++.
[[myView onMainThread] setNeedsDisplay:YES];
result = [[someObject future] someMessage:arg];
combined = [[prefixes collect] stringByAppendingString:[suffixes each]];
The reason this is easy in Objective-C is because its brand of message passing is just (barely) powerful enough to qualify as message passing. In fact, if you squint just a little, you can see it as fully reified message passing with the common-case (a synchronous method is invoked) optimized.[1] http://en.wikipedia.org/wiki/Higher_order_message
[2] http://www.metaobject.com/papers/Higher_Order_Messaging_OOPS...
So if you want to embrace high performance (and concurrent), go message passing. Alan Kay's favor of late binding does not help performance, as method lookup at run-time dominates the cost then, but the fast systems are early bound, i.e. typed.
Of course, you are probably referring to NUMA, but people still actually use that.
Pure OO isn't very much desired in the HPC world, but then neither is pure FP.
Person --> Full Time Employee --> Manager
Person --> Contract Employee
Without inheritance assuming that salary calculation is the only thing which differentiates them.
Person HAS A IEmploymentRelationship
ContractEmployment IMPLEMENTS IEmploymentRelationship
FullTimeEmployment IMPLEMENTS IEmploymentRelationship
FullTimeEmployment HAS A IDirectReport
Manager HAS A Person
Manager IMPLEMENTS IDirectReport
And then salary() is a polymorphic function declared by the IEmploymentRelationship interface, where FullTimeEmployment instances use the manager somehow, and ContractEmployment doesn't.You can even put some sugar on that by having a salary() function on Person that calls the salary() function on its IEmploymentRelationship—but I wouldn't, for the same reason I wouldn't denormalize a relational database.
Those are not Smalltalk's definitions -- even though I think you're right on about Alan Kay's original inspiration -- and confusion can arise if we redefine terms.
sorry, but this is no true Scotsman fallacy. All these "bad implementations" is OOP, real OOP, not some idealized ephemeral non-existent Avalon. If an idea easily and more frequently than not lands itself to the bad implementations then there is something wrong with the idea. (I happen to come from a country which was pursuing what was looking like a pretty good idea - communism - which has got a lot of bashing during recent decades, due to "bad implementations" i guess, and as result it was critically rethought and now we know what it is not a good idea really)
Such a pity that this filtered essence about OOP was lost on me during formative years of learning OO-programming; for no fault of mine! It took me half a decade into professional programming in Java to realize the importance of these key concepts.
And the worse part is that most of the books/blogs start OO programming tutorial with examples that try to literally model the problem state using Objects (e.g., "Animals", "Shapes" etc.,).
I guess tutorials, classes just focus on these key goals and show how concepts such as "polymorphism", "inheritance" etc., are work towards achieving (or not) them. What generally happens is that one is taught about all these peripheral concepts and students are left to wonder the problems they are trying to solve.
Once you start thinking in terms of the API, and how you can design it so someone with minimal documentation could still use it (though you still document it!) you start wanting to hide the implementation etc, and all the other OOP ideas fall into place.
of course, I don't think it's something that can be taught. It's an evolution. When you first start programming, everything is unknown, so you don't have the brain power to focus on design. When you learn more, and you free up brain power you can start concentrating on these other things.
Bam. That is it right there. Java really messed this up.
Strong static typing and OO is an abomination.
But just to show
how stubbornly an idea can hang on, all through the seventies and
eighties, there were many people who tried to get by with "Remote
Procedure Call" instead of thinking about objects and messages. Sic
transit gloria mundi.
Can somebody explain to me what distinction he's drawing here? What's the issue with RPC that's solved by Objects+Messages?[Edit: I've removed most of my original comment since it pertained to messaging between machines, rather than within an application.]
Kay says,
OOP to me means only messaging, local retention and protection and hiding of state-process, and extreme late-binding of all things.
I read this to simply mean encapsulation of state + dynamic typing. RPC as I understand it is making a method call from one process to another, which makes no claim on how state and/or data should be handled and modeled.So I'm with you. Is Kay just arguing here for a specific way of thinking and talking about computing? Or are there some more concrete/tangible computing rules implied by what he's saying?
[1] Dataless Programming (http://www.rand.org/content/dam/rand/pubs/research_memoranda...)
I couldn't say if Kay would agree.
Kay gives the example of the Internet itself. A GET request for a URI used to be understood as an RPC: download the file at this path. But today GET requests are routinely abstracted. There is no literal directory /r/programming on reddit. Instead path components are better understood as parameters, i.e. arguments in a message send! And this lets them do anything they want, be implemented in any manner at all.
Unfortunately, this is one directional. Your browser makes an abstract request, but the server replies with literal code (e.g. JavaScript) that it wants executed on its behalf. The browser is sending messages to the server, but the server is making RPC calls to your browser.
This gives some insight into the relative stagnation of the client-side, compared to the explosion of server-side. Kay wrote that, if you communicate via messages, then "each object could be implemented using the programming language most appropriate for its intrinsic nature." We have that on the server, but are a million miles away from that with clients.
[...] the fundamental problem is that RPC tries to make a distributed invocation look like a local one. This can't work because the failure modes in distributed systems are quite different from those in local systems, so you find yourself having to introduce more and more infrastructure that tries to hide all the hard details and problems that lurk beneath. That's how we got Apollo NCS and Sun RPC and DCE and CORBA and DSOM and DCOM and EJB and SOAP and JAX-RPC, to name a few off the top of my head, each better than what came before in some ways but worse in other ways, especially footprint and complexity. But it's all for naught because no amount of infrastructure can ever hide those problems of distribution. Network partitions are real, timeouts are real, remote host and service crashes are real, the need for piecemeal system upgrade and handling version differences between systems is real, etc. [...]
[1] http://erlang.org/pipermail/erlang-questions/2008-May/035209...
In C# (or Java), it would look something like this:
interface Message : IEnumerable<Token>
{
}
public class Foo
{
public void Consider(Object sender, Message msg)
{
//possibly validate sender...
Executable result = this.Parse(msg);
if(result.IsValid)
sender.Consider(result.Execute(this));
else
sender.Consider(new MethodMissing());
}
private Executable Parse(msg)
{
//the ability to parse the message depends on the state of this object
}
}
The basic idea is that the object is always in control of what it does. Methods are extremely late-bound because the code for the method may not even exist until the object first creates it in response to a received message.But, the big idea is that an object is just a little computer, and in a computer system, a computer is the smallest thing that you want to recapitulate.
What exactly does he mean by that? How does one get rid of data?
> The B5000 almost did this via its almost unbelievable HW architecture.
I've heard about the B5000 numerous times here on HN. What was so fantastic about it?
Could someone explain what he meant here?
The auto "fits" into each of these different problem domains.
That probay doesn't clarify the connection, but at least you'll be pointed in the right direction! :)
"High school algebra" is usually limited to the study of real numbers and the operations of addition and multiplication.
In upper division undergraduate mathematics, you learn about other kind of algebras. For example, there is the set of regular polygons with operations such as rotation and reflection.
In OO, a class of objects defines the operations (methods) that are valid, and thus, a class is an algebra, and a set of classes is a family of algebras. I suppose that you would need a form of multiple-inheritance in order to have a family of algebras for an object.
The algebra of arithmetic is the most familiar, and it lets us determine that f(x) = 1 + (1 + (1 + x)) is equivalent to g(x) = ((1 + 1) + 1) + x for any integer x. In this case, the relevant algebraic law is associativity.
One abstract way to think about integers is as sets of equivalent arithmetic trees, so "3" is a stand in for the set {(1 + 1) + 1, 1 + (1 + 1)}.
Other kinds of objects that can appear in a program can have similar kinds of equivalences under various operations.
As a less familiar example, take axis aligned bounding boxes. Translation and scaling both map an axis aligned bounding box to another axis aligned bounding box. Intersection maps two bounding boxes to one smaller bounding box. "Convex closure" maps two bounding boxes to a larger bounding box--specifically, the smallest bounding box that encloses both of them.
There are then various algebraic laws that let us determine that differently expressed combinations of these operations are in fact equivalent.
If "∧" represents intersection, and A, B, and C are bounding boxes, then f(A, B, C) = (A ∧ B) ∧ C and g(A, B, C) = A ∧ (B ∧ C) are equivalent because intersection is associative.
If we apply the same translation to two bounding boxes and then form the intersection of the results, this is equivalent to intersecting the boxes, and then translating the results.
There are also interesting equivalences that relate intersection and closure.
This kind of broadly construed "algebraic" manipulation can be used to rewrite one program into an equivalent program that executes more efficiently, and this is one way of thinking about what an optimizing compiler is doing when it optimizes a program.
I wanted to get rid of data.
I didn't understand the monster LISP idea of tangible metalanguage then
If what you are working on originally looks understandable, you should be alarmed.
Also, if one approaches a thing by a burning desire just to implement one single thing on top of it they will probably have an internal model that is very much focused on the problem they are solving.This practical need can induce them to create a new formal model or just sidestep lots of non-issues that would be a burden to deal with.