I don't consciously "troll" on reddit (in this post by "reddit" I mean programming reddit, I rarely use main or joel reddits), or for that matter anywhere else. The only place where I can remember starting flame baits on purpose was alt hierarchy on Usenet, and trolling is kinda the point there.
But we all know most flame wars are started unintentionally. Someone makes a completely honest comment, someone else feels strongly about the subject and honestly replies in a way that angers more people, and eventually everything is on fire, and people accuse each other of trolling. Genuine trolls are few and far between.
The way reddit comment system works, everybody can moderate any comment by clicking either up-arrow (+1) or down-arrow (-1). If comment gets score -5 or worse, it is hidden from the default view, and can only be shown by clicking "show comment". Comments start at +1 (reddit assumes everyone up-arrows own comments), so if 6 more people down-arrow than up-arrow your comment, it will be hidden in default view.
Most of my comments on reddit are moderated positively, neutrally, or at worse slightly negatively. However, a few of them were down-arrowed intensely enough to get hidden. I'd like to take a look at them now. Maybe they'll reveal something about me, maybe they'll reveal something about reddit comment system, or reddit community. I have no idea yet.
First some statistics. I made 46 comments. The best rated of them got +17, the worst rated got -10. Mean rating is +2.5, median is +2, two comments got ratings bad enough to be hidden (-6 and -10), eight others had bad ratings but weren't hidden (-3, -2, five -1s, and 0). So ten comments weren't liked by the community. Here they are.
- -10 points, "Common Lisp sucks". It is factually correct, but feels emotionally loaded. Still, one would think that factual correction of article called "Common Lisp - Myths and Legends" that actually contains mostly propaganda would be treated better.
- -6 points, "CLOS sucks". Another 100% factually correct comment. This time it had nothing emotionally loaded inside.
- -3 points, "links to relevant content". This one baffles me most. I linked two articles that were the most relevant articles on the subject. Well, the original poster "read that Steve Yegge piece", but half of what Steve Yegge writes is related to the question, so I wasn't really sure if he meant this one. Mention of RLisp was clearly emoticoned, so it shouldn't matter.
- -2 points, "keep your rants short". This one is emotionally worded, but the point is valid - the original rant should have focused on the important issues. Instead, it criticizes everything, whether it makes sense or not. This kind of ranting is harder to read, less useful for readers, and less powerful at getting the point through, whatever the point is.
- -1 points, "formal methods suck". This one is directly related to the commented paper, and factually correct - some things (like formal methods) are popular in the academia, because they make good papers, but they aren't popular anywhere else, because they aren't very practical. Do you think you could publish a paper on unit testing a simple program ? You couldn't, but the formal method guys could. And what are you going to use in real programs anyway ? Yeah, unit tests.
- -1 points, "XML isn't that bad". A simple list of reasons why XML is better than S-expressions for markup, and better than "simple custom text-based formats" for configuration. I don't see anything controversial here.
- -1 points, "Smalltalk is better than Lisp". I point out that Smalltalk has every feature on the list, and without Lisp paretheses. I also point out that the question of relative power of Lisp macros and Ruby-style metaprogramming can be proven once and for in RLisp. It's not in the post, but heavy macro use doesn't seem to require Lisp syntax, see Nemerle macros and Dylan macros [PDF] (nobody uses Dylan, but the concept of "skeleton syntax" in the paper seems very interesting).
- -1 points, "Technical details why Common Lisp sucks". Someone disagreed with my comment, so I replied explaining some details.
- -1 points, "Common Lisp was designed for Lisp machines". Factual correction, with links to the relevant sources.
- 0 points, "Java is the most popular language". Someone claimed that Visual Basic is more popular than Java, and that popularity doesn't matter. I disagreed on both points.
So there doesn't seem to be a single troll among the downmoded comments. And it's clear that criticizing Common Lisp is a sure way of getting downmoded, whether the criticism is factual or not, and whether the comment it is emotionally loaded or not.
This posts seems pretty boring, so here are three extras.
First, a comment on reddit by some smug Lisp weenie. I think the poster was just angry at me, not trolling on purpose. Still, it's absolutely hillarious.
The second is a point from one of my downmoded comments:
Some people keep repeating that one "language" or another is slow. Assembly coders used to say that about C, now C luddites say that about Java, and smug Lisp weenies together with Java zealots about Ruby. The "performance" argument shows how desperate they are, having run out of more decent arguments. In the real world of course:
- It is extremely atypical for programs to be CPU-bound by operations within the program. Most programs are programmer-bound, or network-bound, or disk I/O-bound, or CPU-bound within some library code (like SSL or movie decoding or whatever).
- If the program is actually CPU-bound by own operations (what is very rare), high-level optimizations like changing the algorithm, caching, etc. usually fix it.
- In extremely rare case when high-level optimizations are not enough, performance-critical parts can usually be rewritten in lower-level language, like C for high-level languages, or assembly for C. The idea that one language must be used for everything (common among the Common Lisp folks) is retarded. The program is 99% high-level language, 1% low-level language, and performs as well or better than one written in 100% low-level language.
- There are a few cases when even rewriting small parts in lower-level languages is not enough. This is extremely rare, you're unlikely to write such program even once in your lifetime. A good example are codecs. But programs that need that much performance are never written in a single language anyway ! They invariably use very heavy assembly. Just look at any audio/video codec, or libssl, or whatever. I've never seen a single program that didn't use any assembly, and it was too performance-critical to use "99% high-level language, 1% low-level language" formula.
And the third point, one that got me downmoded most:
All decent object-oriented languages (like Smalltalk, Ruby, and ... did I mention Smalltalk and Ruby ?) have been designed with object-oriented programming in mind. Bolting it on later invariably results in something uglier, harder to use, and less powerful. A few languages like Python survived the retrofitting relatively well, most of the time however (Perl, OCaml, I'm not going to say a word about C++ here) the result is disastrous.
CLOS tries to bolt something it calls "object-oriented programming" on Common Lisp, mostly by heavy use of macros. The name "object-oriented programming", which originally (in Smalltalk) meant quite a lot, was abused to the point that it doesn't mean much any more. Some common abuses make it mean "class-oriented programming", "encapsulation", or even particular syntax (
CLOS goes even further than that. Basically, it doesn't even have methods. What it has instead "generic functions". The main reason for it is trying too hard not to introduce any syntax for method calls (also known as sending messages). So while other languages have function calls
f(a, b, c)and method calls
a.f(b,c), CLOS has one syntax for both
(f a b c). The big question is - how does it know whether
(f a b c)is a function call or a method call ? It's simple - all methods used anywhere must be first predefined. So if any object has method
(to_yaml whatever)will try to call method
whatever, whether it has such method or not. Actually there's nothing method-like about
to_yaml- it's really just a function. This function can be defined separately for each "class". So in one place you write definition for converting lists to yaml, somewhere else for converting numbers to yaml, and even elsewhere for converting widgets to yaml.
So simple object-oriented programming is possible with CLOS. Unfortunately it's impossible to emulate
method_missingor do anything else advanced.
If generic function like
to_yamlis applied to object of unknown kind, a
no-applicable-methodhandler is called. Unfortunately it is impossible to setup this handler per-object ! So farewell, dynamic proxies which forward messages they receive to some other object.
no-applicable-methodis called only when the "method" was declared as one. So
(foo bar)instead of calling
no-applicable-methodhandler, or even a generic
no-applicable-methodhandler, is going to call
undefined-functionhandler instead, and
undefined-functionhandler doesn't even get to look at function's arguments.
A very limited implementation of
method-missingin CLOS is here:
; Default method-missing
(defmethod method-missing (m (self t) &rest args)
(format t "~s not found, no replacement method provided!~%" (cons m (cons self args)))
; Should throw an exception ...
; Override global no-applicable-method handler
(defmethod no-applicable-method (m &rest args)
(format t "~s not found, calling method-missing!~%" (cons m args))
(apply #'method-missing (cons m args))
; Now it's possible to make limited dynamic proxies
(defclass dynamic-proxy () ((obj :accessor obj :initarg :obj)))
(defun make-dynamic-proxy (obj) (make-instance 'dynamic-proxy :obj obj))
(defmethod set-obj ((self dynamic-proxy) new-obj) (setf (slot-value self 'obj) new-obj))
(defmethod method-missing (m (self dynamic-proxy) &rest args)
(apply m (cons (obj self) args))
Of course it breaks with multiple dispatch (that's a great reason not to have multiple dispatch), with methods that weren't predefined, and basically with pretty much everything non-trivial.
Anyway, The Right Thing is to separate calling functions from sending messages. So functions would be called like
(f a b c), and methods like
(send obj 'meth foo bar). As sending methods is extremely common, we could even introduce different kind of parentheses for it, let's say
[obj meth foo bar]. Now just add full metaprogramming support, a decent standard library, clean up legacy stuff, and you end up with RLisp.
RLisp sucks in many ways, but at least it has a decent object system. Unlike CLOS.