
“What Alan Kay Got Wrong About Objects” - mpweiher
https://blog.metaobject.com/2019/11/what-alan-kay-got-wrong-about-objects.html
======
bitwize
Kay was at least as inspired by _biological_ processes -- bacteria
transmitting chemical signals to one another, for instance -- as he was by
computer networks.

I think the big thing that Kay missed was asynchronicity. What Kay was
thinking of when he coined the term "object oriented" \-- rather than C++ --
was a sort of synchronous actor model in which the actor would always wait for
a response after sending a message. This maps nicely onto function calls, but
considerably more power can be had by letting the actor optionally continue
doing stuff while awaiting a response. Bacteria continue to metabolize after
sending chemical signals to their brethren after all!

As I've seen it said, Erlang is Smalltalk done right.

~~~
imode
What's interesting is that there's no "destination" for these chemical
signals, they're just emitted into the void. There's no sense of
sender/receiver, which has some correspondence to the blackboard model[1,2].

1\.
[https://en.wikipedia.org/wiki/Blackboard_system](https://en.wikipedia.org/wiki/Blackboard_system)
2\.
[https://en.wikipedia.org/wiki/Blackboard_(design_pattern)](https://en.wikipedia.org/wiki/Blackboard_\(design_pattern\))

~~~
chongli
Yeah, exactly. The synchronous, one-to-one method calls of C++ or Java bare
basically no resemblance at all to bacteria chemical signals. The former are
essentially functions which dispatch on the first parameter.

The blackboard model isn't quite accurate though. Chemical signals have
spatial locality, propagation delay, and half-lives. An asynchronous, peer-to-
peer mesh network of actors would be a closer approximation to the bacterial
signal model.

~~~
imode
Something like a "place-based" tuple space would be more accurate, yeah.

------
abernard1
While it's always dangerous to criticize a computer legend, I would add one
more thing that I believe Alan Kay "got wrong about objects": objects are
extremely bad at representing most types of problems in business software.

I mean this in regards to the "true" message-passing type of actor objects,
and not OO as it came to be post-C++ and Java. The reason being is that actors
1) fundamentally involve themselves with state and time, and 2) connect
subject and recipient together directly.

In relation to 1), most business problems involve _data_ processing, and the
thing about data is it is immutable. It's essentially a solid state type of
activity, and bears no resemblance to the organic, messy world of biology
where things are changing. For problems like these, you really want to avoid
state in your program, and persist state after data transformation in an
actual database. Concepts like stateful actor supervision hierarchies, and
what to do with clearing mailbox state when something goes wrong are
fundamentally complex. Those concepts are also broadly unnecessary (and
arguably harmful) for most request/response or async pub-sub type software. I
can't count the amount of time I've wasted redoing systems on an actor model
to be a simple "stateless" request model. On all of those occasions, the model
that didn't persist state in-app was more reliable, easier to understand, less
code, and more maintainable.

With respect to 2), actors basically violate all concepts of dependency
injection. Actors need to know exactly where they're going (or you can add a
proxy, and now your state graph is even more complicated), and even with
message passing, program flow is dependent upon _time_ and the order in which
a program is run. This is a large step backwards in my opinion.

I feel that languages like Elixir that pride themselves on stateless,
immutable functions, have a deep contradiction internally embracing the actor
model, because it is none of those things. Sadly, I also predict that this
generation of Elixir programmers will learn the lessons of the Waldo paper the
hard way: you can't just throw an actor model over the network and have it
work great. (I think it's especially interesting that most of the success
stories around modern day actor systems involve problems that can withstand
data loss: telephones, IOT, content, media streaming, games, etc.)

~~~
paulddraper
> most business problems involve _data_ processing

To quote two other computer legends, Fred Brooks and Linus Torvalds are right:
data not behavior is the more crucial part of programming.

Actors focus on the behavior, whereas the data is the part that is _really_
important.

What `git log` does isn't all that important relative to how the git object
model is structured, as the latter dictates the former.

> I can't count the amount of time I've wasted redoing systems on an actor
> model to be a simple "stateless" request model.

So much this. So often people forget that "it's just code". It can run on a
toaster, or a mainframe, or a VPS, or a Docker container, or a Lambda
function. The lion's share of code should be structured as input => output in
the most straightforward way possible.

~~~
Fice
«What if "data" is a really bad idea?» — Alan Kay,
[https://news.ycombinator.com/item?id=11945722](https://news.ycombinator.com/item?id=11945722)

~~~
paulddraper
Ah, it would seem that is in fact an underlying point of disagreement.

------
Animats
Kay was into discrete-event simulation. There's a nice example of that on an
Alto, a little hospital queuing simulation, in "Personal Dynamic Media". That
concept comes from Simula-67, a variant of Algol-60 used for simulation.

It turns out that discrete-event simulation isn't used much, and that async
model isn't all that useful for other things. If you've never seen a discrete-
event simulation, here are some in Flash, of Disney ride line management.[1]

[1]
[https://www.themagical.nl/simulations](https://www.themagical.nl/simulations)

~~~
Aperocky
You maybe right about discrete event simulation, having created one for my
academic research years ago, I had the feeling it wasn't as useful (there are
so many things you might tune to make it spit out what you want), but the same
model is fun for making random simulations (games).

------
ghjnut
Actor-based programming really interests me. The concepts behind erlang and
smalltalk seem to be the closest to an ideal model for the amount of
distributed computing power we have today.

It seems like we should be able to formalize a generic meta-programming
language that describes discrete components. 'actors' would be concepts close
to functions that receive inputs and return outputs, everything inside would
be generally considered synchronous. These actors speak to other actors via
addresses. That idea was all outlined by alan kay. Furthermore, these actors
can live anywhere. They can be running on a single CPU, live across multiple
threads, cores, processors. Ideally you just throw more processors or remove
processors from the mix and the system distributes.

Where the rubber meets the road is all the communication mediums. The lowest
abstraction is your actor return address is a stack pointer. The highest is
the return address is another system (what we currently do with RESTful
communications).

Once all the inter-actor controls are sorted out, there would need to be a
system of dynamic resource distribution. The profiler/scheduler should be able
to identify things like \- this actor is handling 85% of traffic, distribute
the actor to 6 cores \- the cost of the route from a core to a core on the
same processor is X, the cost of the route to a core across a network is Y \-
distribute actors that have the most cross communication as closely as
possible \- payload size would also need to come into account

on top of that, tooling that identifies workload-specific needs could also be
identified: \- this set of actors should be considered critical and available
on % processors \- take into account things like inter-region availability.

A lot of these concepts have already been hashed out and you notice the
parallels to things like network architecture. Ideally in the end a 'system'
would simply be a pool of usable resources e.g. SYSTEM1: my laptop, an AWS
server, my phone, my watch. Computation work is unevenly distributed to the
system based on route costs, computational power...even storage capabilities
and peripheral access (printers, cameras, etc). A new actor would get
initialized in the network and it could be scheduled on your desktop or your
tablet. Eventually your system would just become an amorphous workload.

My desktop might begin distributing subsets of things that currently run
locally to my AWS server because it's closer to the public API i'm accessing.
If actors were generic enough they might be identified and made a reusable
pool for multiple applications.

Sorry for the stream of consciousness.

~~~
mgummelt
> Once all the inter-actor controls are sorted out, there would need to be a
> system of dynamic resource distribution. The profiler/scheduler should be
> able to identify things like - this actor is handling 85% of traffic,
> distribute the actor to 6 cores - the cost of the route from a core to a
> core on the same processor is X, the cost of the route to a core across a
> network is Y - distribute actors that have the most cross communication as
> closely as possible - payload size would also need to come into account

It's not that simple. Objects that can assume locality are written differently
than those that can't. The optimize for fate sharing, low latency, etc. If you
have just have a mesh of floating objects, you must remove all of those
optimizations.

------
ProfHewitt
The title of this post is _very unfair_ to Alan, who has made important
contributions. For example the SmallTalk browser was extremely innovative
leading to modern Integrated Development Environments that have taken over
software development. Also, SmallTalk was the first to use Simula class
hierarchies for graphics, which are now used everywhere.

Objects as conceived in Simula-67 are _not_ universal primitives of digital
computation. However this was remedied in 1972 with the invention of Actors.

 _It is very important that Actors rigorously formalize the rules for digital
computation._ See the following:

    
    
        https://papers.ssrn.com/sol3/papers.cfm?abstract_id=3418003
    
        https://papers.ssrn.com/sol3/papers.cfm?abstract_id=3459566
    

In this way, computer systems _themselves_ can participate in discourse with
humans about the nature of digital computation and associated software
systems.

Every important scientist (including Einstein) made numerous errors. Fermi
received the 1938 Nobel prize [Fermi 1938] for the discovery of the
_nonexistent_ elements “Ausonium” and “Hesperium”, which were actually
mixtures of barium, krypton and other elements. I have made quite a number of
errors myself, although I am certainly _not_ of the caliber of Einstein or
Fermi! It is important to find and rectify errors ASAP. In order to make
progress, we _must_ make errors.

Reusable Scalable Intelligent Systems _cannot_ be implemented using the
current common programming practice of stateless sever code + relational data
base. See the following:

    
    
        https://papers.ssrn.com/abstract=3428114

~~~
mpweiher
Hello Professor Hewitt,

Hmm...I don't quite understand your criticism, particularly as you yourself
point out that "every important scientist (including Einstein) made numerous
errors", and go on to describe some of those errors.

The fact that Alan is a towering figure who has contributed more to this field
than I (and most people) can ever hope shouldn't mean that we cannot point out
where we believe such an error was made, should it? That's not how science,
even computer science, is supposed to work.

As a matter of fact, it seems even _more_ important in the case of such an
influential figure.

Of course the article points out that it was (a) a "brilliant" (quote from the
article) construction and (b) the fact that it was wrong wasn't really Alan's
fault, because he didn't have any large computer networks to look at, so (c)
using the same brilliant construction with up-to-date inputs gets you a better
answer.

The claims you make about the impossibility of things that are clearly being
done seem a bit strange.

------
mgummelt
Doesn't scaling network interfaces down to be used in local processes present
all the same problems as scaling procedure interfaces up? You still have to be
aware of which objects are remote and which are local.

~~~
ProfHewitt
Runtime system knows approximate latency to intended recipient Actor of a
message, e.g., this core, nearby core, nearby chip on the package, nearby chip
in the same server, nearby server in the same rack, nearby server in the same
datacenter, another datacenter, another IoT, etc. However, Actors can
dynamically move and so the answer can change over time.

~~~
mgummelt
Latency differences aren't just a difference in degree. They're a difference
in kind. Some interactions have to be sufficiently fast or they shouldn't
happen at all. A runtime that minimizes global latency guarantees isn't
sufficient. You also need to guarantee that certain individual Actor
interactions are sufficiently fast, which is only possible through colocation.
You could add a colocation constraint to your Actor scheduler, but now you're
pretty much back to where you started.

And latency is only one of the problems. Partial failure is another. It's
often convenient for authors of colocated actors to assume fate sharing. If
they can't, they have to handle a much wider set of failure modes.

~~~
ProfHewitt
Do you think that the "difference in kind" should be frozen in application
source code?

I agree that latency needs to be carefully controlled. But the software
engineering can be complex!

~~~
mgummelt
Often, yes. Parameterization adds complexity, so for interactions I _know_
must always be colocated, it makes sense to hard code the provisioning of a
local actor.

~~~
ProfHewitt
Good luck finding all the places that various kinds of colocation have been
hard-coded, e.g., same core, nearby core, same chip, same package, same rack,
same datacenter, etc.

------
thewarrior
Interesting post OP. From reading your paper about storage combinators it
seems to suggest that this has been used in the Wunderlist app.

It sounds quite promising in theory but more people would need to try it
before we know how beneficial it is.

Would it be possible to open source the library or be able to read an actual
code sample ?

Might help popularize it better than if this knowledge were in a paper.

~~~
mpweiher
Thanks!

The paper actually talks a little about results: reports were of code size and
productivity improvements in the 50% / 2x region.

I actually met one of the guys who had provided that written feedback a little
later, and he told me that although he had written 2x, the actual results were
more like 10x. The reason he wrote 2x was that he thought 10x would not be
believable/believed. I have a feeling he is right about that ;-)

The libraries _are_ open source, at
[https://github.com/mpw/MPWFoundation](https://github.com/mpw/MPWFoundation)
(The lively project also has a version [https://lively-
web.org](https://lively-web.org))

The Stores/Storage Combinator base implementation is in the Stores subproject,
so
[https://github.com/mpw/MPWFoundation/tree/master/Stores.subp...](https://github.com/mpw/MPWFoundation/tree/master/Stores.subproj)

There are quite a few more stores in Objective-Smalltalk
([http://objective.st](http://objective.st),
[https://github.com/mpw/Objective-Smalltalk](https://github.com/mpw/Objective-
Smalltalk)), which provides linguistic support for stores/storage combinators
with Polymorphic Identifiers.

The Objective-Smalltalk project also has a number of example compositions, but
I do need more sample code.

------
carapace
FWIW, in re: distributed Smalltalk, check out Croquet.

> Implemented in Squeak Smalltalk, Croquet supports communication,
> collaboration, resource sharing, and synchronous computation among multiple
> users. Applications created with the Croquet software development kit (SDK)
> can be used to support highly scalable collaborative data visualization,
> virtual learning and problem solving environments, 3D wikis, online gaming
> environments (massively multiplayer online role-playing games (MMORPGs)),
> and privately maintained or interconnected multiuser virtual environments.

> Since release of the Croquet SDK in 2007, the SDK has not been under active
> development. All further development of the technology has occurred under
> the Open Cobalt effort.

[https://en.wikipedia.org/wiki/Croquet_Project](https://en.wikipedia.org/wiki/Croquet_Project)

------
mgummelt
> each Smalltalk object is a recursion on the entire possibilities of the
> computer.

I've heard Kay say this a few times, but it's always seemed wrong. Self
similarity is a powerful scaling mechanism, yes, but Smalltalk objects and
computers aren't self-simlar. Computers are Turing complete. They can become
any machine. That's what they're good for. Objects can't.

~~~
ProfHewitt
Objects as originally conceived in Simula left out concurrency, i.e., region
of mutual exclusion of an Actor.

See the following:
[https://papers.ssrn.com/sol3/papers.cfm?abstract_id=3418003](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=3418003)

~~~
mgummelt
I'm unsure what this has to do with my comment.

~~~
ProfHewitt
Simula originated the terminology "object", which was then adopted in later
versions of SmallTalk. Objects differ in fundamental ways from Actors.

~~~
mgummelt
What does this have to do with Kay's claim that objects are "mini-computers"?

~~~
ProfHewitt
What is your precise definition of "object"?

~~~
mgummelt
I don't have a precise definition, but regardless which of the many candidate
definitions you choose, none are "mini-computers". A computer, if that term is
to mean anything at all, is Turing Complete. It's a machine that can become
any other type of machine. And unless your object (or actor) happens to be
emulating a Turing Complete machine, it's not a "mini-computer".

The only self-similar architecture we have in computing is the virtual
machine, not the "object", whatever that word means.

~~~
ProfHewitt
What exactly do you think that an Actor cannot do? Trivially, an Actor can
implement a Turing Machine. However, there are some Actors that _cannot_ be
implemented using a Turing Machine, e.g., an Actor with unbounded
nondeterminism.

~~~
mgummelt
Yes, an Actor (or object) can implement a Turing Machine. But most don't. Most
are simpler machines. So this statement by Kay, for instance:

"each Smalltalk object is a recursion on the entire possibilities of the
computer."

is incorrect.

~~~
ProfHewitt
Difficult to know since you don't specify exactly what an "object" is. Seems
more reasonable that "Actors are a recursion on concept of interacting
computers."

~~~
mgummelt
As I said, pick your definition of object (Java objects, Smalltalk objects,
actor, etc.). Unless it's "Turing Complete machine", which isn't anyone's
definition of object, you can't equate objects with computers. Saying objects
are computers is like saying objects are bicycles. Some of them are, yes, but
that's not the point.

What's your definition of computer?

~~~
infinite8s
I think that was Alan's original conception of objects (at least as could
could be implemented in Smalltalk-72).

~~~
mgummelt
No, most Smalltalk objects were not Turing Complete. Take numbers. Numbers are
objects in Smalltalk. They're not Turing Complete.

~~~
infinite8s
He seems to hint a bit what he meant in this HN comment -
[https://news.ycombinator.com/item?id=11946935](https://news.ycombinator.com/item?id=11946935).

Also remember that what most people think of Smalltalk (ie Smalltalk-80)
doesnt seem to be what AK thinks of Smalltalk (I get the feeling that the
Smalltalk-72 approach is closer to the ideals he had in mind).

------
fmakunbound
In-process REST sounds horrible inefficient.

~~~
paulddraper
[https://en.wikipedia.org/wiki/Microkernel](https://en.wikipedia.org/wiki/Microkernel)

------
mgummelt
Can you briefly describe what you mean by "In-Process REST" and what the
benefits are? I tried to read your slides but couldn't understand them. Are
these new in-process interfaces asynchronous? Or are they synchronous
interfaces that adhere to REST principles?

~~~
mpweiher
I talk about this in the _Storage Combinators_ paper[1]

In-Process REST essentially means applying the applicable mechanisms of REST
in-process:

1) URIs

2) a few well-defined verbs

Benefits:

1) Common, concise and familiar API for talking about storage. (Check how much
API surface there is for talking about storage variations in typical OO
libraries. In Cocoa, for example, it's atrocious).

2) Paths. For some of the benefits of paths in general purpose programming,
see _The Programming Language Aspects of ThingLab_ [2]

3) Avoidance of the architectural mismatch between storage-oriented problem
domains (most of them), and procedurally-based implementation technologies.

4) Composability: this is the heart of the _Storage Combinators_ paper, you
can plug these things together to obtain the desired functionality.

5) Performance, at least compared to other ways of getting similar benefits,
such as (over-)used of filesystems, FUSE, Microservices for architectural
reasons etc.

...

[1] [https://www.hpi.uni-
potsdam.de/hirschfeld/publications/media...](https://www.hpi.uni-
potsdam.de/hirschfeld/publications/media/WeiherHirschfeld_2019_StorageCombinators_AcmDL_Preprint.pdf)

[2]
[https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.90...](https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.90.2858&rep=rep1&type=pdf)

~~~
mgummelt
I'll check out the paper, but at a glance, "a few well-defined verbs" seems to
just mean you've introduced a set of standard storage interfaces, right? If
so, calling this REST, to the extent which that word means anything at all,
seems a bit of a stretch.

~~~
superdude264
I just finished reading the paper and that’s what it looks like to me. It’s a
CRUD interface w/ multiple implementations (proxy, cache, route, serialize,
filesystem store, memory store), which they create pipelines out of using some
syntactic sugar in the Objective-Smalltalk language. This syntactic sugar,
discussed in their paper on ‘polymorphic identifiers’, allows you to use the
same syntax for writing content to a file as you would writing to a key in a
map or a field in an object. If you look at the pictures / tables in this
paper, you get a general idea of what they are doing (e.g. replacing the
filesystem store with a memory store while running tests). These dynamically
dispatched processing pipelines are powerful, but can be hard to follow (which
is true of dynamically dispatched processing pipelines in general). The
power/obfuscation is multiplied by the convenient syntax of the language.

My opinion is that the actual innovation is the ‘polymorphic identifiers’ they
introduced in their previous paper, which is definitely worth a read as my one
line description of it can’t really do it justice. It’s kind of like being
able to overload the assignment operator. Once you have that kind of feature,
it’s sort of a no-brainer to say ‘Hey, all I/O (variables in memory,
filesystems, etc) should use the same interface’.

~~~
mgummelt
For 10 years, people have been talking about REST as if it means something. I
could never figure it out. If it means anything more than CRUD, it's lost on
me.

~~~
superdude264
I've had the same feeling and finally came to a few conclusion that Fielding's
REST architectural constraints lead to client applications that are required
to utilize undefined URIs for performance gains. The reason true RESTful APIs
are scarce as compared to HTTP/JSON APIs is due to API developers recognizing
this issue and choosing to deal with it by making URIs part of the API
contract. The REST community has offered no additional guidance or answers
other than to point out (correctly) that HTTP/JSON APIs aren't truly RESTful.
That is OK.

Here is a much longer comment on reddit where I go through Fielding's thesis
and a few other writings and show that following the constraints pretty
naturally leads to the outcome above:
[https://www.reddit.com/r/programming/comments/2oyj65/api_des...](https://www.reddit.com/r/programming/comments/2oyj65/api_design_guide_creating_interfaces_that/cmvcg6y/)

------
signa11
question: would you consider STL (standard-template-library) closer (in some
sense of the word) "philosophically" to theory of objects than 'vanilla' OO ?

i mean, _i_ always find it _intriguing_ that in OO, world can be decomposed in
terms of interfaces that vary on a single type, whereas, imho, what you
_really_ need is to parameterize your program by the structure of data that it
manipulates i.e. a notion of bunch of interfaces spanning across multiple
types...

------
crimsonalucard
OOP feels right because it's an imitation of reality. In the reality we live
in... a verb cannot exist without a noun. Think about it: how can there be
"movement" without the "thing that moves." OOP makes sense from this
perspective.

If however we think of abstractions outside of reality as we know it. Things
like imaginary numbers, negative numbers and non-euclidean geometry appear.

Outside of reality an Object can be further divided into two things that don't
really exist in the real world: pure state and pure action (from certain
perspectives, ... technically the function still occupies state and can be
thought of as an object). In CS it feels as if the discovery came backwards
the real world analogue (OOP) came after the abstraction that doesn't exist in
reality (mathematical functions and numbers).

Anyway, I'm taking this somewhere that has a relation to the parent article so
hear me out. Function and State as separate entities is a smaller
organizational subdivision then Objects which are Functions With State.
Separating Function and State solves a big problem that is central to
Designing Systems. The problem is associated with modularity problems grouping
two primitives together into a single entity. What happens is more often then
not we don't fully understand the true nature of the thing we are building. So
in the initial designs of an OOP system we unionize a certain function with a
certain state and it seems like the correct thing to do at the time, but over
time as requirements change or we gain greater knowledge of the problem we're
solving we realize that the function/method is better used in a separate
context. But it's too late... at this stage the method that we want to pull
out is dependent on the object and that object is a dependency for multitudes
of other objects. Thus we either end up rewriting code or creating a hack,
thereby inventing technical debt.

If that method was never unionized with state, if we used smaller subdivisions
in our code where state and functions are separate entities then this would be
much less of a problem. The function would not be tied to state and that
function can be executed in the context of anything.

This metaobject post talks about the isomorphism between OOP and
HTTP/REST/Servers and talks about the success of that model and how we should
bring it down to the process level. I'm thinking what's the point? JAVA and
smalltalk and a bunch of other languages fill that role you're just changing
the semantics, but the structure is still the same.

He also fails to talk about the problems we have with concept of HTTP, REST
and servers taken to the max. We have a term for this it's called
"microservices." The problems we have with microservices are exactly the same
problems that I just described. I described a problem with OOP and
microservices are an OOP model. The difference here is rather then unionizing
action and state with Code it unionizes state and action with real cold hard
metal. The actual machine that holds state and "does stuff" is the object. So
all the problems of realizing how to divide or unionize services and state in
microservices are exact same problems that existed when trying to figure out
what methods belong with what object in OOP, only when the actual machine is
your abstraction barrier, things are much harder to change. The problem is
well described even by OOP advocate martin fowler:
[https://martinfowler.com/bliki/MonolithFirst.html](https://martinfowler.com/bliki/MonolithFirst.html).
His solution for this problem is less then ideal... basically... build it
wrong first then tear it apart and mutate it into something else... I don't
even know if martin fowler realizes that he's also talking about OOP as the
design structure of microservices and OOP are isomorphic.

Anyway, I digressed... and I'm still disagreeing with the OPs conclusion. It
makes no sense to me why we should bring this server/HTTP model down into code
given the fact that it has all these problems and that it's basically already
done with JAVA. The way forward is actually movement in the opposite
direction. Don't abstract code into a server model rather abstract the server
model into code. Basically code that doesn't compile into assembly language
but compiles into apps that are automatically networked across a constellation
of servers. It's a very hard thing to implement but being allowed to separate
function and state at the server level like we do in code is, in my opinion,
the way forward.

It also sort of exists in a minor way with the whole infrastructure as code
thing and aws lambdas.

~~~
mgummelt
> The function would not be tied to state and that function can be executed in
> the context of anything.

Non-OOP functions are still written against the interface of their parameters,
so they remain tied to state.

~~~
crimsonalucard
Interfaces are usually stateless as they only contain methods.

Technically, the function body itself is a form of state but I addressed this
technicality above.

~~~
mgummelt
No, I mean the function (e.g. a C function) assumes a particular type of
parameter. So it's bound to that type of parameter (by accessing its fields)
in the same way a method is bound to its object. It's the same problem.

~~~
crimsonalucard
Instructions acting on types or interfaces in the purest sense are just
actions and verbs... it is not state. The technicality arises when you
consider the fact that for the instructions to even exist you must write the
instructions down... the result of writing something down is the creation of
state.

So to address what I think will encompass what you're referring to and a lot
more than that... anything that is written down as code is in itself state,
including types, interfaces and the function body. But as I mentioned before
this is a technicality.

We pretend that the computer is executing functions when it is actually
executing assembly code that imitates functions just like we how we can
pretend functions are stateless even though their very existence implies
state.

~~~
kingdomcome50
I think the argument is that the difference between `noun.verb(state)` and
`verb(noun, state)` is only semantic. The former is just syntactic sugar for
the latter under the hood (or not. Look at python). The dependencies are the
same.

~~~
crimsonalucard
I've seen your argument b4. I'm not sure if he's referring to that.

Either way it's more than semantics. Let's say I have two nouns. Noun1 and
Noun2. Only Noun1 contains the verb method. Noun2 does not. How can I use
noun1.verb on noun2?

I cannot use it. But I can use verb(noun, state) on either object. noun1.verb
forms an arbitrary wall that becomes technical debt. Even modifying noun1.verb
will not help, the only way is to move it AND modify it and change all the
things that are dependent on it...

While verb(noun, ...) at most requires a modification, that's it. Semantically
the "meanings" are the same but from a modularity perspective there is a
difference in the "agility" of the method.

Let me put it simply. a method is tied to its parent object/interface by type
AND scope of the parent instantiation. You cannot reuse the function outside
of the scope.

A function is only tied to the type. Your argument is true if you're only
thinking about types.

You might be thinking that the "type" of noun is really the same concept as
scope and that if you get the type of the "noun" right then both examples are
the same. You're not wrong in this sense but rarely do people place the right
method on exactly the right interface or object. Usually they place it on an
interface and realize (months or years later) that the method can be reused on
30 other unrelated objects. The change to correct the design on such a
discovery involves a massive rewrite of a type hierarchy. It is a huge effort
and often not undertaken.

~~~
kingdomcome50
I find it _much_ more likely that shoehorning `verb(noun1, ...)` to accept
`noun2` will result in sub-optimal design than factoring out an interface
(`verb(...)`) that both `noun1` and `noun2` will implement. A verb's
meaning/implementation can shift dramatically depending on the noun to which
it is attributed. E.g. `validate(user)` is materially different than
`validate(order)`.

Any argument predicating on "massive rewrites" and "huge efforts" is a straw-
man. A programmer can model dependencies incorrectly using either approach
above. Expanding a discriminated union (to include `noun2`) will lead to the
exact same amount of refactoring as extracting an interface. We know this
because it _is_ a matter of semantics.

The discussion at hand is about comparing/contrasting the dependencies between
object-methods (`noun.verb(...)`) and stand-alone functions (`verb(noun,
...)`). From the POV of the method/function, the dependencies are the same.
Whether `noun` is explicitly passed as an argument or compiled into `this`
does not change what information is available to the function body (i.e. it's
dependencies).

~~~
crimsonalucard
>I find it _much_ more likely that shoehorning `verb(noun1, ...)` to accept
`noun2` will result in sub-optimal design than factoring out an interface
(`verb(...)`) that both `noun1` and `noun2` will implement.

I am not talking about the case you describe above. Get rid of Union types,
that is a whole different thing. I am talking about a function that does not
need to be shoe horned that can obviously be used for members of both noun1
and noun2 but due to a design decision the function is tied to noun1.

Let me give you a concrete example that is trivial. The example is so trivial
that it probably won't happen in the real world but you can see how for
concepts that are more complex it can happen all the time.

Imagine I have an app with a class in it called SortedListOfPeople. It would
make sense to put a sort method on this class. Now imagine that this app runs
for a bit then you add a feature which involves a class called GroupOfCats.
The feature is very far away from and completely different from
SortedListOfPeople. Then one day you get the task to turn GroupOfCats into
SortedGroupOfCats.

Suddenly you got a problem. How do you re-use the code from sorted list of
people without the sorted list of people? How do you use it with a different
context at all? Not being able to reuse code is NOT a semantic problem. It is
an intrinsic design problem.

Your genius solution above (Note how I call your solution genius instead of
straw-man) is two implementations of the same concept. This is obviously more
genius than one function.

Sortable types is an obvious example, but think about how often this problem
occurs in OOP for more complicated concepts. You end up implementing things
multiple times all over the place.

If the sort function was a stateless function operating on a sortable
interface parameter you would not have this problem. The only thing you need
to implement for GroupOfCats is to give it a sortable interface rather than
reimplement sort for everything that needs to be sorted.

Actually if you think really hard about OOP and the sort function. How would
you make a generic sort function that can be reused across all contexts while
following the rules of OOP? You cannot use static classes and the function
cannot take parameters... as that would imply a stateless function. The sort
function must operate on the classes own state. How can you then share the
sort method across two or more classes in OOP?

The answer is inheritance. Put the sort method in the base class. How would
you share the sort function with classes that already have ancestors? Multiple
inheritance. Too bad everybody hates these two concepts so they resort to
garbage syntax that basically turns the class into a namespace so they can
start using functions as if they weren't tied to some intrinsic state.

~~~
kingdomcome50
You have simply contrived a poor design, then pointed out its flaws. Not only
that, you are _constraining_ the solution space (no static methods and must be
parameter-less). That sounds like a straw-man to me. There is nothing inherent
in OOP that mandates a developer choose your design.

Furthermore, you are comparing a perfectly factored functional design to a
poorly factored OOP design. I can just as easily assert that `sort(people)`
cannot be factored into `sort(comparable)` because "clearly" the body of
`sort(people)` is dependent on some property of `people` that is not present
on `comparable`. Contravariance cannot just be assumed.

Said another way, every function is tied to the entire public surface of the
data to which it is provided (at least in theory). So unless `people` just
happened to have exactly the same interface as `comparable` already, a new,
more generic, `sort(comparable)` function would be necessary.

The solutions are roughly equivalent in either paradigm: move the behavior
into a more generic container. Where composition can be used instead of
inheritance in tandem with double dispatch, for OOP, if the public surface of
SortedGroupOfCats must include a `sort()` function.

~~~
crimsonalucard
>You have simply contrived a poor design

I contrived a poor design that is a reflection of what can happen. There is no
design theory making all designs perfect therefore many isomorphic mistakes in
my design happen all the time uncontrived.

>Not only that, you are _constraining_ the solution space (no static methods
and must be parameter-less).

I constrain it to prevent you from creating a function instead of a method. A
function is outside of OOP a method is 100% OOP. a static class without state
is equivalent to a namespace holding a bunch of functions. If I didn't
constrain you you'd be proving my point by switching to using a regular
function instead of OOP.

>There is nothing inherent in OOP that mandates a developer choose your
design.

That is the problem. There is something inherent in functional programming
that mandates the developer to never be able to make the previous design
choice. If all your functions are stateless there is NO way you can even
contrive the poor design I contrived earlier. That is the secret. Less
expressivity is less ways to screw up. Imagine a programming language where
the syntax only allows you to design your programs in the best possible way...
Functional programming is closer to this goal than OOP.

>I can just as easily assert that `sort(people)` cannot be factored into
`sort(comparable)`

It's better to factor something to be more general than to write 10 flavors of
the same thing. How hard it is doesn't matter here, rewriting sort to solve
this problem is better than OOP where you have to write another version. That
is all I am arguing for.

>Contravariance cannot just be assumed.

The entire essence of my argument is that you discover this property in two
random places, but you cannot apply a function in both places because the
function is tied to another context.

>a new, more generic, `sort(comparable)`

And this is better than two specific flavors of sort. Let's scale this up to
an app that's been around for 5 years.... in this case One generic sort is
better than 20 different flavors of sort.

>The solutions are roughly equivalent in either paradigm: move the behavior
into a more generic container.

But like I've been saying you can't just move the method in OOP you have to
change the object hierarchy. If the method is to be used in another unrelated
object hierarchy than the hierarchies have to be merged via multiple
inheritance. All I want is the function, why am I bringing the whole object
ancestral structure with it?

"I think the lack of reusability comes in object-oriented languages, not
functional languages. Because the problem with object-oriented languages is
they’ve got all this implicit environment that they carry around with them.
You wanted a banana but what you got was a gorilla holding the banana and the
entire jungle."

    
    
        -joe armstrong

~~~
kingdomcome50
>I can just as easily assert that `sort(people)` cannot be factored into
`sort(comparable)`

You are misunderstanding what I am asserting here. If the body of
`sort(people)` is coupled to a property of `people` not present on
`comparable`, you cannot _just_ refactor to a more generic `sort(comparable)`
and expect the behavior to remain consistent. The solution requires two
functions: `sort(comparable)` that abstracts the portion of the function body
concerned with the surface of `comparable`, AND `sort(people)` that interacts
with the property of `people` not present on `comparable`. It's obviously
worth noting here that `sort` could just as easily be some other verb, say
`validate` (I understand `sort` doesn't make much sense in this particular
context).

Similarly, there is no need to "move the method" or "change the object
hierarchy". You conveniently failed to quote the one line in my response above
that addresses this...

>composition can be used instead of inheritance in tandem with double
dispatch, for OOP, if the public surface of SortedGroupOfCats must include a
`sort()` function

And while it makes for a great quote, Joe Armstrong is simply wrong. There is
nothing inherent to OOP (and even less so when examining the languages that
utilize the paradigm) that requires poor design. What if I wanted "the banana
that one specific gorilla is holding in some particular jungle"? How would
that look in OOP vs functional? More importantly, is there a meaningful
difference or is it just semantics?

FWIW, I prefer a functional paradigm myself.

~~~
crimsonalucard
>You are misunderstanding what I am asserting here. If the body of
`sort(people)` is coupled to a property of `people` not present on
`comparable`, you cannot _just_ refactor to a more generic `sort(comparable)`
and expect the behavior to remain consistent.

Refactor sort into the composition of two functions. One is reliant on people,
the other is just sort. The signature of the original sort function remains
the same. But you have a general function that can be reused in different
contexts. This type of change CANNOT be done on OOP.

>composition can be used instead of inheritance in tandem with double
dispatch, for OOP, if the public surface of SortedGroupOfCats must include a
`sort()` function

composition moves the entire state across. Think about it. I have
SortedGroupOfCats and you want me in order to reuse sort, move
SortedGroupOfPeople into SortedGroupOfCats.

>And while it makes for a great quote, Joe Armstrong is simply wrong. There is
nothing inherent to OOP (and even less so when examining the languages that
utilize the paradigm) that requires poor design.

OOP is bad because it makes it possible to shoot yourself in the foot, and
while avoidable, unfortunately the syntax promotes designs that tend to be
bad.

>More importantly, is there a meaningful difference or is it just semantics?

There is.. a function does not need to be instantiated to be used. A function
never modified an entity. That changes everything. The fact that lambda
calculus and turing machine exist in a theoretical sense shows you that the
industry knows about an intrinsic difference between the two concepts.

>FWIW, I prefer a functional paradigm myself.

Note that although I have used the functional paradigm as an example this is
not my overall critique. I am not just saying OOP is better than functional
programming. I am saying OOP is worse than imperative, procedural and
functional programming. Out of all of the most popular ways of programming...
OOP is the least modular and the one with many many design issues. Even non-
functional programmers have noticed this... GO is one of the results of this
realization.

There are cases where OOP works, but in most cases, it's sub-optimal.

~~~
kingdomcome50
>The signature of the original sort function remains the same. But you have a
general function that can be reused in different contexts. This type of change
CANNOT be done on OOP.

This is where you lose me. The above is simply untrue. There is absolutely no
reason one cannot employ `SortingAlogrithm.sort` within the body of
`people.sort()`. Are you suggesting every utility class (and by extension the
entire standard lib) needs to be injected into an object before it can be
used?

Again, you are creating a false-equivalence. A "fair" example would require
our generic `sort(comparable)` be passed into the original as a dependency
like so: `sort(people, csort)`. It's _possible_ that the two functions could
be composed, but that is completely dependent on the semantics of each
function (we cannot just assume composition is possible for every use-case).

The difference between a first-class function and an object is purely
semantics. Yes, you have to `new` an object before you can call a method, but
there is no requirement any "implicit context" has to be provided at the time
of instantiation. Closures offer the exact same capability via "capturing" and
partial application.

Conceptually, all OOP does is take 10 functions that all have the same
parameter and "partially apply" each of them over that parameter into new
functions that don't have a parameter (i.e. they get that "implicit context").
That is, OOP saves you a step. It is common practice in FP to start with
"pure" functions then, higher up in the application, partially apply those
functions into new, domain-specific functions with your data (a.k.a.
dependency injection) that are strung together to carryout a use case. OOP
allows you to _define_ partially applied functions instead of the need to
compose them (of course this also makes the DI mechanism a bit different as
well).

I can agree that the above _can_ make decomposition more difficult, but your
general critique reads more of one leveled at programmers not understanding
the basic principals of software design, not OOP. I could just as easily
create a mess in FP as in OOP.

>More importantly, is there a meaningful difference or is it just semantics?

I urge you to sit down and write out the pseudo-code. It will be plainly
obvious that there is no meaningful difference between each approach.

~~~
crimsonalucard
>This is where you lose me. The above is simply untrue.

No. My statements are true. But you are right about you being completely lost.

>There is absolutely no reason one cannot employ `SortingAlogrithm.sort`
within the body of `people.sort()`

Let's talk about objectives and what you're implying with this suggestion. The
objective is to sort a bunch of people within the the people class.

What is SortingAlogrithm.sort? Is it an object that sorts its own state or is
it a stateless class with a stateless function? If it's an object that sorts
its own state then it CAN'T do what I want. I want it to sort peoples' state
NOT it's own state. If it's a stateless class with a stateless method then you
are no longer doing OOP you have created a function that is not tied to state
thereby proving my point that stateless functions are more modular.

>Are you suggesting every utility class (and by extension the entire standard
lib) needs to be injected into an object before it can be used?

Yes this is the model in pure OOP languages. Otherwise you are using a hybrid
of OOP and functions thereby providing evidence that OOP alone is broken.
Things like JAVA, C++ do all kinds of BS like this further ingratiating my
point.

>Again, you are creating a false-equivalence.

No. You are failing to understand. 'Lost' was the term you, yourself used.

>A "fair" example would require our generic `sort(comparable)` be passed into
the original as a dependency like so: `sort(people, csort)`.

This is not fair at all. in fact it's ugly. I pass a generic sort as a
parameter into a specific sort? If you think that's fair and you code this way
then you're in for a surprise when building a complex system.

>It's _possible_ that the two functions could be composed, but that is
completely dependent on the semantics of each function (we cannot just assume
composition is possible for every use-case).

I'm thinking you got confused by what I mean by composition. There are two
compositions I am referring to in my statements. Function Composition and
Object Composition. Object Composition is exactly the previous example you
gave sort(people, csort) or inserting something via the constructor
People(csort), there's a number of ways to do it.

Function composition of A(x) and B(x) is F(x) = A(B(x)). Function composition
is at the heart of functional programming.

>It's _possible_ that the two functions could be composed, but that is
completely dependent on the semantics of each function (we cannot just assume
composition is possible for every use-case).

If you're not changing state and something has properties of being sortable it
can be done.

you have x = sortableListOfPeople

composedFunctions = f(sortableListOfPeople) {return
doPeopleSpecificStuff(sortGeneric(sortableListOfPeople))}

you can go the other direction if you want. The implementation is situation
specific but if something is sortable this can be done always but only if all
functions are stateless and don't modify values. Note composedFunctions should
have the exact function signature of the original function thereby negating
the need to change other things dependent on it.

>The difference between a first-class function and an object is purely
semantics.

No. A first-class function cannot change. It is immuteable and when called
with the same input Always has the same output. An object with a method when
called at different times can have different output based off of internal
state. Your statement is categorically wrong.

>Yes, you have to `new` an object before you can call a method, but there is
no requirement any "implicit context" has to be provided at the time of
instantiation.

Then you are basically declaring a stateless function. The admission that you
have to do this is an intrinsic flaw. Yes nothing prevents you from going
outside of the OOP paradigm when programming in an OOP language. You likely
have no choice due to inherit flaws in OOP. Try doing OOP without this
ability... You'll see how broken the whole model is.

>Conceptually, all OOP does is take 10 functions that all have the same
parameter and "partially apply" each of them over that parameter into new
functions that don't have a parameter (i.e. they get that "implicit context").
That is, OOP saves you a step. It is common practice in FP to start with
"pure" functions then, higher up in the application, partially apply those
functions into new, domain-specific functions with your data (a.k.a.
dependency injection) that are strung together to carryout a use case. OOP
allows you to _define_ partially applied functions instead of the need to
compose them (of course this also makes the DI mechanism a bit different as
well).

Let me tell you definitively. I completely understand what you're talking
about, I understand it now and I understood it before. No need to reiterate.
What you're not understanding is that despite my 100% comprehension of your
statements I am telling you, that you are failing to understand ME.

Let me try to put it as simply as possible. If there is an Object called
Number and a method called addOneAndReturn... if I call that method on a Zero
Twice? what happens? I get One and then I get a two. The method is returning
two different values despite being called in the same way TWICE. This sort of
thing is NOT POSSIBLE in a stateless function. It Cannot Happen period. THIS
is the fundamental difference. THIS is MORE than semantics.

Yes I understand that currying and first class functions have parallels to
Dependency Injection BUT there is still MORE then a semantic difference
between OOP and functions.

>your general critique reads more of one leveled at programmers not
understanding the basic principals of software design

Design is the domain of things we don't understand. There is no design in type
theory or number theory because we understand all the implications of the
axioms and theorems. We go to design when there is no formal theory that can
say why one design is better than others.

I am not coming from the design perspective. I am coming from the theory
perspective. When you tie functions with state the state must move along with
the function. If you keep state and functions separate then they can move
separately. This is logic. No design principles needed.

Any language with too many design patterns is a language that is very much
lacking in a formal description (think: JAVA)

>I could just as easily create a mess in FP as in OOP.

You can. But there are more ways to do it in OOP then in FP. In fact there are
more ways to shoot yourself in the foot in OOP than in procedural programming
in general. I'm not even referring soley to FP. Even C is better than C++.

>I urge you to sit down and write out the pseudo-code. It will be plainly
obvious that there is no meaningful difference between each approach.

You don't need to write psuedo code. Use your brain dude. A stateless function
versus a function that carries it's own mute-able state. There is MORE than a
semantic difference. The semantic difference you're referring to is when the
SELF value is immuteable. In that case the two ways of calling the function
become more similar, but THAT is NOT OOP.

There is one rule that needs to be followed to make ANY program FP. Just one
rule, that's it. Make all things immutable. OOP is fundamentally different
from this because it involves the mutation of Object state.

~~~
kingdomcome50
I fear the goalposts have moved from "the problem with OOP" to "the problem
with mutability". These are distinct concepts. The fundamental premise of OOP
is, among other things, the encapsulation of behavior _with_ data (as opposed
to _around_ data). It has nothing to do with mutability. One can absolutely
practice OOP with immutability (looking at Scala here). Similarly, OOP doesn't
need to be written imperatively. Are you suggesting `sorted_people =
people.sort()` isn't OOP?

You are building your own concept of OOP to argue against, not the one that
exists in reality. (straw-man emoji)

~~~
crimsonalucard
>I fear the goalposts have moved from "the problem with OOP" to "the problem
with mutability". These are distinct concepts.

No they ARE not. For OOP to work you have to have objects be mute-able. The
modern definition of OOP are nodes that communicate with each other and change
each others state.

The minute you get rid of mute-ability is the minute you are doing functional
programming.

>One can absolutely practice OOP with immutability (looking at Scala here).

Scala is a multi-paradigm language. Also scala is not always immutable. The
objects in scala can mutate.

>Similarly, OOP doesn't need to be written imperatively.

It does if you want the properties of an object to change. That is the
dichotomy of OOP and FP otherwise there is no dichotomy and no point for there
to exist vocabulary to separate the two concepts.

>Are you suggesting `sorted_people = people.sort()` isn't OOP?

If I remove the engine from my car and roll it down a hill while in the
drivers seat am I still driving the car? Yes. Technically I am. But key
feature of the engine moving the car is missing. You can call people.sort()
OOP you can also call it not OOP because it is missing the key feature of self
modification.

>You are building your own concept of OOP to argue against, not the one that
exists in reality.

lol lets look at the definition. [https://en.wikipedia.org/wiki/Object-
oriented_programming](https://en.wikipedia.org/wiki/Object-
oriented_programming)

I directly quote from the site above:

"Object-oriented programming (OOP) is a programming paradigm based on the
concept of "objects", which can contain data, in the form of fields (often
known as attributes or properties), and code, in the form of procedures (often
known as methods). A feature of objects is an object's procedures that can
access and often modify the data fields of the object with which they are
associated (objects have a notion of "this" or "self"). In OOP, computer
programs are designed by making them out of objects that interact with one
another."

Key sentence above: "A feature of objects is an object's procedures that can
access and often modify the data fields of the object with which they are
associated"

The goal post was never moved. It was set by the Actual definition of OOP. I
am explicitly including this feature to make sure that ALL we are dealing with
is OOP and not some hybrid functional or OOP merger.

>(straw-man emoji)

This mechanism of turning macros into emojis doesn't work here on HN! Similar
to your arguments.

~~~
kingdomcome50
The quoted text above is referring to objects, not OOP -- which encompasses a
number of concepts. You can refer to the the "Features" section in your link
above for the complete list (notice one is missing). For further information
about the relationship between OOP and mutability just google it.

It's a waste of time to argue about a topic that is orthogonal to your
original claim (before the goalposts moved): that the "problem" with OOP is
how you invoke a function -- `noun.verb` as opposed to `verb(noun)`; As if
those two systems are subject to different constraints. They are not. It is
just semantics.

The above isn't to say there doesn't exist consequential differences between
OOP and FP, but I absolutely did _not_ engage in this discussion to argue
about OOP vs FP in general. I think we actually both agree FP is a superior
paradigm.

~~~
crimsonalucard
>The quoted text above is referring to objects, not OOP -- which encompasses a
number of concepts. You can refer to the the "Features" section in your link
above for the complete list (notice one is missing). For further information
about the relationship between OOP and mutability just google it.

Makes sense. Object oriented programming isn't programming revolving around
objects. You totally invalidated all my claims with this genius argument here.
You also invalidated the entire definition of OOP and wikipedia too.

>It's a waste of time to argue about a topic that is orthogonal to your
original claim (before the goalposts moved)

At first I was going to say that the goal posts have not moved but your brain
was the thing that moved. Then I realized nothing has moved. Your brain is
still in the same place: A place of ignorance.

>that the "problem" with OOP is how you invoke a function -- `noun.verb` as
opposed to `verb(noun)`; As if those two systems are subject to different
constraints. They are not. It is just semantics.

Let me spell it out for you where the goal posts were when the conversation
started. The goal posts were in a place where 99.999% of all programmers
operate: In a universe of mute-able variables, mute-able objects and immutable
functions. Typically "goal posts" start here because that's how 99.99999% of
all programmers operate.

So within the bounds of these "goal posts" you made a claim that OOP and
Functions only have a semantic difference. Which is CATEGORICALLY wrong. So
then I decided to let you know that your CLAIM is only TRUE if VARIABLES are
immutable you acted AS IF we were ONLY talking about immutable variables ALL
ALONG as if that's the primary assumption all programmers make when talking
about programming. The goal post wasn't moved... get it? I only changed the
context a little to show you WHEN your arguments would be true, BUT nowhere
did I "change the goal posts."

What happened after that is that YOU changed your argument. You imply that
you've been ONLY talking about immutable variables all along and that I
changed the goal posts to suit my needs. I can tell you 100% that you are
either a liar or deeply delusional. You literally refuted a sourced definition
of OOP in your attempt to stay relevant. Give it up dude.

>The above isn't to say there doesn't exist consequential differences between
OOP and FP, but I absolutely did _not_ engage in this discussion to argue
about OOP vs FP in general. I think we actually both agree FP is a superior
paradigm.

I agree that we aren't talking about FP vs. OOP. What we are talking about is,
and I quote:

"that the "problem" with OOP is how you invoke a function -- `noun.verb` as
opposed to `verb(noun)`; As if those two systems are subject to different
constraints. They are not. It is just semantics."

Which you are completely and utterly wrong about. You cannot make this
statement without saying that all variables are immutable which is not a
property that can be ASSUMED OUT OF THIN AIR.

~~~
kingdomcome50
Tone it down.

OOP is not "programming revolving around objects". Simply using objects in
your code-base does not mean you are practicing OOP anymore than using
functions means you are practicing FP. But I digress. Again, the definition of
OOP is unrelated to the claim which prompted this discussion.

>The function would not be tied to state and that function can be executed in
the context of anything

This is the (your) line of text at the top this thread (go look), and the
point to which I wanted to offer some clarification. It has nothing to do with
the definition of OOP or mutability vs immutability.

The point I have been trying to make is that `noun.verb` and `verb(noun)` are
both tied to the same state; That the _caller_ of either of these functions
needs to have a reference to `noun`. In this way, the "context" is also the
same (both functions can only be executed in a context that has `noun`). There
are problems with OOP! The above just isn't one of them.

>You cannot make this statement without saying that all variables are
immutable

How do you know `noub.verb` mutates `noun`? Similarly, how do you know
`verb(noun)` doesn't mutate `noun`? There is no way to make an assessment of
the mutability of `noun` given those snippets. Which is kind of the point:
they are equivalent.

Making an assertion about the behavior of either function (when that behavior
is _clearly_ not shown) is building an argument against something else
entirely. This is called a straw-man. Similarly, shifting the argument to be
about the definition of OOP and/or mutability instead of the relationship
between how a function is written and its dependencies/modularity is to argue
about something else entirely. This is called moving the goalposts.

~~~
crimsonalucard
>How do you know `noub.verb` mutates `noun`? Similarly, how do you know
`verb(noun)` doesn't mutate `noun`? There is no way to make an assessment of
the mutability of `noun` given those snippets. Which is kind of the point:
they are equivalent.

This is why you have to make every possible assertion. Muteable and
immuteable. And in the muteable case your statement is wrong. Since we are
talking about OOP (see first sentence of my first post) by definition only the
muteable case is considered. There was no movement of goal posts, you simply
failed to see where the goal posts were originally.

>Making an assertion about the behavior of either function (when that behavior
is _clearly_ not shown) is building an argument against something else
entirely. This is called a straw-man. Similarly, shifting the argument to be
about the definition of OOP and/or mutability instead of the relationship
between how a function is written and its dependencies/modularity is to argue
about something else entirely. This is called moving the goalposts.

The topic at hand is on OOP. That's because that's the topic in my first post.
Thus since OOP is mentioned in my first post THE DEFINITION of OOP is what I'm
talking about. And since mute-ability is part of the DEFINITION of OOP this is
the topic. What happened is you entered this conversation with the idea that
the goal posts were somewhere else. They were not.

We are talking about noun.verb and verb(noun) in the context of OOP. That is
the topic. And the statement of verb(noun) is the same as noun.verb is
categorically wrong. You are wrong. This is concrete.

~~~
kingdomcome50
The only assertion I need to make (and have made repeatedly), is that
`noun.verb` and `verb(noun)` are subject to the same constraints. In terms of
mutability, we can say that both functions could mutate `noun` or both
functions could not mutate `noun`. It is a straw-man to build an argument
against a premise which arbitrarily asserts that `noun.verb` _behaves_
differently than `verb(noun)`. The behavior of the function(s) is not relevant
to point you were trying to make or my point of clarification (of course two
functions that behave differently are different!). Again:

>The function would not be tied to state and that function can be executed in
the context of anything

The above is the claim which prompted this lengthy discussion. It has nothing
to do with the definition of OOP or mutability. To rephrase your argument in
my own words:

Separating data and behavior (state and functions resp.), in the form of
`verb(noun)`, is superior to combining data and behavior, in the form of
`noun.verb`, because it means `verb` is subject to fewer constraints and, as a
result, is more portable.

The above is not accurate. There _are_ problems introduced by encapsulation.
But one of them is not that functions are tied to state. This remains true for
any function no matter how it is written (the semantics).

I'm not sure why you continue to insist on moving the goalposts here,
especially to an argument for which you are so obviously wrong. The definition
of OOP makes no claims about mutability. Furthermore, many of the most popular
OOP languages provide built-in support for defining objects as immutable
(while at the same time implementing immutable objects in their own standard
libraries. e.g. `string` in many languages). Even a cursory google search on
the subject unambiguously yields this information. I'm not going to waste my
time debating this when you are fully capable of researching and revising your
position. Especially because this has nothing to do with the claims that
provoked this discussion in the first place.

My original comment was rather innocuous. It was intended as a point of
clarification towards a claim you made as part of your broader opinions on the
deficits that OOP impose on a system as it relates to functions, state, and
modularity. You essentially say the same thing later in your post in your
comparison between the OOP model and microservices:

>The difference here is rather then unionizing action and state with Code it
unionizes state and action with real cold hard metal. The actual machine that
holds state and "does stuff" is the object. So all the problems of realizing
how to divide or unionize services and state in microservices are exact same
problems that existed when trying to figure out what methods belong with what
object in OOP...

Just replace "microservices" with "FP" in that last sentence and you will have
basically synthesized my argument:

"all the problems of realizing how to divide or unionize services and state in
_FP_ are exact same problems that existed when trying to figure out what
methods belong with what object in OOP"

For what it's worth, I agree with your ultimate conclusions.

~~~
crimsonalucard
>>The function would not be tied to state and that function can be executed in
the context of anything

>The above is the claim which prompted this lengthy discussion. It has nothing
to do with the definition of OOP or mutability. To rephrase your argument in
my own words:

>Separating data and behavior (state and functions resp.), in the form of
`verb(noun)`, is superior to combining data and behavior, in the form of
`noun.verb`, because it means `verb` is subject to fewer constraints and, as a
result, is more portable.

>The above is not accurate. There _are_ problems introduced by encapsulation.
But one of them is not that functions are tied to state. This remains true for
any function no matter how it is written (the semantics).

Have you ever thought about the difference between a list of "noun.methods"
that encapsulate a "noun" vs. a list of "verb(noun)" that also encapsulate a
noun? Under your semantic equivalence principle it's the same thing. IN your
universe one can encapsulate a noun with procedural functions through type
signatures AND it can be done with OOP as well. We are of course negating the
usage of a noun as a global variable.

Also what is the "noun" in "noun.verb"? Can it be a namespace? Is "noun.verb"
the same as "namespace.verb"? Namespaces hold variables and functions and so
do Objects... Are these two concepts isomorphic? If regular programming
already has namespaces what's so special about Object Oriented programming?
What's the point of calling a namespace an object?

Well then you could say that OOP allows the user to "generate" or
"instantiate" namespaces at runtime. That's neat except what is the point of
generating a new namespace for what is essentially the same thing? Why do I
need namespace1.verb and namespace2.verb when I can just have verb(namespace)
or just get rid of OOP and have a single namespace.verb?

Well you could argue that namespace1 and namespace2 have different states.
That's why you need the ability to instantiate them. But then what's the point
of instantiating different namespaces at runtime when you can just have
verb(namespace1) or verb(namespace2)? What's the point of OOP if it's the same
thing as everything else in existence? Was OOP invented for semantic confusion
only?

Well no, in OOP the namespace.verb() verb modifies the instantiated namespace.
namespace1.verb is DIFFERENT from namespace2.verb because they are modifying
different states. This is OOP. If VERB was stateless and did not touch the
state of namespace2 or namespace1 then there would be no difference and you
wouldn't be doing OOP.

It is mutation that ties a method to state. The goal posts were never moved.
When you talk about OOP you have to talk about it in the context of mutation
because that's what Wikipedia lists as part of the definition and that is the
only unique and logical difference between OOP and other forms of programming.
Thus you must be mutating or reading internal state to be doing OOP.

In the context of OOP and the sort example, noun.verb MUST modify noun
otherwise we aren't talking about OOP. IN the context of procedural functions
verb(noun), verb COULD modify noun OR it could NOT. In FP verb CANNOT modify
noun ever.

FP: verb(noun), verb cannot modify noun OOP: noun.verb, verb MUST modify noun
Procedural programming: verb(noun), verb can modify noun or it may not.

The implementation changes depending on the context and the context is 100%
OOP. For any styles to be isomorphic (which is what you are implying) the
properties must match exactly. I talked about OOP in my first comment, you
were making a clarification about it in reference to another person who was
also talking under the SAME oop context. The title of this entire thread has
OOP in it. We are talking about OOP.

You can bend procedural programming to be isomorphic to OOP. But this isn't a
two way equivalence, you cannot always bend OOP to fit a procedural function.

This statement from you (a perversion of a statement I made earlier) is ALSO
categorically wrong:

>"all the problems of realizing how to divide or unionize services and state
in FP are exact same problems that existed when trying to figure out what
methods belong with what object in OOP"

In FP, everything has to be immutable. This the exact opposite of a required
property for OOP. OOP uses mutability to tie methods with state.

Also you should note the definition of encapsulation is literally my argument
of unionizing state with methods plus the added property of information hiding
or aka private members and methods
([https://www.wikiwand.com/en/Encapsulation_(computer_programm...](https://www.wikiwand.com/en/Encapsulation_\(computer_programming\))).
That's it. Since you're basically saying that the unionization of state and
methods ISN'T the problem... you must be referring to information hiding. The
private keyword, according to you is the problem with OOP. All of the problems
with OOP (encapsulation) according to you could be fixed if people stopped
using the private keyword. Amazing. Take a look at python... no private
keyword... didn't fix anything.

>For what it's worth, I agree with your ultimate conclusions.

If you think encapsulation is the cause of the "ultimate conclusion" you need
to realize, namespaces and modules and libraries also encapsulate things with
no problems. The source of OOP's problems is not in encapsulation. You or
whoever introduced that idea to you is completely wrong. Literally you can
write a metaprogramming script that removes all the private keywords from
objects and according to your logic will fix the problem.

~~~
kingdomcome50
In OOP, unlike FP, immutability is an implementation detail, not a
requirement. I'm trying to be gentle about this, but your insistence is
becoming tiresome. Again, just do a search and inform yourself. I'm not going
to patronize you by listing the numerous links/resources that clarify the
above distinction.

>The problem is associated with modularity problems grouping two primitives
together into a single entity

>If that method was never unionized with state, if we used smaller
subdivisions in our code where state and functions are separate entities then
this would be much less of a problem

>all the problems of realizing how to divide or unionize services and state in
microservices are exact same problems that existed when trying to figure out
what methods belong with what object in OOP

Maybe I'm misunderstanding you argument, but I understand "the problem[s]"
above (your words) to be a matter of organization not implementation -- I see
no reference to mutability.

I don't have to be wrong about this. `noun.verb` doesn't have to be materially
different than `verb(noun)` for the validity of your point to hold about the
difficulties of designing and distributing systems being the major obstacle
and that abstracting the server model into code being more pragmatic than
abstracting the code into the server model.

I am simply clarifying that you can create the same problems with organization
in FP as OOP. That is, you can write a function with the wrong signature just
the same as you can put a method on the wrong object. Modelling a domain
happens before any code is written (theoretically). There is nothing inherent
in either paradigm that forces a developer to synthesize a useful abstraction
of the functional requirements of their system any better than the other one.

If anything I am _strengthening_ your argument.

~~~
crimsonalucard
>In OOP, unlike FP, immutability is an implementation detail, not a
requirement. I'm trying to be gentle about this, but your insistence is
becoming tiresome. Again, just do a search and inform yourself. I'm not going
to patronize you by listing the numerous links/resources that clarify the
above distinction.

I patronized you with wikipedia. Go ahead and send me some links to some blog
posts. Just note that some medium blog posters "opinion" on OOP like your
opinion doesn't mean anything without a proper logical reasoning. You will see
tons of people who say garbage like "OOP" is "orthogonal" to "FP" which is
equal to the amount of people who don't know what FP actually is.

>Maybe I'm misunderstanding you argument, but I understand "the problem[s]"
above (your words) to be a matter of organization not implementation -- I see
no reference to mutability.

I didn't mention it because it's a very subtle property that's very hard to
see and very hard to explain. People understand how OOP is organized on the
surface, they don't understand the subtleties of it. Only when we get into
details does it come out: Mutability is the very property that dictates the
organization of OOP. I get how it appears that I'm moving "goal posts" since I
didn't bring it up explicitly in the beginning.

What happened was you noticed a subtle isomorphism between two paradigms but
the details were even subtler then that. This is when I chose to bring up the
topic of mutability because this is the core property that is intrinsically
tied to the organization of OOP. In short, I dove into the details when you
brought up a detail... Anyway, mutability It is the core property that breaks
the isomorphism and dictates our vocabulary... it's why we have the term OOP,
FP and Procedural Programming in the first place.

>I am simply clarifying that you can create the same problems with
organization in FP as OOP. That is, you can write a function with the wrong
signature just the same as you can put a method on the wrong object. Modelling
a domain happens before any code is written (theoretically). There is nothing
inherent in either paradigm that forces a developer to synthesize a useful
abstraction of the functional requirements of their system any better than the
other one.

You're talking about the application of programming styles to the real world
which is amenable to opinion.

One paradigm is more flexible to change.

Much easier to change a function operating on the wrong type than it is to
change a method intrinsically tied to scoped variables that change state.

The biggest key difference is that FP gives you flexibility to change the
model once the inevitable design flaws become apparent.

You will note that in OOP there are no functions or data. Only data bundled
with methods called Objects can exist. It's easy to see how these arbitrary
walls cause numerous design issues. Also, again, it is the mutability of each
object that is the actual instigator of this organizational scheme, I am not
talking about the "semantic difference" you pointed out earlier.

>If anything I am _strengthening_ your argument.

I disagree. I believe OOP is actually _worse_ than most other styles of
programming for most cases. You are saying OOP is the same as all other forms.

~~~
kingdomcome50
The Wikipedia page to which you keep referring does not support the argument
that mutability is "core property" of OOP. The quote you've cited (far above
at this point) is referring to a feature of objects, not OOP. OOP encompasses
range of features. You can explore them on that very same page under the
"Features" section. You will certainly notice that "Mutability" is not listed
as a feature. OOP is an _approach_. Simply using objects does not mean you are
practicing OOP any more than using functions means you are practicing FP.

I urge to to a ctrl+F on "mutable" and read the top 2 (of 3) passages where it
is referenced (the third is not relevant):

> ... in most OOP languages, in particular in all those that allow mutable
> objects.

> ... in OOP languages (with mutable objects) ...

The clarifications in the above passages are unnecessary if mutability is
considered a necessary feature for OOP. If that's not enough, how about you
read the first sentence of
[https://en.wikipedia.org/wiki/Immutable_object](https://en.wikipedia.org/wiki/Immutable_object):

> In object-oriented and functional programming, an immutable object
> (unchangeable[1] object) is an object whose state cannot be modified after
> it is created.

If immutable objects are incompatible with OOP, why is it included in the
above?

Are you suggesting that if I write a Java program and I use all of the
features of OOP (inheritance, polymorphism, encapsulation, etc.) but don't use
mutability, that my system is better understood as functional? Come on. What
about an OOP system that doesn't mutate by design? Not every program requires
changes of state. We need to put this to rest. I can pretend "this never
happened". After all, this entire argument is not relevant to the point I was
trying to make (the whole goalpost thing).

> Much easier to change a function operating on the wrong type than it is to
> change a method intrinsically tied to scoped variables

_This_ is to the point I was trying to make. The above is simply untrue. If I
have a function referenced all over my code base, `validate(giraffe)`, and we
change the signature to `validate(gorilla)`, it isn't any easier to refactor
the system than if it were modeled in OOP. In both cases, the _caller_ needs
to have a reference to a different piece of data in order to call our
`validate` function. Which means the caller of the caller needs to have a
different piece of data (so now the caller needs to change), etc. up the
stack. In the end, the most flexible solution in either paradigm is to
"inject" the appropriate data (`giraffe`/`gorilla`) via the "DI" mechanism
that the paradigm supports. In OOP this is in the constructor. In FP we can
use partial application. These two concepts _are_ isomorphic.

I am _not_ saying that OOP is "the same as" all other forms. I am saying, in
terms of the pitfalls regarding modelling a domain, all forms are the same. As
I understand it, this is the argument your OP was making (you just left FP out
of it).

I agree that OOP is worse than FP. There are a few features of FP that make it
superior in many respects (notably required immutability and an algebraic type
system).

~~~
crimsonalucard
>The Wikipedia page to which you keep referring does not support the argument
that mutability is "core property" of OOP. The quote you've cited (far above
at this point) is referring to a feature of objects, not OOP. OOP encompasses
range of features. You can explore them on that very same page under the
"Features" section. You will certainly notice that "Mutability" is not listed
as a feature. OOP is an _approach_. Simply using objects does not mean you are
practicing OOP any more than using functions means you are practicing FP.

Dude. OOP is programming oriented around objects. The core feature of OOP is
objects. Any feature that an object possesses is a "core property." Also it's
a pretty safe bet that anything mentioned in the first paragraph of the
Definition of OOP is likely a core property.

>If immutable objects are incompatible with OOP, why is it included in the
above?

>Are you suggesting that if I write a Java program and I use all of the
features of OOP (inheritance, polymorphism, encapsulation, etc.) but don't use
mutability, that my system is better understood as functional?

Yes I am. 100% if you use immutability your program is isomorphic to
functional programming. It's included because you CAN do this. Just like how
you can do functional programming in a procedural language. If you want to
compare OOP to other styles you compare the features that are variant not the
features that are identical.

>_This_ is to the point I was trying to make. The above is simply untrue. If I
have a function referenced all over my code base, `validate(giraffe)`, and we
change the signature to `validate(gorilla)`, it isn't any easier to refactor
the system than if it were modeled in OOP.

it is easier. We've talked about the deeper difference. validate in OOP is
attached to a concrete instance, it cannot be moved up to a more abstract type
without affecting everything it's attached to.

>What about an OOP system that doesn't mutate by design?

You may lack the insight to realize it, but if you are doing this your program
is basically a functional one. Your loops become recursion, you become unable
to write procedural steps and your methods become isomorphic to stateless
functions. You are no longer in OOP land.

>I agree that OOP is worse than FP. There are a few features of FP that make
it superior in many respects (notably required immutability and an algebraic
type system).

An algebraic type system is not exclusive to FP. It's included in Rust which
is not an FP language. It has nothing to do with OOP or FP.

~~~
kingdomcome50
>OOP is programming oriented around objects. The core feature of OOP is
objects

Objects DO NOT HAVE to be mutable. As I have _repeatedly_ stated, you are
building a straw-man. That is, you are creating your _own_ definition of OOP
(objects and to some degree FP) and using it to support your argument about
modularity. Refer to the "Specialized Objects" section of:
[https://en.wikipedia.org/wiki/Object_(computer_science)](https://en.wikipedia.org/wiki/Object_\(computer_science\))

>Immutable object: an object set up with a fixed state at creation time and
which does not change afterward.

Crystal clear. Even the single sentence in which you are basing this entire
waste-of-time argument on:

>A feature of objects is an object's procedures that can access and often
modify the data fields of the object with which they are associated

in no way supports your conclusion with any rational reading. A "feature" of
objects is procedures that can "often" modify fields. It takes some serious
gymnastics to read that as "mutability is a required property of OOP". I have
yet to find a resource that supports your definition of OOP (and I'm
looking!).

>if you use immutability your program is isomorphic to functional programming

Being isomorphic to a functional program doesn't mean the program isn't OOP.
From the same page above:

>Object-oriented programming is an approach to designing modular reusable
software systems

OOP is an approach. It is the _approach_ one takes when designing a system
that determines whether or not that system should be understood as OOP. If the
approach uses the "Features" of OOP (listed on the wiki), then the system is
OOP.

Your entrenchment on this topic is astounding. Again, I don't have to be wrong
about `noun.verb` vs `verb(noun)` for your conclusions about how we abstract
software to stand. My intention wasn't to disagree with you, it was simply to
point out that all paradigms suffer from modularity problems as they relate to
functions acting on state.

>it is easier. We've talked about the deeper difference

No, but we have. And I've clearly demonstrated that same problem presents
itself. That's how we got here. You needed to change the constraints of the
problem (that objects _must_ mutate) in order to make a coherent argument (the
straw-man). That got us to this separate argument about the definition of OOP
(moved goal posts). Here is the moment above when you played your hand (and
lost the argument):

>A stateless function versus a function that carries it's own mute-able state.
There is MORE than a semantic difference. The semantic difference you're
referring to is when the SELF value is immuteable. In that case the two ways
of calling the function become more similar, but THAT is NOT OOP

Instead of doubling down and starting this dumper-fire of a discussion, you
could have simply responded with something like:

"That's correct. Which makes it even more pragmatic that we strive to abstract
the server model into code, because the problems with modularity/distribution
cannot be avoided in _any_ programming paradigm. That is, the level of
abstraction where we WRITE code is not the same, or appropriate level of
abstraction used to modularize/distribute code. If, instead of explicitly
hard-coding the boundaries of communication into a system, we could abstract
the boundaries into compilation as a matter of configuration, it would allow
for any arbitrary level of modularization/distrubution without the need to
change the source code itself".

The above makes a great point (your point), and has actually served as
inspiration for my latest side-project. So kudos to you for that.

~~~
crimsonalucard
>Objects DO NOT HAVE to be mutable. As I have _repeatedly_ stated, you are
building a straw-man. That is, you are creating your _own_ definition of OOP
(objects and to some degree FP) and using it to support your argument about
modularity. Refer to the "Specialized Objects" section of:
[https://en.wikipedia.org/wiki/Object_(computer_science)](https://en.wikipedia.org/wiki/Object_\(computer_science\))

I don't know how to get it through to you what I'm talking about. You fail to
understand repeatedly.

In procedural programming YOU CAN MAKE values immutable. Mutability is not a
requirement. You don't even have to have procedures in procedural programming.
Your functions can be singular expressions of one procedure, equivalent to a
functional function. Additionally you can attach all your first class
functions in lists, dictionaries or namespaces which makes it equivalent to an
OBJECT.

So why even have the words "procedural program" when it has utterly no
requirement and can mutate to fit any form of programming? Above I describe
using procedural programming to fit OOP and to fit functional programming.
It's THE SAME STORY for OOP.

OOP can be used to imitate what we traditionally call functional programming
and even procedural programming. Thus everything has an isomorphism.

THEREFORE: When you compare procedural programming and functional programming
you HAVE to COMPARE the variant features. PROCEDURAL PROGRAMMING has
procedures, while functional programs have expressions.

What does this mean with OOP and all other forms of PROGRAMMING? Mutability.
Technically YOU DON'T HAVE TO use mutability, but it's pretty pointless if you
DON'T and you can pretty much call your programming style functional if you
don't. Mutability is one of THE CORE FEATURES that separates it from other
forms of programming. The reason why is because having every single method in
an OOP program be a method that mutates its own state leads to horrible design
so people usually use it with a combination of both stateless functions and
mutating methods. The issue is Almost NOBODY realizes this.

The logic is inescapable: THE CORE DIFFERENTIATOR IS MUTABILITY.

>Crystal clear. Even the single sentence in which you are basing this entire
waste-of-time argument on:

No man. It's my time that you are wasting here.

>in no way supports your conclusion with any rational reading. A "feature" of
objects is procedures that can "often" modify fields. It takes some serious
gymnastics to read that as "mutability is a required property of OOP". I have
yet to find a resource that supports your definition of OOP (and I'm
looking!).

Read my explanation above. Procedural programming, for loops and while loops
DO NOT REQUIRE Muteable values. Yet try to write a for loop without a mutable
value see how far you can go in writing a closed function like that without
IO.

You won't find anything on the topic JUST LIKE you won't find anything talking
about methods and functions being ONLY semantically equivalent. If you do find
some idiot blogger who actually supports this claim without mentioning
immutability then he likely doesn't know what he's talking about.

>Being isomorphic to a functional program doesn't mean the program isn't OOP.
From the same page above:

It's LITERALLY equivalent ACCORDING TO YOU. You called it only a SEMANTIC
DIFFERENCE. And I said the SEMANTIC DIFFERENCE ONLY EXISTS if the values are
immutable but to you they ARE ALL THE SAME.

>OOP is an approach. It is the _approach_ one takes when designing a system
that determines whether or not that system should be understood as OOP. If the
approach uses the "Features" of OOP (listed on the wiki), then the system is
OOP.

The approach according to you is basically the SAME THING as everything else.
I mean verb1(noun1) verb2(noun2) is the same damn thing as noun2.verb2() and
noun1.verb1(). There is literally NO DIFFERENCE from this APPROACH to any
other APPROACH according to your misguided logic.

>Your entrenchment on this topic is astounding. Again, I don't have to be
wrong about `noun.verb` vs `verb(noun)` for your conclusions about how we
abstract software to stand. My intention wasn't to disagree with you, it was
simply to point out that all paradigms suffer from modularity problems as they
relate to functions acting on state.

What's astounding is your lack of understanding. You're intentions don't
matter, the topic that I am pointing out is that you are completely and
utterly WRONG. You being RIGHT has incredibly absurd consequences.

>No, but we have. And I've clearly demonstrated that same problem presents
itself. That's how we got here. You needed to change the constraints of the
problem (that objects _must_ mutate) in order to make a coherent argument (the
straw-man). That got us to this separate argument about the definition of OOP
(moved goal posts). Here is the moment above when you played your hand (and
lost the argument):

You've clearly demonstrated a LACK of understanding. AGAIN, what you see as an
unnecessary constraint is NECESSARY.

Let me use a more clear analogy. How do you compare the difference between a
MAN and a WOMAN? Why you compare the color of their hair, eyes and the amount
of fingers they have. Do you really? Or is it a complete act of stupidity to
compare the properties THAT ARE NOT EXCLUSIVE TO EITHER?

Let me use a more clear analogy. How do you compare the difference between OOP
and FP_______? Why you compare how OOP can be immuteable and how FP can be
immutable, you compare how methods and functions can return values... Do you
really? Or is it a complete act of stupidity to compare the properties THAT
ARE NOT EXCLUSIVE TO EITHER?

Read the above to paragraphs. This is what your entire illogical argument
looks like. The only person who lost is you.

>Instead of doubling down and starting this dumper-fire of a discussion, you
could have simply responded with something like:

>"That's correct. Which makes it even more pragmatic that we strive to
abstract the server model into code, because the problems with
modularity/distribution cannot be avoided in _any_ programming paradigm. That
is, the level of abstraction where we WRITE code is not the same, or
appropriate level of abstraction used to modularize/distribute code. If,
instead of explicitly hard-coding the boundaries of communication into a
system, we could abstract the boundaries into compilation as a matter of
configuration, it would allow for any arbitrary level of
modularization/distrubution without the need to change the source code
itself".

The above is completely wrong. The problems with modularity AND distribution
CAN be avoided but it comes at a cost. You're just too blind to see it.
Modularity is actually a very clear concept that is quantifiable.

If every single possible primitive in your program was a immutable module THAT
is the MAXIMUM modularity your program can afford. If your program has 5
primitives then 5 is the maximum amount of modules you can have. At a
modularity of 5 modules can be composed into higher level modules of your
choosing building a pyramid of modules where each level has less modularity
then the level below it.

IF your entire program was one single MODULE that could not be reused that is
the LOWEST possible level of modularity your program can achieve. In short 1
is the lowest number of modules a program can have.

The only thing we are doing with modularity is picking arbitrary walls and
grouping arbitrary amounts of primitives. It's a multidimensional gradient. In
a program with ABC primitives you have this many possible groupings (A)(B)(C),
(AB)(C), (AC)(B), (BC)(A), (ABC). So 5 possible ways with 3-1 groupings.

What FP does is eliminate arbitrary walls by eliminating mutations.

    
    
       F(x) = (x + 1 + 2) is easily factored into 
       F(x) = G(H(X)) 
       Where G(X) = x + 1 and H(X) = x + 2
    

whereas

    
    
       Object F {
          int val
          H(){val += 1}
          G(){val += 2}
       }
    

cannot be decomposed.

Both programs have two primitive concepts: the addition of 1 and the addition
of 2. That means it has a maximum modularity of 2 modules. However only
function F can be decomposed into two modules without changing the
nature/signature/interface of F itself. Object F cannot be decomposed without
changing what F is.

So in short if your FP program was modularized via (HG) it can easily be
broken down to (H)(G) in which case modules can be recomposed however you
like... The OOP version cannot be decomposed it is (HG) forever because
mutability ties both methods to state.

The problem that exists at the infrastructure level is that MUTABILITY must
exist. It's called databases. No server is an F(X) but rather it is a method H
or G that is coupled with val (the database).

>The above makes a great point (your point), and has actually served as
inspiration for my latest side-project. So kudos to you for that.

You mean taking my idea of writing code or a framework that compiles into
servers? Having decorators on functions that specify what part of the
infrastructure a function is located in? Composing two functions in code and
having that compile into two servers communicating?

It's sort of been done. See RPC frameworks like thrift and gRPC. If you use
the same language for all your servers with something like thrift as the
connector between all the servers then you achieve roughly the same effect as
a language that compiles into servers. The only difference is that your code
won't influence the infrastructure, RPC only removes the walls between
servers.

~~~
kingdomcome50
I urge you to attempt to condense your replies into more coherent prose. I'm
not entirely sure what my takeaways from the above should be.

You seem to have moved the goalposts again from "OOP requires mutability"
(which I think you have given up) to "OOP is different from FP":

>THE CORE DIFFERENTIATOR IS MUTABILITY

Aside from the fact that the above is not true (the core differnetiator is all
of those "features" listed in the OOP wiki), I have explained a couple of
times now that I did engage in this to argue about the differences between OOP
and FP. There are numerous differences, and they have very little to do with
my (or your) original claims -- other than the fact that you keep trying to
move the goalposts to this topic as a means to say that because OOP is
different than FP, `noun.verb` must also be different than `verb(noun)` in
terms of modularity/dependencies. You are broadening my claim substantially
(straw-man).

Again, this is the claim you made:

>If that method was never unionized with state, if we used smaller
subdivisions in our code where state and functions are separate entities then
this would be much less of a problem. The function would not be tied to state
and that function can be executed in the context of anything.

to which myself and two other commentors sought to clarify. The `function`
above cannot be executed in the context of anything. It _must_ be executed
from a context that has a reference to `state` (because `state` is an argument
to `function`). Notably, this is the _same_ context required to invoke the
`method`. Similarly, the context _of_ the `function` and the context _of_ the
`method` are the same -- they both have access to the same variables
(dependencies). So yes, `noun.verb` vs `verb(noun)` is just semantics; both
the surrounding and internal contexts are the same. Choosing one approach to
express the behavior over the other makes no difference in terms of
modularity/dependencies.

~~~
crimsonalucard
>I urge you to attempt to condense your replies into more coherent prose

My prose is coherent. I urge you to gain the intelligence to comprehend it.
The only real option is to take english classes. This is not an insult, I see
no alternative to help you comprehend english better other than taking a
class. Seriously. It's not me, it's you.

> I'm not entirely sure what my takeaways from the above should be.

It's your comprehension that needs work. Re-read it if you can't understand or
ask for clarification before you respond. If you have good english then
honestly the only other logical explanation is your intelligence. Again not an
insult, just observations.

>"OOP requires mutability"

It does THIS NEVER CHANGED. But many methods can be stateless. For your
Program to be OOP there must exist methods that mutate state. It IS REQUIRED.
If not then you're not doing OOP. Get it?

>Aside from the fact that the above is not true (the core differnetiator is
all of those "features" listed in the OOP wiki), I have explained a couple of
times now that I did engage in this to argue about the differences between OOP
and FP. There are numerous differences, and they have very little to do with
my (or your) original claims -- other than the fact that you keep trying to
move the goalposts to this topic as a means to say that because OOP is
different than FP, `noun.verb` must also be different than `verb(noun)` in
terms of modularity/dependencies. You are broadening my claim substantially
(straw-man).

Why don't you read my entire claim and respond to each snippet as I have done
for you. Rather than take one of my claims ignore all the evidence I provided
and go off on your own wild tangent and calling it a straw man. If you want to
make my claim a strawman you need to respond to EACH of my points of evidence.
I honestly don't even think you read my post. You just did a quick scan and
used coherency as an excuse to avoid reading. I responded to your "kudos" as
well, which was completely ignored.

>to which myself and two other commentors sought to clarify. The `function`
above cannot be executed in the context of anything. It _must_ be executed
from a context that has a reference to `state` (because `state` is an argument
to `function`). Notably, this is the _same_ context required to invoke the
`method`. Similarly, the context of the `function` and the context of the
`method` are the same -- they both have access to the same variables
(dependencies). So yes, `noun.verb` vs `verb(noun)` is just semantics; both
the surrounding and internal contexts are the same. Choosing one approach to
express the behavior over the other makes no difference in terms of
modularity/dependencies.

Man, we're going in circles. This is crystal clear and you are WRONG. Read all
previous post CAREFULLY. Respond to each point if you disagree. The logic is
inescapable if you have the ability to follow it. If not this conversation is
over.

~~~
kingdomcome50
It never ceases to amaze me how transparently people project their
insecurities. I read your post. It was far too long, and all over the place.
My response was focused only on the aspects I find relevant to the discussion
at hand. I do not need (nor have any desire) to pick apart every point you
attempt to make, however inaccurate or imprecise I find them to be, in order
to compose my argument.

>For your Program to be OOP there must exist methods that mutate state

Provide me with a single resource that supports this claim (emphasis on
"must"). I have found exactly zero corroborating sources that affirm the
above, but many that (coincidentally enough all agree) mutability is an
implementation detail in OOP. As far I have seen your logic is:

1\. Objects _can_ mutate state

2\. OOP uses objects

3\. OOP _must_ mutate state

Something is amiss... But digress.

I have quoted, a number of times now, the single excerpt from your OP to which
I sought to add some clarity. I suppose I can do it again:

>If that method was never unionized with state, if we used smaller
subdivisions in our code where state and functions are separate entities then
this would be much less of a problem. The function would not be tied to state
and that function can be executed in the context of anything.

It's rather narrow in focus, and suggests that separating functions and state
leads to more modularized/portable behavior. My response is rather simple in
substance: Simply reorganizing `noun.verb` to `verb(noun)` doesn't make any
difference in terms of modularization. In other words, the `verb` is tied to
`noun` in either case.

That is _not_ to say there is no difference at all. In terms of extension (the
expression problem) it is well-known that basic OOP and basic FP are
complimentary in this regard. Where OOP allows for open extension of data, FP
allows for open extension of operation.

~~~
crimsonalucard
>It never ceases to amaze me how transparently people project their
insecurities. I read your post. It was far too long, and all over the place.

It wasn't. Likely you just scanned it without any real analysis. The post is
long because of charity to you. It was done with examples to help YOU
understand. I have obviously failed to anticipate the complete nature of your
mental aptitude. The logical conclusion is that you likely aren't intelligent
enough to comprehend any of this, this is not my insecurity rather more you
reassuring yourself that it isn't reflection of your intellectual abilities.
Unfortunately, It is.

Also, Nothing was off topic, each part of my response was a reply to each
point in your response.

>Provide me with a single resource that supports this claim (emphasis on
"must"). I have found exactly zero corroborating sources that affirm the
above, but many that (coincidentally enough all agree) mutability is an
implementation detail in OOP. As far I have seen your logic is:

>1\. Objects _can_ mutate state

>2\. OOP uses objects

>3\. OOP _must_ mutate state

>Something is amiss... But digress.

I have stated this point a dozen times.

Because we are COMPARING OOP with other forms. The attribute of MUTABILITY
must be compared. Because THAT is the form that breaks the isomorphism between
OOP and FP. Otherwise we are comparing the Exact Same thing. There's no point.
That is the property that breaks the "semantic equivalence" So when comparing
definitions you MUST incorporate the property of mutability. It MUST be part
of the DEFINITION we compare For this reason otherwise we are comparing
nothing.

I used procedural programming as an isomorphic example of this above and the
comparison of Human Males and Females. Read it again, it may kick some of
those brain cells into gear. You believe that you are putting more "focus" but
rather your incapability of understanding things is making you perceive things
as off topic.

This conversation won't go anywhere unless you address those topics because
what you are doing right now is restating your opinion when I have already
addressed why your opinions are wrong. So to move forward you must address why
I am wrong about you being wrong. This is how discussions/debates go. That's
an extra IQ point given to you for free.

Also big thank you for stealing my idea. You're a real stand up guy.

~~~
kingdomcome50
>Because we are COMPARING OOP with other forms

I cannot stress this enough: I am _NOT_ comparing OOP with other forms (in a
general sense). I have corrected you repeatedly on this (and pointed out how
it is straw-man). My claim that `noun.verb` does not differ from `verb(noun)`
in terms of modularity is _not_ that same as the (much broader) claim that OOP
is isomorphic to FP. I have never made the latter claim, nor do I believe it
to be true [1].

I understand that it does not behoove you to address my argument in good
faith, but at some point we have to stop running in circles. Maybe you just
misunderstood what I was attempting to say? (this is me giving you a chance to
save face)

[1] If I were pressed to describe the relationship between OOP and FP, I would
say they are complimentary approaches to designing software (in reference to
the expression problem). I _wouldn't_ go so far as to say they are
incompatible with one another:
[https://stackoverflow.com/questions/3949618/are-fp-and-oo-
or...](https://stackoverflow.com/questions/3949618/are-fp-and-oo-orthogonal)
(as a matter of sheer coincidence many of the answers also discuss OOP and
mutability)

~~~
crimsonalucard
>My claim that `noun.verb` does not differ from `verb(noun)` in terms of
modularity is _not_ that same as the (much broader) claim that OOP is
isomorphic to FP. I have never made the latter claim, nor do I believe it to
be true [1].

Yes but the context of the entire thread is OOP. The semantic claim is made in
that context. Also intuitively everyone who reads that will think noun.verb is
OOP and verb(noun) is not. It's more like you moved the goal posts.

This also contradicts your claim of FP being different from OOP despite
semantic equivalence. If there was only a semantic equivalence between
noun.verb and verb(noun) then this implies OOP and FP are isomorphic. There is
no other way to call functions or methods in either case and therefore they
are the same under this misguided logic.

>Maybe you just misunderstood what I was attempting to say? (this is me giving
you a chance to save face)

Save face from what? The thousands of people watching this conversation? I
don't even care... this is the internet. Nothing was misunderstood by me.
You're the one that's misunderstanding.

>If I were pressed to describe the relationship between OOP and FP, I would
say they are complimentary approaches to designing software (in reference to
the expression problem). I _wouldn't_ go so far as to say they are
incompatible with one another:
[https://stackoverflow.com/questions/3949618/are-fp-and-oo-
or...](https://stackoverflow.com/questions/3949618/are-fp-and-oo-or..). (as a
matter of sheer coincidence many of the answers also discuss OOP and
mutability)

The expression problem is the same problem in FP and OOP according to your
semantic equivalence logic. Simply rewriting noun.verb into verb(noun)and vice
versa makes both data and operation problems exist in all forms of programming
ONLY when values are immutable.

Another way to put it is that FP/immutability solves the expression problem by
allowing you to change between the two styles of organization.

When OOP is immutable the two approaches are not orthogonal, they become
parallel or identical. It is only when mutability is forced by only allowing
member functions that mutate values rather then return results does the
expression problem begin to change. This is when both design paradigms
actually change and the dichotomy of the expression problem becomes apparent
in the context of OOP and FP.

Stack overflow is even less credible than a medium blog post. There's no
reason to resort to what you perceive to be authority to dictate what OOP and
FP is. I don't even believe there's an officially sourced definition. All you
need to do is take what humans as a majority intuitively understand as OOP and
translate that into english. Likely when you ask a typical layman to translate
his own intuition he'll get it wrong like the teeming millions on the
internet. Just use logic to translate the ludicrous consequences of various
"proposed" definitions to see which are valid.

~~~
crimsonalucard
You haven't responded which I presume means you've finally been enlightened.

------
butterisgood
Bit of a clickbait title... reasonable discussion.

------
wildster
They should not have class variables.

------
di4na
Cough cough. Seems someone has not really looked at the reality of the field.

Erlang is right there, i advise a look :)

~~~
mpweiher
The "reality of the field" is that the WWW was/is built with Erlang?

I definitely _did_ miss that.

Back to the drawing board, I guess... ;-)

------
frozenport
History needs to reevaluate Alan Kay as most of what he said was wrong.

Here is a cringe worth talk from 1997 where he claims the internet is
disfunctional because it nit standalone and that all developers should build
their own tools and compilers.

[https://m.youtube.com/watch?v=oKg1hTOQXoY](https://m.youtube.com/watch?v=oKg1hTOQXoY)

~~~
edejong
"HTML on the internet has gone back to the dark ages because it presupposes
there should be a browser that understands its format."

This is the _fundamental_ reason the modern internet is centralizing to a
couple of entities.

"This has to be one of the worst ideas since MS-DOS."

Yes, the modern browsers have taken us back at least 20 years when it comes to
UI design, component based programming and distributed systems. The web is an
endless stack of kludges, held together by duck-tape. I can back this up, in
case you don't believe me.

But, we should ask ourselves how it became such a stack of kludges. And I
think Alan hits the nail on the head.

"At the very least, every object should have a URL. I believe every object on
the internet should have an IP. It represent much better what the actual
abstracts are of the physical hardware to the bits. "

Beautiful insight. The URL does not scale from a systems perspective. In my
designs, I see myself often using UUIDs and negotiation to transfer knowledge
about entities. The URL (and RESTful communication) is an annoyance. It
fixates the location to something arbitrary. I can only use one hierarchy to
denote the same object. I cannot easily renegotiate how the same things are
named in my systems. And, the worst: the type of the object is often included
in the url. `[https://foo.bar/person/123`](https://foo.bar/person/123`)
_fixes_ the type 'person' to the object 123.

URLs nowadays are an abomination. Most are not durable, contain excess
information and suffer from projecting the information against an arbitrary
axis.

Finally, all developers should at least once have implemented their own
compiler. It is not a hard experience at all and can be done in around 100
hours by someone with a medium skill in programming using a good text-book. It
gives a truly fundamental insight into systems design and should simply not be
skipped.

W.r.t. tools: I assume any programmer worth his salt has build at least some
of their tools! Perhaps I should start asking this at interviews. If you don't
understand how your tools are built, how can you even begin thinking about
building tools for others? And how can you understand, without attempting a
crude build yourself? All the hard things are already done, the literature is
there, the books are written.

So, anyways, you make a bold claim: "most of what he said was wrong." This is
awfully vague, I am afraid. Lets make it a challenge. Except for him making
predictions, I challenge you to come up with a couple of statements from Alan
Kay, and we'll discuss it.

~~~
mgummelt
> This is the fundamental reason the modern internet is centralizing to a
> couple of entities

The reason Google and Facebook dominate the internet has little to do with
technology and much to do with economics, namely scale economies and network
effects.

> Yes, the modern browsers have taken us back at least 20 years when it comes
> to UI design.

I'll grant that CSS is a mess. What else?

> I can only use one hierarchy to denote the same object.

You can create multiple URLs that point to the same object.

~~~
edejong
> The reason Google and Facebook dominate the internet has little to do with
> technology and much to do with economics, namely scale economies and network
> effects.

And the network effects can only happen because there is a tight coupling
between the data (contained and scrambled within the HTML page) and the
presentation. Had data and presentation be decoupled, I could have combined
network information from various providers and present it to me in one
overview.

> I'll grant that CSS is a mess. What else?

Everything. The security model, the fact that the user has limited control
over their identity (and it is not build into the protocols), the multi-
threaded nightmare, no component standardization, very limited integration
with low-level OS systems, the 'one-tab is one context' metaphor, the box-
model, the misfit of page-to-interaction (and the history API), the non-
existent voice interaction, the color-model, the DPI/pixels/ems
transformations, the invisible local storage we barely manage, the resource
utilisation, the lack of uniformity in the programming model, the peer-to-peer
communication (WebRTC does not count, since it is not standardized and has
quite some flaws), the lack of (easy) customization abilities (high-contrast
websites), the limited math-rendering, the enourmous complexity... I could go
on.

> You can create multiple URLs that point to the same object.

Yes, but they would not denote equivalence. I could use a redirect, but then
one system needs to know the representation of the other. It would be
fundamentally asymmetric.

Also, it would contradict the term _Unique_ Resource Locator.

~~~
mgummelt
> no component standardization

This one is interesting because Alan Kay is so expressly against it ("browsers
shouldn't have features"). He thinks every object should just render itself as
a bitmap.

Besides, browsers do have standard components. That's what the semantic HTML
tags like <button /> are. The specific views vary between browsers. Is that a
problem? Regardless, almost no site uses the standard stylings that do exist.
They use a de facto standard like Bootstrap, or they build their own.

I agree with some of your other points, but I don't understand your lament of
"enormous complexity" while you're advocating for more features.

~~~
discreteevent
One thing about rendering to a bitmap is that it is more robust over time.
Look how much code is in the browser to support older styles of html. Smart
endpoints dumb pipes, prevents ossification. The browser tries to be far too
smart for its own good and ends up making a mediocre job of everything while
being hugely complex (as outlined by parent above)

------
ganitarashid
Title assumes that Alan did in fact get anything wrong, which is incorrect

