samhuri.net


By Sami Samhuri

August 2007

5 ways to avoid looking like a jerk on the Internet

Let me begin by stating that these are tips I have gathered by posting in many public forums on the Internet and I have learned most of these rules by making the mistakes myself. I'm not trying to point fingers at anyone or act all holier-than-thou. It's a cold, emotionless medium text is. It can be difficult to accurately convey one's feelings when typing a quick reply somewhere. John Gabriel's theory certainly plays a part as well, but I'll try and assume that you are generally a nice person. I also assume that we are talking about a text medium (IRC, forums, Slashdot/Reddit/Digg). None of that fancy voice or video conferencing stuff!

Also, this is not a guide on how to really be an arrogant prick, but just not look like one when you engage in conversations on the Internet. It's also not a guide on not being a jerk. Should you lack basic manners you will have to learn them elsewhere.

Rule #1: Forget the medium

One thing that is quite difficult to do is look past the medium and remember that these are all real people conversing with each other. Don't type anything that you wouldn't say to their face in real life. This is, of course, not exclusive to the Internet.

Rule #2: Remember the medium!

While obeying Rule #1 it's important to remember that in a text medium there is no emotion or tone to our words. If you think that smilies / emoticons are lame and for 12 year olds, well you're right. However, there's no reason for an adult to refrain from using them as well. They can be important quick clues to how your message should be interpreted. You can always rephrase what you write so that there's little ambiguity to your words, but if you're typing something quickly on Digg, Reddit or some forum then you probably aren't spell checking and proof reading each and every post.

Rule #3: Avoid know-it-all responses

Starting a reply with "But ...", "Well ...", "No ...", or "Your mother's a ..." often sounds confrontational. There's obviously no harm in using these in the right context, but many times I have found that removing these from the front of a sentence can drastically alter the tone and make it clear that I am trying to converse rather than argue.

Rule #4: Address the correct party

If you're not speaking directly to the reader avoid using "you" when you mean "one". This is a particularly hard one to get in the habit of doing, for me at least. I am just not used to speaking so formally but in writing it really does make a world of difference. People are defensive creatures by nature and we don't like being singled out or accused. Hell, half of the time we don't even like honest, kind advice.

Rule #5: Accept the fact that people know more than you

Geeks often come across as know-it-alls. While most geeks probably do think they're rather clever (guilty as charged) they probably also know that they don't know everything. When one knows nothing of a topic it's easy to admit that others are right and they are wrong (often because they won't have an opinion on the subject yet). The trouble starts once they learn something about the matter, once they have formed opinions and ideas about it.

I'm not saying that we should all stop discussing things we're not experts on, just that we should try harder to keep open minds about things and realize that others may have some insight we do not. If in doubt, partake in civil discourse and try not to dismiss others without even asking them to back up their claims or ideas.

Cue the comments pointing out how many of these rules I broke in this very post... :)

Captivating little creatures

Someone posted this JavaScript implementation of an old gem on Reddit, Lemmings! There goes my Sunday! :)

Cheat productively in Emacs

By now you may have heard about cheat, the command line cheat sheet collection that's completely open to editing, wiki style. A couple of weeks ago I posted cheat.el which allows one to cheat from within Emacs. There's an update. However, before I get to cheat.el there's a small detour.

Cheat is not just about Ruby! A few examples of cheats available are:

As of today, Aug-21 2007, the count is at 166 cheat sheets so there's probably something there that you'll want to look up from the command line or Emacs sometime. That's enough stroking cheat's ego, but there seems to be a notion that cheat is only for Ruby stuff and that's really not the case.

So what's new in this version of cheat.el? Completion! The only thing that bothered me about cheating in Emacs was the lack of completion. It now has completion, thus it is now perfect. :) In all likeliness this won't be the last release, but I can't really foresee adding anything else to it in the near future. Enjoy!

Download it now: cheat.el

For any newcomers, just drop this into ~/.emacs.d, ~/.elisp, or any directory in your load-path and then (require 'cheat). For more info check the original article for a rundown on the cheat commands.

Catch compiler errors at runtime

While coding just now I had a small epiphany about Ruby. Though Ruby is highly dynamic and compiled at runtime, that doesn't preclude one catching some mistakes at compile time. I'm not talking about mere syntax errors or anything either. The only proviso to catching mistakes at compile time is that you must have a decent chunk of code executed during compilation. One benefit of Ruby's blurring of compile time and runtime is that you can run real code at compile time. This is largely how metaprogramming tricks are pulled off elegantly and with ease in projects such as Rails.

Sure you won't get all the benefits of a strictly and/or statically typed compiler, but you can get some of them. If you have a library that makes substantial use of executing code at compile time then the mere act of loading your library causes your code to run, thus it compiles. If you require your lib and get true back then you know the code that bootstraps the runtime code is at least partially correct.

Compile time is runtime. Runtime is compile time. Just because you have to run the code to compile it doesn't mean you can't catch a good chunk of compiler errors before you send out your code. Tests will always be there for the rest of your mistakes, but if you can pull work into compile time then Ruby's compiler can augment your regular testing practices.

I admit that this is of limited use most of the time, but let it not be said that you can't catch any errors with your compiler just because you have to run your code to compile it. With Ruby the more meta you get the more the compiler rewards you.

[Of course this is true of languages such as Common Lisp too, which make available the full programming language at compile time. I just happened to be using Ruby when I realized this.]

Opera is pretty slick

Though I usually prefer free software, I don't have any problems using proprietary stuff if I think it's good. I had Firefox open for a couple of days and noticed that it was using 700M of memory. That's not a problem at all since I have 4G but it's also a lot of RAM to be in use for just one window with one tab open. The fact that Firefox gets sluggish after some time and needs to be restarted tells me that this isn't expected behaviour and is likely not due to caching for quick back/forward or whatever they claim is taking up the leaked memory.

Konqueror is ok but I'm not a huge fan of it, partly due to its kitchen-sink browser/file manager hybrid design. IMO the KDE folks should break out the file manager part, but I digress. I can't really put my finger on anything specific I dislike about Konqueror, it's just not for me. To my dismay it seems to be the snappiest browser on Linux.

The only other decent browser I know of (for Linux) is Opera so I found some quick instructions on the Ubuntu forums and shoehorned the x86 build of it into my amd64 installation. Everything went well, Flash works and all that stuff. Opera is not nearly as snappy as I like but it is still fairly pleasant to use, once you find a skin that fits into your desktop. For the record Firefox isn't snappy enough either. Apart from AdBlock I don't miss many extensions for every day browsing.

I'm not sure if I'm going to stick with it yet but I've been using it for 2 days and haven't really missed Firefox at all. Of course as soon as I do any development I need Firefox for Firebug and the Web Developer extension and such. I've yet to investigate development tools on Opera. I'm comfortable developing in Firefox already so why switch?

Man am I glad we're not in a Netscape/IE world anymore! If I open up my MacBook I can choose from at least 2 other browsers for every day browsing (Camino, Safari).

Cheat from Emacs

Update: I had inadvertently used string-join, a function provided by something in my ~/.emacs.d. The script has been updated to work with a vanilla Emacs (23, but should work with 22 as well).

Update #2 [2007.08.10]: Editing cheats and diffs have been implemented.

Update #3 [2007.08.21]: I added completion to cheat.el. The file linked on this page is still the latest version.

We all know and love cheat. Now you can cheat without leaving Emacs (and without using a shell in Emacs).

Just save cheat.el in ~/.emacs.d and then (require 'cheat) in your ~/.emacs. I also bind C-z C-c to cheat, you may want to do something similar.

You can't do everything you can do with cheat on the command line yet

, and for most of the commands the cheat command itself is used. Now you can do everything the command line client does from within Emacs, though you may need to revert to using cheat-command (described below).

Here's the rundown:

Any time you enter a cheat name there are both completion and a cheat-specific history available. Unless you are adding a new cheat. In that case you should use a new, unique name (duh).

(Added) I may add support for --diff and --edit in the future.

Please do send me your patches so everyone can benefit from them.

Snap, crunchle, pop

I think that every now and then we need to be reminded of the frail nature of our human bodies. Yesterday morning as I walked to my kitchen I was turning right by pivoting on my right foot when my 24 years of walking experience suddenly failed me. I clearly did something wrong, as I heard a crunching pop or two in my right ankle and went down. Luckily it's just a sprain but my foot is fairly bruised and still sore today. I'm trying to follow the RICE method for recuperating but one can only lay down for so long before having to eat, work, use the bathroom, etc. Thank goodness I don't work on my feet or I'd be out of commission. If it still hurts next week I'm going to see a doctor but until then I'm trying not to leave my house. The idea of hopping and hobbling to a bus to go to a doctor does not thrill me in the slightest.

Oh, if you find yourself in a bind an upside down hockey stick is a decent makeshift crutch. You'll need 2 hands to operate the thing though.

At the opposite end of the spectrum there are times when we seem to be amazingly resilient creatures. Check out a documentary called "101 Things Removed from the Human Head" if you can find it anywhere. One of those things was a boat anchor, I kid you not.

ElSchemo: Boolean logic and branching

I've been developing a Scheme interpreter in Haskell called

ElSchemo

. It started from Jonathan's excellent Haskell tutorial which I followed in order to learn both Haskell and Scheme. Basically that means the code here is for me to get some feedback as much as to show others how to do this kind of stuff. This may not be too interesting if you haven't at least browsed the tutorial.

I'm going to cover 3 new special forms: and, or, and cond. I promised to cover the let family of special forms this time around but methinks this is long enough as it is. My sincere apologies if you've been waiting for those.

Short-circuiting Boolean logic

Two functions from the tutorial which may irk you immediately are

and

and or, defined in Scheme in the given standard library. If your code is free of side-effects then it may not bother you so much. It bothered me. The problem with the implementation in stdlib.scm is that all the arguments are evaluated before control enters the function. Besides being inefficient by doing unnecessary work, if any of the arguments have side-effects you can make use of short-circuiting by using and to sequence actions, bailing out if any fail (by returning nil), and using or to define a set of alternative actions which will bail out when the first in the list succeeds (by returning anything but nil). Had we macros then we could implement them as macros. We don't, so we'll write them as special forms in Haskell.

Unlike the special forms defined in the tutorial I'm going to implement these as separate functions for clarity, rather than lump them all in eval. However, they will be invoked directly from

eval

so their type is easy; it's the same as eval's.

Code first, ask questions later. Haskell is a pretty clear and concise language. My explanations may be redundant because of this.

lispAnd

1
2
3
4
5
6
7
8 
lispAnd :: Env -> [LispVal] -> IOThrowsError LispVal
lispAnd env [] = return $ Bool True
lispAnd env [pred] = eval env pred
lispAnd env (pred:rest) = do
    result <- eval env pred
    case result of
      Bool False -> return result
      _ -> lispAnd env rest

Starting with the trivial case, and returns #t with zero arguments.

With one argument, a single predicate, simply evaluate and return that argument.

Given a list of predicates, evaluate the first and inspect its value. If the argument evaluated to #f then our work is done and we return

#f

, otherwise we keep plugging along by making a recursive call with the first argument stripped off. Eventually we will reach our base case with only one predicate.

It's possible to eliminate the case of one predicate. I think that just complicates things but it's a viable solution.

lispOr

Predictably this is quite similar to lispAnd.

1
2
3
4
5
6
7
8 
lispOr :: Env -> [LispVal] -> IOThrowsError LispVal
lispOr env [] = return $ Bool False
lispOr env [pred] = eval env pred
lispOr env (pred:rest) = do
    result <- eval env pred
    case result of
        Bool False -> lispOr env rest
        _ -> return result

With no arguments lispOr returns #f, and with one argument it evaluates and returns the result.

With 2 or more arguments the first is evaluated, but this time if the result is #f then we continue looking for a truthy value. If the result is anything else at all then it's returned and we are done.

A new branching construct

First let me define a convenience function that I have added to ElSchemo. It maps a list of expressions to their values by evaluating each one in the given environment.

1
2 
evalExprs :: Env -> [LispVal] -> IOThrowsError [LispVal]
evalExprs env exprs = mapM (eval env) exprs

lispCond

Again, lispCond has the same type as eval.

1
2
3
4
5
6 
lispCond :: Env -> [LispVal] -> IOThrowsError LispVal
lispCond env (List (pred:conseq) : rest) = do
    result <- eval env pred
    case result of
        Bool False -> if null rest then return result else lispCond env rest
        _ -> liftM last $ evalExprs env conseq

Unlike Lisp – which uses a predicate of T (true) – Scheme uses a predicate of else to trigger the default branch. When the pattern matching on Atom "else" succeeds, we evaluate the default expressions and return the value of the last one. This is one possible base case. Atom "else" could be defined to evaluate to

#t

, but we don't want else to be evaluated as #t anywhere except in a cond so I have chosen this solution.

If the first predicate is not else then we evaluate it and check the resulting value. If we get #f then we look at the rest of the statement, if it's empty then we return #f, otherwise we recurse on the rest of the parameters. If the predicate evaluates to a truthy value – that is, anything but #f – then we evaluate the consequent expressions and return the value of the last one.

Plumbing

Now all that's left is to hook up the new functions in eval.

1
2
3 
eval env (List (Atom "and" : params)) = lispAnd env params
eval env (List (Atom "or" : params)) = lispOr env params
eval env (List (Atom "cond" : params)) = lispCond env params

You could, of course, throw the entire definitions in eval itself but eval is big enough for me as it is. YMMV.

Done!

So, that's a wrap. It only took 20 lines of code for the 3 new special forms, and it could easily be done with less code. Next time I will show you how to implement the various let functions. Really!

Do you like me describing ElSchemo piece by piece as I have been? I plan on posting the Haskell code and my stdlib.scm in their entirety sometime, and I could do that before or after I finish writing about the features I've developed beyond the tutorial. Just let me know in the comments.