Tuesday, December 30, 2003

The digital security infrastructure

Doc Searls notes a good summary of the state of digital security infrastructure. Some of the flavors he lists I've never even heard of—a nice chance to read something new and different and yet the same old thing.

Sunday, December 28, 2003

Microsoft is dead, long live Microsoft

I've seen Microsoft put the kibosh to its own obit too many times to let myself any longer have hope. Nonetheless, those of you who still think defeating the Eye of Redmond is possible can take heart in this article from The Enquirer. I fear it is more likely to belong in this Enquirer.

Wednesday, December 24, 2003

A great link for automated testing

Manageability has a great list of automated testing tools for Java. If you have a need for this sort of thing (and anyone programming in Java who says they are without a need is pulling your leg), this is the list for you.

JDK 1.5

Are you ready for JDK 1.5? Members of JavaLoby may preview the alpha as long as you follow the stipulations. Sun is looking for feedback. Go forth, and backfeed.

Thursday, December 18, 2003

Careful what you wisk for

The Web Starter Kit (Wisk) project is now open for business on SourceForge. Their are no web pages (yet) but I hope to upload the starting code base into CVS over the weekend.

Tuesday, December 16, 2003

Friday, December 12, 2003

My name is ...

Fellow ThoughtWorker Mike Mason hits it on the head:

We realised that ThoughtWorks isn’t a consultancy — it’s a self-help group for developers who are really testers. We should have these meetings where we sit round in a circle and say stuff like “My name’s Mike and I’m test infected.” I’ve been writing code with lots of tests ever since joining ThoughtWorks, and I don’t think I could go back…

Amen, brother. Test-driven development really is faster, better cheaper.

Thursday, December 11, 2003

Web Starter Kit

I'm considering putting to together a "Web Starter Kit" (WSK or wisk) for starting J2EE webapp projects. Basically, it would be all the technology which goes into iteration 0 of such a project, all hooked together to help others get a jump start. It becomes tiresome to redo the same week's worth of plumbing on every new project. I'm thinking of constructing it with:

What would you add? What would you change?

Friday, December 05, 2003

Swing low

These days I do mostly Java web programming, but I also worked on PCGen for a few years where I cut my teeth on Swing (Rule #1 of large, distributed open-source programming: change as little as possible to get your work done — this is the opposite of close-at-hand XP programming where refactoring rules; I'm embarrassed to even contemplate this). And BileBlog has it right: Swing programming is hard. I never felt completely happy with the results, always with the niggle in the back of my mind that my work could be done better. It was easy to fall into custom widgets (why is JTabbedPane so minimally functional?) and such without addressing the bigger picture. Perhaps someday I can get back to the problem.

Tuesday, December 02, 2003

Does maven suck?

I am presently enamored by maven, more specifically, by its very nice report generation when I run maven site. But I also like to read the other side, and Why Maven Sucks is about as "other side" as it comes. Welcome to The BileBlog. :-)

Sunday, November 30, 2003

Setting up a Subversion server on Windows

I found mostly excellent instructions on the TortoiseSVN site for setting up a Subversion server on Windows. Included: setting up Apache 2, setting up Subversion, setting up Windows domain authentication, setting up SSL. Quite a decent start. Unfortunately, I am now facing:

<?xml version="1.0" encoding="utf-8"?>
<D:error xmlns:D="DAV:" xmlns:m="http://apache.org/dav/xmlns" xmlns:C="svn:">
<C:error/>
<m:human-readable errcode="165005">
Expected version '2' of repository; found no version at all; is 'C:/SVN/local' a valid repository path?
</m:human-readable>
</D:error>

Time for some Google research.

Wednesday, November 26, 2003

Able hands

It's official: Linus is handing off the 2.6 kernel to Andrew Morton:

From: Linus Torvalds [email blocked]
To: Kernel Mailing List [email blocked]
Subject: Beaver in Detox!
Date: Wed, 26 Nov 2003 12:55:00 -0800 (PST)


Ok,
 for everybody who thought "stoned beaver" wasn't an appropriate name for
a kernel (yeah, I'm sure IBM really minds my naming scheme, and is deathly
afraid it will scare away customers), I'm happy to tell you that the
beaver just went into detox, and I'm taking the Thanksgiving weekend off.

I give you "Beaver in Detox", aka linux-2.6.0-test11. This is mainly
brought on by the fact that the old aic7xxx driver was broken in -test10,
and Ingo found this really evil test program that showed an error case in
do_fork() that we had never handled right. Well, duh!

While at it, this also pulls in some firewire fixes and a few potential
skbuff leakage points.

Please don't even bother sending me patches, because I'll be stuffing my
face away from email over the next few days. And after that it will be up
to Andrew to say how to go on from here.

Mmmm. Turkey.


		Linus

Sparse

Doc Searls posts in The Linux Journal a fascinating talk (with slides! :-) by Linus at the Linux Lunacy Geek Cruise III on the Sparse <garbled> asset compiler, a great GCC extension to improve the typechecking system of ANSI C.

UPDATE: to go with Part I there's also Part II and Part III.

Wednesday, November 19, 2003

Coplien against classes

Classes, who needs them? Coplien (yes, that Coplien) argues for roles and interfaces—objects—to have primacy, not classes.

(Thanks to Carlos Perez for posting about this.)

New Swing tutorial

Sun has a new Swing tutorial updated for 1.4. It's a work in progress, but it's still excellent.

Subversion VC backend for Emacs

Although I use vi and Emacs roughly equally, I do recognize Emacs as The One True Editor, and so I spend much of my programming time booted into Emacs. And as I am now methodically replacing CVS with Subversion for my own needs, I cannot survive without the C-x v family of key sequences. Looking around for an Emacs VC backend for Subversion, I found two and decided to go with the one in the Emacs repository (Monnier) as it will ship with Emacs for the next release. Also, I was unable to find a canonical site for the other backend (Bowman) and when I byte-compiled the two, the Monnier compiled more cleanly than Bowman.

Time for the real test: work.

UPDATE: Well, one drawback to the Monnier version in the Emacs CVS repository: it only works with the CVS HEAD version of Emacs. Oops. For Emacs 21.4 (the current release), I need to use the Bowman version. But, it does not load ok. Live and learn.

And... there's yet a third version (Blandy) according to Karl Fogel. I'll give it a try also. Two things in its favor: it also compiles but and is the only one which loads ok, and it's the only version with useful setup for .emacs:

(add-to-list 'vc-handled-backends 'SVN)

(Magic, isn't it?) Easiest however probably is the most simple:

(load-library "vc-svn")

This seems the right one for now until Emacs 21.4 is out.

Wednesday, November 12, 2003

Microsoft continues to hinder web development

Sometimes overlooked is that Microsoft's embrace and extend strategy doesn't always require the extend portion. Instead Microsoft implements 85% of a standard and misimplements 5% more, never fixing the defects or implementing the remainder. This renders a standard unusable across platforms and implementations. Tables and CSS layout are examples of this dastardy. Reinforcing my ire at Big Black are recent entries on Java Today, Microsoft retrenches around fat clients and Web and rich interfaces: it should be easier than this. It is obvious to all that Microsoft continues to abuse its monopoly position and undermines the web and its potential to illegally maintain that monopoly. Justice may be blind, but the free market isn't. The laws of the jungle applied equally to the mammoth as to the moth and changing business climates will eventually do to Microsoft what the PC did to IBM: reform an incorrigible. Although not everyone agrees.

Tuesday, November 11, 2003

Source control in flux

MickBlog has some nice comments on source control choices. There seems to be a lot of flux right now and I suspect that software development is at a tipping point and not too far from jumping ship from CVS to an alternative. The obvious replacement is subversion, but the present situation is the sort where no contender can be discounted. For now I'm using subversion at home, but I'd like to give arch a spin as well. May the best code win.

Wednesday, November 05, 2003

Java isn't my favorite programming language

As Ravi Mohan writes in Ruby vs Scheme vs Java ... and the winner is ...:

The java code came to about 300 lines , the ruby code had about 70 lines and the scheme code had around 20.The scheme code "cheats" a bit bacause i used a tree walker macro i have been working on for sometime.Since a macro "expands" at runtime, the scheme code when fully expanded would be about 50 odd lines ...Also I am sure the ruby code could be much shorter but i am a novice @ Ruby Programming ! Eclipse was Java's key advantage, but on a code base this small, an ide is not too important.
More than "number of lines" both the scheme and ruby code were very clear and the java code had lots of casts,enumerations, iterators etc. which put a barrier between your mind and the code. I didn't really believe it when Paul Graham said "Succinctness is Power" but I am slowly veering around to this view, even though i still don't think macros are the best ways to provide succinctness .

Now if only Ravi had considered Python as it is much further down the path of having a Java-like development environment than most other modern languages.

Tuesday, November 04, 2003

Fresh, fresh, fresh

Talk about fresh: Python 2.4a0. That's about as alpha as it comes. As always, the most intersting bit is what's new. Of course it is so fresh that it says little of interest. Patience never was one of my virtues.

Agile Python

Declared: Python is an agile programming language.

Somehow, I don't see this happening to Perl anytime soon.

Friday, October 31, 2003

Programming Language Quotes

I found just what I was looking for on an entertaining list of programming language quotes:

Using TSO is like kicking a dead whale down the beach. (Stephen C Johnson)

I'm on the beach again at ThoughtWorks. That means I'm presently without a project. It's a weird feeling to be home with little to do but job hunt via proxy. It's also a good time to retool, rethink and retune. I'm trying to get the latest AppFuse working with Mckoi (an open-source, all-Java SQL database) so I can make a pre-packaged webapp in all it's glory but without requiring any additional software setup. Just for fun, you see?

Wednesday, October 29, 2003

Agile Perl

Perl is usually not thought of as a very agile programming language, but I found a nice introductory link to XP pointing to the LAMP section of O'Reilly's website. Even better, Michael Schwern talks about refactoring DBI code. Tasty DBI—where's my O-R mapper? Actually, Schwern's work on Class::Fields is pretty cool.

Friday, October 24, 2003

A rant against tool GUIs

The BileBlog has a terrific rant against tool GUIs with specific bile reserved for web application cruft. I draw great delight from this quote: GUI Culprits include the horrific weblogic workshop, websphere's I'm-going-to-chew-off-my-arm-now-to-distract-myself-from-the-pain deployment tools, and my current cross to bear, tibco's just-stab-me-in-the-face-now-to-end-it-all schema designer tool. Pure gold.

Thursday, October 23, 2003

AppFuse

AppFuse is a kick-ass combination of test-first, open-source packages for writing web applications all rolled up for you. It includes O-R persistence (hibernation), a framework (struts), automated configuration generation (xdoclet), soup-to-nuts testing (too many to list :-) and an out-of-the-box login management system. What a superb demonstration of smart integration. If only the commercial world could do as well.

Monday, October 20, 2003

Using OpenSSL to set up your own CA

It took me quite a long time to track down these instructions. I've been looking for setting up SSL on tomcat/jetty (any web server, really) with client authentication and self-signed server certificates. Surprisingly, I had great difficulty in finding a resource with just the right set of incantations. 17 steps in all, including hand editing of some of the output files. Without these instructions, I wasn't going to get it right on my own. I'm hoping this post saves someone else some time.

If I ever meet Christopher Williams—whoever he is—,I'm buying him a beer. A really big one.

Saturday, October 18, 2003

Remember when...

Remember when MULTICS was new and cool? Well I don't either, but I'd be remiss as an OS fan if I didn't read this article on the venerable, breaththrough system which spawned UNIX and influenced Windows NT via VMS. Now that is seminal.

More on Java 1.5

I missed earlier this year an interesting discussion on Java 1.5: should Java adopt macros (in the Lisp sense, not the C sense) in lieu of globbing on features version after version? I link; you decide.

Monday, October 06, 2003

Saturday, September 27, 2003

Agile Taguchi

When I think about it, I can see that Agile methods are aiming for a software equivalent of the Taguchi Method from product engineering. As I, Cringely says:

Taguchi's objective is robust design, which means building a product, system, or process that works well even in the presence of degrading influences. That means products that deliver value without breaking and services that are enduring while being as simple as possible. Taguchi first determines the control factors that go into designing a product, their interdependencies, then generates an orthogonal array specifying the number of experiments required to find the optimal solution.

If the last paragraph reads like Esperanto to you, maybe that explains why mainly eggheads have been attracted to Taguchi. The short version is that however they work, the Taguchi Methods can take a project with thousands, even millions of combinations of variables, and quickly reduce it to a couple dozen simple experiments that can be run simultaneously and will determine the cheapest way to achieve a goal. Instead of considering one variable at a time, Taguchi is able to test many variables at once, which is why the number of tests can be so small. It's a bloody miracle. Taguchi not only shows the right way to do something, it also tells you what the cost in dollars will be of doing it the wrong way.

Unfortunately, no one yet knows how to generate such an array for a software product. (Or, perhaps, it is just me that doesn't know how to do this.) You can make a feature array, but software is much more than a blob of features. But anyone able to apply the Taguchi Method to software would produce the greatest software ever—ever. And become richer than Bill Gates in the process.

Drive an SUV today

I'm reading a debate on if Java is an SUV of computer languages because there are too many ways to do things (it is not orthogonal enough). If Java is an SUV, then what does that make C++—an aircraft carrier? Of course, Python is a sleek racing machine in comparison.

Monday, September 22, 2003

Copyright notice

All code published on this blog is Copyright (C) B. K. Oxley (binkley) <binkley@alumni.rice.edu> effective the date of publication under the terms of the GPL version 2 unless otherwise noted.

Live from Chicago! Iterators, generators

Java has it wrong. The iterators in the Java Collections Framework are not actually iterators: they are generators. The real culprit is next() which does two things at once. It advances the iterator and then fetches the value therefrom. This is the generator model.

Contrast with iterators from the STL. Because they model a pointer, they have a separate advance and fetch operation implemented with operator++()/operator++(int) and operator*(). You may freely advanced an STL iterator without fetching the contents; and you may fetch and refetch the contents without needing to adjust the position of the iterator. Of course STL iterators do have the wart that they lack any hasNext() equivalent. Instead you have to carry around a second iterator to compare against to see when you've reached the end.

Why is this? It is because Java is paradigm-poor language while C++ is a paradigm-rich one. Java supports object-oriented programming and that is the end of the tale. C++ supports object-oriented programming, but also generic programming. STL iterators are definitely a generic idiom, not an object-oriented one. But Java has to fit an object-oriented shoe onto an iterator foot, so they compromise by using generators instead, objects which produce a new value upon request.

Incidentally, this is why remove() is so weird and has to be optional. Optional methods to an interface are a sign of design mismatch. There should instead be a Generator base interface with just hasNext() and next(), and a CollectionGenerator which extends Generator and adds advance() and get(). Implementors of CollectionGenerator simply write next() to call advance() and then return get(). To modify the underlying collection, extend CollectionGenerator further and add remove().

Thursday, September 18, 2003

ListIterator and List equivalent

A ListIterator is equivalent to the List interface. To demonstrate this, I'm writing a IteratorList class which implements the List interface over an underlying ListIterator; it's actually quite simple. More fun with iterators! Here it is (note, not tested—I just wanted to sketch it out to see what it'd look like):

/*
 * IteratorList.java
 * Copyright 2003 (C) B. K. Oxley (binkley)
 * <binkley@alumni.rice.edu>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 * USA
 *
 * Created on June 4, 2003.
 */

package hm.binkley.util;

import java.lang.reflect.Array;
import java.util.AbstractList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;

/**
 * <code>IteratorList</code> implements <code>List</code> from an
 * underlying <code>ListIterator</code>.
 *
 * @author <a href="mailto:binkley@alumni.rice.edu">B. K. Oxley (binkley)</a>
 * @version 1.0
 */
public class IteratorList extends AbstractList {
    /** The underlying list iterator. */
    private final ListIterator it;

    /**
     * Constructs a <code>IteratorList</code> code from an underyling
     * <code>ListIterator</code> object.
     *
     * @param it the list iterator
     */
    public IteratorList(ListIterator it) {
	this.it = it;
    }

    /**
     * Resets the underlying list iterator back to its starting state.
     */
    private void reset() {
	while (it.hasPrevious())
	    it.previous();
    }

    /**
     * Positions the underlying iterator before <var>index</var>.  The
     * caller needs to then call {@link #next()} as required.
     *
     * @param index the index
     * @throws IndexOutOfBoundsException if <var>index</var> is out of
     * range
     */
    private void scrollTo(int index) {
	if (index < 0)
	    throw new IndexOutOfBoundsException();

	// Ensure we call one extra next for the index itself
	while (index-- > 0)
	    if (it.hasNext())
		it.next();
	    else
		throw new IndexOutOfBoundsException();
    }

    /** {@inheritDoc} */
    public int size() {
	int n = 0;

	for ( ; it.hasNext(); ++n)
	    it.next();

	reset();

	return n;
    }

    /** {@inheritDoc} */
    public Object get(int index) {
	try {
	    scrollTo(index);

	    if (it.hasNext())
		return it.next();
	    else
		throw new IndexOutOfBoundsException();
	}

	finally {
	    reset();
	}
    }

    /** {@inheritDoc} */
    public Object set(int index, Object element) {
	try {
	    scrollTo(index);

	    if (it.hasNext()) {
		Object old = it.next();
		it.set(element);
		return old;
	    }

	    else
		throw new IndexOutOfBoundsException();
	}

	finally {
	    reset();
	}
    }

    /** {@inheritDoc} */
    public void add(int index, Object element) {
	try {
	    scrollTo(index);

	    if (it.hasNext()) {
		it.next();
		it.add(element);
	    }

	    else
		throw new IndexOutOfBoundsException();
	}

	finally {
	    reset();
	}
    }

    /** {@inheritDoc} */
    public Object remove(int index) {
	try {
	    scrollTo(index);

	    if (it.hasNext()) {
		Object old = it.next();
		it.remove();
		return old;
	    }

	    else
		throw new IndexOutOfBoundsException();
	}

	finally {
	    reset();
	}
    }
}

Wednesday, September 17, 2003

Iterators

I've become fascinated by iterators, those small bits of code which turn out an object one at a time. For example, Python has generator comprehensions while Java has iterators and C++ likewise.

Presently I'm adding to my list of Java iterator adaptors, objects which wrap an underlying iterator to produce one with modified behavior. Two excellent examples are FilterIterator which wraps a ListIterator [1] and produces only elements matching a criteria, and ReverseIterator which also wraps a ListIterator to produce the underlying elements in reverse order. I also coded ListIterator versions of each which are bidirectional.

I still have a lot of work, however. C++'s STL is still way ahead of Java's collection classes. I am thinking of putting my work up on SourceForge or some other similar place (perhaps something more Java-specific) under the GPL but have let laziness get the better of me so far. Laziness, Impatience, Hubris [pdf]. What could be better?

[1] FilterIterator wraps a ListIterator rather than an Iterator for a good reason. To properly filter, one needs lookahead which implies the ability to back up the underlying iterator if lookahead failed, hence one needs a reversible iterator with previous(). FilterIterator doesn't just produce the right output, it makes the underlying Iterator behave as if it contained only the filtered elements.

Extending BASH

I started yesterday writing a new builting command for BASH, the Bourne-again Shell. It's called eset and it works the same as in 4DOS making it easy for you to edit environment variables. In addition, eset edits aliases and shell functions. All this is possible because BASH makes it easy for you to write new extensions and add them to the shell:

    $ make eset
    ... output from make ...
    $ enable -f ./eset eset # load builtin into the shell
    $ eset
    eset [-aef] var
    $ eset PATH
    PATH=/bin:/usr/bin:.

If you are interested in trying it out, please write me.

UPDATE: Apologies, but after several moves and change of servers, I have lost the source.

Tuesday, September 16, 2003

Is extends evil?

Alan Holub argues that the extends keyword is evil. Is he right?

I think the root of the evil is not implementation inheritance per se but single inheritance. With non-diamond multiple inheritance, inherit specific interface implementations to make a compound object and an is-a relationship rather than use interface forwarding and a has-a relationship. This is more efficient and much easier to maintain: no forwarding code to write and test. Even better would be generic multiple inheritance (template base classes in C++) so that a consumer of the code can specify which implementation to inherit for a particular interface.

In contrast, single inheritance makes it very difficult as you must upfront decide which interfaces a superclass implements. Changes in that decision require changing the interfaces and implementations in both the superclass and subclass. This is a disaster for maintainability and comprehension.

Checkstyle

I've always been a stickler for good programming style. It's one reason I often prefer Emacs over IDEs when writing code, especially when fixing existing code: Emac's formatting facilities are peerless. But there's more than one way to skin a cat, the saying goes.

Checkstyle is an automated style checker for Java including the hooks for an Ant task. By style, I don't just mean code formatting, I mean all the rest: javadoc comments, naming conventions, overlarge files, etc. Checkstyle handles these, producing reports suitable for further consumption.

Right now I'm changing some of my Collections extensions to use checkstyle in the build process. I'm updating build.xml to include a check target which checks the style of my Java sources, outputs problems to stdout so Emacs can parse and step through the errors, and writes an XML report to the docs directory for inclusion in the code metrics.

Spiffy.

Monday, September 15, 2003

Goto, come-from

Ah, the joys of structureless programming...

A Linguistic Contribution of GOTO-less Programming

By R. Lawrence Clark*

From DATAMATION, December, 1973


Nearly six years after publication of Dijkstra's now-famous letter[1], the subject of GOTO-less programming still stirs considerable controversy. Dijkstra and his supporters claim that the GOTO statement leads to difficulty in debugging, modifying, understanding and proving programs. GOTO advocates argues that this statement, used correctly, need not lead to problems, and that it provides a natural straightforward solution to common programming procedures.

Numerous solutions have been advanced in an attempt to resolve this debate. Nevertheless, despite the efforts of some of the foremost computer scientists, the battle continues to rage.

The author has developed a new language construct on which, he believes, both the pro- and the anti-GOTO factions can agree. This construct is called the COME FROM statement. Although usage of the COME FROM statement is independent of the linguistic environment, its use will be illustrated within the FORTRAN language.


box 1

Unconditional COME FROM statement:

     General Form
     COME FROM xxxxx
     Where: xxxxx is the number of an executable statement in the same
     program unit.

     This statement causes control to be transferred to the next
     statement (the statement immediately following the COME FROM upon
     completion of the designated statement.

     Example:
               10 J=1
               11 COME FROM 20
               12 WRITE (6,40) J STOP
               13 COME FROM 10
               20 J=J+2
               40 FORMAT (14)
     

Explanation:

In this example, J is set to 1 by statement 10. Statement 13 then causes control to be passed to statement 20, which sets J to 3. Statement 11 then causes control to be passed to statement 12, which writes the current value of J. The STOP statement then terminates the program.


box 2

Conditional COME FROM statement:

     General Form
     IF (cond) COME FROM xxxxx
     Where: cond is any logical expression.
     xxxxx is the number of an executable statement in the same
     program unit.

     This statement causes control to be transferred to the next
     statement whenever the condition cond is true and the designated
     statement has just been completed.

     Example:
               I = 1
               IF (I .LT. 10) COME FROM 50
               I = I+1
       50 WRITE (6,60) I
                 STOP
       60          FORMAT (14)
     

Explanation:

The COME FROM takes effect only while I is less than 10. Thus when I is equal to 10, the program continues past statement 50 and terminates. This is equivalent to the now-obsolete formulations:

               I = 1
       30          I = I+1
               WRITE (6,60) I
               IF (I .LT. 10) GO TO 30
               STOP
       60          FORMAT (14)
     or
               DO 50 I = 2, 10
       50          WRITE (6,60) i
               STOP
       60          FORMAT (14)
     

Note how much cleaner is the intent of the code containing the COME FROM construct.


box 3:

Computed COME FROM statement

     General Form
     COME FROM (x1, x2, x3....,xn), i
     Where: Each x is the number of an executable statement in the
     same program unit.
               i is an integer variable.

This statement causes control to be transferred to the next statement whenever any of the following conditions holds:

               * statement x1 has just been executed and i is equal to 1
               * statement x2 has just been executed and i is equal to 2
               * statement x3 has just been executed and i is equal to 3
               * statement xn has just been executed and i is equal to n

If, when statement xj is executed, i has any value other than j, this statement has no effect.

Example:

               DO 200 INDEX=1,10
       10          X=1.
       20          X=X*2.
       30          X=X*3.
       40          X=X*4.
       50          X=X*5.
       60          X=X*6.
       70          X=X*7.
       80          X=X*8.
       90          X=X*9.
       100         X=X*10.
               COME FROM (10,20,30,40,50,60,70,80,90,100),INDEX
               WRITE (6,500) INDEX,X
       200          CONTINUE
               STOP
       500          FORMAT (14,2X,F12.0)
     

Example:

This program illustrates the power of the computed COME FROM by providing a compact algorithm for computing factorials. On the first iteration (INDEX=1), as soon as statement 10 has been executed, control passes to the WRITE statement. As a more general case, consider the fifth iteration: X is set to 1, and the multiplied by 2., 3., 4. and 5. before control passes to the WRITE statement.


box 4:

Assign and assigned COME FROM statements

     General Form
               ASSIGN xxxxx TO m
                 *
                 *
                 *
               COME FROM m, (x1,x2,x3,...,xn)
               Where: xxxxx is the number of an executable
               statement. It must be one of the numbers x1,x2,x3...,xn
                         Each xx if the number of an executable
                         statement in the same program unit.
                         m is an integer variable which is assigned
                         one of the statement numbers x1,x2,x3,...,xn.

The assigned COME FROM causes control to be transferred to the next statement upon completion of the statement whose number is currently assigned to m. This provides a convenient means of passing control to a common point from a variety of points in the program unit. The actual point from which control is to be passed can be selected under program control.

Example:

               DO 60 I=6,32
       20          X=I*6+14
               IF (X-20.) 10, 30, 50,
       10          ASSIGN 40 TO JUMP
       30          Y=2*X**2.-17.4
               COME FROM JUMP, (40,20,30)
               ASSIGN 30 TO JUMP
               X=X*Y-X**2
       40          ASSIGN 40 TO JUMP
               IF (Y-X) 20, 60, 50
       50          ASSIGN 20 TO JUMP
       60           CONTINUE

Explanation:

This example is self-explanatory.

The author feels that the COME FROM will prove an invaluable contribution to the field of computer science. It is confidently predicted that this solution will be implemented in all future programming languages, and will be retrofitted into existing languages. Although it is clear that the COME FROM statement fulfills most of the requirements of the advocates of GOTO-less programming, it remains for the practitioners of automatic programming to evaluate just how much this construct contributes to the development of automatic proofs of program correctness. Having at last put to rest to GOTO controversy, we now may enter the era of the COME FROM conundrum.

* The author is indebted to G.F. Groner and N.A. Palley for a valuable discussion which took place in New Haven, Conn.

[1] E. W. Dijkstra, "GOTO Statement Considered Harmful," Letter of the Editor, Communications of the ACM, March 1968, pp. 147-148.


Mr. Clark is a programmer/analyst in the computation center of the Rand Corp. He has been active in the development of user-oriented, interactive computer systems, especailly graphics systems. He has a BS in mathematics from Pennsylvania State Univ.

Friday, September 12, 2003

Why Java sucks more than C++ does

No, this isn't a language rant; I just wanted a catchy title.

I've been writing various containers, adaptors, iterators and algorithms for Java and I'm growing tired of some of the obstacles. The Collections Framework gets a solid B but no higher. This is because while Java is an excellent language for object-oriented programming, it is very poor for generic programming. In particular, Java lacks support for generics and mixins and the generics proposals for Java 1.5 only partly addresses these deficiencies. (See the NextGen project for something more in the right direction.) In a very fundamental way, Java is a single paradigm programming language. In contrast, C++ strives to be a multi-paradigm language. A quick comparison:

  C++ Java
Structured Excellent Good
Object-oriented Excellent Excellent
Generic Good None
Funtional Fair None

What does all this mean?

Structured programming is ubquitous now days, and C++ and Java are both intellectual heirs to ALGOL and other early structured-programming languages. They have syntax-driven control structures such as if ... else and while to remove the need for the much dreaded goto. But I fault Java for lacking goto for certain kinds of effecient exception handling within a method and for making Duff's device illegal. How could they?

Object-oriented programming we all know and love. The problem even here is that Java requires OOP even when you don't need it. But it does have OOP in spades.

Generic programming is parameterization by type permitting strong typing of untyped language constructs. The classic example is List which is a list container of Foo objects. C++'s weakness is it's over-strong type system which prevents true virtual constructors and the like. Java simply lacks the facility all together.

Functional programming is programing to the Lambda Calculus. C++ supports this with functors, objects supporting function call syntax, but still lacks truly first-class function objects (although the proposed <functional> is closer than before).

On the gripping hand, there is no VM for C++ to run my compiled object code everywhere without recompilation, and Java's package system is very excellent; namespaces are a compiler symbol table hack, not a fully integrated run-time feature.

As you can see from this list, writing generic containers, adaptors, iterators and algorithms is tricky with Java. The lack of good generics really blows. A particular example: I'm been writing and rewriting a Stack interface. Because of Java's single-inheritance, I am unable to make a really good adaptor with it. How do you tack it onto an existing List implementation in a really smart way? If your implementation is a RandomAccess container (read ArrayList), then you want to push objects onto the end of the list since adding to the front is so expensive; if it is not a RandomAccess container (read LinkedList) then you want to push objects onto the front of the list since accessing the last element is so expensive. In C++ I can handle this easily with template specialization and mixins (multiple inheritance), but these are foreign to Java.

Perhaps in Java 1.6 things will be easier.

Thursday, September 11, 2003

Job!

After more than 5 months without work I found myself in the enviable position of having two offers at the same time, one with ThoughtWorks of XP fame and the other with ORIGIN in Austin, makers of Ultima Online. What a choice! I decided to accept the position with ThoughtWorks; orientation begins on the 23rd. Yah!

Wednesday, September 10, 2003

Blogger and Konqueror

Blogger now seems to work with Konqueror when you compose posts and manage your blog. Fantastic! I tire of starting up Mozilla just to blog. I like Mozilla just fine, but I don't like having to run several different browsers to work.

Sunday, September 07, 2003

Two great sites

Martin Fowler, Chief Scientist at ThoughtWorks where I am interviewing tomorrow (my first chance to see Chicago!), has two great sites: Martin Fowler's Bliki, an interesting cross between a blog and a wiki, and Refactoring Home Page, a site devoted to refactoring (just consider this small example, seemingly trivial but subtle and insightful, like a good koan). I stumbled across them while looking up UML information. Presently I'm going through Gang of Four to refresh myself and wanted more information on the diagram styles used in the book.

I've also noticed that the way I read texts has changed because of the Internet. Growing up and in college, I'd read text straight through in a linear fashion. Now I find myself treating them like web pages and jumping around to follow my train of thought rather than the author's. And I have no compunction against setting down the text and switching to another one that continues the thread of my thinking. The World Wide Web is truly a new, marvelous thing.

About my interview tomorrow: Wish me a good day!

Thursday, September 04, 2003

The Unix Guide to Defenestration

I haven't read this book in a while but its lessons remain: large, clunky, closed systems always lose out to nimbler, cleaner, open ones. For a practical example, I'll let you guess from the book title which is which in referring to two well-known operating systems.

Tuesday, September 02, 2003

A vision paper from my EBS days

Because of a conversation with a recruiter in Dallas about an interesting embedded Linux project, I looked through some old files and found a vision paper I wrote during the good times at Enron Broadband Services, The Enron Media Lab at Rice University. As the technology discussed has passed its heyday and one of the companies no longer exists, I'll reproduce it here to give an idea of the sort of cool projects that were hot at Enron. Note the dated obsession with stock price—this was key to getting internal support for the project. This paper is also a good example of how to handle endnotes in HTML. (I apologize for the layout; the default stylesheet Blogspot provides me is fine for regular posting, but looks poor with a quoted HTML document such as here.)

The Enron Media Lab at Rice University

  1. About the Enron Media Lab
  2. Motivation
  3. How It Really Works

About the Enron Media Lab

The Enron Media Lab will be a state-of-the-art facility for researching and developing both fundamental and practical techniques to control end-to-end quality in IP/optical networks for high bandwidth multimedia applications. Housed at Rice University, and funded in part by Enron, one of the main goals is to provide a physical environment to commercialize the best in university research.

Models for the Enron Media Lab include the famed MIT Media Lab and Lucent Bell Labs Innovations™ (formerly just "Bell Labs"). The idea is twofold: to foster great research in an open environment and transfer that wealth into success in the marketplace, and to raise Enron's image as a technology leader and member of the New Economy by association with Rice and support for research.

Motivation

First Day Jitters

When I entered Rice as a transfer in 1987, I took my mother on a walk about campus. It was a hot day in August, typical for Houston, and most of the time we spent trying to stay in the shade. At every building, we'd step out into the sun for a moment to get a good look and try to figure out what the building was for. We had the standard map of campus with us, but all that was good for was finding the names of buildings. When we wanted to know something about the building, it's history, or the classes taught there, the map was useless.

But this will soon change.

Nokia™ will build a high-speed wireless network[1] throughout campus and provide 3rd-generation phones to all the faculty, staff and students. And with all that bandwidth, Rice will need something to fill it with. In a year or two, when a freshman enters Rice and takes her parents walking about campus, the experience should be rather different than mine.

Using her 3rd-generation cell phone complete with a small, high-resolution color screen[2], she points the phone at a building and asks out loud, "What's that building?". The phone asks here some questions to identify the building clearly, drawing on the Enron Media Lab's systems integration. She continues her conversation, "What classes do they have in there?" The phone tells her. "Could you show me what that class is like?" At this point, the phone plays an excerpt from one of the lectures held in the building, using the Enron Media Lab's distance learning system. Her parents marvel at their daughter's decision to attend Rice.

How does it work?

Nokia™ and other cell phone companies provide the high-speed wireless network. Enron Broadband Services provides the media services and technologies to run multimedia on broadband networks, applications like 3rd-generation video cell phones, high-quality interactive audio-visuals and distance learning. And the Enron Media Lab provides the research that forms the basis for these services and technologies. The Enron Media Lab finds answers to questions like:

  • How can we integrate systems such as wireless networks, video-on-demand, and interactive and live multimedia?
  • How can we store large multimedia efficiently and quickly send it to the consumer?
  • How can we switch broadband from supply to demand, timely and efficiently?

A Great Day for Enron, A Great Day for Rice

While walking about campus and thinking about the Enron Media Lab, it occurred to me that there was so much available at Rice that was locked away unless you were present at just the right place, just the right time. When Willie's statue was turned around[3], I was there, but anyone else now would hear only second-hand stories.

But this will soon change.

Enron Broadband Services will deploy a high-speed multimedia bonanza, and everything from live speeches, classroom lectures and discussions, music school concerts and special events will be available as they happen to anyone who is interested, no matter where they are or what device they use. And they will be available for anyone to reexperience days, months or years later.

Sitting in his dorm room, a senior electrical engineer watches Ken Lay hand over a check for $10 million to Rice for the business school. He's watching from his PC, receiving the broadcast from the Enron Media Lab's experimental live broadcast system using Rice's high-speed network, and can pause, rewind, and catch up to the speeche as it happens. And some weeks later, he reviews the event on his PDA as he walks about campus, using the Enron Media Lab's experimental video-on-demand system, while preparing to go downtown for an interview at Enron.

How does it work?

Again, Enron Broadband Services provides the media services and technologies to run multimedia on broadband networks, applications like live broadcast, video conferencing and video-on-demand. And again the Enron Media Lab provides the research that forms the basis for these services and technologies. The steps are clear:

  • Without the Enron Media Lab to provide the fundamental research for multimedia and broadband, Enron does not have the technologies for applications and systems.
  • Without Enron Broadband Services and other Enron companies to provide the deployment for multimedia and broadband, vendors like Nokia™ do not have the applications and systems for their broadband networks.

Finally, the Lab

In a year or so, Fortune™ or Forbes™ Magazine send a reporter to write up on the Enron Media Lab. What further proof can there be that Enron has completed its movement from Old Economy to New Economy? He walks around, sees the routers, the computers, the video demonstrations, the rapid provisioning tools, the quality-of-service testbeds. That day Enron stock closes at 122-5/8. In the week following the publishing online of the article, Enron stock closes at 134-1/4. Just ask yourself why.

How It Really Works

The physical Enron Media Lab is a main facility provided by Rice University (presumably in Duncan Hall, where Computer Science and Electrical Engineering are located), with smaller satellite locations around campus for testing and prototype deployment. It constains Cisco core and edge routers, IP and optical measurement equipment of various sorts, Sun workstations and servers for testing, deployment and monitoring, and high-speed Ethernet and optical fiber cables and links. Enron's corporate logo will be prominent.

The intangible Enron Media Lab is the ideas people take with them after visiting: a high-technology company for the New Economy supporting great things, and working to do even greater things. That idea comes from the researchers in the lab who:

  • Take advantage of the structure provided by the Enron Media Lab, and move research from the lab to the field
  • Experiment with multimedia technologies, such as streaming and video-on-demand, using advanced bandwidth management equipment and the high-speed network connecting the students and the faculty
  • Demonstrate and deploy the reality of rapid provisioning and gigabit routing in the lab, and then in the field to satellites throughout campus

When you tour the Enron Media Lab, the things you see first are the physical: the structure, the equipment, the staff, the "blinking lights"[4]. Surounding you are various advanced traditional and optical routers, workstations and network monitoring tools. And you can't help but see Enron's corporate logo, or see the prominent words, Enron Media Lab.

While you are there, you see real working demonstrations and test deployments of IP QoS and platinum VPN services, rapid provisioning and resource reservation, dynamic web caching, multimedia streaming and video-on-demand, and distance learning. You can reexperience lectures, plays and performances from Rice University and it's sister campus in Bremen.

When you finish the tour, the things you remember most are the intangible: the brilliance of Rice, and the vision and vigor of Enron.


[1] 3rd-generation cell phone networks should run at 384kbs out doors and 2Mbs indoors. Typically, VHS-quality video at TV resolutions requires 1.7Mbs.

[2]Erricson has some nice pictures of what some 3rd-generation cell phones will be like. Think PalmPilot™ rather than portable handset.

[3]Students at Rice really did rotate William Marsh Rice's 2000-lb. statue 180°. Now that isn't something you see every day.

[4]It is important not to underestimate the imporance of a physical demonstration of high technology in helping people understand how things work, and why it benefits them.

Great Kernighan quote

From a Rik van Riel post on LKM:

Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it. - Brian W. Kernighan

Proxied data members

There's a neat trick I've used for a while when writing C++ code: proxied data members. The idea is straight-forward. The user of your class can write normal-looking access to data member, but behind the scenes your class calls accessor member functions on the user's behalf. I was unable to find a similar technique in Boost but it is nothing new. Proxied data members relies on a helper class which curries an object pointer and member function pointers, applying them as needed via assignment and conversion operators.

The simplest form for a read-only data member is:

#include <iostream>

using namespace std;

template<class P, class T>
class read_only {
  typedef T (P::*read_t) ( ) const;

  P &parent;
  read_t read;

// protected:
public: // no friend template parameters
  read_only (P &parent, read_t read) : parent (parent), read (read) { }

public:
  operator T ( ) const { return (parent.*read) ( ); }
};

class bob_t {
  int i;

  int read_i ( ) const { return i; }

public:
  read_only<bob_t, int> roi;

  bob_t ( ) : i (42), roi (*this, &bob_t::read_i) { }
};

int 
main ( )
{
  bob_t bob;

  // bob.roi = 24; // doesn't compile
  int i = bob.roi;

  cout << i << endl;
}

There are a lot of details which this example glosses over including returning a const reference instead of a copy, handling other types of functions besides member functions (use Boost.Function) and access to the constructor of read_only<P, T>. Ideally, the constructor would be private and I could declare friend P;, but that isn't legal C++.

The idiom for a write-only data member is similar.

Saturday, August 30, 2003

Java filter iterator

Several separate Java projects have led to using the same simple Iterator implementation, AbstractFilterIterator. The idea is very simple: use a single method to filter an underlying Iterator and decide which subset of the data to reveal. Perhaps it is more easily shown than explained, at least for me:

/*
 * AbstractFilterIterator.java
 * Copyright 2003 (C) B. K. Oxley (binkley)
 * <binkley@alumni.rice.edu>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 * USA
 *
 * Created on July 15, 2003.
 *
 * $Id: AbstractFilterIterator.java,v 1.1 2003/08/28 19:07:52 binkley Exp $
 */

package hm.binkley.util;

import java.util.Iterator;
import java.util.ListIterator;

/**
 * <code>AbstractFilterIterator</code> is a partial list iterator.
 *
 * @author <a href="mailto:binkley@alumni.rice.edu">B. K. Oxley (binkley)</a>
 * @version 1.0
 */
public abstract class AbstractFilterIterator
    implements Iterator {
    /** <code>ListIterator</code> through the elements. */
    protected ListIterator it;

    /** The current element after {@link #next()}. */
    protected Object cursor = null;

    /**
     * Construct an <code>AbstractFilterIterator</code> from an
     * underlying iterator over a range.
     *
     * @param it the underlying iterator
     *
     */
    protected AbstractFilterIterator(ListIterator it) {
	this.it = it;
    }

    /**
     * Match <var>element</var>.  If the match is
     * <code>true</code>, <code>AbstractFilterIterator</code> will
     * present <var>element</var> in the view of the underlying
     * iterator.
     *
     * @param element the element to match
     * @return <code>true</code> if the element matches
     */
    protected abstract boolean match(Object element);

    /**
     * Scroll the underlying iterator forward to find the next match.
     * Afterwards, use {@link #rewindNext(int)} to return the
     * underlying iterator to its original position.
     *
     * @return boolean <code>true</code> if there is a next match
     */
    protected boolean findNext() {
	while (it.hasNext())
	    if (match(it.next()))
		return true;

	return false;
    }

    /**
     * Return the underlying iterator to previous position after an
     * earlier call to {@link #findNext()}.
     *
     * @param current the previous position
     */
    protected void rewindNext(int current) {
	for (int next = it.nextIndex(); next > current; --next)
	    it.previous();
    }

    /** {@inheritDoc} */
    public boolean hasNext() {
	// We have do it this way so that you can use next()
	// independently of hasNext().
	int current = it.nextIndex();
	boolean hasNext = findNext();

	rewindNext(current);

	return hasNext;
    }

    /** {@inheritDoc} */
    public Object next() {
	while (!match(cursor = it.next()))
	    ; // nothing

	return cursor;
    }

    /** {@inheritDoc} */
    public void remove() {
	it.remove();
    }
}

As you might suspect, AbstractFilterListIterator is similar and extends AbstractFilterIterator to include methods from ListIterator. This is very straight-forward as AbstractFilterIterator already has a protected ListIterator member, it, to work with.

Friday, August 22, 2003

Duff's device

Periodically while my mind wanders I alight upon Duff's device, one of the cleverest pieces of C code I have ever seen. (Apparently Stroustrup thinks so as well; he included it in his book). I understand perfectly well what the code does, but somehow it still seems elusive every time I see it.

send(to, from, count)
	register short *to, *from;
	register count;
	{
		register n=(count+7)/8;
		switch(count%8){
		case 0:	do{	*to = *from++;
		case 7:		*to = *from++;
		case 6:		*to = *from++;
		case 5:		*to = *from++;
		case 4:		*to = *from++;
		case 3:		*to = *from++;
		case 2:		*to = *from++;
		case 1:		*to = *from++;
			}while(--n>0);
		}
	}

One of the best interview questions I have seen is a slightly obfuscated version of Duff's device with the variable names replaced and all comments unhelpfully removed. The questioner then asks a job applicant, What does this function do? Why? Familiarity with the literature is a great help here.

Thursday, August 21, 2003

Magic, more magic

Template technology is advancing so quickly in C++ I sometimes wonder where it will all lead. The obvious answer is LISP:

for_each(a.begin(), a.end(), std::cout << _1 << ' ');

Naturally, one thinks of the Story about 'Magic'.

Monday, August 18, 2003

The joy of macros

C and C++ is two of my favorite languages, but the macro preprocessor can be unwieldy at times. Consider this:

#define STR_1(line)   #line
#define STR_2(line)   STR_1(line)
#define malloc(n)      \ 
    (debug_malloc(       \ 
         (n), __FILE__ ":" STR_2(__LINE__)))

What is this? It's the only way to convert the current line number into a string usable in program diagnostics: you have to use the double macro call to make it work. Nasty, isn't it? I'm glad Jon Jagger wrote about that so I wouldn't have to.

An STL-like array container for JNI

After some tinkering, I tried this for an STL-like container for JNI arrays. Tell me what you think:

// Emacs, this is -*- c++ -*- code.

#ifndef JVECTOR_H_
#define JVECTOR_H_

#include <jni.h>

#include <algorithm>
#include <vector>

#include <stdint.h>

template<typename T>
class jtype;

/**
 * Base class with specializations to hide type differences in the JNI
 * API.
 *
 * XXX - handle exceptions (e.g., NULL return from NewArray).
 *
 * XXX - should switch to Get<Type>ArrayRegion and use a scroll window
 * ala SQL result sets.
 */
template<>
struct jtype<jint>
{
  typedef int32_t value_type; // jint == int32_t
  typedef jintArray array_type;

  mutable JNIEnv* env;

  explicit jtype (JNIEnv* env) : env (env) { }
  jtype (const jtype& that) : env (that.env) { }
  jtype& operator= (const jtype& that)
  { jtype tmp (that); swap (tmp); return *this; }
  ~jtype ( ) { env = 0; }

  /*
   * jsize (JNICALL *GetArrayLength)
   *   (JNIEnv *env, jarray array);
   */
  jsize GetArrayLength (jarray jarr) const
  { return env->GetArrayLength (jarr); }

  /*
   * jintArray (JNICALL *NewIntArray)
   *   (JNIEnv *env, jsize len);
   */
  array_type NewArray (jsize len) const
  { return env->NewIntArray (len); }

  /*
   * jint * (JNICALL *GetIntArrayElements)
   *   (JNIEnv *env, jintArray array, jboolean *isCopy);
   */
  value_type* GetArrayElements (array_type jarr, bool& is_copy)
  {
    jboolean b = is_copy ? JNI_TRUE : JNI_FALSE;
    value_type* arr = env->GetIntArrayElements (jarr, &b);
    is_copy = b == JNI_TRUE ? true : false;
    return arr;
  }

  value_type* GetArrayElements (array_type jarr)
  { return env->GetIntArrayElements (jarr, 0); }

  /*
   * void (JNICALL *ReleaseIntArrayElements)
   *   (JNIEnv *env, jintArray array, jint *elems, jint mode);
   */
  void ReleaseArrayElements (array_type jarr, value_type* arr, jint mode)
  { env->ReleaseIntArrayElements (jarr, arr, mode); }

  void ReleaseArrayElements (array_type jarr, value_type* arr)
    // 0 --> copy back and free element buffer
  { env->ReleaseIntArrayElements (jarr, arr, 0); }

  /*
   * void (JNICALL *GetIntArrayRegion)
   *   (JNIEnv *env, jintArray array, jsize start, jsize len, jint buf);
   */
  void GetArrayRegion (array_type jarr, jsize start, jsize len,
		       value_type* arr)
  { env->GetIntArrayRegion (jarr, start, len, arr); }

  /*
   * void (JNICALL *SetIntArrayRegion)
   *   (JNIEnv *env, jintArray array, jsize start, jsize len, const jint *buf);
   */
  void SetArrayRegion (array_type jarr, jsize start, jsize len,
		       const value_type* arr)
    // Not const.  What gives?  XXX
  { env->SetIntArrayRegion (jarr, start, len, const_cast<value_type*> (arr)); }

  void swap (jtype& that) throw ( ) { std::swap (env, that.env); }
};

template<typename T>
void
std::swap (jtype<T>& lhs, jtype<T>& rhs)
{ lhs.swap (rhs); }

/**
 * jvector<T> is an STL-like wrapper for Java arrays.  Note that Java
 * arrays are immutable although the values can be changed.  Therefore
 * operations like clear, resize, max_size, etc., make no sense are
 * are not included.
 */
template<typename T>
class jvector
  : public jtype<T>
{
public:
  typedef typename jtype<T>::value_type value_type;
  typedef typename jtype<T>::array_type array_type;
  typedef value_type* pointer;
  typedef const value_type* const_pointer;
  typedef value_type& reference;
  typedef const value_type& const_reference;

  // Replace with checked versions.  XXX
  typedef value_type* iterator;
  typedef const value_type* const_iterator;
  typedef jsize size_type;
  typedef std::ptrdiff_t difference_type;
  typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
  typedef std::reverse_iterator<iterator> reverse_iterator;

private:
  array_type jarr;
  size_type len;
  pointer arr; // XXX counted_arr<T>
  bool changed;

public:
  jvector (JNIEnv* env, array_type jarr)
    : jtype<T> (env),
      jarr (jarr),
      len (GetArrayLength (jarr)),
      arr (GetArrayElements (jarr)),
      changed (false)
  { }

  jvector (const jvector& that)
    : jtype<T> (that),
      jarr (that.jarr),
      len (that.len),
      arr (that.arr),
      changed (that.changed)
  { }

  jvector operator= (const jvector& that)
  { jvector tmp (that); swap (tmp); return *this; }

  // Switching to a counted array for arr may remove the memory burden
  // on the JVM for the calls to {Get,Release}IntArrayElements past
  // the first one.  XXX
  ~jvector ( )
  { ReleaseArrayElements (jarr, arr, changed ? 0 : JNI_ABORT); }

  iterator begin ( )
  { changed = true; return arr; }
  const_iterator begin ( ) const
  { return arr; }
  iterator end ( )
  { changed = true; return arr + len; }
  const_iterator end ( ) const
  { return arr + len; }
  reverse_iterator rbegin ( )
  { changed = true; return reverse_iterator (end ( )); }
  const_reverse_iterator rbegin ( ) const
  { return const_reverse_iterator (end ( )); }
  reverse_iterator rend ( )
  { changed = true; return reverse_iterator (begin ( )); }
  const_reverse_iterator rend ( ) const
  { return const_reverse_iterator (begin ( )); }

  size_type size ( ) const
  { return size_type (end ( ) - begin ( )); }

  bool empty ( ) const
  { return begin ( ) == end ( ); }

  reference at (size_type n)
  { check_range (n); changed = true; return (*this)[n]; }
  const_reference at (size_type n) const
  { check_range (n); return (*this)[n]; }
  reference operator[](size_type n)
  { changed = true; return *(begin ( ) + n); }
  const_reference operator[](size_type n) const
  { return *(begin ( ) + n); }

  reference front ( )
  { changed = true; return *begin ( ); }
  const_reference front ( ) const
  { return *begin ( ); }

  reference back ( )
  { changed = true; return *(end ( ) - 1); }
  const_reference back ( ) const
  { return *(end ( ) - 1); }

  void swap (jvector& that)
  {
    std::swap (base, that.base);
    std::swap (jarr, that.jarr);
    std::swap (len, that.len);
    std::swap (arr, that.arr);
    std::swap (changed, that.changed);
  }

private:
  void check_range (size_type n) const
  { if (n > len) throw std::out_of_range ("jvector"); }
};

template<typename T>
void
std::swap (jvector<T>& lhs, jvector<T>& rhs)
{ lhs.swap (rhs); }

#endif // JVECTOR_H_

Wednesday, August 13, 2003

JNI and the STL

While looking through some JNI code I started thinking more about IntArray and friends. To write a non-mutating STL-like jvector<T> wrapper for the underlying JNI calls would not be much work. A quick Google search did not turn up the code I hoped to find. Perhaps I should look for a std::vector<T> adaptor implementation and host it onto the JNI calls such as GetArrayLength. The easy thing to do would be to specialize jvector<> on each native type in Java. For example, JNI jint would use GetIntArrayElements. Seem simple enough?

Thursday, August 07, 2003

The old standby

I'm filling out a programming quiz and run into that old standby, reverse the words of a string in place in linear time. I've done this one at the whiteboard too many times so I did a quick Google search: lots of references to the problem but no reusable code*. So, I write my own. To save some other person the trouble, I'm posting it here. Also, I'm hoping to get mail from someone pointing out how I could do it better. Good advice is a precious commodity.

* I am a big advocate of code reuse. I can't stand to see cut&paste coding and NIH (not invented here) syndrome drives me nuts.

#include <ctype.h>

/*
 * In C++ just use std::swap.  This macro uses the XOR hack to avoid
 * the stack and a temporary.
 */
#define SWAP(a,b) \ 
  do { (*a) ^= (*b); (*b) ^= (*a); (*a) ^= (*b); } while (0)

/* 
 * Although wordrev could be written using strtok(3), many
 * implementation of strtok run in quadratic time with respect to the
 * token string and strtok only expresses membership in the token
 * class rather than non-membership.  I contrast, most implementations
 * optimize isspace(3) very well usually using a table-driven macro
 * for contant time performance even avoiding the function call cost.
 *
 * If wordrev proves to be a hotspot, then unroll the loop:
 *
 *   switch (b - a) {
 *   case 0: case 1: break;
 *   case 2: SWAP(a[0], a[1]); break;
 *   case 3: SWAP(a[0], a[2]); break;
 *   case 4: SWAP(a[0], a[3]); SWAP(a[1], a[2]); break;
 *   case 5: SWAP(a[0], a[4]); SWAP(a[1], a[3]); break;
 *   default: // use the loop below
 *   }
 *
 * I prefer not to unroll it unless a profiler indicates that it
 * matters and that the unrolling makes a difference.
 */

int
wordrev (char* s, int len)
{
  char* m; /* word boundary marker */

  if (! s) return 0; /* protect against a null pointer */
  if (len < 0) return 0; /* nonsense argument */

  m = s;

  for (;;) {
    const char* X = s + len; /* end of search space */
    char* a, *b; /* pointers for reversing word */

    while (m < X && *m && isspace(*m))
      ++m; /* advance m to start of next word */

    a = m; /* word start */

    while (m < X && *m && ! isspace(*m))
      ++m; /* advance m to next word break */

    if (m == a)
      break; // EOS

    b = m - 1; /* word finish, skipping the space */

    for ( ; a < b; a++, --b)
      SWAP(a, b);
  }

  return m - s;
}

Blogging 1, Job boards 0

I just got an interesting phone call from a firm recruiting for software talent. How did the caller find me? This blog. I looked up the company, ThoughtWorks, and saw that it focuses on agile development which fits hand and glove with extreme programming practises. Good for them! The programming world need more companies like that.

Java 1.5 and generics

I've been experimenting with the new generics support in Java 1.5. One disappointment is a lack of mixins—you must still inherit from a single, fixed class; no generic superclasses. (For that you need to use Rice's NextGen.) But otherwise I'm having a great time. This will be an excellent feature when 1.5 is released.

Friday, August 01, 2003

Effective Java

Tim Bell, a Sun Java engineer, recommended to me Effective Java while discussing a feature report I made. He said:

And if I could put in a plug for Bloch's book, I will. I bought my copy out of my own pocket money. It is well worth it. It is full of lessons learned the hard way. Reading it will save you much of your own debugging time, and you will write better code.

That's how you praise a programming book!

My resume

Looking for a programmer in Austin or Houston? My overview says:

Senior programmer and Unix/Linux expert in all areas, including development, administration, configuration and kernel programming. Strong Windows development experience, and exposure to other operating systems. Knowledgeable in most networking areas with strong design background in systems, protocols, libraries and applications. Designed and implemented various client-server and N-tier architectures.

Successful record leading design and programming teams of various sizes, and bringing long-range projects to completion on-time and under-budget. Frequently found ways to save my company money by recommending existing solutions over in-house redevelopment. Designed and built reliable software where failure was not an option.

Seeking a principal-level programming, architecture, systems design or software management position in the software industry with a focus on Java, C/C++, SQL, Unix/Linux or other advanced systems and networking technologies. Thrive on variety, difficulty, tight deadlines and jobs no one else wants or can get done.

I also blog. :-)

First post

The new, non-toxic binkley's BLOG.