Archive for the ‘Uncategorized’ Category

Dependent types and plus

Tuesday, January 4th, 2011

My story starts with a simple function: +

Starting with Java… tell me what’s wrong with this picture?

public void blah() {
  int x = 3;
  int y = 5;
  int z = x + y;
  System.out.println("z = " + z);
}

z evaluates fine… but what about this?

public void blah() {
  int x = Integer.MAX_VALUE;
  int y = Integer.MAX_VALUE;
  int z = x + y;
  System.out.println("z = " + z);
}

Apparently z = -2. AAAAAAAAAAAAAARGH! That’s nonsensical! Surely an exception would be better than an incorrect value. Yes, incorrect. No, I don’t care about the semantics of overflows in 32-bit calculations in CPUs. It’s just plain wrong. For the purposes of discussion, let’s just pretend + doesn’t terminate when it overflows.

Ok, so why does the compiler allow this? What’s going on?

In maths, integers are closed under addition – i.e. int + int = int. This relies on the integers being unbounded. In (most? all?) programming languges, we only have bounded integers. Bounded integers are not closed under addition.

So, + is int -> int -> int… but this is only correct for unbounded integers. For bounded integers, + is really int -> int -> long

Why long? Simply that Integer.MAX_VALUE + Integer.MAX_VALUE <= Long.MAX_VALUE.

So, in java, an int is an integral type with bounds -2,147,483,648 … 2,147,483,647 (Integer.MIN_VALUE and MAX_VALUE). Let’s denote this as int[-2,147,483,648, 2,147,483,647]. Similarly, long would be int[-9,223,372,036,854,775,808, 9,223,372,036,854,775,807]. Then, + would be:

int[-2,147,483,648, 2,147,483,647] -> int[-2,147,483,648, 2,147,483,647] -> int[-9,223,372,036,854,775,808, 9,223,372,036,854,775,807]

But, 2,147,483,647 + 2,147,483,647 = 4294967294, which is far less than the long bound. So, we could say + is:

int[-2,147,483,648, 2,147,483,647] -> int[-2147483648, 2147483647] -> int[−4,294,967,296, 4,294,967,294]

My head is spinning from big numbers. Sorry. Anyway, this pattern generalises to:

+ :: int[a1, b1] + int[a2, b2] -> int[a1 + a2, a2 + b2]

Note, above, the result of the addition could fit into either a int[-9,223,372,036,854,775,808, 9,223,372,036,854,775,807] or an int[−4294967296, 4294967294] – i.e. a value of the narrower type could fit into the larger type. So we could say that:

int[a1, b1] is a subtype of int[a2, b2] for all a1 <= a2 and b1 >= b2

Back to +, notice that the return type is actually defined in terms of +! How can that be? Well, there’s something missing from the definition of +.

+ :: int[a1, b1] + int[a2, b2] -> int[a1 + a2, a2 + b2] for all a1, a2, b1, b2 :: int[-∞, ∞]

As such, + for bounded integers is defined in terms of + for unbounded integers. We just need an unbounded integer type. I haven’t seen one in practise yet – we seem to be stuck with bounded integers as they easily map to the underlying hardware. We need to break free of this – we need the unbounded integers we take for granted in pure maths, and then, if we need bounded integers, implement them in terms of unbounded integers. Then, we can optimise for hardware capabilities in the compiler and runtime.

A similar recursive definition happens with values. Take the value 3. What type is it? Well, a 3 can’t be more than 3 or less than 3, so it’s bounds are 3 and 3. i.e. int[3, 3]. More generally, x :: int[x, x] for all x :: int[-∞, ∞]. This gives us one type for each value – as such, what is the difference between the value 3 and the once-inhabited type int[3, 3]? What really is the difference between a type and a value? I can imagine a type system whereby types and values are completely unified, rather than distinct concepts.

Anyway, let’s look at a practical example. Take the expression 3 + 4. Adding type annotations:

3 :: int[3, 3] + 4 :: int[4, 4]

and it would evaluate to 7 :: int[7, 7]

but, I could also say: z :: int[0, 256] = 3 + 4, because int[0, 256] is a supertype of int[7, 7]

So, if we type-alias, say, smallint = int[0, 256], I can say: z :: smallint = 3 + 4. This is looking more like normal code. Now, if java did this, then int x = Integer.MAX_VALUE + Integer.MAX_VALUE wouldn’t type-check, but long x = Integer.MAX_VALUE + Integer.MAX_VALUE would.

Ahhhhhhhhhhhhhhhhhhh. Sigh of relief. That’s so much better!

But, what happens if I need to narrow a type? Say, I have an integer from user input, which could be anything, but I need to store it in, say, an int[0, 256]? Yawn. It’s just validation, and we just need a function like this:

narrow :: int[a1, b1] -> Maybe int[a2, b2]

This all seems a lot for just avoiding integer overflows, but it has potential to prevent bugs, and this is just the tip of the iceberg for dependent types.

sliding puzzle game

Sunday, July 4th, 2010

Over the last week, I wrote a simple sliding jigsaw puzzle game using jQuery and underscore js. There’s a demo page and the source is open.

Amazing modding discovery at bunnings

Saturday, June 5th, 2010

Wow… just wow. For months I’ve been searching for the right way to mount hard drives for my new case modding project. Everything had too few drives or was too expensive.

Today I spent a few hours wandering around Bunnings and I found these little L brackets that were perfect. I honestly can’t believe it. They’re pre-drilled with holes that just so happen to be in exactly in the right place for hard drives! Each bracket is about $3.50; get 4 of them and you’ve got a cage that supports 6 hard drives.

FYI the sticker says “Make-a-Bracket GALVANIZED 150x50x40mm 2mm thick CARINYA MFG PAT.PEN NO 2003906533 Made in China.”

ArrayMangler 1.2 released

Tuesday, June 1st, 2010

Just a couple more minor features – get the first or last x elements of an array.

ArrayMangler 1.1 released

Tuesday, June 1st, 2010

My open source swiss-army-knife of Java arrays has been given some new goodness. Version 1.1 has been released and you can grab it from here. Apache 2 license.

So what can it do?

  • contains
  • Collection to array
  • make an array of a specified class and length
  • concatenate arrays
  • get parts of an array: head (first), toe (last), tail (all except first), torso (all except last)
  • parallel arrays to Map
  • reverse
  • append
  • prepend

Enjoy!

Immutablility ftw

Tuesday, March 30th, 2010

When you start dealing with immutability, some interesting properties start to emerge. I’m new to it, but here’s some initial observations:

  • You can eagerly cache calculations, e.g. in constructors
  • You can start caching common values in factories – e.g. generics aside there is only ever one empty list
  • You can save memory. If a list consists of a head element and tail list, then the tail list only needs to exist once.
  • You obviously don’t need setters… but bizarrely, you stop needing getters. You can use public final fields instead.
  • As the ‘mutator’ methods return new structures, it becomes easy to chain calls. e.g. list = list.add(“a”).add(“b”)
  • Recursion doesn’t just become more necessary, it becomes easier

And then, yeah, yada yada yada functional purity yada yada blah blah concurrency blah blah. Yeah, the functional purists like to rave on about this, but I’m more interested in how it affects day-to-day coding, and it looks good.

Java Immutable Stack

Monday, March 29th, 2010

Pure awesome. Well done.

http://imjorge.spaces.live.com/blog/cns!85B5DB672654118C!1021.entry

The new techtangents

Wednesday, March 24th, 2010

techtangents has moved to its new home at www.techtangents.com and I’ve given it a fresh new look. The new techtangents will not only be my blog, but also a hub for my open source projects. I’m still getting set up, but stick with me and there’ll be plenty more updates soon.

Running Ant tasks in Java part deux

Friday, March 12th, 2010

I think this is the right way to do it:

Task task = new SomeTask();
task.setProject(myProject);
task.init();
// set fields
task.perform();

Finalising the architecture

Wednesday, March 3rd, 2010

Today, I heard someone use the phrase “finalise the architecture”. Software architecture isn’t something that should ever be finalized. Actually, one of its key roles is to change and facilitate change in the system.