In Java, many projects overuse getters and setters. Getters and setters break encapsulation. More so public setters since they allow any piece of code anywhere can change the value of an object's internal state at any time.
Consider a class Person. A person has a name, SSN, salary. Let's assume name and SSN cannot be changed. What about salary? We don't have to add a setSalary() method. Instead, we should have something like: public void acceptNewJob(Job newJob) { salary = newJob.getSalary(); }
Yep, and that’s pretty much the simplest and most modular design for that problem.
This is one of the cases where OOP(whether using methods or messages) leads to more coupling and less flexibility.
I do like your use of the word "anemic" to describe the method free classes that pass for objects these days.
Everything you say is confusing to me, but I'll just pick on one:
> An Object-Oriented language according to Alan Kay (according to me) then is one where the only way objects can communicate with other objects is by calling methods i.e. by message passing, never by modifying the objects directly from their outside.
What guarantees that when I send a message to an object, that object won't decide to change itself in response?
In other words, that distinction you are trying so hard to build between message passing and function calling is nonexistent.
I don't think that's what the other commenter is saying.
They're saying that internal state is not directly manipulable from external sources. So an object `x` cannot have a method that takes in another object `y` and does `y.foo += 3`. Instead, it must do something like `y.addFoo(3)` to accomplish the goal.
This is superficial in some sense, but then every distinction between various programming languages is superficial if you look at it right. :)
The idea is that the object itself is the only thing which can manipulate its internal state. Therefore, to use these objects, the programmer must have imbued them with the necessary methods. This is restrictive (you have to implement the methods before you can manipulate the state), but this is the core design principle I think the other commenter is trying to tell you about. Objects cannot be manipulated willy-nilly; they must have implemented some method which can be called from the outside. This restriction creates a much more solid barrier of distinction between the responsibilities of the various objects at play.
Control structures
Control structures do not have special syntax in Smalltalk. They are instead implemented as messages sent to objects. For example, conditional execution is implemented by sending the message ifTrue: to a Boolean object, passing as an argument the block of code to be executed if and only if the Boolean receiver is true.
The following code demonstrates this:
result := a > b ifTrue:[ 'greater' ] ifFalse:[ 'less or equal' ]
For example in Kotlin:
class Boolean {
fun ifTrue(closure: -> ())
fun ifFalse(... whatever)
}
a.ifTrue { /* do something */ }IIRC, Smalltalk has Boolean class and two subclasses of Boolean: True and False. There is a single method with two arguments (:ifTrue:ifFlase). The method is then overloaded. True calls ifTrue argument. Flase calls ifFalse argument. This is happening dynamically, at runtime. Again, the mechanism is generic enough to fully replace all use cases of "traditional" if/else constructs.
Clearly, you haven't thought this through.
Edit: People here would do well to read this: https://pozorvlak.livejournal.com/94558.html
----
My best guess, especially given Alan Kay's statement "I wanted to get rid of data" is that it is more of a style of coding than a technical distinction. I could be misinterpreting him and it would be nice if he would mention a small and concrete example that illustrates the True Meaning of Messages.
I see it as the style of coding you run into reading AST-processing code in Java, where, because the language lacks discriminated unions and pattern matching, you don't simply look at the `expression` object you're given and see that it is an `AdditionExpression(LiteralInteger(1), VariableName("x"))`. Rather, you politely ask the expression to describe itself to your own `visitor` object, and the structure of the expression reveals itself by calling `visitor.VisitAddition(leftSide, rightSide)`, and the left side calls `visitor.VisitLiteral(1)` and the right side calls `visitor.VisitVariableName("x")`. Data has been reformulated into a series of calls.
That is the same pattern of coding as having booleans be defined by whether they call the ifTrue or ifFalse branch.
Subjectively I despise programming that way and much prefer using a language that lets me define my data structures immutably and precisely without code, then process them with compiler guarantees that I handle all cases. Reading the data types is the fastest way to understand what a piece of code is trying to accomplish. As Fred Brooks said:
> Show me your flowcharts and conceal your tables, and I shall continue to be mystified. Show me your tables, and I won’t usually need your flowcharts; they’ll be obvious.
(a == 1).ifTrue {
// ...
}.else {
// ...
}
is standard Kotlin with its DSL syntax.`ifTrue` and `else` are extension methods added to the `Boolean` type.
You know that there have been new developments in PLT since Smalltalk, right?
You don't seem to understand what this discussion is about. Extension functions in Kotlin are statically dispatched, so while they are a nice feature, they are completely irrelevant here.
It's not about how your invocation code looks like. The important part is that at some point the code needs to make a decision whether to invoke "if" case or "else" case. Smalltalk achieves this by having two objects/classes (True and False) that handle the same message differently. The implementation of those objects does not have a hidden control flow statement. Your code would.
General-purpose programming languages, by their very nature, cannot provide us with constructs that are specially suited to our domain; they can only provide us with generally-useful building blocks, like booleans, integers, functions, etc.
We could try to solve our problems using only those languge-provided constructs directly, e.g. using maps-of-lists-of-booleans-of-whatever. In that case, we get "callback hell", pyramids/triangles of doom, etc. because the same code needs to implement our solution and encode information about our domain.
Alternatively, we can use those language-provided constructs to write our own domain-specific constructs; then use those domain-specific constructs to solve our problem.
I've worked with people who avoid this second approach because understanding the solution requires learning those domain-specific constructs, whereas in the first approach we already know how built-in constructs like booleans work.
The nice thing about Smalltalk in this example is that if/then/else, loops, etc. are not built-in; they're library code. This takes them off the pedestal that they occupy in other languages, and makes it easier to think about replacing them with our own tailor-made alternatives.
(Note that this isn't specific to message-passing style OOP; we can also do this with e.g. recursive functions for loops, induction schemes (e.g. Church encoding) for control flow, etc.)
To better understand what Alan Kay is talking about it helps to know a specific fact about Smalltalk, the language he invented. Unlike in C++ or Java or JavaScript Smalltalk objects can not have public data-members. They can only have methods. Methods can read and write the "instance variables" inside the object, no-one else except the object itself can.
This means that objects can only communicate by calling methods. They can not read or write data stored into another object. Thus they are totally ignorant about the "implementation" stored inside other objects. They can "send it messages" meaning call its methods. But because all communications with an object are processed by the methods of that recipient object, the recipient object itself is wholly responsible for the MEANING and effect these method-calls have. "Message-passing" is an apt metaphor for such a thing.
This is "message passing" because it is the recipient object who must ALWAYS INTERPRET ALL messages it receives. Therefore method-calls have the semantics of "messages".
Whereas in Java and C++ and JavaScript the caller of an object can also directly modify other objects without the object being modified being "aware" it is being modified. The "meaning" of such modifications is then determined by whoever makes them. Say I store into your object the property "you.age = 253". But what does that mean what does that signify? Only the other object which stored that value "knows" why it did that, what it "means" what implications it should have for the later progress of the program.
So even though in Java etc. you can implement message-passing simply by calling methods, you can also do other things to the object from their outside than only send them "messages". An Object-Oriented language according to Alan Kay (according to me) then is one where the only way objects can communicate with other objects is by calling methods i.e. by message passing, never by modifying the objects directly from their outside.