Archive | October, 2007

User interface semantics

27 Oct

One of the largest deficiencies in most software interfaces lies in their poor use of semantic categorization. This is most clearly seen in windowed applications’ menu bars, where organization is done in several different ways (often inconsistently within the same application):

  • organization by hierarchy of action, e.g. “Paste” goes under “Edit” because pasting is a kind of editing
  • organization by hierarchy of things, e.g. “Layers” goes under “Window” because the layers dialog is a window
  • organization by phrase completion, e.g. “Grid” goes under “View” because one views the grid
  • organization by inverted/scrambled phrase completion, e.g. “Rotate 90 degrees” goes under “Image” because one rotates the image 90 degrees
  • organization by free association, e.g. “Back” and “Forward” go under “History” because they are navigation links like a previous-site link is a navigation link
  • organization by fuck all, e.g. “Preferences” go under “Help”, “Tools”, “Edit”, “File”, et al.

The hopeful thing about this problem is it suggests much software could be greatly improved simply by re-examining a few word choices and moving some menu items around. The discouraging thing about the problem is that getting semantics and categorization “right” is very, very hard and may in fact be an intractable problem (see Clay Shirky here and here).

RMS vs. libertarians

27 Oct

RMS (Richard “Not Milhous” Stallman) has always been insistent that the important virtues of “free software” are ethical, not practical or technical. As best as I can surmise, RMS’s ethical claims boil down to:

  1. Society is better off with a non-proprietary software infrastructure because it protects users against software that does not have their interests at heart.
  2. A society of unfettered experimentation, education, discovery, and cooperation is better to live in.
  3. Sharing of modified or unmodified intellectual works (he objects to the term “intellectual property”) is a right, the abridgment of which is an affront to freedom.

The first point has been well argued by many: governments and the proprietary media industries increasingly want to undermine the technological power that general-purpose computing puts in the hands of end-users. (See any discussion of DRM, trusted computing, or government efforts to nerf encryption.)

It’s not surprising that libertarians of the FOSS movement concur on the first claim, but it’s perhaps surprising there’s not more friction on the second: I’ve always thought of libertarian ideology as wanting to “unrestrain” the exceptional few so that they can stride above the masses like the colossi of self-made virtue that they are, which doesn’t seem consistent with the promotion of greater cooperation. The explanation for this departure, I think, is that free software development, for all its openness, is actually brutally meritocratic: good code survives, bad or not-so-good code gets tossed or ignored, so generally, the better programmers rule the FOSS landscape.

It is this third claim—the right to take and share non-rivalrous copies—that I would expect to hear more debate about, but both sides are surprisingly quiet on this issue, including Stallman himself, who as far as I can tell views the right-to-share as axiomatic. The only examples of debate I’m aware of aren’t much more than assertions: assertions of the goodness of sharing and counter assertions of the goodness of property. So if you’re aware of real debate on this issue, please let me know.

In the end, this tension between free software and libertarian ideology can probably just be ignored, for the libertarians of FOSS seem to be a peculiar Silicon Valley variety, a breed that mainly focuses on the stupidity of regulation and political correctness (*yawn*). (A most peculiar example of this is Wikipedia founder Jimbo Wales, a self-proclaimed Randian with a very, um…unfamiliar spin on Objectivism; see this CSPAN interview with Wales)

WinDirStat is neat

26 Oct

WinDirStat is a simple Windows program that displays the files and directories of a partition as rectangles proportional to their size, allowing you to quickly see what’s taking up the space. Among the good design decisions the authors made, the files are colored by file type and very helpfully shaded.

windirstat

Of course, the program basically has to index your partition anew each time it starts, but I was pleased to find this process doesn’t take too long (~ 2 min. for a 200 GB drive).

Poorly explained aspects of Java explained not so poorly (part 1)

20 Oct

Most Java instruction materials fail to make certain basic things as clear as they could be, so here’s a FAQ-like rundown.

What are the types of values in Java?

Java divides its types into what it calls ‘primitive’ and ‘reference’ types (this terminology is unique to Java):

  • The primitive value types consist of five integer types of different sizes (int, long, char, short, byte), the floating-point types of different sizes (float and double), and the boolean type.
  • A reference value is an instance of a class.

(A reference value might also be an instance of an enum—a class-like enumeration. I won’t discuss enums as they were added late to the language and most programmers get by without using them.)

Confusingly, the terms value type and value variable are sometimes used as a synonym for primitive type and primitive-type variable, respectively. Less surprisingly, reference variable is used to mean a reference-type variable.

What’s a literal?

Values of some types can be expressed as ‘literals’, i.e. literal representations of particular values:

  • 35 : a literal int value (all integer literals are of type int by default)
  • -12.51 : a literal double value (all floating-point literals are of type double by default)
  • ‘b’ : a literal of type char (the ASCII value of ‘b’ is 98, so if used in an arithmetic expression, it will act as that integer value, e.g. (‘b’ + 2) is 100)
  • true : the reserved words true and false are literals of the two boolean values
  • “Aye carumba!” : a String literal

Notice that the only non-primitive type of literal is a string literal (a string is an object, an instance of the class String in the package java.lang).

What’s an expression?

An expression is one of two things:

  • a value
  • an operation

A value is either a literal or a variable. A literal obviously evaluates into the value which it represents, while a variable expression evaluates into the value it holds at the time it is evaluated.

An operation consists of an operator and operands and evaluates into a value. For instance:

3 + 2      // the operation + has operands 3 and 2 and evaluates into the value 5

Note that the operands are themselves expressions. In this case, the operands are values, but they could be any kind of expression as long as those expressions evaluate into the right type of value, e.g.:

3 + (9 - 2)     // the first operand of + is 3 and the second operand is the expression (9 - 2)

Also note that, in all cases, an operation evaluates down into a value—we can say that the operation ‘returns‘ a value—and that value has some particular type. In Java, it’s an important feature of the language that the type of value returned by an operator expression is always known from the operator and the types of its operands, e.g.:

('b' + 3)      // the + operator with a char operand and an int operand will return an int value

The language is designed such that the compiler always knows the type of each expression, i.e. the type of each value and the type returned by each operation. For the language to know this, you must always declare the type of each variable, the type of each parameter, and the return type of each function. This is the essence of what it means for Java to be a statically-typed language.

Each operator has its own rules about how many operands it takes, their types, and the type of the value it returns. Some operators change what type of value they return depending upon the number and type of their operands. For instance, the + operator will return a String rather than an int when used with a String operand:

"Johnny" + 5    // a + operation with a String and int operand will convert the int into a string and return a concatenation of the two strings as a string: "Johnny5"

There are a few dozen operators in Java:

  • a few are unary (taking one operand, e.g. the ! operator)
  • most are binary (taking two operands)
  • one rarely used operator is ternary (taking three operands), the ? : operator

Parentheses and the rules of precedence are used to determine which operations are the operands to which other operations:

3 + 7 * 9    // * has higher precedence than +, so (7 * 9) is evaluated first and is an operand to the + operation
(3 + 7) * 9     // the parentheses override the usual precedence, so (3 + 7) is evaluated first and is an operand to the * operation

(Note that the whole point of operator precedence is so lazy mathematicians don’t have to put each individual operation in its own set of parentheses.)

The operators and their precedences are listed here.

Not all operations are denoted by operators, however, for a method call can be thought of as an operation: as determined in its definition, a method takes some number of operands of particular types and returns a value of some particular type. (Some think of the parentheses of a method call as an operator such that the name of the method and the arguments are the operands, but I prefer thinking of the method name itself as the operator and just the arguments as the operands.)

What’s an expression statement?

An expression statement simply has this form:

expression;

In Java, an expression statement must be either an assignment operation or a method call, e.g.:

x = 3 + foo;     // an assignment statement
cow.moo();    // a call statement

In some other languages with similar syntax, such as C, many compilers won’t complain if you have an expression statement like foo; (which says, ‘evaluate the value of variable foo and do nothing with it’) even though such statements are pointless. Java will complain if you write such do-nothing expression statements.

(Of course, it’s quite possible a method call expression might not do anything useful, but the Java compiler can’t know that; it only objects to expression statements it knows couldn’t possibly be useful, such as 3 + 5;)

What’s a declaration statement?

A declaration statement has the form:

type name;

For instance:

int x;     // declare a variable named 'x' of type int

Cat c;     // declare a variable name 'c' of type

For convenience, you can declare multiple variables of one type in one declaration statement using commas to separate the names, e.g.:

int x, y, z;  // declare three ints: x, y, and z

Also for convenience, you can assign a value to a variable as you declare it using this form:

type name = expression;

…where the expression evaluates into the value assigned to the variable.

In a multiple declaration, assigning values to the variables looks like this:

int x = 3, y, z = 2;

…which is no different from writing the same thing as three successive statements:

int x = 3;
int y;
int z = 2;

What’s a control statement?

A control statement is one of the statements having to do with flow of execution: if, while, for, break, continue, try-catch, return, and a few others. The rules and meaning of these statements are particular to each kind.

What’s the difference between a value variable and a reference variable?

Variables of primitive types are value variables, meaning they directly hold a primitive value:

int x = 3;
int y = x;
x = 4;  // though y got its value from x, modifying x afterwards has no effect on y
 System.out.print(y); // print 3

Here, x and y represent two locations in memory where an integer value is directly held. After the second assignment, the memory locations of x and y each hold separate copies of the value 3.

Variables of reference types are reference variables, meaning they hold a reference (address) to an object, not the object itself:

Cat x = new Cat(); // a new Cat is created, and memory location x now holds the address of that object
x.name = "Fluffy";
 Cat y = x;   // the expression (x) evaluates into the object referenced by x, and so the new Cat reference named y is assigned the address of the very same object referenced by x
 x.name = "Mittens";    // modify the property of the cat object referenced by x
 System.out.print(y.name); // prints "Mittens" because y referenced the very same object as x when we modified the object's 'name' property via the reference x

Here, x and y represent two locations in memory where addresses are held. The actual Cat object is elsewhere in memory. Both x and y are assigned the same Cat object address, so modifying the object referenced by x is the same thing as modifying the object held in y—they’re the same Cat.

What are the primitive types?

The integer primitive types are:

  • byte
  • char
  • short
  • int
  • long

The floating-point primivite types are:

  • float
  • double

For all these types, see here for their exact sizes. If your code requires high-precision floating-point calculations, you should read up on the strictfp modifier.

Finally, there’s the boolean primitive type, which consists of two special values, true or false. In other languages, such as C, numbers are used to mean true or false in special contexts—usually zero represents false while all other values represent true—so why have a unique type for true and false? Well the thinking is that this protects you against accidentally using a number when you meant to use a true/false value and vice versa and helps clarify the intent of code when it is read.

Is = really an operator?

In Java, yes. However, the = operator may seem like something of a special case, and that’s because it is: the = operator’s left operand is not a value (and hence not an expression) but rather a target, i.e. a variable to assign to. Consider:

foo = 2;

It wouldn’t make sense for foo to evaluate into its value here because you can’t assign a new value to a value—that just doesn’t make any sense. Rather, we are assigning a value to the variable itself.

Despite this unique difference, = is still an operation and does return a value, which is the value assigned to the target:

3 + (x = 4)       // first 4 is assigned to x, then 3 is added to 4

Because = operations are right-to-left associative, we can chain assignments:

x = y = z = 5;

This is equivalent to:

x = (y = (z = 5));

A common typo is to type = when you meant to type ==. In C, this creates a problem in such cases as:

if (x = 3)  { ... }

…because, in C, an integer can be used as a true/false value, so the value 3 returned by (x = 3) is accepted as the condition value even though the programmer certainly meant to use == instead. In Java, in contrast, a condition must be a boolean value, so the compiler will complain here about an invalid if condition.

Some other languages think it’s a bad idea to allow assignments to occur in unexpected places, so they make = useable only as the outer operation of an expression statement. In general, you should follow this convention, as code is hard to read when assignment operations occur in unexpected places. E.g., instead of:

 foo(x = 3);

…do this:

x = 3;
foo(x);

What’s the order of the modifiers?

Java contains some keywords which modify reference-type declarations (classes, interfaces, and enums), local variables, fields, and methods. Some of these modifiers can’t be used with other modifiers, but Java doesn’t care about the order in which you write the modifiers as long as they all go before the thing they modify, like so:

  • class: modifiers class Name {}
  • variable (local or field): modifiers type name;
  • method: modifiers return_type name(parameters) { }

So, for instance, you could write a field as :

static final int x = 3;

…or:

final static int x = 3;

…but not:

final int static x = 3;  // modifier 'static' must go before the type ('int')

Why is the syntax for creating objects so verbose? E.g. Foo foo = new Foo();

The reason it’s so verbose is because really two independent things are going on in such a statement. If we have a class named Foo, then this:

Foo foo;

…declares a reference of type Foo. No object has yet been assigned to foo, so it holds the default value of null, the special value representing a reference to nothing. To actually create a Foo object, we use the new operator followed by a call to the constructor:

new Foo()

Understand that, like all other calls to functions, this is an expression! It just looks funny because ‘new’ (which is a unary operator just like ‘!’) is always separated by whitespace from its operand (the call to the Foo constructor). The new operator must be used when calling a constructor to create a new object. In the most common use of new, the newly created object is immediately assigned to a reference, like so:

Foo foo = new Foo();

…but a new operator expression is really an expression like any other, so you can create a new object of a type anywhere an object of that type can be used without having to assign it to a reference:

funky(new Foo());  // the method funky taking a new Foo object as its argument
 new Foo().bla();  // create a new Foo object and then call its bla() method

In this last example, the new Foo object is not assigned to a reference and so lost after the statement. This is not the most common thing to do, but it is not all that rare in real code.

An initially confusing thing about the syntax of new is that it has a higher precedence than the dot operator, so the last statement of the last example could equivalently be written:

(new Foo()).bla();

For clarity, it might help to always imagine parentheses around every use of new and its constructor call operand like above.

What’s the deal with calling one constructor from another?

Within a constructor, we might call another constructor of the same class—or even call the current constructor recursively—to continue the job of constructing the object. To do this, you wouldn’t prefix the call with new. Conceivably—if rarely—you might wish to create a new separate instance of the same class inside a constructor (e.g. inside a Cat constructor, you might wish to instantiate a new Cat that is independent of the Cat being constructed), in which case you would use new.

Is new necessary?

Arguably, if you got rid of new, the compiler could simply infer the creation of a new instance from the fact that you are calling a constructor, e.g.:

Cat c = Cat();    // not proper Java (assuming Cat() is a constructor call)

However, (as discussed in the previous section) the new operator helps distinguish between calling one constructor to another and creating a separate object of the same type. For instance, inside the Cat constructor, new Cat() would create a new separate Cat while Cat() would either invoke another Cat constructor or the current Cat constructor (recursively) for the purpose of constructing the current object, not a new separate Cat.

Arguably a better solution could have been used to make this distinction, allowing us to avoid typing new so much, but in any case, I find having new is nice because it makes object instantiations stand out in code.

What is “the stack”?

When loaded, your program is alloted a contiguous piece of memory called ‘the stack’, where all of its local variables are stored. It works like this:

  • The stack starts out empty.
  • As a function executes, its local variables are pushed (stored) on the top of the stack.
  • When the currently executing function call returns, the local variables it created are popped (removed) from the stack before execution returns to the function which called it.

The set of locals created by a function call is called a stack frame.

Notice that, AT ALL TIMES, the frame at the top of the stack belongs to the currently executing function, and the frame below it belongs to the function which called the currently executing function, and the second frame down belongs to the function which called the function which called the currently executing function…and so on, until you get all the way to the bottom frame, which belongs to the main() function of your program. When main() returns, the program ends and the stack is empty.

Such stack-based execution is the dominant model of execution in programming.

If your program’s stack outgrows its space in memory, the Java runtime will request more memory from the operating system if it needs more; if the OS refuses the request (which happens when there isn’t enough memory to be had), the Java runtime causes an exception to be thrown in your program, crashing your program if you don’t catch the exception. (This is a good example of an exception you shouldn’t catch, as there’s generally nothing you can do to recover from running out of stack space; at most, you should catch it, try to do some clean-up work and preserve data you don’t want to lose, then terminate the program.) This kind of error is called a stack overflow because your stack needed to ‘overflow’ its space to continue execution. On a modern desktop system, the amount of memory available makes it hard to imagine a well-designed program that needs more stack space than it can have, so an overflow should generally be seen as a bug or design flaw in your code, not a vexing system limitation. By far, the most common cause of stack overflows is accidentally allowing a function to make too many recursive calls.

(Programs may actually use more than one stack: as I’ll discuss later, each ‘thread’ of a program has its own stack. However, all programs start with one thread, and many programs never need more than one, so we can ignore multi-threading for now.)

What is “the heap”?

Aside from the stack, the ‘heap’ is the other part of memory used by your program. Remember that local variables in Java consist of only primitives and references to objects, not any objects themselves, so you won’t find any objects on the stack; rather, all objects are stored in the heap.

No matter how many threads you have, there is always only one heap for your program.

While the stack is a strictly organized piece of memory that preserves the local variables of each function call, in contrast, the heap, as its name suggests, is a disorderly place. Much intelligence goes into keeping track of which areas of the heap are free, deciding which spots to place new objects in, and avoiding wasteful gaps between objects, but you don’t worry about all that, for it is the job of the Java runtime to manage all of it.

Like with the stack, the Java runtime will request more memory from the operating system if it needs more; if the OS refuses the request (most likely because there isn’t enough more memory to be had), an exception is raised.

Classes are objects too!

When you start a Java program, each class that is used in the course of the program is loaded as an object of the special class java.lang.Class. Among other things, this object is where the static fields of a class are stored (in case you were wondering.)

Yes, it is confusing to have a class named Class. For one thing, if all classes are represented by a Class object, what about Class itself? Is there an instance of Class representing the Class class? Which came first: the Class class or the Class instance? There can’t simply be code that says new Class() because the Class class would need to be loaded as a Class instance first before the Class constructor could be used. (In fact, Class has no constructors.) The answer is that Class requires special treatment by the Java runtime at load time.

You can get the Class object of a class using the static forName method of Class:

Class stringClass = Class.forName(“java.lang.String”); // get a Class object representing the String class

There’s not much you’d normally want to do with Class objects, but they make some meta-programming techniques possible that otherwise wouldn’t be.

What’s a local variable?

Any variable you declare inside a function—including the parameter variables—are local variables. A local variable is created when its declaration statement is reached in the execution of a function. The local variables of a function call are discarded when the call returns: they don’t actually get erased on the spot, but the memory they occupy on the stack becomes free game to be overwritten by the creation of local variables in later function calls, so they’re as good as dead.

Actually, if a local variable is declared within a control block, such as of an if, for, try, catch, etc., then it is said to be local to that block rather than local to the whole function, and it will actually be discarded from the stack when the block is finished, not when the whole function call is finished. Therefore, you can use a variable only in the block in which it is declared or in sub-blocks thereof.

If you declare a local with the same name as a variable of an outer scope, then the name in that inner scope refers to the local:

int x = 3;

if (true) {    // an if with the condition true is, of course, a silly thing to have, but it serves our demonstration
    int x;
    x =  5;
    if (true) {
        int x;
        x = 7;
        System.out.println(x); // print the value 7
    }
    System.out.println(x); // print the value 5
}
System.out.println(x); // print the value 3

What is overloading good for?

Method overloading (not to be confused with method overriding) occurs when a class is given multiple methods of the same name; this is allowed as long as the methods do not share the same number and/or type of parameters. When you call the method of that name, the compiler can tell which method you mean to call based upon the number and type of the arguments.

So just like some operators vary their effect and type of returned value based upon the type and number of their operands, an overloaded method can vary its effect and type of returned value based upon the type and number of its operands (the parameters).

Understand that overloaded methods are really entirely independent methods that just happen to share a name. The reason Java allows overloading is because it is often simply desirable to have a method which is callable in different ways without having to come up with distinct names for each variation. In general, a set of methods in a class that share the same name should all perform something like the same purpose as each other; if not, you are probably just confusing the users of your class. (Just like having the + operator used for both addition and String concatenation is confusing for learners of Java.)

What’s the difference between “overriding” and “overloading”?

If your class inherits a method foo but you write a method of the same name and same number and types of parameters, then this is considered overriding. If you add your own variants of foo with the same name but different numbers and/or types of parameters, that is overloading because the new variants don’t replace the inherited foo.

Improved improved Firefox tabbing

9 Oct

I’ve rethought my ideas for better tabbing in Firefox (first mentioned here) and have revised my mockup in Javascript accordingly. The performance of the tab switching and previewing is much better, previews are now seen as the full size of the page, and the ‘all tabs’ pulldown now causes the page to scrunch over, better preserving the look of pages in the previews and thereby making them more instantly recognizable. CAVEATS: Only tested in Firefox 2.