June 22, 2008

Setter methods make kittens cry

Do use setters if being edited is the central purpose of that class. Do not use setter methods to create an object. Setter methods intended for creation will still be accessible during the whole lifetime of the object. Someone might use them and break all your stuff. Basically everything involving caches or hashCode() will die in your arms. Like when changing an attribute will cause some remote piece of code have maps with broken mappings and suddenly sport sets with duplicate elements. Being paranoid makes for good code karma.

Furthermore, do not use setters to wire up required attributes. I often see code like this:

Foo foo = new Foo();
foo.setAttribute1(a1);
foo.setAttribute2(a2);
foo.setAttribute3(a3);

This is bad because until the last line has executed, foo lives in some sort of twilight zone, where it exists but may not be used yet. Your class should not allow to create an object with invalid state. Better use the constructor to wire up attributes:

Foo foo = new Foo(a1, a2, a3);

Some people will argue that this will become hard to read if you have a lot of attributes. In such cases you should use a Builder separate factory class that collects all attributes with setters and can create the object once all required attributes are present (otherwise throw an exception). This shifts the enforcement of valid object creation from compile time to runtime, but still fails fast if necessary.

A related point I would like to make is that immutable objects (objects that cannot change their state after instantiation) also make for good code karma. Mutable objects can be a pain to work with and force their clients to make defensive copies. Immutable objects are also thread-safe by default (you might still screw it up though).

Comments (1)

May 11, 2008

Hahahahahaha

Some consultant guy writes about PHP 6:

The language and syntax differences in PHP V6 may or may not affect you as much as the next features, which are those that directly allow you to introduce Web 2.0 features into your PHP application.

Apparently Web 2.0 means libraries for SOAP and XML. I love it when I hear someone say the words "Web 2.0" with a straight face, because then I know I'm in for comedy gold.

But wait, there's more! Here are some features being removed from PHP:

magic_quotes
register_globals
safe_mode

Awesome. I couldn't name a favorite. The $SECURITY = true superglobal will still be in PHP6 though.

PHP is like a crippled old man beating himself up.

Comments (0)

April 12, 2008

You don't know Java: Method type parameters

When someone tells you they know Java, smile and say "no, you don't". Proceed to soften them up with questions about covariance and contravariance and how they relate to parametrized types. When they start crying, go in for the kill.

But let's talk about something nice today: Method type parameters. Few people know that type parameters in Java are not limited to types, but that every method and constructor can declare their own type parameters. And if this alone wasn't cool enough, it can actually be useful!

To illustrate, I need a couple of interfaces from Java kindergarden:

interface CanWalk {
    void walk(int steps);
}

interface CanSwim {
    void swim(int strokes);
}

interface CanSleep {
    void sleep(int minutes);
    boolean isSleeping();
}

interface Animal implements CanSleep { }

interface Cat implements Animal, CanWalk { }

interface Dog implements Animal, CanWalk, CanSwim { }

Say we want to write a method that simply takes an Animal and returns it. This is the way we used to roll:

Animal returnMe(Animal animal) {
    return animal;
}

What's bad about this method is, that it returns its value as Animal, even if we gave it a Cat. So if we wanted our cat back, we need to cast it manually:

Cat cat = (Cat)returnMe(new Cat());

We can improve on this by binding a type variable to the returnMe method like this:

<A extends Animal> A returnMe(A a) {
    return a;
}

This way we don't need the cast:

Cat cat = returnMe(new Cat());

To give an actually useful example, let's write a method getAwake that is given a list of objects implementing CanSleep, and returns those objects that return false from isSleeping():

<A extends CanSleep> List<A> getAwake(List<A> potentialSleepers) {
    return Lists.select(potentialSleepers, new Filter<A>() {
        public boolean passes(A element) {
            return !element.isSleeping();
        }
    });
}

... with Lists.select working like select in Ruby lists, but you cool kids already figured that out by yourself. Again we can give getAwake a list of cats, and get a list of cats back, rather than a list of animals. You can see how method type parameters allow us to be more expressive about our method signatures.

This might be stretching the attention span of the YouTube generation, but here's one more cool thing: Method type parameters with composite upper bounds:

<Duckish extends CanWalk & CanSwim & CanSleep> void rockTheBeach(Duckish duckish) {
    duckish.walk(100); // check out the chicks
    duckish.swim(20);  // cool down in the water
    duckish.sleep(60); // take a nap
}

This is about as much fun as you'll ever be able to have writing Java. Enjoy!

Comments (0)

March 21, 2007

Names are important

For a profession that is all about naming things, most programmers are being terribly careless with names. Although you get away with it most of the time, you look so immensely stupid when two pieces of code disagree over the meaning of a name. Names are important.

One of the things I still love about Perl is that, by convention, it is considered rude to invade other people's namespace. So we put all our public methods and constants into the @EXPORT_OK array and let the client decide which part of that he wants to use in their code. I should be able to do the same with code extending existing classes: Let me decide which extensions I want patched in on a per-class basis. I believe extension methods in C# 3.0 work this way. Do copy this.

Another name issue few languages get right are namespaces. Namespaces are important, because sooner or later you will have two different Node classes in your project and you need to tell your code which one to use. Let's look how some popular languages are dealing with this:

PHP

Bashing PHP is a bit like beating up an old man, but here we go anyway: PHP has no notion of namespaces at all. To work around this, people are using Really_Long_Classnames_With_Packagish_Names_Prefixed to lessen the chance of namespace clashes. LOL.

Java

Has a wonderful culture of putting classes in packages named after some domain you own. So my Node class would be packaged as org.netalive.swsu.Node and people could import this name and just write Node. Bad: When you need to use two different Node classes in the same piece of code. As you can only import one Node without name clashes your code will look like Map<Node, incredibly.long.package.name.of.other.Node>. Horrible when it happens, and it happens frequently. For instance, both the most basic GUI widget in Swing and the most basic data structure in Java are called List.

Perl and Ruby

Uses Package::Subpackage::Classname syntax for improved looks, but since you cannot import or alias these long names, this is more about organizing files and not really better than PHP's Package_Subpackage_Classname workaround. At least you can switch into a namespace and add and replace methods without using fully qualified names. It's kind of OK for untyped languages because you only need to reference types when calling a constructor or another static method. Still the possibility of another Tree::Node class in a second library is always there and sometimes urges you to use more unique package names than you would like.

Python

I don't speak Python, but from what I've seen this is a language that got namespaces right. You can import a namespace as in Java, you can selectively import symbols as in Perl, and here's the goodness: You can import reallylongmodulename as shortcut to alias reallylongmodulename into shortcut. Nice.

I think what Python does (importing and importing into aliases) should be the minimum requirement for any language that wants to take names seriously. The package naming convention from Java is cool, because the DNS is the only naming scheme humanity ever reached something like an agreement over, and unique names are good. Imagine blowing up the planet because some piece of code felt ambivalent about the semantics of System.Nuke. We would look all kinds of stupid if this sort of thing ever happened.

Comments (5)

March 20, 2007

Whoops! Open classes not cool after all!

Ruby, Perl and many other languages let you reopen an existing class or namespace and add additional methods to it, or replace existing methods with new code. Everyone thinks that is "like super-cool" and "really feels the spirit of getting things done", probably accompanied by some generic "LOL Java, agile languages FTW!" rant.

Surprisingly, open classes have one serious problem: People are using them!

Right now the two most popular uses for reopening classes are (1) adding methods to core classes like objects or lists and (2) patching totally not public code with your own funky version. Both are terrifyingly bad ideas which will probably break with the next update of the code you're patching, or as soon as another clever library attempts to do the same. But let's enjoy some examples together:

  1. It is impossible to use prototype.js and json.js at the same time because prototype.js does something nasty to Object.prototype. But never mind since these are only the two most commonly Javascript libraries on the planet.

  2. What Rails is doing to the Ruby core, and what some plugins are doing to Rails, is downright scary in some places. Thankfully Rails is heavily maintained and bugs are patched quickly.

  3. While developing a World of Warcraft addon in Lua, we discovered that the preferred way to intercept chat messages was to replace the existing message handler, intercept the messages you need and hand over the rest to a copy of the old handler. Unfortunately, since our addon name was lexically smaller than the name of another addon that used the same trick, and World of Warcraft loads addons in alphabetical order, our new message handler was replaced by a third addon handler by that other, lesser addon and everything went to hell.

I'm not even sure if the last example is valid in this context, but it's also about bad scope and globals, and I really needed to stress the fact that I'm writing kick-ass World of Warcraft addons this very minute.

Anyway, don't you think it's funny how twenty years after people realized that "globals are teh suck" we're falling into the same bad habits all over again? Yes, open classes are fun toys to play with, but you can also fuck up royally if you don't pay attention. So, please, do think about what happens when other libraries attempt to pull the same hackery as you. Do consider the chance that a second library also wants to decorate the draw method, and do assume it will also save the existing method using alias :original_draw :draw. And OH MY GOD do not patch up private methods that have clearly not been cleared for public consumption by the original author!

Patching private methods. I mean, what the hell. Think of the children!

Comments (3)

January 16, 2007

Gapless MP3 loops in Flash

When encoding a sound loop as MP3, the encoder will add ugly gaps of silence at the beginning and end of your track, making the resulting file not very loopable at all. This is due to the way MP3 encoding works.

Although there are some instructions (scroll down to "Part 2") how to remove those gaps from your sound file, the amount of hackery involved is not for the faint of heart. The same guy also wrote a tool to automate the process but it's restricted to a maximum of 8 seconds of sound, and you can totally not buy a full version.

You're lucky if you're working in Flash however. The MP3 encoder inside the Flash IDE knows about the problem and will make sure any MP3 it compresses will loop without gaps. So:

  1. Have an uncompressed sound loop as WAV oder AIFF. If your loop is already an MP3, remove the silent padding at the beginning and end of the track and save it as WAV.
  2. Import the uncompressed sound into the library of your clip.
  3. In the sound properties, set the desired MP3 compression.
  4. Loop away.

Comments (0)

December 24, 2006

You don't know jack about thread-safety

All you hotshot programmers need to drop what you're doing and secure a copy of Java Concurrency in Practice. 50 pages into the book my face was frozen in pure horror, as Brian Goetz and his friends happily ran over everything I ever thought I knew about thread-safe programming.

What do you think the following code will print to the console?

public class NoVisibility {

    private static boolean ready;
    private static int number;

    private static class ReaderThread extends Thread {
        public void run() {
            while (!ready) Thread.yield();
            System.out.println(number);
        }
    }

    public static void main(String[] args) {
        new ReaderThread().start();
        number = 42;
        ready = true;
    }
}

Unless your answer is "either zero, 42 or nothing at all" you really need to read the book before someone notices.

Comments (4)

December 08, 2006

There's nothing wrong with bloggers

<tom> there's nothing wrong with bloggers
<tom> it's just that like
<tom> when they're ALL in ONE ROOM, all SWEATING, all POSTING, 
<tom> all EDITING ONE DOCUMENT COLLABORATIVELY WITH SUBETHAEDIT, 
<tom> it gets a bit much
<liz> do non-bloggers not sweat then?
<tom> they do, but their sweat doesn't have an rss feed

Comments (0)

July 30, 2006

Why you should stop blogging

Look kids, I really believe this blogging thing has gone out of hand, so here are some things I need to get off my chest before anyone gets hurt.

First off, you really don't have to apologize for not having updated your weblog in a while. I'll just assume you had something better to do. Also your guides on overcoming writer's block and getting your daily blogging rythm going make me cry. It's not a freaking competition, mmkay? The whole beauty of this syndication thing is that I will still hear you after three years of blogging absence. I actually prefer reading occasional burts of goodness over the stream of consciousness shit that is clogging up the internet.

Second, if you ever forego a night with your friends in order to be able to update your weblog and I catch you, it's not going to be a pretty sight. Understand that our time on this planet is very limited and there are only so many bars you can hit before nature collects its toll. You must choose how to spend the time that is given you, and if the majority of it is spent blogging, you really need to reconsider that choice.

Also your weblog is probably not going to get you laid, ever. That implies that you should not see blogging as a popularity contest. You probably don't want to be among the "A-List" bloggers and if you ever find yourself aspiring that goal, please see the previous paragraph about bars and friends. Enjoy what weblogs have to offer, but don't use weblogs as your sole source of knowledge and self-affirmation. Always remember that the "blogosphere" is an echo chamber that can give you a very distorted image of reality if consumed without enough perspective. The vast majority of the online world does not read or write weblogs, and in no way are we smarter or hipper or more interesting or better informed than they are.

The most important people in your life will probably not have a weblog. They also won't turn up on a Google search.

Finally, stay away from World of Warcraft. That is all.

Comments (2)

June 29, 2006

My homework could totally beat up your homework

How's that for a university project: We're currently writing the AI code for a heavily pimped Lego Mindstorms robot, which has to collect "flags" in a labyrinth and shoot down the Lego bots of the other, lesser teams.

Best project ever.

Comments (1)