Thursday, March 31, 2005

Partial Replacing Lambda?

Wonder if partial functions are going to replace lambda in python3000.

partial(operator.add, 1) isn't such an attractive substitute for lambda x: x+1, but that's more about operator than it is about partial().

Maybe partial()+1 should be supported using operator overloading. It'd be especially nice to be able to do partial()+x+y instead of partial(operator.add, x+y)

This form should probably be a differently named built-in, but built-ins aren't cheap, and the no argument constructor isn't otherwise meangingful.

Wednesday, March 23, 2005

Humble and Smart

The more you learn about something, the more you realize how little you know about it.

This isn't just philosophy; when people know nothing about a thing, they assume that there's "nothing to it". Then they confidently make decisions based on incomplete information. (It could be because interesting elements exploit the interplay of the simple and the complex. Or it could just be because small details aren't visible at a distance.)

Paradoxically, bright people are more susceptible to this thinking. Bright people are accustomed to quickly understanding ideas outside of their field of expertise, and this understanding is often superior to experts'. A bright person can start to believe (subconsciously) that much of the work in a field is characterized by lack of understanding.

This has ramifications for religious leadership. That religious leaders have insight into issues not technically within the sphere of religious practice is a doctrine of Judaism, and probably other religions as well. It's only logical; following Judaism is about living wisely, and someone with a deeper understanding of Judaism should have attained greater wisdom. In order to be truly wise, however, a person must be aware of his limitations. Maybe this awareness can be achieved by encountering sufficiently dramatic examples (for example the abuse cases involving religious leaders in recent years), or maybe it requires learning a little bit about alot of different things.

(It is troubling to think that G-d confers special wisdom in a way that is completely independent of the natural working of the world. For one thing, thinking that you've got supernatural aid from G-d certainly exacerbates the problem described above. For another, there is no good way to tell when you got it, and when you don't. "Trust in God, but steer away from the rocks", applies here as well.

At any rate, I don't think Judaism encourages completely ignoring the rules of the physical world. There's a gemara in niddah that gives advice about achieving various goals; in each case the gemara advises both acting according to natural way of the world, and also praying for success. In this era characterized by hester panim ("G-d hiding His face"), we certainly shouldn't abdicate the responsibility to do our hishtadlus (effort), especially where other people are involved.)

Friday, March 18, 2005

Idiomatic Python

Programming languages, like human languages, each have their own idiomatic usage. Though there are many different ways to express a single thing, some patterns of expression just feel much more natural.

The idiomatic style of python is beautiful.

Here's an example. You'd like to allow categorizing emails using their subjects, by prefixing the normal subject with the category and a colon. So for a message with subject "game on tuesday", you could use subject "sports: game on tuesday". If no category is specified, you'd like to use "misc". Here's the Pythonic way to do it:
try:
category, subject = headers['Subject'].split(':')
except:
category, subject = 'misc', headers['Subject']

There are a few different features at work here:
  • "It's easier to ask forgiveness than permission"
  • Exceptions are used heavily
  • Language support for collections is simple and easy

Friday, March 11, 2005

"Startups" and Small Businesses

At least since the dot-com bubble, the idea of the startup has been enshrouded in glamor. Most recently Paul Graham posted How to Start a Startup, but his advice is for dot-com-bubble type startups. He suggests that starting a company means compressing a career of 40 years into 4, and assumes that every new business will either flop or become an industry giant.

It could be that when Graham says "startup", he means a company that would rather flop than settle for staying small. Only talking about these startups is strange for a few reasons. Many companies consider themselves successful without making a public stock offering, or being bought out for piles of cash. How about creating a successful small company first, on the way to becoming an industry giant later? And which ideas and strategies are appropriate for which goal? These questions are a lot more relevant today than how to handle a Venture Capitalist imposed CEO.

After all, though more people are employed by big companies, there are many more small companies than big ones.

Wednesday, March 09, 2005

Note to Future Self

Whenever I put something down in an unusual place, there's a strong chance I will "lose" it.

Hopefully when I'm older I'll look back at this note and realize that I'm not going senile.

Tuesday, March 08, 2005

Ipod Shuffle for Lectures

The IPod Shuffle is a wonderful device. One more feature would make it perfect for listening to lecture series (or books on tape or language courses), without bloating its wonderfully simple interface.

The IPod Shuffle should remember the current "song" after it's turned off.

So apparently this is supported for purchases from ITunes and Audible. In order to get it to work with anything else, you have to use faac to create .m4b files.

UPDATE: It works great. If you're using linux, get gnupod, mpg321, and faac. Then you can do something like:
mkdir /mnt/ipod 2>/dev/null
mount /dev/sda1 /mnt/ipod
for mp3 in *.mp3
do
m4b=${mp3%.*}.m4b
mpg321 -w $mp3 | faac -b 10 -c 3500 - -o $m4b
gnupod_addsong.pl -m /mnt/ipod $m4b
done
mktunes.pl -m /mnt/ipod
umount /mnt/ipod
Incidentally, it would be great if gnupod would expose a filesystem-type api to the ipod using fuse.

UPDATE#2: Don't use gnupod; use the iPod shuffle Database Builder.

Thursday, March 03, 2005

Warn of Unsaved Changes Javascript

OK, this will get all the javascript out of my system. This one is intensely useful for web "applications". It warns the user if she tries to leave the form with unsubmitted changes, whether leaving by moving to a different page or by closing the window. It requires a recent firefox or ie browser.
<body onLoad="lookForChanges()" onBeforeUnload="return warnOfUnsavedChanges()">
<form>
<select name=a multiple>
<option value=1>1
<option value=2>2
<option value=3>3
</select>
<input name=b value=123>
<input type=submit>
</form>

<script>
var changed = 0;
function recordChange() {
changed = 1;
}
function recordChangeIfChangeKey(myevent) {
if (myevent.which && !myevent.ctrlKey && !myevent.ctrlKey)
recordChange(myevent);
}
function ignoreChange() {
changed = 0;
}
function lookForChanges() {
var origfunc;
for (i = 0; i < document.forms.length; i++) {
for (j = 0; j < document.forms[i].elements.length; j++) {
var formField=document.forms[i].elements[j];
var formFieldType=formField.type.toLowerCase();
if (formFieldType == 'checkbox' || formFieldType == 'radio') {
addHandler(formField, 'click', recordChange);
} else if (formFieldType == 'text' || formFieldType == 'textarea') {
if (formField.attachEvent) {
addHandler(formField, 'keypress', recordChange);
} else {
addHandler(formField, 'keypress', recordChangeIfChangeKey);
}
} else if (formFieldType == 'select-multiple' || formFieldType == 'select-one') {
addHandler(formField, 'change', recordChange);
}
}
addHandler(document.forms[i], 'submit', ignoreChange);
}
}
function warnOfUnsavedChanges() {
if (changed) {
if ("event" in window) //ie
event.returnValue = 'You have unsaved changes on this page, which will be discarded if you leave now. Click "Cancel" in order to save them first.';
else //netscape
return false;
}
}
function addHandler(target, eventName, handler) {
if (target.attachEvent) {
target.attachEvent('on'+eventName, handler);
} else {
target.addEventListener(eventName, handler, false);
}
}
</script>

Wednesday, March 02, 2005

Telephone Shell Javascript Widget

Here's some javascript I wrote to coerce uniformly styled phone numbers. If you don't use any punctuation, it defaults to american style. You can enter unrestricted text after the number. You should be able to copy the following into an html file to try it out.
<form>
phone #<input onkeypress="return phone_only(event)">
</form>

<script>
function phone_only(myevent) {
mykey = myevent.keyCode || myevent.which; //ie||netscape
myfield = myevent.srcElement || myevent.target; //ie||netscape
if (mykey == 8) //backspace (netscape only)
return true;
f = myfield.value;
g = myfield.value;
ndigits = f.replace(/-/,'').length;
ngroupdigits = g.replace(/.*-/,'').length;
if (ndigits == 0) {
if (50 <= mykey && mykey <= 57) { //2-9, can't start with 0 or 1
return true;
} else {
return false;
}
} else if (ndigits <= 7) { //only need 2 hyphens: 123-456-7
if (32 <= mykey && mykey <= 47 && ngroupdigits != 0) { //punctuation
myfield.value += "-";
return false;
} else if (48 <= mykey && mykey <= 57) { //0-9
if ((ngroupdigits % 4) == 3) {
myfield.value += "-";
}
return true;
} else {
return false;
}
} else {
return true;
}
}
</script>

Tuesday, March 01, 2005

Forms Support in Javascript, not Template

Turns out it's pretty simple to populate forms generically in javascript. This means that your template engine doesn't need special html forms support; you can just use a pair of templating "for" loops to create the javascript data structure. You could even grab the data using xmlhttprequest. Html made the the mess, so html can clean it up.

Here's an example form, followed by the code. You should be able to copy into a file and try it.
<form>
<input name=a>
<input name=b type=checkbox value=x1>
<input name=b type=checkbox value=y1>
<input name=b type=checkbox value=z1>
<select name=c multiple>
<option value=x2>X2
<option value=y2>Y2
<option value=z2>Z2
</select>
<button onClick="populateForm(this.form, {'a':'x0',b:['x1','z1'],'c':['x2','z2']}); return false">Populate</button>
<input type=reset>
</form>

<script>
function populateForm(myForm,myHash) {
for (var k in myForm) {
if (!(k in myForm) || !(k in myHash)) continue;
if (typeof myHash[k] == 'string')
myHash[k] = [myHash[k]];
if (myForm[k].type == 'text') {
myForm[k].value = myHash[k][0];
} else {
var field = 'type' in myForm[k] && myForm[k].type.match('^select') ? 'selected' : 'checked';
var selected = Array();
for (var i=0; i<myHash[k].length; i++)
selected[myHash[k][i]] = 1;
for (var i=0; i<myForm[k].length; i++)
myForm[k][i][field] = myForm[k][i].value in selected;
}
}
}
</script>

Tuesday, February 22, 2005

Even More On Presentation Done Right

I changed my mind back; StringTemplate isn't the way to go.

Templates are neither necessary nor sufficient for separating model and view (presentation). Not necessary because the separation is really accomplished by the model/view protocol, and not sufficient because presentation code can always seep into the model code. In fact, the StringTemplate approach requires complex views to be implemented in the model code.

A great m/v separation may be achieved by just having separate code for model and for view, even in the same language. The only requirements are on the data passed from the model to the view:
  1. it should be available before the view code runs
  2. it should consist only of lists of lists, and lists of opaque objects
Flagrant violations are possible (like the view code writing to a database), but should be easy to spot. The view code isn't artificially limited; it can implement fancy animations or fractal decorations, for example.

It's probably worth noting explicitly that the view depends on the model and not vice versa.

Recent javascript interfaces from google seem to contradict requirement number one, but really they just use a lazy loaded model. The view treats the model as if it's present, but because of the model's prohibitive size, each piece is loaded only just before it's needed.

The StringTemplates author acknowledges that his solution is insufficient to keep view logic out of the model code. The model code could pass data like "the color red" to the view layer. Since StringTemplates is such a simple language, more complex view features must be implemented with the help of model code. Any possible document may be generated, but only with the help of the model code.

So if m/v separation isn't the point of templates, what is? Separation of roles. The roles of programmer and designer aren't necessarily performed by different people, but they do require different approaches. The designer role includes everything that can be done in a WYSIWYG editor, with all visible elements, "includes", and conditionals. As document formats evolve, this could become part of the normative editor functionality. CSS visibility could be hacked to support conditionals, and XInclude takes care of the rest.

Sunday, February 20, 2005

Google Maps and Free Source

If you haven't already, check out Google Maps; it's extremely cool. Besides being a generally superior implementation of maps, it loads new maps without reloading the page in your browser, just like gmail. After you view a map, its pieces are cached by your browser. This means they're fast, and can be viewed even without an internet connection.

A yet un-remarked-upon feature of these "network applications" is how similar they are to free source. Though the intellectual property restrictions of google and of free source are just as strict as those of the most proprietary software vendor, the implementations of both google maps and GPL'ed code are available for anyone to poke at. GPL developers have so much faith in their model that they don't worry about commercial competitors, and google developers apparently have so much confidence in their own skills that they don't worry.

You already have free access to both the google maps client software and the map data. Without too much difficulty, you could extend either. For example, you could use the google client to view your own map data, you could run your own software on the map data (which is already cached on your pc), and people are already hacking new features onto the whole google maps solution.

The major change in these new applications is that the interface is exposed. With regular google search, you either have to use the Google Web APIs or else screenscrape the html pages. With a little reverse engineering of the new applications, you can access the same interface that's used as part of their normal functioning.

(The Google Web APIs limit developers to 1000 queries a day, and presumably a higher volume of screenscraping or access to the new APIs would get shut down by Google.)

The Internet Changing Everything

  • Traditional categories of media become irrelevant

    Does a given piece of information belong in a book, an academic paper, a weekly magazine article, an editorial, a letter to the editor? The internet makes the distinctions increasingly irrelevant.

  • The description of an idea may be canonicalized

    A web page is an expression of an idea that is universally available (at least theoretically). It's easy to refer to, and easy to maintain. The internet will one day provide a distributed wikipedia, in which every idea has a URI and page(s) containing all public human knowledge of that idea.

  • The context of an idea may be completely specified
  • Traditional bibliographies are klunky in comparison. It will be possible to link a given piece of information with every other piece of information on which it relies. That metadata will itself be data, subject to easy analysis.

Apologies for early outline version.

Thursday, February 17, 2005

URL Features

Computers should record all operations on URLs. For example, I should have a list of URLs that I've emailed (along with the recipient and date), that I've instant-messaged, or printed, or transferred, or mentioned in any document.

"URL" means both local and remote. I should have a full history of every file I've opened (explicitly), even if it wasn't using the browser. Another operation that I want recorded is when I change files, and when I post forms.

I should get a smarter handling of "cached" and downloaded files. Browsers already have caches, so why I should have to manually make copies of files for speed or reliable access?

Thursday, February 10, 2005

Perl Problems

1 Obscure Features

The core language has so many features that even the greatest perl wizard does not know them all. Find a wizard and ask him how many of the following features from the core language he understands (without consulting the manual).

  1.  split(' ') vs split(/ /) vs split('') vs split(//)  
  2.  $x{'a', 'b'} vs @x{'a', 'b'}
  3.  $[ = 3
  4.  [{foo => 1, bar => 2}, "FOO", "BAR"]

And here's a realistic example of idiomatic perl:

    sub with_gs_acct_check_digit{"$_[0]-".substr(10-(map$_[2]+=$_,map/\d/?$_[1]++%2?split'',$_*2:$_:0,split'',$_[0])[-1]%10,-1)}

Since these features usually address a real need, they can be very tempting to use. Even if someone were to do the work to specify a sane perl subset, there is no tool to enforce its use. Often a perl expert isn't aware that the language features that he uses are obscure or difficult for the nonexpert to understand.

Perl's fast feature accretion is a direct result of its core design philosophy, "There's More Than One Way To Do It".

2 Few Errors are Caught by the Compiler

Since every new feature is encoded using a fixed set of operators, very few errors actually cause a compiler error.

    print "Strings are equal\n" if "abba" == "baba";

2.1 Context Confusion

Every perl expression has several entirely different results depending on its "context", the code in which the expression occurs. The following example will trip up even experienced perl coders:

    sub myPrint($) {
my $arg = @_;
print "the first argument is $arg ?\n";
}

3 Unsafe Features

Many commonly used features are unsafe. The "use strict" directive only catches the most blatant.

3.1 $_

For example, one of perl's major conveniences is the $_ short-hand for referring to the current index of a loop. The following is great way to print upper-cased versions of some strings.

    @t = qw( ibm dell msft );
for (@t) {
print uc "$_\n"
}

However, if you want to instead use a different function in place of "uc", this code may fail in mysterious ways. Functions called in the body of the loop can alter what the $_ reference refers to, and neither the caller nor the callee may realize the danger.

3.2 Exceptions

Exception support is inconsistent and dangerous. When most function fail, they just return false and sometimes an error code. Other functions expect to be called in "eval blocks", and will otherwise cause the entire program to terminate (e.g. mkpath from File::Path)

3.3 Auto-vivification

Another example is auto-vivification, or the on-the-fly creation of datastructures. For the following data structure:

    use strict;
my %myhash1=( "a"=>1, "b"=>2 );
my %myhash2 =( "myhash1"=>\%myhash1, "c"=>3, "d"=>4 );

Perl will properly catch the error:

    $myhash3{c}++;            # %myhash3 is not defined

But will happily allow:

    $myhash2{myhash3}{c}++;   # a new hash will be created!

4 Data Structures

Nested data structures in perl are unwieldy. They require using references, and most people are confused by references.

Wednesday, February 09, 2005

Reusing Software

A big difference between software and physical engineering is that software changes greatly over the course of its life. The object oriented programming approach is supposed to make this change easier and more reliable. Instead of duplicating and modifying code, we'd like to extend existing code and make our changes in the extensions.

There are still a few impediments to reuse in popular platforms. The following is a small collection of research into these impediments.

There mustn't be conflicts between new symbols added to the base code and the extensions. It wouldn't be difficult for languages to support this better.

The non-private call graph of public and protected methods in the parent mustn't change.
There must be a way to better encapsulate objects.
There must be a way to encapsulate and compose concurrent access to state.

Thursday, January 27, 2005

Software Commodification

Though there's been a lot of talk about software commodification (and commoditization), I've never seen the issues formulated simply, so here goes...

A commodity is any product which meets some agreed upon criteria, such that any instance of that commodity may be substituted for any other. A quart of milk from any supplier will satisfy your cupcake recipe, no matter who produces it, so milk is a commodity. A necktie, however, is subject to all sorts of weird style criteria, so it is not a commodity. It might not even be your color.

All software programs are commodities in essence. Programs follow logical rules and perform to a specification, but we can't say a given program is a commodity before it has an actual substitute. So commodity nature is revealed when a given piece of software acquires competing alternatives.

Most software alternatives are not perfect substitutes in the sense that you can switch implementations and barely notice. Usually switching requires retraining the people that use the product and porting the software that uses the product. Vendors obviously want to keep switching as difficult as possible, and techniques for doing so are called "lock-in". By definition, strong lock-in hurts the consumer, but it also usually hurts the consumer by creating an inferior product. A product with strong lock-in will generally be monothilic, have complicated interfaces, and have hidden dependencies.

Given a choice, anyone (whether selling software or anything else) would prefer to have their product not to be a commodity. This is because markets are especially efficient at setting commodity prices, and this means suppliers will have stiff competition.

It's worse to have your software product become a commodity. This is because of the nature of software (and any non-physical product). The first copy of your software will cost you $2,000,000 but every subsequent copy will cost you only $2. This means that when someone enters your market, they've already done the hard part, and there's no incentive to leave. More importantly, the price of a software product is completely arbitrary. A price war could bring prices all the way down to zero.

Free competitors may be particularly formidable. Only with software is free competition realistic, because with physical products, revenue must reliably exceed costs. Free software makes it particularly easy to pool contributions from disparate sources, with very little administrative overhead, and very little reliance on a single controlling entity. (If a maintainer isn't doing a sufficiently good job, then someone may "fork" the development effort.) Free efforts also generally aren't motivated to lock-in.

All things being equal, it's desirable for software vendors to have the other software that they depend on to be commodified. This is for a few reasons: your dependencies have power over your product, and when your dependencies are cheaper, your overall product solution will be cheaper. There'll be a larger market for your product.

So if free software is so easy and desirable, how can a commercial software vendor stay in business? By presenting a moving target. Any given software release may be straightforwardly commodified, but the release process may not be. No entity or group of entities will have external incentive to track a series of upgrades. This is partially why "tying" is so important to a large software vendor, because tying is the only way for a mature product to escape commodification.

Ironically, the vendor is really in the business of selling timely upgrades, a service business which uses the base software product as merely a barrier to entry.

Wednesday, January 26, 2005

Intuitive Interfaces

An interface can be intuitive for a many reasons:

  • It works like other similar interfaces that the user has seen. (Green means "go".)
  • It's logical. (Cars' signalling interface correspond to the way that you turn the wheel.)
  • It's internally consistent. (The same abstraction works the same way in different contexts.)
  • It has a shallow learning curve.
    • It has helpful pointers, ideally inobtrusive. (Examples are popup help bubbles and pie menus)
    • It allows safe experimentation. (You can "undo" any operation.)
  • It's simple. :)

Python Evolution and AOP

An interesting trend in the evolution of the python language is that it has acquired ways of hooking into more and more code points that are not traditionally hooked into.

For a while, python has had metaclasses, which allow customizing the behavior of whole classes of classes :). These metaclasses allow running code on class creation, and routinely involve customizing object creation.

In order to obviate java's setter/getter pattern, python has the ability to run code on getting an attribute or setting an attribute or both.

Recently, python attained a decorator feature, which allows running code on function/method creation. This feature was originally motivated by wanting to specify things like a method being "static".

Now there's talk about implementing type-checking use adaption of function/method arguments and return values.

This trend could seem a lot like Aspect Oriented Programming, but it has the important difference that the path to the hook code is always evident at the hooked code. A main point of AOP is perfect "obliviousness", according to which you can alter the behavior of foreign code without making any modification to it. In python, the main code body can be oblivious of the hook, but it's always preceded by an explicit reference to the hook, almost like an annotation.

In python, each of these hooking mechanisms has a different syntax, presumably tailored to its primary use case. These features are mostly made possible by python's easy introspection support, and by its uniform "object" treatment of all of these abstractions.

Monday, January 24, 2005

Managing Change

It's time to release an upgrade to your whiz-bang widget library. If you want to avoid breaking all the code that people have written to use and even extend your library, here's what to do.

Obviously, don't remove public and protected methods, or change their semantics. For protected methods, this includes having them continue to call other nonprivate methods under the same conditions.

Less obviously, if you're creating new public or protected methods, you should move your code to an entirely new class! Someone may have extended your class with a method that has the same signature that you've just added, causing a needless conflict. Under the old class, create proxy classes that delegate every method to the new code. You don't have to worry about the maintenance overhead, because these proxies represent the legacy interface; you shouldn't have to change them later.

This hints at the fact that your library should be very careful about calling its own nonprivate methods. Calling internal nonprivate methods should be reserved for supported abstractions, because your library will down-call into extensions of these methods. If you don't want to support the abstraction, move the implementation into a private method. Have your internal code call the private method, and have your public method just be a wrapper for clients.

This approach is not so elegant because it requires code changes in order to support unchanging function. Maybe languages should support using interfaces for encapsulation, so that any symbols not present in the specified interface(s) would be completely hidden. However, all the recent python typechecking and adaption thinking seems to be focused on method calls, not base class specification.

Thursday, January 06, 2005

Minimum Curriculum

Everyone should learn the most important ideas of human civilization. There should be a year-long lecture course that introduces all the "must see" ideas, the best that the human race has found, the stuff that would be tragic for a person to have lived and never learn. Certainly many things require lengthy study to be useful, and many things are already as clear as day to many people, but there are many important ideas of which educated people are ignorant.

Even if this makes sense for ideas, it certainly makes no sense for art. The survey courses in dance, art history, music history, and world literature probably can't be meaningfully condensed any further. But no one should miss out on the major ideas of the introductory courses in math, astronomy, physics, chemistry, biology, psychology, economics, computer science, philosophy, political science, philosophy, and history. Some ideas fall through the cracks of all of these intro courses. (For example, what about the central points of The Death and Life of Great American Cities?) Some ideas are also too new to make it into conventional courses. For many ideas, only a few minutes explanation would be sufficient.

Many survey courses take the historical approach, but in this context it would waste too much time. To make it more interesting, the course (and more importantly the reading list) could touch on the limits of human knowledge and current work.

I originally had this idea in yeshiva, in a spirit of parochialism: "take this course, and then forget about the rest." Ironically, the course would probably not be popular with the insular (even if it were to omit evolution). This idea came back to me recently, thinking about John Rawls. I realized that neither my college survey in humanities nor intro to philosophy mentioned him.

The following are the ideas that I could come with quickly; please suggest more.

big bang, scale and elements of the universe, basic probability, limits, idea of calculus, newton's laws, four forces, electricity, nature of light, relativity, phases of matter, entropy, periodic table, cells, virii, bacteria, dna, systems of the body, evolution, milgram study, the unconscious, supply and demand, how a computer works and what a program looks like, urls, kant's categorical imperative, veil of ignorance, a myriad of -isms: utilitarianism, facism/socialism/capitalism(democracy), world religions, epistemology, problem of induction, logic and godel for dummies, mixed-use cities, human history in 30 minutes :), how toilets work