Thursday, January 24, 2008

Emergency Elisp

Are you an Emacs user but don't know Lisp? Welcome to my first Emacs Lisp primer! This should hopefully help get you over cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 hurdle so you can have more control over your Emacs sessions.

There are lots of ways to do things in Lisp, and some are "Lispier" than ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365rs. I'm going to focus on how to do things you probably already know how to do from C++ or Java.

I'm mostly focusing on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 language itself, since that's arguably cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 hardest part. There are tons of Emacs-specific APIs that you can learn how to use from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 documentation.

Lisp is good at some things (like code that generates code) and not so good at ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365rs (like arithmetic expressions). I will generally avoid talking about good vs. bad, and just talk about how to do things. Emacs Lisp is like any ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r language – you get used to it eventually.

Most Lisp introductions try to give you cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 "Tao of Lisp", complete with incense-burning, chanting, yoga and all that stuff. What I really wanted in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 beginning was a simple cookbook for doing my "normal" stuff in Lisp. So that's what this is. It's an introduction to how to write C, Java or JavaScript code in Emacs Lisp, more or less.

Here goes. Let's see how short I can make it. I'll start with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 boring (but hopefully familiar) lexical tokens and operators, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n move on to how to implement various favorite statements, declarations and ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r programming constructs.

Quick Start

Lisp is written as nested parencá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365sized expressions like (+ 2 3). These expressions are sometimes called forms (in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 sense of "shapes".)

There are also "atoms" (leaf nodes, basically) that are not parencá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365sized: strings, numbers, symbols (which must be quoted with apostrophe for use as symbols, like 'foo), vectors, and ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r miscellany.

There are only single-line comments: semicolon to end of line.

To set a variable named foo to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 value "bar":
(setq foo "bar")  ; setq means "set quoted"

To call a function named foo-bar with arguments "flim" and "flam":
(foo-bar "flim" "flam")

To compute cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 arithmetic expression (0x15 * (8.2 + (7 << 3))) % 2:
(% (* #x15 (+ 8.2 (lsh 7 3))) 2)

In ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r words, arithmetic uses prefix notation, just like lisp function calls.

There's no static type system; you use runtime predicates to figure out cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 type of a data item. In elisp, predicate functions often end with "p". I'll let you figure out what it stands for.

Important: You can (and should) experiment with Lisp in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 *scratch* buffer. You can evaluate an expression and see its result in any of several ways, including:

  1. Put your cursor after cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 last close-paren and type C-j (control + j)

  2. Put your cursor inside cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 expression and type M-C-x (alt + control + x)

  3. Put your cursor after cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 last close-paren and type C-x C-e


The first approach spits cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 result into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 *scratch* buffer, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 next two echo it into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 minibuffer. They all also work for atoms – expressions not in parens such as numbers, strings, characters and symbols.

Lexical Stuff


Lisp has only a handful of lexical tokens (i.e. atomic program elements).

Comments:

Single-line only. They start with a semicolon:
(blah blah blah)   ;  I am a comment

Strings:

Double-quoted only.
"He's said: \"Emacs Rules\" one time too many."

You can embed newlines in strings, like so:
"Oh Argentina!
Your little tin of pink meat
Soars o'er cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Pampas"

Characters:

  • ?x is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 syntax for an ASCII character: ? followed by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 character.

  • e.g.: ?a is ascii 97 ('a'), ? (that is, question-mark space) is ascii 32 (' ').

  • Some need to be escaped, such as ?\(, ?\) and ?\\

  • Emacs 22+ has unicode support. Out of scope for this primer.

Characters are just int values internally, so you can use arithmetic operations on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m (for instance, to iterate through ?a to ?z).

Numbers:

  • Integers are 29 bits of precision (not cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 usual 32). -32, 0, 157, etc.

  • Binary: start with #b, e.g. #b10010110

  • Octal: #o[0-7]+, e.g. #o377

  • Hexadecimal: start with #x, e.g. #xabcd, #xDEADBEE

  • Floating-point: cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 usual. -10.005, 0.0, 3.14159265 (64 bits of precision.)

  • Scientific: cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 usual. 6.02e23, 5e-10


The variables most-positive-fixnum and most-negative-fixnum are cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 largest and smallest integers representable in Emacs Lisp without bignum support. Emacs 22+ comes with a fancy bignum/math library called calc, if you need it. Arithmetic operations overflow and underflow cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 way you'd expect (in, say, C or Java.)

Booleans

The symbol t (just a letter 't' by itself) is true.

The symbol nil is false (and also means null).

In Emacs Lisp, nil is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 only false value; everything else evalutes to true in a boolean context, including empty strings, zero, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 symbol 'false, and empty vectors. An empty list, '(), is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same thing as nil.

Arrays

Elisp has fixed-sized arrays called "vectors". You can use square-brackets to create a pre-initialized literal vector, for instance:
[-2 0 2 4 6 8 10]
["No" "Sir" "I" "am" "a" "real" "horse"]
["hi" 22 120 89.6 2748 [3 "a"]]

Note that you do not (and cannot) use commas to separate cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 elements; use whitespace.

Vectors can have mixed-type elements, and can be nested. You usually use cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 function make-vector to create cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m, since literal vectors are singletons, which can be surprising.

Lists

Lisp makes heavy use of linked lists, so cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re's lexical syntax for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m. Anything in parencá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ses is a list, but unless you quote it, it will be evaluated as a function call. There are various ways to quote things in Lisp:
(quote (1 2 3)) ; produces cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 list (1 2 3) with no list-element evaluation
'(1 2 3)  ; apostrophe is shorthand for (quote (...))
; note that it goes _outside_ cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 left-paren
(list 1 (+ 1 1) 3) ; also produces (1 2 3), since it evaluates cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 elements first
`(1 ,(+ 1 1) 3)  ; anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r (1 2 3) via a template system called "backquote"
There's a lot more that could be said about lists, but ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r people have already said it.

Pairs

You can set cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 head and tail (also known as car and cdr) fields of a lisp link-list node struct (also known as a cons cell) directly, using it as a 2-element untyped struct. The syntax is (head-value . tail-value), and you have to quote it (see above).

A common lookup-table data-structure for very small data sets is an associative list (known as an alist). It's just a list of dotted pairs, like so:
'( (apple . "red")
(banana . "yellow")
(orange . "orange") )
Emacs Lisp has built-in hashtables, bit-vectors, and miscellaneous ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r data structures, but cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re's no syntax for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m; you create cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m with function calls.

Operators


Some operations that are typically operators in ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r languages are function calls in elisp.

Equality

Numeric equality: (= 2 (+ 1 1)) Single-equal. Yields t or nil. Works for floats too.

Not-numerically-equal: (/= 2 3) I know, it looks like assign-divide-equal. But it's not.

Value equality: (eq 'foo 2) Like Java ==. Works for ints, symbols, interned strings, and object references. Use eql for floating-point numbers (or just =).

Deep (structural) equality: use equal, as in:
(equal '(1 2 (3 4)) (list 1 2 (list 3 (* 2 2))))  ; true

The equal function is like Java's Object.equals(). Works for lists, vectors, strings, and just about anything else.

String

Strings don't have any operators, but cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re are lots of string functions. Some common ones:
(concat "foo" "bar" "baz")  ; yields "foobarbaz"

(string= "foo" "baz") ; yields nil (false). Can also use equal.

(substring "foobar" 0 3) ; yields "foo"

(upcase "foobar") ; yields "FOOBAR"

Do M-x apropos RET \bstring\b RET to see a list of functions related to strings.

Arithmetic

Easiest to show as a table...

C/Java/JS Operator Emacs Lisp Example Result
+ + (+ 1 2 3 4 5) 15
- - (- 6 2 3) 1
* * (* 2 -1 4.2) -8.4
/ / (/ 10 3) 3 (use floats for float div)
% % (% 10 2) 0
<< lsh (lsh 1 5) 32
>> ash (negative amount) (ash -32 -4) -2
>>> lsh (negative amount) (lsh 32 -4) 2
++ incf (requires 'cl library) (incf x 6) x+6
-- decf (ditto) (decf x 5) x-5
? : (ternary) (if test-expr cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n-expr else-expr) (if t 3 4) 3
&& and (and t t t nil) nil
|| or (or nil nil nil t) t
! (logical-not) not (not 3) nil
~ (bit-not) lognot (lognot #b1001) -10
^ (bit-xor) logxor (logxor 5 3) 6
& (bit-and) logand (logand 1 3) 1
| (bit-or) logior (logior 1 3) 3
< < (< 5 3) nil
> > (> 5 3) t
<= <= (<= 3 3) t
>= >= (>= 5 3) t
. (field access) see setf below n/a n/a
[] (array access) aref/aset (aref [2 4 6] 1) 4

Statements


This section has some recipes for simple Java-like statements. It's not comprehensive – just some recipes to get you going.

if/else

Case 1: no else clause: (if test-expr expr)

Example:
(if (>= 3 2)
(message "hello cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re"))

Case 2: else clause: (if test-expr cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n-expr else-expr)
(if (today-is-friday)         ; test-expr
(message "yay, friday") ; cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n-expr
(message "boo, ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r day")) ; else-expr

If you need multiple expressions (statements) in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n-expr, you wrap cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m with a call to progn, which is like curly-braces in C or Java:
(if (zerop 0)
(progn
(do-something)
(do-something-else)
(etc-etc-etc)))

You don't need cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 progn around cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 else-expr – everything after cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n-expr is considered to be part of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 else-expr. Hence:
(if (today-is-friday)
(message "yay, friday")
(message "not friday!")
(non-friday-stuff)
(more-non-friday-stuff))

Case 3: else-if clause: Just nest 'em. Or use cond (see below).
(if 'sunday
(message "sunday!") ; cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n-expr
(if 'saturday ; else-if
(message "saturday!") ; next cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n-expr
(message ("weekday!")))) ; final else

Case 4: no else-if, multiple body expressions – use when:

If you don't have an else-clause, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n you can use cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 when macro, which provides an implicit progn:
(when (> 5 1)
(blah)
(blah-blah)
(blah blah blah))

You can also use unless, which is like when but inverts cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 sense of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 test:
(unless (weekend-p)
(message "anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r day at work")
(get-back-to-work))

switch

Elisp has two versions of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 classic switch statement: cond and case.

Elisp does not have a table-lookup optimization for switch, so cond and case are just syntax for nested if-cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n-else clauses. However, if you have more than one level of nesting, it looks a lot nicer than if expressions. The syntax is:
(cond
(test-1
do-stuff-1)
(test-2
do-stuff-2)
...
(t
do-default-stuff))

The do-stuff parts can be any number of statements, and don't need to be wrapped with a progn block.

Unlike classic switch, cond can handle any test expression (it just checks cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m in order), not just numbers. The downside is that it doesn't have any special-casing for numbers, so you have to compare cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m to something. Here's one that does string compares:
(cond
((equal value "foo") ; case #1 – notice it's a function call to `equal' so it's in parens
(message "got foo") ; action 1
(+ 2 2)) ; return value for case 1
((equal value "bar") ; case #2 – also a function call (to `+')
nil) ; return value for case 2
(t ; default case – not a function call, just literal true
'hello)) ; return symbol 'hello

The final t default clause is optional. The first matching clause is executed, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 result of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 entire cond expression is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 result of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 last expression in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 matching clause.

The 'cl (Common Lisp) package bundled with Emacs provides case, which works if you're comparing numbers or symbols, so in a sense it works more like standard switch. Example:
(case 12
(5 "five")
(1 "one")
(12 "twelve")
(ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365rwise
"I only know five, one and twelve.")) ; result: "twelve"

With case you can use eicá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r t or ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365rwise for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 default case, but it must come last.

It's cleaner to use case when you can get away with it, but cond is more general.

while

Elisp has a relatively normal while function: (while test body-forms)

Example, which you can evaluate in your *scratch* buffer:
(setq x 10
total 0)
(while (plusp x) ; while x is positive
(incf total x) ; add x to total
(decf x)) ; subtract 1 from x

First we set two global variables, x=10 and total=0, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n run cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 loop. Then we can evaluate cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 expression total to see that its value is 55 (cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 sum of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 numbers 1 to 10).

break/continue

Lisp has a facility for upward control-flow transfers called catch/throw. It's very similar to Java or C++ exception handling, albeit possibly somewhat lighter-weight.

To do a break from inside a loop in elisp, you put a (catch 'break ...) outside cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 loop, and a (throw 'break value) wherever you want to break inside cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 loop, like so:

Emacs Lisp Java

(setq x 0 total 0)
(catch 'break
(while t
(incf total x)
(if (> (incf x) 10)
(throw 'break total))))
var x = total = 0;
while (true) {
total += x;
if (x++ > 10) {
break;
}
}

The symbol 'break is arbitrary, but is probably a nice choice for your readers. If you have nested loops, you might consider 'break-outer and 'break-inner in your catch expressions.

You can (throw 'break nil) if you don't care about cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 "return value" for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 while-loop.

To continue a loop, put a catch expression just inside cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 loop, at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 top. For instance, to sum cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 numbers from 1 to 99 that are not evenly divisible by 5 (artificially lame example demonstrating use of continue):

Emacs Lisp Java
(setq x 0 total 0)
(while (< x 100)
(catch 'continue
(incf x)
(if (zerop (% x 5))
(throw 'continue nil))
(incf total x)))
var x = total = 0;
while (x < 100) {
x++;
if (x % 5 == 0) {
continue;
}
total += x;
}

We can combine cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se examples to show using a break and continue in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same loop:

Emacs Lisp JavaScript
(setq x 0 total 0)
(catch 'break
(while t
(catch 'continue
(incf x)
(if (>= x 100)
(throw 'break nil))
(if (zerop (% x 5))
(throw 'continue nil))
(incf total x))))
var x = total = 0;
while (true) {
x++;
if (x >= 100) {
break;
}
if (x % 5 == 0) {
continue;
}
total += x;
}

All cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 loops above compute cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 value 4000 in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 variable total. There are better ways to compute this result, but I needed something simple to illustrate break and continue.

The catch/throw mechanism can be used across function boundaries, just like exceptions. It's not intended for true exceptions or error conditions – Emacs has anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r mechanism for that, discussed in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 try/catch section below. You should get comfortable using catch/throw for normal jumps and control transfer in your Elisp code.

do/while

Pretty much all iteration in Emacs Lisp is easiest using cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 loop macro from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Common Lisp package. Just do this to enable loop:
(require 'cl)  ; get lots of Common Lisp goodies

The loop macro is a powerful minilanguage with lots of features, and it's worth reading up on. I'll use it in this primer to show you how to do basic looping constructs from ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r languages.

You can do a do/while like so:
(loop do
(setq x (1+ x))
while
(< x 10))

You can have any number of lisp expressions between cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 do and while keywords.

for

The C-style for-loop has four components: variable initialization, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 loop body, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 test, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 increment. You can do all that and more with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 loop macro. For instance, this arbitrary JavaScript:
// JavaScript
var result = [];
for (var i = 10, j = 0; j <= 10; i--, j += 2) {
result.push(i+j);
}

Could be done with loop like so:
(loop with result = '()         ; one-time initialization
for i downfrom 10 ; count i down from 10
for j from 0 by 2 ; count j up from 0 by 2
while (< j 10) ; stop when j >= 10
do
(push (+ i j) result) ; fast-accumulate i+j
finally
return (nreverse result)) ; reverse and return result

It's a bit more verbose, but loop has a lot of options, so you want it to be reasonably transparent.

Notice that this loop declares cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 result array and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n "returns" it. It could also operate on a variable declared outside cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 loop, in which case we wouldn't need cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 finally return clause.

The loop macro is astoundingly flexible. Its full specification is way out of scope for this primer, but if you want to make Emacs Lisp your, uh, friend, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n you should spend some time reading up on loop.

for..in

If you're iterating over a collection, Java provides cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 "smart" for-loop, and JavaScript has for..in and for each..in. There are various ways to do it in Lisp, but you really might as well just learn how to do it with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 loop macro. It's a one-stop shop for iteration.

The basic approach is to use loop for var in sequence, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n do something with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 individual results. You can, for instance, collect cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m (or a function on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m) into a result list like so:
(loop for i in '(1 2 3 4 5 6)
collect (* i i)) ; yields (1 4 9 16 25 36)

The loop macro lets you iterate over list elements, list cells, vectors, hash-keys, hash-values, buffers, windows, frames, symbols, and just about anything else you could want to traverse. See cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Info pages or your Emacs manual for details.

functions

You define a function with defun.

Syntax: (defun function-name arg-list [optional docstring] body)
(defun square (x)
"Return X squared."
(* x x))

For a no-arg function, you use an empty list:
(defun hello ()
"Print cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 string `hello' to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 minibuffer."
(message "hello!"))

The body can be any number of expressions. The return value of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 function is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 result of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 last expression executed. You do not declare cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 return type, so it's useful to mention it in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 documentation string. The doc string is available from M-x describe-function after you evaluate your function.

Emacs Lisp does not have function/method overloading, but it supports optional and "rest" parameters similar to what Python and Ruby offer. You can use cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 full Common Lisp specification for argument lists, including support for keyword arguments (see cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 defstruct section below), if you use cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 defun* macro instead of defun. The defun* version also lets you (return "foo") without having to set up your own catch/throw.

If you want your function to be available as a M-x command, put (interactive) as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 first expression in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 body after cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 doc string.

local variables

You declare function local variables with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 let form. The basic syntax is (let var-decl var-decl)

(let ((name1 value1)
(name2 value2)
name3
name4
(name5 value5)
name6
...))

Each var-decl is eicá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r a single name, or (name initial-value). You can mix initialized and uninitialized values in any order. Uninitialized variables get cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 initial value nil.

You can have multiple let clauses in a function. Code written for performance often collects all declarations into a single let at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 top, since it's a bit faster that way. Typically you should write your code for clarity first.

reference parameters

C++ has reference parameters, which allow you to modify variables from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 caller's stack. Java does not, so you have to work around it occasionally by passing in a 1-element array, or using an instance variable, or whatever.

Emacs Lisp does not have true reference parameters, but it has dynamic scope, which means you can modify values on your caller's stack anyway. Consider cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 following pair of functions:
(defun foo ()
(let ((x 6)) ; define a local (i.e., stack) variable x initialized to 6
(bar) ; call bar
x)) ; return x

(defun bar ()
(setq x 7)) ; finds and modifies x in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 caller's stack frame

If you invoke (foo) cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 return value is 7.

Dynamic scoping is generally considered a bad design bordering on evil, but it can occasionally come in handy. If nothing else, it's good to know it's what Emacs does.

return

A lisp function by default returns cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 value of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 last expression executed in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 function. Sometimes it's possible to structure your function so that every possible return value is in a "tail position" (meaning cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 last expression out before cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 door closes, so to speak.) For instance:

Emacs Lisp JavaScript
(require 'calendar)

(defun day-name ()
(let ((date (calendar-day-of-week
(calendar-current-date))))
(if (= date 0)
"Sunday"
(if (= date 6)
"Saturday"
"weekday"))))
function dayName() {
var date = new Date().getDay();
switch (date) {
case 0:
return "Sunday";
case 6:
return "Saturday";
default:
return "weekday";
}
}

The return value is just cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 result of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 last expression, so whatever our nested if produces is automatically returned, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re's no need here for an explicit return form.

However, sometimes restructuring cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 function this way is inconvenient, and you'd prefer to do an "early return".

You can do early returns in Emacs Lisp cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same way you do break and continue, using cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 catch/throw facility. Usually simple functions can be structured so you don't need this – it's most often useful for larger, deeply-nested functions. So for a contrived example, we'll just rewrite cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 function above to be closer to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 JavaScript version:
(defun day-name ()
(let ((date (calendar-day-of-week
(calendar-current-date)))) ; 0-6
(catch 'return
(case date
(0
(throw 'return "Sunday"))
(6
(throw 'return "Saturday"))
(t
(throw 'return "weekday"))))))

Obviously using catch/throw here is slow and clunky compared to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 alternatives, but sometimes it's exactly what you need to get out of a deeply nested construct.

try/catch

We've already discussed catch/throw, an exception-like facility for normal control flow transfers.

Emacs has a different facility for real error conditions, called cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 "conditions" system. Going through cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 full system is out of scope for our primer, but I'll cover how to catch all exceptions and how to ignore (squelch) cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m.

Here's an example of a universal try/catch using cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 condition-case construct, with a Java equivalent:


Emacs Lisp Java
(condition-case nil
(progn
(do-something)
(do-something-else))
(error
(message "oh no!")
(do-recovery-stuff)))
try {
doSomething();
doSomethingElse();
} catch (Throwable t) {
print("uh-oh");
doRecoveryStuff();
}

If you want an empty catch block (just squelch cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 error), you can use ignore-errors:
(ignore-errors
(do-something)
(do-something-else))

It's sometimes a good idea to slap an ignore-errors around bits of elisp code in your startup file that may not always work, so you can still at least start your Emacs up if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 code is failing.

The condition-case nil means "Don't assign cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 error to a named variable." Elisp lets you catch different kinds of errors and examine cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 error data. You can read cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Emacs manual or Info pages to learn more about how to do that.

The progn is necessary if you have multiple expressions (in C/Java, statements) to evaluate in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 condition-case body.

condition-case will not catch values thrown by throw – cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 two systems are independent.

try/finally

Emacs has a "finally"-like facility called unwind-protect.


Emacs Lisp Java
(unwind-protect
(progn
(do-something)
(do-something-else))
(first-finally-expr)
(second-finally-expr))
try {
doSomething();
doSomethingElse();
} finally {
firstFinallyExpr();
secondFinallyExpr();
}

Like condition-case, unwind-protect takes a single body-form followed by one or more cleanup forms, so you need to use progn if you have more than one expression in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 body.

try/catch/finally

If you make cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 condition-case (which is basically try/catch) cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 body-form of an unwind-protect (which is basically try/finally), you get cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 effect of try/catch/finally:
(unwind-protect                 ; finally
(condition-case nil ; try
(progn ; {
(do-something) ; body-1
(do-something-else)) ; body-2 }
(error ; catch
(message "oh no!") ; { catch 1
(poop-pants))) ; catch 2 }
(first-finally-expr) ; { finally 1
(second-finally-expr)) ; finally 2 }

Classes

Emacs Lisp is not object-oriented in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 standard sense: it doesn't have classes, inheritance, polymorphism and so on. The Common Lisp package includes a useful feature called defstruct that gives you some simple OOP-like support. I'll walk through a basic example.

These two declarations are essentially equivalent:

Emacs Lisp Java
(require 'cl)  ; top of file  

(defstruct person
"A person structure."
name
(age 0)
(height 0.0))
/* A Person class */
class Person {
String name;
int age;
double height;
public Person() {}
public Person(String name) {
this(name, 0, 0);
}
public Person(int age) {
this(null, age, 0);
}
public Person(double height) {
this(null, 0, height);
}
public Person(String name, int age) {
this(name, age, 0);
}
public Person(String name, double height) {
this(name, 0, height);
}
public Person(int age, double height) {
this(null, age, height);
}
public Person(String name, int age, double height) {
this.name = name;
this.age = age;
this.height = height;
}
}

Both create a "class" with three named fields, and constructors for initializing any subset of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 fields. With defstruct you get one constructor with keyword parameters, so cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se are all valid:
(make-person)  ; new Person()
(make-person :age 39) ; new Person(39)
(make-person :name "Steve" :height 5.83 :age 39) ; new Person("Steve", 39, 5.83)

The defstruct macro supports single-inheritance (to arbitrary depth):

Emacs Lisp Java
(defstruct (employee
(:include person))
"An employee structure."
company
(level 1)
(title "n00b"))
/* An Employee class */
class Employee extends Person {
String company;
int level = 1;
String title = "n00b";
public Employee() {
}
public Employee(String name,
String company) {
super(name);
this.company = company;
}
public Employee(String name,
int age,
String company) {
super(name, age);
this.company = company;
}
public Employee(String name,
int age,
double height,
String company) {
super(name, age, height);
this.company = company;
}
public Employee(String name,
int age,
String company,
int level) {
super(name, age);
this.company = company;
this.level = level;
}
public Employee(String name,
int age,
String co,
int lvl,
String title) {
super(name, age);
this.company = co;
this.level = lvl;
this.title = title;
}
// (remaining 150 overloaded constructors elided for brevity)
}

The defstruct macro provides a flexible default constructor, but also gives you a fair amount of control over your constructor(s) if you prefer.

The defstruct macro creates an instanceof-like predicate function named after cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 struct, so you can say:
(person-p (make-person))
t
(employee-p (make-person))
nil
(employee-p (make-employee))
t
(person-p (make-employee)) ; yes, it inherits from person
t
Java may suck at declaring constructors, but Emacs Lisp makes up for it by sucking at setting fields. To set a field in a struct, you have to use cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 setf function, and construct cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 field name by prepending cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 structure name. So:


Emacs Lisp Java
(setq e (make-employee))
(setf (employee-name e) "Steve"
(employee-age e) 39
(employee-company e) "Google"
(employee-title e) "Janitor")
Employee e = new Employee();
e.name = "Steve";
e.age = 39;
e.company = "Google";
e.title = "Janitor";

The Lisp one doesn't look too bad here, but in practice (because Elisp has no namespace support and no with-slots macro), you wind up with long structure and field names. So your defstruct-enabled elisp code tends to look more like this:
(setf (js2-compiler-data-current-script-or-function compiler-data) current-script
(js2-compiler-data-line-number compiler-data) current-line
(js2-compiler-data-allow-member-expr-as-function-name compiler-data) allow
(js2-compiler-data-language-version compiler-data) language-version)
So it goes.

To fetch cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 value of a field in a struct variable, you concatenate cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 struct name with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 field name and use it as a function call:
(person-name steve)  ; yields "Steve"
There's more that defstruct can do – it's a pretty decent facility, all things considered, though it falls well short of a full object system.

Buffers as classes

In Elisp programming it can often be useful to think of buffers as instances of your own classes. This is because Emacs supports cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 notion of buffer-local variables: variables that automatically become buffer-local whenever cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y are set in any fashion. They become part of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 scope chain for any code executing in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 buffer, so cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y act a lot like encapsulated instance variables.

You can use cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 function make-variable-buffer-local to declare a variable as buffer-local. Usually it comes right after cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 defvar or defconst declaration (see below.)

Variables

You can declare a variable, optionally giving it some runtime documentation, with defvar or defconst:
(defconst pi 3.14159 "A gross approximation of pi.")
The syntax is (defvar name value [ doc-string ]).

Ironically, defconst is variable and defvar is constant, at least if you re-evaluate cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m. To change cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 value of a defvar variable by re-evaluating its declaration you need to use makunbound to unbind it first. You can always change cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 value of any defvar or defconst variable using setq. The only difference between cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 two is that defconst makes it clearer to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 programmer that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 value is not intended to change.

You can use setq to create brand-new variables, but if you use defvar, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 byte-compiler will be able to catch more typos.

Furcá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r reading

Emacs Lisp is a real programming language. It has a compiler, a debugger, a profiler, pretty-printers, runtime documentation, libraries, I/O, networking, process control and much more. There's a lot to learn, but I'm hoping this little primer has got you over cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 hump, as it were.

In spite of its various quirks and annoyances, Elisp is reasonably fun to program in once you get cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 hang of it. As a language it's not that great, and everyone wishes it were Common Lisp or Scheme or some ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r reasonable Lisp dialect. Some people even wish it weren't Lisp at all, if you can believe that! (hee)

But it's really, really useful to be able to customize your editor, and also to be able to fix problems with elisp code you borrowed or inherited. So a little Elisp goes a long way.

For those of you learning Emacs Lisp, please let me know if you found this useful. If you try writing some Emacs extensions, let me know what you would like to see documented next; I can always do anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r installment of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Emergency Elisp series if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re's enough interest.

Good luck!

Monday, January 07, 2008

Blogging Theory 201: Size Does Matter

I'm always getting criticized for writing long blogs. "Way too verbose! Couldn't he have said all that in two paragraphs?" Not everyone feels that way, of course; lots of people tell me to keep doing what I'm doing. But cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 size critics are doggedly persistent. And I don't think it's just people who are slow readers. Even friends of mine will sometimes advise me to trim my entries down, which is a surprise, since I thought most of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m would have picked up on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 cause and effect relationship between blog length and popularity. Evidently not!

So, like, let's get this out in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 open: I'm doing it on purpose. Yes, sure, I could do with an editor (cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 people kind), but only if said editor were on board with long blogs, because that's cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kind I want to write.

In short, I think long blogs have better survival characteristics: greater reach and greater impact. And I've decided to celebrate cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 august occasion of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 1000th kneebiter publicly maligning my style by explaining why I do it. And yes, it'll be long. Set aside at least 20 minutes to read this thing. You've been warned!

The Expectations Problem

Let's start with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 obvious. People expect blogs to be short – at least, shorter than mine. They expect that because it's pretty much how everyone does it. Short entries, and frequent. Here's my cat today. Doesn't he look sooo different from yesterday? No wonder so many people hate bloggers.

When I write my long blogs, I'm bucking established social convention, so it's natural that some people will whine that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y're too long.

Well, how far off cultural expectations am I? Doing a quick print preview in my browser shows that my last entry, formatted at about 14 words per line (typical for a printed book) weighs in at about ten pages. So it's roughly essay-sized. I'm not talking about those toy five-paragraph essays cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y made you write in high school. I'm talking about real-life essays by real-life essayists. Real essays can range from three pages to 30 or more, but ten pages is not an unusual length.

If I were attempting to publish cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se entries as books, publishers would laugh at me. They're way too short to be books. Sure, I could bundle cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m, but that's beside cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 point. The fact is, two different real-world audiences have entirely incompatible views on what cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 proper length for my writing should be.

Trying for Essays

I like to shift between writing articles and essays. The two overlap to some extent, in that an "opinion article" can be essay-like. But an essay attempts to be richer and deeper than an article. Essays can take all sorts of forms – prose, poems, stage plays, screenplays, short stories, even songs. And yes, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y can take cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 form of blog entries.

Essays have different goals: some introduce new ideas, some aim to change minds that have been made up, some try to rally people to a cause, some just poke fun. Regardless of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 goal, I think what unites cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m as essays is that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y strive to imprint cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 reader with an idea, some hopefully unforgettable perspective, even if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 reader doesn't necessarily agree with it.

Essays might use humor to endear you, or satire to shock you, or storytelling to entertain and lull you, or logic to convince you, or rhetoric to persuade you, but in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 end cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y're trying all trying to imprint you with a little piece of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 essayist's personal perspective on life.

So we've established that my longer entries are for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 most part essays in blog form, with nary a cat picture to be found. I think cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 appearance of my entries in feed-readers alongside cat pictures and ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r non-essays is a big contributor to why so many people feel cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y're too long. If I instead herded cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m off into a page titled "Essays", as essayist Paul Graham does, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n my guests might arrive with more appropriate expectations.

But let's face it – that's more work. Blogs are cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 closest thing we've got today to a ready-made, turn-key, high-availability essay publishing system, one that permits comments, subscriptions, biographical links and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r trappings you'd expect. It's not ideal – I even talked about this in my first-ever Blogger entry, but none of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 issues I raised cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n have been resolved, doubtless because most people don't write essays, so cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re isn't a pressing need.

Blogging's cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 best medium I've got today, so that's where I publish my essays.

Amusing true side-story: I met Paul Graham at Foo Camp last summer. After his crowd of admirers had dispersed on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 first day (he's pretty famous), I came up and introduced myself. He was very nice and polite, and he was even kind enough to venture: "I've read some of your ...essays." He said cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 word essays with this funny pained look on his face, as if he'd just swallowed a gob of wasabi and was trying to play it off like nothing was wrong. I think he meant well, but that expression was just priceless.

I already knew my work wasn't for everyone. :)

Anyway, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re's more to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 long-blog problem than mere expectations. You can still make a valid argument that my entries are too long even for essays, or at any rate for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 material I'm covering or cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 points I'm making. And I'll still disagree with you. Let's see why.

Blowing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Cache

So, I have this pet cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ory I'm going to foist on you. It's probably total hokum, and someday I may be proven as wrong as Lamarck, but for now it's a hypocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365sis that fits cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 data pretty well.

First, let me tell you what cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 pet cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ory is about. I talked about it a little in an essay I wrote in 2004, You Should Write Blogs. In cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 essay I outlined some unexpected behavior of an essay my friend had written and circulated at Amazon: nobody read cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 thing, but somehow a year later everyone knew about it, and its core message had been imprinted on everyone in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 company, up to and including cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 executive staff.

In cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 intervening three years since I wrote that essay, my own blog has taken off to level that can only be described as absurd. I've been lampooned in web comics, discussed endlessly on Reddit, Slashdotted, invited to Foo Camp and various big conferences, approached about writing books, recruited constantly, and heckled mercilessly by my coworkers, all of whom are smarter than I am, both technically and also in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 sense that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y don't make public asses of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365mselves once a month.

It's undeniable that I'm doing something right, at least in terms of reach. My blogs may or may not be any good, but cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y're widely read. So are cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y really too long?

Well, people always tell me: "Steve, you'd be doing yourself – and us – a huge favor if you just made your entries shorter." So I try it now and again, and I've observed a correlation between blog size and splash size. It's as if you're all in a pond, and I'm throwing a rock into it. Bigger rock, bigger splash.

I think you can actually stretch that metaphor one more level. I think if I throw in a sufficiently large rock, it'll crush you, which for most of you is an undesirable outcome. The rock needs to be big enough to splash you and get you all wet, but it shouldn't kill you.

To translate that bizarre thought into non-metaphorical terms, a blog that's too big will cause "too many" readers to drop off, for some value of "too many". A longer entry means that fewer people will read it immediately, although I'd argue based on experience that longer entries that are worth reading will ultimately achieve a wider audience. It just takes longer for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m to make cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 rounds - sometimes months or years. But cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re's a tradeoff cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re. It can be useful to make a big splash all at once, in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 style of Gladwell's Tipping Point.

So we've got a tricky number to solve for. Very short entries get ignored; I've tried that. Longer entries can make a splash but may not have broad long-term staying power. Very long entries tire people out, so cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y can take years to make cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 rounds. What's cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 right length for making a big splash cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 day it's published?

That's where my pet cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ory comes in. Oh, you may laugh! Ha, ha, you might say! But I, who know absolutely nothing whatsoever about Cognitive Science, have a pop cog-sci cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ory about cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 right length for an essay.

The right length for an essay, I believe, is exactly "one sitting": no more, no less. You should be able to read and absorb it fully in one go, with no breaks. Moreover, after you finish, you should be at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 point where you need to take a break. You should want to stand up, stretch your legs, grab a coffee, play some foosball, get your mind off everything for a while. If you don't need a break after cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 essay, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n it wasn't long enough.

I suspect cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 maximum length for a "sitting" is 50 minutes, given various government studies I learned about while I was in Navy Nuclear Power School. They determined that people absorb information best (and concentrate best) in school in 50-minute intervals with 10-minute breaks. They'd figured out all sorts of ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r stuff too: use outline form, make cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 students copy cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 outline into a notebook, repeat everything exactly 3 times, and so on, all ways cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y'd found that lead to better retention of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 material. But cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 50-minute thing seemed intuitively reasonable. Those ten-minute breaks were indispensable.

I actually think 50 minutes is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 absolute upper bound for a sitting; cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 optimal duration is probably lower. But cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 takeaway here is that one consequence of my pet cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ory, which we'll get to shortly, is that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ideal length for a blog is measured as a duration, not a word count.

Of course, that presents a problem, because duration is a function of word count and reading speed. I need to account for different personal speeds, and some folks like to read slowly. Heck, some don't even read at all. It's one of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 amazing miracles of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 internet: write-only people. They can't read but cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y somehow find a way to write. You see cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m commenting all cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 time in my blogs: "I didn't actually read your entry, but allow me to comment on it all cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same..." Lovely.

So I need to aim for something lower than 50 minutes, to make it possible for average readers, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n hope that for fast readers I'll still have blown cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir entire page cache. Being a fast reader is actually a disadvantage here.

Figured my pet cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ory out yet? I'll bet some of you have!

Stevey's Brain-Cache Theory of Essays

My pet cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ory is predicated on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 hopefully obvious axiom that our brain is a computer. As a computer, even though it's structually different from a von Neumann machine, it's still constrained by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same laws of physics. Hence, it probably has a multi-level cache.

I have some even more farfetched pet cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ories about cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 architecture of this cache, but whatever cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 architecture, caches all share cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 property of being limited short-term storage.

I really want to talk more about how I think this cache works, and I keep deleting paragraphs about it. I'm in a bind: if I talk more about it, my pond-boulder will get too big and crush people. But if I don't, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n I'll be accused of grossly oversimplifying.

So it goes. Let's oversimplify.

Your brain clearly has at least two obvious caches: your short-term memory and your long-term memory. Your long-term memory is more complex than a cache, but behaves like a cache in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 way it forgets things that aren't refreshed periodically.

The Wikipedia entry on short-term memory, linked above, says short-term memory lasts about 20 seconds. And long-term memory, of course, is persistent and can last up to a lifetime.

My pet cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ory posits cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 existence of at least one second-level cache in your brain that holds data for a while before deciding whecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r to commit it to long-term memory. That "while" varies but is at least 10 to 15 minutes.

Of course, writing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ory down like this makes all cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 holes in it pretty obvious, and I'm way too lazy to try to patch cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m all up here. Following cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 best academic tradition, I leave cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 hole-patching as an exercise for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 reader.

In my pet cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ory of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 brain, such as it is, your second-level cache keeps track of all your sensory input for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 past few minutes. It also serves as a scratchpad area for doing computation: if you're trying to follow a complex argument, you need to construct a graph: idea A leads to B and C, C implies D, etc. Even following a scene in a story requires a graph and some computation: think of a bank robbery movie scene with five people involved. Following its progress requires a little short-term memorization and some deduction, and your mind does this for you automatically for situations up to a certain low level of complexity.

What about bigger arguments and more complex scenarios? Well, if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 graph is too big to fit in your second-level cache, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n your brain needs to swap some ideas to "disk" (your long-term memory). This is also known as "learning stuff." Painful, I know. I've been cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re.

So my pet cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ory is that if you want to make a lasting impression, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n you need to fill up cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 reader's second-level cache and start blowing pages (cache elements) out into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir long-term memory. If you want to imprint cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m with something memorable, you've gotta flush it to disk. To fill cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 cache you have to create a story big enough to fill cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir short- and medium-term memory and start spilling over into long-term memory, at which point you're guaranteed that some of it will stick. It won't be just anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r funny blurb that your reader sees, laughs at, and immediately forgets.

This obviously entails some effort on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 part of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 reader, even if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y're having fun. You watch a 2-hour movie and you'll be exhausted (or at least ready for a break) because your brain is busy swapping stuff out. It uses more energy because of those pesky laws of physics that led to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 cache structure in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 first place.

I think this whole idea scales up to N-level caching; if you write a whole book about something, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 reader manages to get through it all, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n you've probably left cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m with a lot more long-term memories and patterns.

But a good essay is usually just trying to get one idea across. One idea, one big rock in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 pond: one sitting, one story. That's my cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ory. And it's cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365sis of this essay, with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 conclusion being that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 relationship between blog length and popularity is actually causative.

"There's one thing in particular that struck me..."

In cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 spirit of filling your second-level cache, I'd like to offer you just one detail of my pet architecture: I think our caches are only partly LRU; I think cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re's some randomness involved in which pages your short-term memory chooses to discard when you're interrupted with new data. In fact, if anything, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y may be MRU (Most Recently Used), given that when you're having a conversation with your friend and you both get interrupted, you often can't remember cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 thing you were just now talking about, but you can both remember things you talked about a few minutes before.

If that's true, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stuff that gets swapped to disk is probably different for every reader, and may be somewhat random. In ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r words, everyone comes away with some different memory of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 essay. It's likely also in no small part a function of how well any given turn of phrase is a match for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 reader's experience. So a good essay needs to try to say cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same thing in a bunch of different ways, hoping that whenever cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 reader's brain decides to latch onto something that "strikes" cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m more or less permanently, it's hopefully related to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 core message of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 essay.

So everyone gets something different. But I think that's a good thing. If cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 readers come away thinking about it at all, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 essay has succeeded.

Wrap-Up

There's more I could say about my style. Expectations and page-caching cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ories aside, I think cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re's entertainment value in a good story-essay; you can't really weave in good jokes without some supplemental material, for instance. And I like to tackle inherently complex topics because cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y're more interesting, so it's never as easy as summarizing with something as pithy as "Java sucks". It's not that simple, no matter how people want it to be so.

So yes, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re's more I could say, but my gut tells me I've reached cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 one-sitting limit. So I'll wrap up here.

I know I've oversimplified. I know I have no business talking about cog sci when I've never even read a book on it, unless you count Gödel, Escher, Bach. And I know that even if I'm right, I may still sometimes overshoot cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ideal length significantly.

But I'm convinced, and I hope you are now as well, that my blog entries are successful because of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir length, and not in spite of it. It's OK if you don't agree with my pet cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ory as to why cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 longer ones are more successful; I've certainly got nothing but intuition backing me up here. But by getting you to disagree with it, I've left my mark. At least you'll remember cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 idea now. Consider yourself imprinted. This one's on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 house!

At this point I recommend stretching your legs. Take a walk, get some fresh air, let those disk drives cool down. You can ponder this stuff later. It'll still be cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re in your brain, like it or not. I guarantee it.