
Execution in the Kingdom of Nouns (2006) - ksdlck
http://steve-yegge.blogspot.de/2006/03/execution-in-kingdom-of-nouns.html
======
fmstephe
It's nice to see this classic appearing on HN. Certainly worth a reread.
(Edited, thx tikhonj)

The first time I read this article was about one year after leaving
University. I graduated as a near pure Java developer and worked in a pure
java consultancy. I could have recited various GOF design patterns from
memory. By pure luck I was hacking about in Erlang in my spare time.

In Erlang I was managing to piece together a pretty mind bending (for me)
application for distributing depth-first search algorithms over a network. I
was neck deep in learning about all sorts of hard problems and it was only
afterwards that I noticed that I had barely missed the lack of Java-style
object orientation. I was a changed man :) I am still a Java dev but I preach
OO moderation.

Objects are great, but 90% of the time you probably wouldn't miss them if they
weren't there. Now I program Go in my spare time :)

<https://github.com/fmstephe/Erlang-Sat-Solver>

~~~
tikhonj
A "reread if you haven't read it before", eh? :P

That said, I certainly agree with you--it's a great article. It gives a very
good perspective on the issue, and hopefully convinces people who have only
ever worked with nouns to broaden their gaze.

I don't entirely agree with everything Yegge writes--like the most recent
liberal/conservative stuff--but I do agree with this article wholeheartedly.
But then again, I am very clearly the sort of person to verb nouns and then to
lambda :).

~~~
fmstephe
It is probably the most entertaining of all Yegge's articles. And I think it
actually gives a really useful overview of the alternatives that are
available.

------
KevinEldon
I like first class functions. I get hung up on the trash example in this essay
though. To show the commonality of verbs in a person's general understanding
Yegge says 'get the garbage bag from under the sink'. WTF (Who the fuck)
'gets' the garbage? I do. 'I' is implied. I get the garbage from under the
sink. Or perhaps 'Steve' gets the garbage from under the sink. These are nouns
(or pronouns, whatever).

If anything, verbs do nothing without a noun to do them, and nouns need verbs
to do anything. So perhaps we should just acknowledge the value of traits,
objects, and functions and move on. Forgive me (but correct me first) if I
have missed something massive here... I'm trying to drink as much as Steve is
alleged to while writing this comment.

~~~
fmstephe
It is true that there is some being, or noun, that is implicitly taking out
the garbage in his example. I think the important thing to note is that we can
happily _describe_ the process of taking out the garbage without mentioning
who does it.

If we step back and look at it in terms of programming the principle here is
that an Object Oriented insistence on defining and instantiating a doer for
every action is unnecessary clutter.

When a programming paradigm makes people insist that 'everything is an object'
or more alternatively 'static methods are terrible' we have strayed from
simply finding ways to directly describe what we want a computer to do. We are
instead forced into being object oriented.

The example nursery rhymes are a fantastic example of what this culture leads
to. That is my daily life and it can be a horror.

I don't think that Steve Yegge would claim that objects are bad, but it is a
very effective parody of modern Java programming (perhaps C++ and others but I
don't do any of that).

I feel his essay is an excellent rebuttal to the complaint that a piece of
code is 'not very object oriented' in some corners of the programming world
objects have become and end in themselves. Steve is humorously pointing out
that there are alternatives.

~~~
KevinEldon
This was a very nice clarification; thank you. I think your point to look at
this 'in terms of the programming principle' identifies the truth that Yegge
is getting at, the functions should be first class, without the clutter of the
English metaphor.

------
habosa
This is a real classic. As someone who had only done imperative programming
before reading this it really inspired me to give FP a try and led me down the
road to trying Scala and then Haskell. However a year into this adventure, I
still prefer "nouns". I think the human brain really does work imperatively
for most logical problems. I can't deny that for a single problem the
functional solution is often more " beautiful" , but the end user can't see
the beauty of my voice and I can always think of an efficient imperative
solution much faster. I hope one day I'll have a functional epiphany and be
able to write Haskell as fast as I can write Java but so far I haven't had
such luck.

~~~
chc
I think you've mistaken Yegge's point if you see it as "Declarative functional
languages are better than imperative ones." It's more about how the version of
OO embodied in Java warps your program designs in an awkward way. He presents
functional languages as the antithesis of this because, well, they are. But
it's certainly possible for an imperative language to put functions and data
on the same level — Yegge's favorite language, JavaScript, is an imperative
language that does this.

~~~
habosa
I understand it was more anti-Java than pro anything else, I just saw
functional as his solution to this problem. I'm already fluent enough with
Java that I see absolutely no need to switch to a different imperative
language as my main workhorse, so I looked at Haskell as a sort of "go big or
go home" approach to weaning myself off of mutable state, etc.

------
abecedarius
OOP goes bad when you take a centralized design and nominalize the verbs, yes.
It's more fun to think in terms of trained animals: "Trash, go empty yourself
outside."

    
    
        TrashBag >> emptyInto: vessel
          |here| here := self place.
          self go: vessel place.
          vessel add: self spill.
          self go: here
    

This seems just as reasonable as the English he wrote. (I like functional
programming too.)

~~~
russellallen
Trained animals is a good metaphor. Not passive objects acted upon but actors.
Your example is even cleaner in Self which allows implicit 'self':

    
    
      emptyInto: vessel = (| here |
        here: place.
        go: vessel place.
        vessel add: spill.
        go: here
      )

------
zby
The problem with verbs is that they are black boxes. With objects you can
subclass and override methods - do stuff like the Universal Design Pattern -
basing something on prototypes that you tweak here and there. Functions you
can only apply, objects have parts that have names.

~~~
tikhonj
This is why the fundamental operation in the land of the verbs is composition:
do this _then_ do that. It turns out that composition is such a useful idea
that we want more of it, which is where categories, monads and arrows come in.

The most obvious type of composition for functions is, well, function
composition. In math we define the composition of functions f and g as
f(g(x)), usually written as f ∘ g. We can write this directly in Haskell
pretty trivially:

    
    
        f ∘ g = λ x → f (g x)
    

And, in fact, you will see this operator everywhere in Haskell, except most
people are too boring for ∘ and use the ASCII . instead. (Weak.)

Also, a cool aside. I just realized that Haskell syntax is even more regular
than I had assumed. In general, in Haskell, you can rewrite expressions like

    
    
        f x = λ y → ...
    

as

    
    
        f x y = ...
    

Turns out this even works for operators! So you could actually write the above
composition as:

    
    
        (f ∘ g) x = f (g x)
    

I think that's pretty cool, but maybe I'm just easily impressed.

The idea of a category just takes the ∘ operator and generalizes it to other
types, letting you use it for things that aren't normal functions. As I
mentioned above, these things could be arrows or functions involving monads,
but they can really be anything at all. This is, coincidentally, one of the
main reasons we care about category theory: at its very heart, category theory
is the study of composition. (Okay, I'm probably really misrepresenting the
mathematics here, but that's how it works out for programmers :).)

There _are_ also other things you can do with functions. In particular, you
can map functions to other functions. And this is, indeed, what the well-known
map function does. Normally, you think of the map function as taking a
function and a list and then mapping that function over the list. In Haskell,
this has the following type:

    
    
        map :: (α → β) → [α] → [β]
    

However, I posit that map actually does something rather different and more
subtle--it takes normal functions and produces list functions. In fact, the
type signature is better thought of this way:

    
    
        map :: (α → β) → ([α] → [β])
    

(This is why currying is so great--both interpretations are equally valid!)
So, in fact, we can think of the list type as a way of mapping existing types
(like a) to new types (like [a]) and mapping existing functions (like (α → β))
to new functions (like ([α] → [β])).

This operation also turns out to be exceptionally useful. So useful, in fact,
that it's the basis for one of the most fundamental concepts--the functor. In
fact, a functor (in Haskell) is simply any type with a function analogous to
the list type's map. For historical reasons, we call this function fmap and it
has the following type:

    
    
        fmap :: Functor f => (α → β) → (f α → f β)
    

All this says is that, given a functor type, we can map normal functions to
functions over the functor. Another way of thinking about this is that a
functor is roughly like a function at the type level.

Of course, we have other ways to transform functions as well; fmap is just the
simplest. Similarly, we have other ways to compose functions, function
composition is just the simplest.

So the most important idea is that we actually have a fairly wide variety of
operations over functions. We can sling them around as easily as any other
data type, really.

We move forward by _combining_ functions rather than trying to modify them.
Instead of starting with a composite piece and working inwards, we start with
the basic building blocks (functions and types) and work outwards, combining
them in different ways to get a composite program.

It's a difference in philosophy, and I think a rather important one.

~~~
realitygrill
Your explanations of Haskell concepts have been impressing me lately. Do you
write elsewhere?

~~~
metaphorm
of course he does. every Haskell programmer has a blog. some have several.

------
gweinberg
It's funny that this is so popular, because I think it is probably the single
most counterproductive thing written about software ever. Seriously.

As far as I can tell, the only point of speaking about the poor oppressed
"verbs" is to screw up the thinking of the reader, making the reader feel
sorry for them. It seems to have worked in some cases, but is there some other
reason for it?

But what really annoys me is that the author is an illiterate. He doesn't know
what nouns and verbs are. He says nouns don't do much, but of course its only
nouns that do things; verbs are what nouns do. How can anyone read this
without wanting to point out to the author that functions are nouns?

The only substance to his complaint is that Java seems unnecessarily verbose.
Because some objects are one-trick ponies, it seems unnecessary to say "call"
or "execute" or "doit", when that can be implied. But calling a function is
calling a function, whether your language uses the word "call" or not. It is
only because a function is a noun that it makes sense to use a function itself
(rather than its output) as argument to another function or as a return value.
You can use the function as an object precisely because the function itself is
something different from calling (or if you prefer "executing" the function.

~~~
qu4z-2
Is "eat" a noun too now?

What's the subject of the previous sentence?

If we insisted on only using gerunds + "do", English would be a very strange
world indeed. I imagine it would sound much like Java often does: "Eating is
done by me of a sandwich.". Sometimes even "An eating is done [...]" :)

PS: The author is hardly illiterate. That's plain uncharitable.

~~~
gweinberg
<i>What's the subject of the previous sentence?</i>

"eat". Words used as words are nouns in that context. Like the word "eat".
Like the word "word". When something is eaten, someone or something is doing
the eating, eat" doesn't eat itself.

I think it's fair to be a bit harsh when the entire essay is based on grade-
school level misunderstanding of what nouns and verbs are.

~~~
qu4z-2
The question was somewhat rhetorical.

The point I was trying to convey was that even though verbs can be used in a
noun context, that doesn't really make them nouns.

Similarly functions and objects. There's a certain verbiness to a multiply
function that a Cat object doesn't have.

For further consideration: "It rained." What's doing the raining?

------
metaphorm
Yegge is a great author. I really wish his collected rants book was available
in paper and not just the Kindle edition.

------
pcote
I remember reading this. Highly recommended but the methodology dogma goes
both ways.

My take on it is this. Object-oriented and imperative style is eating with a
fork and a spoon. Functional technique gives you a knife. The people I'm most
suspicious of are the ones who think I'd be more productive if one of my
utensils were taken away.

------
abc_lisper
Yeah, but you can always have static methods, which let you call a function
without creating an object.

~~~
Roboprog
Sure, which you can use the following ways:

* C: function pointer

* Pascal/Delphi: procedural type

* JavaScript: function/expression as r-value (weakly typed)

* C#: delegate

* Java: er, ah, well, I guess you're screwed, as there is no way to pass that function around to other functions. Maybe in Java version N+1! (or Scala or Groovy) -- that is, a static function is even worse than a "virtual" function, since you cannot even pass an object/class/interface as a way to call that function (method).

~~~
qu4z-2
I believe the Java equivalent is something like

    
    
      passableF = new NotAClosure() {
        public void execute(int i) {
          return f(i);
        }
      }
    

But maybe someone knows better than me. I've had thankfully little to do with
Java recently.

EDIT: Which I guess defeats the purpose of "without an object", but...

~~~
abc_lisper
Just to note, I am in no way claiming Java is superior. Java is inferior in
ways I think are not the ones Yegge claims.

For me, these are the things Java sucks at.

1) There is no easy way to create lists or maps. Look at python; how easy it
is to create a dictionary. In Java, you have to "write code" to put elements
in a map.

2) Reflection is very weak. It is not type checked at compile time. You have
to write a lot of garbage just to run the show.

3) The getters/setters are a hell. Not to write them mind you, but the amount
of cruft that creeps in, that you have to filter out to get to the heart of
the problem during reading.

4) The constructors: A a = new A() (wtf....)

5) piss-poor Generics.

6) File Operations are pure crap.

7) One class per file? Omg.. For a long time, I thought i sucked at OOPS. The
single biggest reason it took me long to get acquainted with OOPS is because
of one class per file. Any other class is a new file, a context switch in my
mind. In Java, Objects are first class entities; it should be cheap(in terms
of things i need to look at) to define, create, and switch between them.

Finally, I think Java sucks because of its verbosity. And a subliminal style
that it supports. There are a lot of programmers in Java who think the best
way of multiplying two numbers is to add one of them other number of times .
Somehow, everything should be drawn out.

~~~
Roboprog
For all of its warts, Groovy really makes much of this more tolerable in an
environment that readily interoperates (call either way in/out) with legacy
Java code.

Java file handling with dozens of classes still seems a horrific solution,
like you said. I don't miss having to constantly check return codes and
"errno", vs getting IOException, but I do miss the simplicity some days of
"FILE *" and fopen()/popen(). (I also don't miss maintaining code that FAILS
to check error codes while doing I/O)

Thanks for your replies, by the way. Thoughtful without being combative.

~~~
vorg
> For all of its warts, Groovy really makes much of this more tolerable in an
> environment that readily interoperates (call either way in/out) with legacy
> Java code.

5 yrs ago Groovy had the best interop with Java, and its promoters said so
often, but things have changed a lot since then. Perhaps now you'll find
another language has all the interop you need but without those warts.

------
cmbaus
Oldie but a goodie.

------
dschiptsov
Too long. An idea could be stated in a few sentences.)

Java:

This is an instance of an mammal of an animal kingdom which doesn't include
dolphins and whales, which has a..., placed within the instance of a class
Plain of polymorphic shape which has some private attributes...

ML-family:

This is a member of a set of only mammals of animal kingdom, excluding
dolphins and whales, of small size, which has a..., located on the member of a
set of geometric figures....

Lisp:

The cat sat on the mat.

~~~
arethuza
Well, with CLOS you really define your verb behaviour on tuples of nouns
(methods) and the verbs (generic functions) are separate and you can, if you
want, get as creative as you want as to how your methods get invoked by your
generic functions.

[Mind you, it's been a while since I developed in CLOS, so apologies in
advance if this is incorrect].

~~~
dschiptsov
CLOS is really required in about 5% of very specialized tasks, such as
simulations.

~~~
arethuza
I'm not sure - "simple" CLOS is really pretty simple and arguably works in a
more intuitive way than most OO environments. However, if you do want more
sophistication, as with most of Lisp, taking the Red Pill of the MOP can take
you as deep as you want to go....

[Damn - I really need to do some more Lisp development]

~~~
pnathan
I would agree with this... basic defgeneric/defmethod/defclass work is
straightforward. It's when you start with the advice partial methods and the
MOP that things get... _exotic_.

(I read the AMOP earlier this year and I'm pretty sure I haven't recovered
from that mind bender).

