9 ms·
Execution in the Kingdom of Nouns (2006)
- fmstephe 14y agoIt'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 https://github.com/fmstephe/Erlang-Sat-Solver
- tikhonj 14y agoA "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 14y agoIt 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.
- dschiptsov 14y agoToo 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 14y agoWell, 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 14y agoCLOS is really required in about 5% of very specialized tasks, such as simulations.
- arethuza 14y agoI'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 14y agoI 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).
- zby 14y agoThe 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.
- crntaylor 14y agoThat's why functional aficionados love to work with higher-order functions!
- tikhonj 14y agoThis 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.
- cmbaus 14y agoOldie but a goodie.
- habosa 14y agoThis 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 14y agoI 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 14y agoI 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.
- fmstephe 14y agoI would strongly suggest you give Erlang a try. It is a fairly pure functional language, but very very simple. You don't have to user the concurrency distributed parts. I think this is actually an important thing that is missed when functional languages are touted as the next-big-thing we are always talking about Scala and Haskell. When we go learn either of these languages you climb a steep ladder into a world of very sophisticated type systems and this becomes the focus of our discussion of functional programming. Alas, I fear we lose the most powerful lessons that functional programming has to give us. 1: Code operating on immutable data-structures is often really easy to reason about effectively 2: Recursion is a really great way to think about programming 3: Functions are wonderful when you can pass them around like data The type systems in Haskell and Scala, not to mention the venerable Ocaml, are amazing and powerful. But I think they are often a distraction from the core benefits that a functional code base provides.
- abc_lisper 14y agoYeah, but you can always have static methods, which let you call a function without creating an object.
- metaphorm 14y agoand you can, in principle eat soup with a fork. but in practice you shouldn't.
- abc_lisper 14y agoThis, I agree. It is in the spirit of "Beware of the Turing tar pit in which everything is possible but nothing of interest is easy."
- Roboprog 14y agoSure, 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).
- deleted 14y ago[deleted]
- deleted 14y ago[deleted]
- deleted 14y ago[deleted]
- abc_lisper 14y ago* C: function pointer is a hack. The evidence of this is in the code. Most people don't even know it can be done, and it is rarely done in code(in some central piece no body looks at) * Pascal: It's been a decade since I last looked at it, but I don't know if procedural type can be passed around. * Java: Yep, Java doesn't have first class functions. Will give you that. However, in his example, Yegge was talking as if everything in Java has to be a object, and that somehow functions cannot be called without an associated object. If you think C function pointers are a valid argument, I can provide a similar hack in java http://pastebin.com/cSJ8ffar http://pastebin.com/cSJ8ffar You can call as many methods as you want. It is disturbing to me when people think C is some holy grail. C, at it is best, is conceptually weak. It is great for working with hardware, but for language features, it would be at the bottom of my list to look at.
- abecedarius 14y agoOOP 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 14y agoTrained 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 )
- metaphorm 14y agoYegge is a great author. I really wish his collected rants book was available in paper and not just the Kindle edition.
- gweinberg 14y agoIt'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.
- rdouble 14y agoThe common complaint is that he's ok, but needs an editor. However, he is an awful writer. An honest editor would tell him to give up.
- Roboprog 14y agoPart of the humor in this post, to those who find it funny, is that it is in fact so painfully long. ... in the same way that Java's OOP "purity" forces things to be too bloody long all too often.
- qu4z-2 14y agoIs "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.
- KevinEldon 14y agoI 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 14y agoIt 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 14y agoThis 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.
- pcote 14y agoI 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.