MATHEMATICS

Kamis, 24 Januari 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 the 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 others. 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 the language itself, since that's arguably the hardest part. There are tons of Emacs-specific APIs that you can learn how to use from the documentation.

Lisp is good at some things (like code that generates code) and not so good at others (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 other language – you get used to it eventually.

Most Lisp introductions try to give you the "Tao of Lisp", complete with incense-burning, chanting, yoga and all that stuff. What I really wanted in the 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 the boring (but hopefully familiar) lexical tokens and operators, then move on to how to implement various favorite statements, declarations and other programming constructs.

Quick Start

Lisp is written as nested parenthesized expressions like (+ 2 3). These expressions are sometimes called forms (in the sense of "shapes".)

There are also "atoms" (leaf nodes, basically) that are not parenthesized: strings, numbers, symbols (which must be quoted with apostrophe for use as symbols, like 'foo), vectors, and other miscellany.

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

To set a variable named foo to the 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 the arithmetic expression (0x15 * (8.2 + (7 << 3))) % 2:
(% (* #x15 (+ 8.2 (lsh 7 3))) 2)

In other words, arithmetic uses prefix notation, just like lisp function calls.

There's no static type system; you use runtime predicates to figure out the 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 the *scratch* buffer. You can evaluate an expression and see its result in any of several ways, including:

  1. Put your cursor after the last close-paren and type C-j (control + j)

  2. Put your cursor inside the expression and type M-C-x (alt + control + x)

  3. Put your cursor after the last close-paren and type C-x C-e


The first approach spits the result into the *scratch* buffer, and the next two echo it into the 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 the Pampas"

Characters:

  • ?x is the syntax for an ASCII character: ? followed by the 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 them (for instance, to iterate through ?a to ?z).

Numbers:

  • Integers are 29 bits of precision (not the 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: the usual. -10.005, 0.0, 3.14159265 (64 bits of precision.)

  • Scientific: the usual. 6.02e23, 5e-10


The variables most-positive-fixnum and most-negative-fixnum are the 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 the 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 the only false value; everything else evalutes to true in a boolean context, including empty strings, zero, the symbol 'false, and empty vectors. An empty list, '(), is the 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 the elements; use whitespace.

Vectors can have mixed-type elements, and can be nested. You usually use the function make-vector to create them, since literal vectors are singletons, which can be surprising.

Lists

Lisp makes heavy use of linked lists, so there's lexical syntax for them. Anything in parentheses 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 the list (1 2 3) with no list-element evaluation
'(1 2 3)  ; apostrophe is shorthand for (quote (...))
; note that it goes _outside_ the left-paren
(list 1 (+ 1 1) 3) ; also produces (1 2 3), since it evaluates the elements first
`(1 ,(+ 1 1) 3)  ; another (1 2 3) via a template system called "backquote"
There's a lot more that could be said about lists, but other people have already said it.

Pairs

You can set the 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 other data structures, but there's no syntax for them; you create them with function calls.

Operators


Some operations that are typically operators in other 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 there 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 then-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 there"))

Case 2: else clause: (if test-expr then-expr else-expr)
(if (today-is-friday)         ; test-expr
(message "yay, friday") ; then-expr
(message "boo, other day")) ; else-expr

If you need multiple expressions (statements) in the then-expr, you wrap them 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 the progn around the else-expr – everything after the then-expr is considered to be part of the 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!") ; then-expr
(if 'saturday ; else-if
(message "saturday!") ; next then-expr
(message ("weekday!")))) ; final else

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

If you don't have an else-clause, then you can use the 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 the sense of the test:
(unless (weekend-p)
(message "another day at work")
(get-back-to-work))

switch

Elisp has two versions of the 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-then-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 them in order), not just numbers. The downside is that it doesn't have any special-casing for numbers, so you have to compare them 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 the result of the entire cond expression is the result of the last expression in the 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")
(otherwise
"I only know five, one and twelve.")) ; result: "twelve"

With case you can use either t or otherwise for the 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, then run the loop. Then we can evaluate the expression total to see that its value is 55 (the sum of the 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 the loop, and a (throw 'break value) wherever you want to break inside the 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 the "return value" for the while-loop.

To continue a loop, put a catch expression just inside the loop, at the top. For instance, to sum the 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 these examples to show using a break and continue in the 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 the loops above compute the value 4000 in the 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 another mechanism for that, discussed in the 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 the loop macro from the 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 other 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 the do and while keywords.

for

The C-style for-loop has four components: variable initialization, the loop body, the test, and the increment. You can do all that and more with the 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 the result array and then "returns" it. It could also operate on a variable declared outside the loop, in which case we wouldn't need the 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, then you should spend some time reading up on loop.

for..in

If you're iterating over a collection, Java provides the "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 the loop macro. It's a one-stop shop for iteration.

The basic approach is to use loop for var in sequence, and then do something with the individual results. You can, for instance, collect them (or a function on them) 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 the 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 the string `hello' to the minibuffer."
(message "hello!"))

The body can be any number of expressions. The return value of the function is the result of the last expression executed. You do not declare the return type, so it's useful to mention it in the 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 the full Common Lisp specification for argument lists, including support for keyword arguments (see the defstruct section below), if you use the 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 the first expression in the body after the doc string.

local variables

You declare function local variables with the 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 either a single name, or (name initial-value). You can mix initialized and uninitialized values in any order. Uninitialized variables get the 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 the 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 the 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 the 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 the caller's stack frame

If you invoke (foo) the 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 the value of the last expression executed in the function. Sometimes it's possible to structure your function so that every possible return value is in a "tail position" (meaning the last expression out before the 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 the result of the last expression, so whatever our nested if produces is automatically returned, and there's no need here for an explicit return form.

However, sometimes restructuring the function this way is inconvenient, and you'd prefer to do an "early return".

You can do early returns in Emacs Lisp the same way you do break and continue, using the 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 the function above to be closer to the 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 the 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 the "conditions" system. Going through the full system is out of scope for our primer, but I'll cover how to catch all exceptions and how to ignore (squelch) them.

Here's an example of a universal try/catch using the 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 the 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 the code is failing.

The condition-case nil means "Don't assign the error to a named variable." Elisp lets you catch different kinds of errors and examine the error data. You can read the 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 the condition-case body.

condition-case will not catch values thrown by throw – the 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 the body.

try/catch/finally

If you make the condition-case (which is basically try/catch) the body-form of an unwind-protect (which is basically try/finally), you get the 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 the 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 the fields. With defstruct you get one constructor with keyword parameters, so these 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 the 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 the setf function, and construct the field name by prepending the 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 the value of a field in a struct variable, you concatenate the struct name with the 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 the notion of buffer-local variables: variables that automatically become buffer-local whenever they are set in any fashion. They become part of the scope chain for any code executing in the buffer, so they act a lot like encapsulated instance variables.

You can use the function make-variable-buffer-local to declare a variable as buffer-local. Usually it comes right after the 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 them. To change the value of a defvar variable by re-evaluating its declaration you need to use makunbound to unbind it first. You can always change the value of any defvar or defconst variable using setq. The only difference between the two is that defconst makes it clearer to the programmer that the value is not intended to change.

You can use setq to create brand-new variables, but if you use defvar, the byte-compiler will be able to catch more typos.

Further 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 the hump, as it were.

In spite of its various quirks and annoyances, Elisp is reasonably fun to program in once you get the hang of it. As a language it's not that great, and everyone wishes it were Common Lisp or Scheme or some other 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 another installment of the Emergency Elisp series if there's enough interest.

Good luck!

Rabu, 23 Januari 2008

Soal UN Matematika ternyata mudah

Judul di atas bukan basa-basi, kalau diperhatikan tidak semua soal pada UN itu sesulit yang dibayangkan, terkadang kalau kita mampu melihat dengan teliti sebuah soal, dengan logika yang sederhana pun kita bisa mengerjakannya.Berikut salah satu contohnya :1. Persamaan lingkaran yang pusatnya terletak pada garis 2x – 4y – 4 = 0, serta menyinggung sumbu x negatif dan sumbu y negatif adalah ….a. x² +

Sabtu, 19 Januari 2008

Download Soal matematika SMA

Kalau sebelumnya saya belum punya tempat untuk mendownload soal - soal Ujian Nasional yang ada di blog ini ( selama ini numpang di websitenya sekolah ), mulai sekarang anda bisa download semua soal ujian nasional tersebut ( dalam file microsoft word ) di blog saya yang lain.anda bisa klik disini untuk bisa mendapatkan semua file tersebut.Oh ya, dalam waktu dekat ini insya ALLAH semua materi bisa

Selasa, 15 Januari 2008

Utak - atik turunan

Akan ada 2 soal yang keluar untuk materi turunan pada UjianNasional :1. materi tentang turunan berantai ( chain rule )soal hadir dalam bentuk fungsi aljabar atau fungsi trigonometri2. materi tentang aplikasi turunansoal yang bakal hadir adalah tentang :mencari nilai maksimum atau nilai minimum atau mungkin juga tentang persamaan garis singgung kurva

Sabtu, 12 Januari 2008

Bahan belajar ( power point )

Berikut adalah daftar download tentang bahan belajar dalam bentuk power point ;1. Koordinat kartesius dan koordinat kutub2. Irisan Bangun Ruang3. Dimensi Tiga ( Proyeksi )

Privacy Policy Statement

This is the blog of Matematika SMA. Our postal address is Jl. Makrik No 37A, Rt 006/04 Rawa Lumbu, Bekasi Jawa Barat, Indonesia We can be reached via e-mail at matematika3sma@gmail.com or you can reach us by telephone at +62081908053359For each visitor to our web page, our web server automatically recognizes the consumer's omain name and e-mail address (where possible).We collect the domain name

Kamis, 10 Januari 2008

Matematika SMA

2 hari yang lalu saya coba mencari blog ini menggunakan search engine " Mbah Google " yang .co.id dengan menggunakan kata kunci " matematika " ternyata yang selama ini berada di urutan kedua sekarang sudah berada di urutan No. 1( mudah-mudahan langgeng).Sebenarnya saya mau posting tentang hal tersebut 2 hari yang lalu tetapi saya khawatir jangan-jangan ini hanya mampu bertahan sesaat, ternyata

Senin, 07 Januari 2008

Soal Vektor

Berikut adalah soal Vektor tahun 20071. Diketahui segitiga PQR dengan P(0, 1, 4), Q(2, –3, 2), dan R(–1, 0, 2). Besar sudut PRQ = ….a. 120°b. 90°c. 60°d. 45°e. 30°Soal Ujian Nasional tahun 20072. Diketahui segitiga ABC, dengan A(0, 0, 0), B(2, 2, 0) dan C(0, 2, 2).

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 the 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 them would have picked up on the cause and effect relationship between blog length and popularity. Evidently not!

So, like, let's get this out in the open: I'm doing it on purpose. Yes, sure, I could do with an editor (the people kind), but only if said editor were on board with long blogs, because that's the 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 the august occasion of the 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 the 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 they'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 they 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 these entries as books, publishers would laugh at me. They're way too short to be books. Sure, I could bundle them, but that's beside the point. The fact is, two different real-world audiences have entirely incompatible views on what the 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, they can take the 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 the goal, I think what unites them as essays is that they strive to imprint the reader with an idea, some hopefully unforgettable perspective, even if the 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 the end they're trying all trying to imprint you with a little piece of the essayist's personal perspective on life.

So we've established that my longer entries are for the most part essays in blog form, with nary a cat picture to be found. I think the appearance of my entries in feed-readers alongside cat pictures and other non-essays is a big contributor to why so many people feel they're too long. If I instead herded them off into a page titled "Essays", as essayist Paul Graham does, then my guests might arrive with more appropriate expectations.

But let's face it – that's more work. Blogs are the 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 the other trappings you'd expect. It's not ideal – I even talked about this in my first-ever Blogger entry, but none of the issues I raised then have been resolved, doubtless because most people don't write essays, so there isn't a pressing need.

Blogging's the 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 the 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 the 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, there's more to the 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 the material I'm covering or the points I'm making. And I'll still disagree with you. Let's see why.

Blowing the Cache

So, I have this pet theory 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 hypothesis that fits the data pretty well.

First, let me tell you what the pet theory is about. I talked about it a little in an essay I wrote in 2004, You Should Write Blogs. In the essay I outlined some unexpected behavior of an essay my friend had written and circulated at Amazon: nobody read the thing, but somehow a year later everyone knew about it, and its core message had been imprinted on everyone in the company, up to and including the executive staff.

In the 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 the sense that they don't make public asses of themselves 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 they're widely read. So are they 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 them to make the rounds - sometimes months or years. But there's a tradeoff there. It can be useful to make a big splash all at once, in the 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 they can take years to make the rounds. What's the right length for making a big splash the day it's published?

That's where my pet theory 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 theory about the 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 the 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 the essay, then it wasn't long enough.

I suspect the 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 other stuff too: use outline form, make the students copy the outline into a notebook, repeat everything exactly 3 times, and so on, all ways they'd found that lead to better retention of the material. But the 50-minute thing seemed intuitively reasonable. Those ten-minute breaks were indispensable.

I actually think 50 minutes is the absolute upper bound for a sitting; the optimal duration is probably lower. But the takeaway here is that one consequence of my pet theory, which we'll get to shortly, is that the 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 the amazing miracles of the internet: write-only people. They can't read but they somehow find a way to write. You see them commenting all the time in my blogs: "I didn't actually read your entry, but allow me to comment on it all the same..." Lovely.

So I need to aim for something lower than 50 minutes, to make it possible for average readers, and then hope that for fast readers I'll still have blown their entire page cache. Being a fast reader is actually a disadvantage here.

Figured my pet theory out yet? I'll bet some of you have!

Stevey's Brain-Cache Theory of Essays

My pet theory is predicated on the 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 the same laws of physics. Hence, it probably has a multi-level cache.

I have some even more farfetched pet theories about the architecture of this cache, but whatever the architecture, caches all share the 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, then 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 the 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 theory posits the existence of at least one second-level cache in your brain that holds data for a while before deciding whether to commit it to long-term memory. That "while" varies but is at least 10 to 15 minutes.

Of course, writing the theory down like this makes all the holes in it pretty obvious, and I'm way too lazy to try to patch them all up here. Following the best academic tradition, I leave the hole-patching as an exercise for the reader.

In my pet theory of the brain, such as it is, your second-level cache keeps track of all your sensory input for the 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 the graph is too big to fit in your second-level cache, then 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 there.

So my pet theory is that if you want to make a lasting impression, then you need to fill up the reader's second-level cache and start blowing pages (cache elements) out into their long-term memory. If you want to imprint them with something memorable, you've gotta flush it to disk. To fill the cache you have to create a story big enough to fill their 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 another funny blurb that your reader sees, laughs at, and immediately forgets.

This obviously entails some effort on the part of the reader, even if they'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 the cache structure in the first place.

I think this whole idea scales up to N-level caching; if you write a whole book about something, and the reader manages to get through it all, then you've probably left them 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 the pond: one sitting, one story. That's my theory. And it's the thesis of this essay, with the conclusion being that the relationship between blog length and popularity is actually causative.

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

In the 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 there'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, they 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 the thing you were just now talking about, but you can both remember things you talked about a few minutes before.

If that's true, then the stuff that gets swapped to disk is probably different for every reader, and may be somewhat random. In other words, everyone comes away with some different memory of the essay. It's likely also in no small part a function of how well any given turn of phrase is a match for the reader's experience. So a good essay needs to try to say the same thing in a bunch of different ways, hoping that whenever the reader's brain decides to latch onto something that "strikes" them more or less permanently, it's hopefully related to the core message of the essay.

So everyone gets something different. But I think that's a good thing. If the readers come away thinking about it at all, the essay has succeeded.

Wrap-Up

There's more I could say about my style. Expectations and page-caching theories aside, I think there'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 they'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, there's more I could say, but my gut tells me I've reached the 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 the ideal length significantly.

But I'm convinced, and I hope you are now as well, that my blog entries are successful because of their length, and not in spite of it. It's OK if you don't agree with my pet theory as to why the 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 the idea now. Consider yourself imprinted. This one's on the 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 there in your brain, like it or not. I guarantee it.

Kamis, 03 Januari 2008

Soal Transformasi Geometri

Berikut ini adalah soal – soal transformasi geometri 2 tahun terakhir ( file wordnya dapat diklik disini )1. Bayangan kurva y = x² – 3 jika dicerminkan terhadap sumbu x yang dilanjutkan dengan dilatasi pusat O dan factor skala 2 adalah ….a. y = ½ x² + 6b. y = ½ x² – 6c. y = ½ x² – 3d. y = 6 – ½ x²e. y = ½ x² + 6Soal Ujian Nasional tahun 20072. Bayangan garis 4x – y + 5 = 0 oleh transformasi yang

Senin, 31 Desember 2007

Matematika itu menyenangkan

Anda boleh setuju atau tidak, hasil polling pada blog ini menunjukkan baha ternyata matematika bukanlah pelajaran yang menyeramkan seperti yang diperkirakan. memang masih ada 1/3 responden yang berpikir matematika itu susah, akan tetapi hasil secara keseluruhan menunjukkan bahwa matematika itu mudah/menyenangkan. Mudah-mudahan hasil polling ini dapat semakin mematahkan mitos yang mengatakan

Rabu, 26 Desember 2007

Link di Internet

Berikut ini adalah beberapa link yang cukup menarik dalam bentuk microsoft word :1. Soal Matematika SMA ( klik disini )2. Soal Matematika SMK kelas 10 ( klik disini )3. rpp kelas 11 IPA ( klik disini )4. silabus matematika kelas 10, 11 dam 12 ( klik disini )

Rabu, 19 Desember 2007

Code's Worst Enemy

I'm a programmer, and I'm on vacation today. Guess what I'm doing? As much as I'd love to tell you I'm sipping Mai Tais in the Bahamas, what I'm actually doing on my vacation is programming.

So it's a "vacation" only in the HR sense – I'm taking official time off work, to give myself some free time to get my computer game back online. It's a game I started writing about ten years ago, and spent about seven years developing. It's been offline for a while and I need to bring it back up, in part so the players will stop stalking me. It's going to take me at least a week of all-day days, so I had to take a vacation from work to make it happen.

Why did my game go offline? Not for want of popularity. It's a pretty successful game for a mostly part-time effort from one person. I've had over a quarter million individuals try it out (at least getting as far as creating a character), and tens of thousands of people who've spent countless hours playing it over the years. It's won awards and been featured in magazines; it's attracted the attention of game portals, potential investors, and whole schools full of kids.

Yup, kids. It was supposed to be a game for college students, but it's been surprisingly popular with teenagers and even pre-teens, who you'd think would be off playing some 3D console game or other. But I wrote it for myself, and apparently there are sufficient people who like the same kinds of games I do to create a sustainable community.

I took the game down for all sorts of mundane reasons - it needed some upgrades, work got busy, I didn't have lots of time at nights, etc. But the mundane reasons all really boil down to just one rather deeper problem: the code base is too big for one person to manage.

I've spent nearly ten years of my life building something that's too big.

I've done a lot of thinking about this — more than you would probably guess. It's occupied a large part of my technical thinking for the past four or five years, and has helped shaped everything I've written in that time, both in blogs and in code.

For the rest of this little rant, I'm going to assume that you're a young, intelligent, college age or even high school age student interested in becoming a better programmer, perhaps even a great programmer.

(Please – don't think I'm implying that I'm a great programmer. Far from it. I'm a programmer who's committed decades of terrible coding atrocities, and in the process I've learned some lessons that I'm passing along to you in the hopes that it'll help you in your quest to become a great programmer.)

I have to make the assumption that you're young in order to make my point, because if I assume I'm talking to "experienced" programmers, my blood pressure will rise and I will not be able to focus for long enough to finish my rant. You'll see why in a bit.

Fortunately for me, you're young and eager to learn, so I can tell you how things really are. Just keep your eyes open for the next few years, and watch to see if I'm right.

Minority View


I happen to hold a hard-won minority opinion about code bases. In particular I believe, quite staunchly I might add, that the worst thing that can happen to a code base is size.

I say "size" as a placeholder for a reasonably well-formed thought for which I seem to have no better word in my vocabulary. I'll have to talk around it until you can see what I mean, and perhaps provide me with a better word for it. The word "bloat" might be more accurate, since everyone knows that "bloat" is bad, but unfortunately most so-called experienced programmers do not know how to detect bloat, and they'll point at severely bloated code bases and claim they're skinny as a rail.

Good thing we're not talking to them, eh?

I say my opinion is hard-won because people don't really talk much about code base size; it's not widely recognized as a problem. In fact it's widely recognized as a non-problem. This means that anyone sharing my minority opinion is considered a borderline lunatic, since what rational person would rant against a non-problem?

People in the industry are very excited about various ideas that nominally help you deal with large code bases, such as IDEs that can manipulate code as "algebraic structures", and search indexes, and so on. These people tend to view code bases much the way construction workers view dirt: they want great big machines that can move the dirt this way and that. There's conservation of dirt at work: you can't compress dirt, not much, so their solution set consists of various ways of shoveling the dirt around. There are even programming interview questions, surely metaphorical, about how you might go about moving an entire mountain of dirt, one truck at a time.

Industry programmers are excited about solutions to a big non-problem. It's just a mountain of dirt, and you just need big tools to move it around. The tools are exciting but the dirt is not.

My minority opinion is that a mountain of code is the worst thing that can befall a person, a team, a company. I believe that code weight wrecks projects and companies, that it forces rewrites after a certain size, and that smart teams will do everything in their power to keep their code base from becoming a mountain. Tools or no tools. That's what I believe.

It turns out you have to have something bad happen to you before you can hold my minority opinion. The bad thing that happened to me is that I wrote a beautiful game in an ugly language, and the result was lovely on the outside and quite horrific internally. The average industry programmer today would not find much wrong with my code base, aside from the missing unit tests (which I now regret) that would, alas, double the size of my game's already massive 500,000-line code base. So the main thing they would find wrong with it is, viewed in a certain way, that it's not big enough. If I'd done things perfectly, according to today's fashions, I'd be even worse off than I am now.

Some people will surely miss my point, so I'll clarify: I think unit testing is great. In fact I think it's critical, and I vastly regret not having unit tests for my game. My point is that I wrote the game the way most experienced programmers would tell you to write that kind of system, and it's now an appallingly unmanageable code base. If I'd done the "right thing" with unit tests, it would be twice appalling! The apparent paradox here is crucial to understanding why I hold my minority belief about code base size.

Most programmers never have anything truly bad happen to them. In the rare cases when something bad happens, they usually don't notice it as a problem, any more than a construction worker notices dirt as a problem. There's just a certain amount of dirt at every site, and you have to deal with it: it's not "bad"; it's just a tactical challenge.

Many companies are faced with multiple million lines of code, and they view it as a simple tools issue, nothing more: lots of dirt that needs to be moved around occasionally.

Most people have never had to maintain a half-million line code base singlehandedly, so their view of things will probably be different from mine. Hopefully you, being the young, eager-to-learn individual that you are, will realize that the only people truly qualified to express opinions on this matter are those who have lived in (and helped create) truly massive code bases.

You may hear some howling in response to my little rant today, and a lot of hand-wavy "he just doesn't understand" dismissiveness. But I posit that the folks making these assertions have simply never been held accountable for the messes they've made.

When you write your own half-million-line code base, you can't dodge accountability. I have nobody to blame but myself, and it's given me a perspective that puts me in the minority.

It's not just from my game, either. That alone might not have taught me the lesson. In my twenty years in the industry, I have hurled myself forcibly against some of the biggest code bases you've ever imagined, and in doing so I've learned a few things that most people never learn, not in their whole career. I'm not asking you to make up your mind on the matter today. I just hope you'll keep your eyes and ears open as you code for the next few years.

Invisible Bloat


I'm going to try to define bloat here. I know in advance that I'll fail, but hopefully just sketching out the problem will etch out some patterns for you.

There are some things that can go wrong with code bases that have a nice intuitive appeal to them, inasmuch as it's not difficult for most people to agree that they're "bad".

One such thing is complexity. Nobody likes a complex code base. One measure of complexity that people sometimes use is "cyclomatic complexity", which estimates the possible runtime paths through a given function using a simple static analysis of the code structure.

I'm pretty sure that I don't like complex code bases, but I'm not convinced that cyclomatic complexity measurements have helped. To get a good cyclomatic complexity score, you just need to break your code up into smaller functions. Breaking your code into smaller functions has been a staple of "good design" for at least ten years now, in no small part due to the book Refactoring by Martin Fowler.

The problem with Refactoring as applied to languages like Java, and this is really quite central to my thesis today, is that Refactoring makes the code base larger. I'd estimate that fewer than 5% of the standard refactorings supported by IDEs today make the code smaller. Refactoring is like cleaning your closet without being allowed to throw anything away. If you get a bigger closet, and put everything into nice labeled boxes, then your closet will unquestionably be more organized. But programmers tend to overlook the fact that spring cleaning works best when you're willing to throw away stuff you don't need.

This brings us to the second obviously-bad thing that can go wrong with code bases: copy and paste. It doesn't take very long for programmers to learn this lesson the hard way. It's not so much a rule you have to memorize as a scar you're going to get whether you like it or not. Computers make copy-and-paste really easy, so every programmer falls into the trap once in a while. The lesson you eventually learn is that code always changes, always always always, and as soon as you have to change the same thing in N places, where N is more than 1, you'll have earned your scar.

However, copy-and-paste is far more insidious than most scarred industry programmers ever suspect. The core problem is duplication, and unfortunately there are patterns of duplication that cannot be eradicated from Java code. These duplication patterns are everywhere in Java; they're ubiquitous, but Java programmers quickly lose the ability to see them at all.

Java programmers often wonder why Martin Fowler "left" Java to go to Ruby. Although I don't know Martin, I think it's safe to speculate that "something bad" happened to him while using Java. Amusingly (for everyone except perhaps Martin himself), I think that his "something bad" may well have been the act of creating the book Refactoring, which showed Java programmers how to make their closets bigger and more organized, while showing Martin that he really wanted more stuff in a nice, comfortable, closet-sized closet.

Martin, am I wrong?

As I predicted would happen, I haven't yet defined bloat except in the vaguest terms. Why is my game code base half a million lines of code? What is all that code doing?

Design Patterns Are Not Features


The other seminal industry book in software design was Design Patterns, which left a mark the width of a two-by-four on the faces of every programmer in the world, assuming the world contains only Java and C++ programmers, which they often do.

Design Patterns was a mid-1990s book that provided twenty-three fancy new boxes for organizing your closet, plus an extensibility mechanism for defining new types of boxes. It was really great for those of us who were trying to organize jam-packed closets with almost no boxes, bags, shelves or drawers. All we had to do was remodel our houses to make the closets four times bigger, and suddenly we could make them as clean as a Nordstrom merchandise rack.

Interestingly, sales people didn't get excited about Design Patterns. Nor did PMs, nor marketing folks, nor even engineering managers. The only people who routinely get excited about Design Patterns are programmers, and only programmers who use certain languages. Perl programmers were, by and large, not very impressed with Design Patterns. However, Java programmers misattributed this; they concluded that Perl programmers must be slovenly, no good bachelors who pile laundry in their closests up to the ceiling.

It's obvious now, though, isn't it? A design pattern isn't a feature. A Factory isn't a feature, nor is a Delegate nor a Proxy nor a Bridge. They "enable" features in a very loose sense, by providing nice boxes to hold the features in. But boxes and bags and shelves take space. And design patterns – at least most of the patterns in the "Gang of Four" book – make code bases get bigger. Tragically, the only GoF pattern that can help code get smaller (Interpreter) is utterly ignored by programmers who otherwise have the names of Design Patterns tatooed on their various body parts.

Dependency Injection is an example of a popular new Java design pattern that programmers using Ruby, Python, Perl and JavaScript have probably never heard of. And if they've heard of it, they've probably (correctly) concluded that they don't need it. Dependency Injection is an amazingly elaborate infrastructure for making Java more dynamic in certain ways that are intrinsic to higher-level languages. And – you guessed it – DI makes your Java code base bigger.

Bigger is just something you have to live with in Java. Growth is a fact of life. Java is like a variant of the game of Tetris in which none of the pieces can fill gaps created by the other pieces, so all you can do is pile them up endlessly.

Millions of Lines of Code


I recently had the opportunity to watch a self-professed Java programmer give a presentation in which one slide listed Problems (with his current Java system) and the next slide listed Requirements (for the wonderful new vaporware system). The #1 problem he listed was code size: his system has millions of lines of code.

Wow! I've sure seen that before, and I could really empathize with him. Geoworks had well over ten million lines of assembly code, and I'm of the opinion that this helped bankrupt them (although that also appears to be a minority opinion – those industry programmers just never learn!) And I worked at Amazon for seven years; they have well over a hundred million lines of code in various languages, and "complexity" is frequently cited internally as their worst technical problem.

So I was really glad to see that this guy had listed code size as his #1 problem.

Then I got my surprise. He went on to his Requirements slide, on which he listed "must scale to millions of lines of code" as a requirement. Everyone in the room except me just nodded and accepted this requirement. I was floored.

Why on earth would you list your #1 problem as a requirement for the new system? I mean, when you're spelling out requirements, generally you try to solve problems rather than assume they're going to be created again. So I stopped the speaker and asked him what the heck he was thinking.

His answer was: well, his system has lots of features, and more features means more code, so millions of lines are Simply Inevitable. "It's not that Java is verbose!" he added – which is pretty funny, all things considered, since I hadn't said anything about Java or verbosity in my question.

The thing is, if you're just staring in shock at this story and thinking "how could that Java guy be so blind", you are officially a minority in the programming world. An unwelcome one, at that.

Most programmers have successfully compartmentalized their beliefs about code base size. Java programmers are unusually severe offenders but are by no means the only ones. In one compartment, they know big code bases are bad. It only takes grade-school arithmetic to appreciate just how bad they can be. If you have a million lines of code, at 50 lines per "page", that's 20,000 pages of code. How long would it take you to read a 20,000-page instruction manual? The effort to simply browse the code base and try to discern its overall structure could take weeks or even months, depending on its density. Significant architectural changes could take months or even years.

In the other compartment, they think their IDE makes the code size a non-issue. We'll get to that shortly.

And a million lines is nothing, really. Most companies would love to have merely a million lines of code. Often a single team can wind up with that much after a couple years of hacking. Big companies these days are pushing tens to hundreds of millions of lines around.

I'll give you the capsule synopsis, the one-sentence summary of the learnings I had from the Bad Thing that happened to me while writing my game in Java: if you begin with the assumption that you need to shrink your code base, you will eventually be forced to conclude that you cannot continue to use Java. Conversely, if you begin with the assumption that you must use Java, then you will eventually be forced to conclude that you will have millions of lines of code.

Is it worth the trade-off? Java programmers will tell you Yes, it's worth it. By doing so they're tacitly nodding to their little compartment that realizes big code bases are bad, so you've at least won that battle.

But you should take anything a "Java programmer" tells you with a hefty grain of salt, because an "X programmer", for any value of X, is a weak player. You have to cross-train to be a decent athlete these days. Programmers need to be fluent in multiple languages with fundamentally different "character" before they can make truly informed design decisions.

Recently I've been finding that Java is an especially bad value for X. If you absolutely must hire an X programmer, make sure it's Y.

I didn't really set out to focus this rant on Java (and Java clones like C#, which despite now being a "better" language still has Java's fundamental character, making it only a marginal win at best.) To be sure, my minority opinion applies to any code base in any language. Bloat is bad.

But I find myself focusing on Java because I have this enormous elephant of a code base that I'm trying to revive this week. Can you blame me? Hopefully someone with a pet C++ elephant can come along and jump on the minority bandwagon with me. For now, though, I'll try to finish my explanation of bloat as a bona-fide problem using Java for context.

Can IDEs Save You?


The Java community believes, with near 100% Belief Compliance, that modern IDEs make code base size a non-issue. End of story.

There are several problems with this perspective. One is simple arithmetic again: given enough code, you eventually run out of machine resources for managing the code. Imagine a project with a billion lines of code, and then imagine trying to use Eclipse or IntelliJ on that project. The machines – CPU, memory, disk, network – would simply give up. We know this because twenty-million line code bases are already moving beyond the grasp of modern IDEs on modern machines.

Heck, I've never managed to get Eclipse to pull in and index even my 500,000-line code base, and I've spent weeks trying. It just falls over, paralyzed. It literally hangs forever (I can leave it overnight and it makes no progress.) Twenty million lines? Forget about it.

It may be possible to mitigate the problem by moving the code base management off the local machine and onto server clusters. But the core problem is really more cultural than technical: as long as IDE users refuse to admit there is a problem, it's not going to get solved.

Going back to our crazed Tetris game, imagine that you have a tool that lets you manage huge Tetris screens that are hundreds of stories high. In this scenario, stacking the pieces isn't a problem, so there's no need to be able to eliminate pieces. This is the cultural problem: they don't realize they're not actually playing the right game anymore.

The second difficulty with the IDE perspective is that Java-style IDEs intrinsically create a circular problem. The circularity stems from the nature of programming languages: the "game piece" shapes are determined by the language's static type system. Java's game pieces don't permit code elimination because Java's static type system doesn't have any compression facilities – no macros, no lambdas, no declarative data structures, no templates, nothing that would permit the removal of the copy-and-paste duplication patterns that Java programmers think of as "inevitable boilerplate", but which are in fact easily factored out in dynamic languages.

Completing the circle, dynamic features make it more difficult for IDEs to work their static code-base-management magic. IDEs don't work as well with dynamic code features, so IDEs are responsible for encouraging the use of languages that require... IDEs. Ouch.

Java programmers understand this at some level; for instance, Java's popular reflection facility, which allows you to construct method names on the fly and invoke those methods by name, defeats an IDE's ability to perform basic refactorings such as Rename Method. But because of successful compartmentalization, Java folks point at dynamic languages and howl that (some) automated refactorings aren't possible, when in fact they're just as possible in these languages as they are in Java – which is to say, they're partly possible. The refactorings will "miss" to the extent that you're using dynamic facilities, whether you're writing in Java or any other language. Refactorings are essentially never 100% effective, especially as the code base is shipped offsite with public APIs: this is precisely why Java has a deprecation facility. You can't rename a method on everyone's machine in the world. But Java folks continue spouting the provably false belief that automated refactorings work on "all" their code.

I'll bet that by now you're just as glad as I am that we're not talking to Java programmers right now! Now that I've demonstrated one way (of many) in which they're utterly irrational, it should be pretty clear that their response isn't likely to be a rational one.

Rational Code Size


The rational response would be to take a very big step back, put all development on hold, and ask a difficult question: "what should I be using instead of Java?"

I did that about four years ago. That's when I stopped working on my game, putting it into maintenance mode. I wanted to rewrite it down to, say, 100,000 to 150,000 lines, somewhere in that vicinity, with the exact same functionality.

It took me six months to realize it can't be done with Java, not even with the stuff they added to Java 5, and not even with the stuff they're planning for Java 7 (even if they add the cool stuff, like non-broken closures, that the Java community is resisting tooth and nail.)

It can't be done with Java. But I do have a big investment in the Java virtual machine, for basically the same reason that Microsoft now has a big investment in .NET. Virtual machines make sense to me now. I mean, they "made sense" at some superficial level when I read the marketing brochures, but now that I've written a few interpreters and have dug into native-code compilers, they make a lot more sense. It's another rant as to why, unfortunately.

So taking for granted today that VMs are "good", and acknowledging that my game is pretty heavily tied to the JVM – not just for the extensive libraries and monitoring tools, but also for more subtle architectural decisions like the threading and memory models – the rational answer to code bloat is to use another JVM language.

One nice thing about JVM languages is that Java programmers can learn them pretty fast, because you get all the libraries, monitoring tools and architectural decisions for free. The downside is that most Java programmers are X programmers, and, as I said, you don't want X programmers on your team.

But since you're not one of those people who've decided to wear bell-bottom polyester pants until the day you die, even should you live unto five hundred years, you're open to language suggestions. Good for you!

Three years ago, I set out to figure out which JVM language would be the best code-compressing successor to Java. That took a lot longer than I expected, and the answer was far less satisfactory than I'd anticipated. Even now, three years later, the answer is still a year or two away from being really compelling.

I'm patient now, though, so after all the dust settles, I know I've got approximately a two-year window during which today's die-hard Java programmers are writing their next multi-million line disaster. Right about the time they're putting together their next Problems/Requirements slide, I think I'll actually have an answer for them.

In the meantime, I'm hoping that I'll have found time to rewrite my game in this language, down from 500,000 lines to 150,000 lines with the exact same functionality (plus at least another 50k+ for unit tests.)

The Next Java


So what JVM language is going to be the Next Java?

Well, if you're going for pure code compression, you really want a Lisp dialect: Common Lisp or Scheme. And there are some very good JVM implementations out there. I've used them. Unfortunately, a JVM language has to be a drop-in replacement for Java (otherwise a port is going to be a real logistics problem), and none of the Lisp/Scheme implementors seems to have that very high on their priority list.

Plus everyone will spit on you. People who don't habitually spit will expectorate up to thirty feet, like zoo camels, in order to bespittle you if you even suggest the possibility of using a Lisp or Scheme dialect at your company.

So it's not gonna be Lisp or Scheme. We'll have to sacrifice some compression for something a bit more syntactically mainstream.

It could theoretically be Perl 6, provided the Parrot folks ever actually get their stuff working, but they're even more patient than I am, if you get my drift. Perl 6 really is a pretty nice language design, for the record – I was really infatuated with it back in 2001. The love affair died about five years ago, though. And Perl 6 probably won't ever run on the JVM. It's too dependent on powerful Parrot features that the JVM will never support. (I'd venture that Parrot probably won't ever support them either, but that would be mean.)

Most likely New Java is going to be an already reasonably popular language with a very good port to the JVM. It'll be a language with a dedicated development team and a great marketing department.

That narrows the field from 200+ languages down to maybe three or four: JRuby, Groovy, Rhino (JavaScript), and maybe Jython if it comes out of its coma.

Each of these languages (as does Perl 6) provides mechanisms that would permit compression of a well-engineered 500,000-line Java code base by 50% to 75%. Exactly where the dart lands (between 50% and 75%) remains to be seen, but I'm going to try it myself.

I personally tried Groovy and found it to be an ugly language with a couple of decent ideas. It wants to be Ruby but lacks Ruby's elegance (or Python's for that matter). It's been around a long time and does not seem to be gaining any momentum, so I've ruled it out for my own work. (And I mean permanently – I will not look at it again. Groovy's implementation bugs have really burned me.)

I like Ruby and Python a lot, but neither JVM version was up to snuff when I did my evaluation three years ago. JRuby has had a lot of work done to it in the meantime. If the people I work with weren't so dead-set against Ruby, I'd probably go with that, and hope like hell that the implementation is eventually "fast enough" relative to Java.

As it happens, though, I've settled on Rhino. I'll be working with the Rhino dev team to help bring it up to spec with EcmaScript Edition 4. I believe that ES4 brings JavaScript to rough parity with Ruby and Python in terms of (a) expressiveness and (b) the ability to structure and manage larger code bases. Anything it lacks in sugar, it more than makes up for with its optional type annotations. And I think JavaScript (especially on ES4 steroids) is an easier sell than Ruby or Python to people who like curly braces, which is anyone currently using C++, Java, C#, JavaScript or Perl. That's a whooole lot of curly brace lovers. I'm nothing if not practical these days.

I don't expect today's little rant to convince anyone to share my minority opinion about code base size. I know a that few key folks (Bill Gates, for instance, as well as Dave Thomas, Martin Fowler and James Duncan Davidson) have independently reached the same conclusion: namely, that bloat is the worst thing that can happen to code. But they all got there via painful things happening to them.

I can't exactly wish for something painful to happen to Java developers, since hey, it's already happening; they've already taught themselves to pretend it's not hurting them.

But as for you, the eager young high school or college student who wants to become a great programmer someday, hopefully I've given you an extra dimension to observe as your tend your code gardens for the next few years.

When you're ready to make the switch, well, Mozilla Rhino will be ready for you. It works great today and will be absolutely outstanding a year from now. And I sincerely hope that JRuby, Jython and friends will also be viable Java alternatives for you as well. You might even try them out now and see how it goes.

Your code base will thank you for it.

Selasa, 18 Desember 2007

Your Comment

Terima kasih atas beberapa masukkan yang disampaikan baik melalui email ataupun shoutbox untuk blog ini. Berikut adalah tanggapan atas saran yang masuk :1. Pembahasan soal - soal dan kisi - kisi untuk Ujian Nasional akan segera muncul segera setelah 3 bab kumpulan soal yang tersisa selesai, be patient !2. Blog ini secara khusus memang hanya seputar matematika sma khususnya materi - materi yang

Kamis, 13 Desember 2007

Search Engine Optimize ( SEO )

Search Engine Optimize ( SEO ) adalah sebuah upaya yang dilakukan agar mendapatkan rangking yang baik pada hasil pencarian. Sebenarnya ada banyak teknik SEO ( klik disini ) yang bisa diterapkan agar kita bisa mendapat rangking yang baik di SERP ( Search Engine Result Page ).Tulisan ini bukan untuk membahas tentang SEO, karena saya juga tidak menguasai hal tersebut. So saya hanya ingin menunjukkan