Tuesday, December 30, 2008

QOTD: Hans Küng

From The Catholic Church: A Short History:
Those who deliberately step in all the puddles should not complain too loudly about how bad the road is.

Monday, December 22, 2008

Bad RSpec! BAD RSPEC!!

My first gig as a consultant for ThoughtWorks has been a whirlwind of security lines, flights to Texas, and Ruby on Rails. I'm very pleased that they were able to make me billable so quickly; to be getting paid to work on Rails again after two years in the Java mines is an extra added bonus.

My pair and I spent today upgrading one of our apps to Rails 2.2, as a sort of trial run for eventually upgrading all our apps. This involved the usual amount of concomitant upgrades to plugins, with no shortage of "great, this is broken...now something else is broken...not that too!" hijinks. The best part of the day, though, was the RSpec tests that kept failing no matter what we tried to throw at them.

Long story short, we have a controller that uses a rescue_from handler to redirect in the event of a connection error. Works like a charm when we're clicking through the app. But after upgrading RSpec and RSpec-Rails it simply refused to pass the specs that verified the redirect behavior.

It turns out that the latest version of RSpec has some secret sauce that defeats rescue_from, instead going directly to raising the exception that needed rescuing from in the first place. I guess I wouldn't mind so much if we didn't have several behavior-driven tests that, you know, tested behavior.

Not too cool, Rudy.

There is, of course, a workaround. Simply add controller.use_rails_error_handling! to your test and you can defeat RSpec's defeating of rescue_from. But, just as double negatives fail to not clutter English prose (see what I did there?), having to demand that RSpec get out of the way of Rails' standard and -- in this case -- reasonable behavior just uglies up my code. I would much rather the maintainers of RSpec had elected to make the ability to bypass the rescue handler and skip straight to the underlying exception an "opt-in" behavior.

Monday, December 01, 2008

One of These Things is Not Like the Others...

I (heart) Amazon's recommendations service, but...

...I'm not entirely sure what the message is here. For me or any other fans of programming languages and/or algorithms.

Friday, October 17, 2008

QOTD: Donald Knuth

Ripped directly from this interview:
...I trust my family jewels only to Linux.
I'm a Mac guy myself, but...respect, brother. Respect.

Friday, August 15, 2008

Regarding Ruby, instance_of?, kind_of?, and ===

So I was reading through some Ruby source code tonight -- primarily because I haven't in a while, thanks to a busy stretch of Java work -- and I ran across an idiom that I found a little confusing at first. The Ruby source code belongs to Why the Lucky Stiff's Shoes project, "a very informal graphics and windowing toolkit" (according to the official website).

One of the first files I looked at, lib/shoes.rb, opens right up with this interesting bit of interestingness:
class Range 
def rand
conv = (Integer === self.end && Integer === self.begin
? :to_i
: :to_f)
((Kernel.rand * (self.end - self.begin))
+ self.begin).send(conv)
Okay. So we're defining a rand() method on the built-in Ruby class Range, which will return a random value from within the begin and end values of the Range. Neato. And apparently the use of conv is meant to produce a result of a float or an integer, depending on the nature of the endpoints of the Range. Again: neato. But I hadn't seen the use of the === operator in this context before.

The docs and the Pickaxe book are a little obtuse on this, so I did some irb spelunking:
>> r = (1..27)
=> 1..27
>> r.class
=> Range
>> r.begin
=> 1
>> r.begin.instance_of? Integer
=> false
>> r.begin.class
=> Fixnum
>> r.begin.kind_of? Fixnum
=> true
>> r.begin.kind_of? Integer
=> true
Hmm. So instance_of() doesn't mean quite the same in Ruby as, say, the instanceof operator in Java does. (That, or Fixnum doesn't truly inherit from Integer in Ruby.)

Also, as it turns out:
>> Fixnum === r.begin
=> true
>> Integer === r.begin
=> true
So it would seem that the [class] === [value] syntax is syntactic sugar for [value].kind_of? [class]

It's the bit about:
>> r.begin.instance_of? Integer
=> false
that surprised me most, being the pathetic Java programmer that I am. And being that (according to the documentation for Integer on ruby-doc.org):
Integer is the basis for the two concrete classes that hold 
whole numbers, Bignum and Fixnum.
Apparently "is the basis for" != "is a superclass of".

Or is that "!==="...?

Monday, July 07, 2008

Fixing Eclipse's Workspace Dialog: A Unix One-Liner in Only Three (Okay, Four) Lines

cd /Applications/eclipse_3_3/configuration/.settings
&& sed '/RECENT_WORKSPACES/d' org.eclipse.ui.ide.prefs
> org.eclipse.ui.ide.prefs.fixed
&& mv org.eclipse.ui.ide.prefs.fixed org.eclipse.ui.ide.prefs

I usually (heart) Eclipse, but sometimes I just want to smack it upside its virtual head. One of those times is when it's starting up and I change focus to some other app and start typing something and Eclipse at some point grabs focus and inserts whatever I thought I was typing somewhere else and prepends it to its "which workspace do you want to use?" dialog and promptly creates a new workspace with a name of whatever nonsense text ended up in the dialog box. You know?

So I now have this little bit of bash magic saved as zapEclipseWorkspaceSelection.sh in my home directory. The downside is that it zaps all of your prior workspace selections, not just the smack-Eclipse-upside-the-head ones. You could maybe modify it to, say, ask for input on what invalid workspace names it should delete. Not me, man. Subtlety is not one of my vices.

Friday, June 20, 2008

HOWTO: Display a Custom Boot Message for Your VMWare Appliance

So I'm building a VMWare appliance for Stratavia's Data Palette data center automation application, and I want it to be like all the other cool appliances that print out some system-specific configuration information (e.g., IP address) when it finishes booting. This is useful for when, say, your appliance runs a webapp via an HTTP server like Apache or Mongrel or Tomcat and you want to tell the user where to point his browser to see it in action.

I happen to be using the latest Ubuntu JEOS as the base OS for this appliance. As such, in order to hook in to the boot process, I am adding my changes to the /etc/rc.local file.

(Author's Note: The exact location and name of this file vary -- sometimes wildly -- between Linuxen. Some flavors use /etc/rc.d/rc.local. Gentoo uses /etc/conf.d/local.start. I paraphrase the immortal Daffy Duck in "The Scarlet Pumpernickel": "Fancy, thy name is Linux. To coin a phrase.")

Let's say you want your user to visit http://[whatever the IP address ends up being] following bootup to get the virtual ball rolling. But you don't know what that IP address will be when you bundle your appliance; it's going to be assigned dynamically at bootup (as it should be). No problema. Simply write a bit of script to scrape the IP address in your Linux flavor's version of rc.local, thusly (Note: The following bit of awesome is directly ripped off from the rc.local file of the MindTouch Deki Wiki appliance):
IP=`ifconfig eth0 | grep "inet addr" | awk -F ' ' '{print $2}' 
| awk -F ':' '{print $2}'`
If you're Richard Stallman or some other Unix guru and you already know what the heck all this does, you can just smile smugly and skip the next few paragraphs. For the rest of us:

ifconfig eth0 -- Run the system command ifconfig to print out the general networking information for this box (specifically, the first ethernet interface), and send ("pipe") its output to the grep command. The output for ifconfig eth0 will look something like this:

eth0      Link encap:Ethernet HWaddr 00:0c:29:2d:f7:73
inet addr: Bcast: Mask:
inet6 addr: fe80::20c:29ff:fe2d:f773/64 Scope:Link
[et cetera]

There are several more lines, but all we care about is the second line. The next command in the chain, grep "init addr", will filter out all the stuff we don't want, leaving us with just the second line. This is then fed to the first of two awk scripts.

The first awk script uses a field separator of "space" (-F ' '); this splits the inet addr line into its constituent "words", like "inet" and "addr:". We just want the "addr:" word, so we print it as the output of the first awk script and send it to the second ({print $2}).

The second awk script splits its input using the colon as its field separator (-F ':') and prints the second word, which is -- tada! -- the IP address of the virtual machine. Whew.

The Rubyistas reading this blog (assuming I have any left) may have downloaded Ezra Zygmuntowicz's way-cool EngineYard Express VMWare image. Its bootup a little more involved, asking for input from the user on initial boot, and displaying several bits of information after every boot thereafter, such as the randomly-generated root and express user passwords. EY Express is running on Gentoo, so its startup hook is in /etc/conf.d/local.start.

EY being EY, they delegate all the heavy lifting to Ruby via some custom Ruby Gems: ey_reporter, config_system, and system. You have to do some serious filesystem spelunking to get there, but you can find the Ruby code that figures out the IP address (the equivalent of the bash script above) in

Monday, June 09, 2008

WWDC Keynote 2008: Are You Kidding Me?

iPhone and the .Mac replacement: About two full hours.

Next-gen Mac OS (10.6 -- "Snow Leopard"): About 10 seconds (a brief announcement that it's being discussed in an afternoon session with Bertrand Serlet).

New Mac hardware (e.g., the rumored Mac tablet): 0 seconds.

Mac hardware updates (e.g., the rumored laptop redesign/s): 0 seconds.

"One-More-Thing": 0 seconds.

I'm just waiting for this announcement from Cupertino:
Apple Inc. (formerly-and-clearly-no-longer Apple Computer Inc.) proudly announces the obliteration of any computer-related product from its catalog. Going forward, the laptop computer formerly known as the "MacBook Air" will be known as the "iPhone Maxi"*. And the segment-dominating laptop computers formerly known as the "MacBook" and "MacBook Pro" will be renamed the "iPhone Big-n-Bulky"* and "iPhone Bigger-n-Bulkier"*.

*iPhone cell phone functionality not included.

Wednesday, May 21, 2008

[Mac] pbcopy == Brilliant

For Mac users only (as far as I know):
cat filename | pbcopy
This bit of magic, as I just discovered, will copy the contents of the cat-ed file to the clipboard, for easy pasting wherever you need to paste it.

Macs. Rule.

Sunday, May 11, 2008

[OT] Out of the Mouths of Babes...

I promise I'm not going to turn into one of those bloggers who turns his blog into a blog about blogging every precious blogging word that comes out of his three-year-old son's mouth. But I'm submitting this to the Interbits in the hopes that some day when I'm old and grey and he's graduating from high school I'll be to retrieve it and *really* get some peoples' eyes rolling.

So we're celebrating Mother's Day and my wife gets to the card that "he" gave her. It's got a Winnie the Pooh theme, with a typical "you're the best mommy ever" verse. Inside is a picture of Kanga (also a mommy) giving Roo (also a little boy) an affectionate hug. So Angela points to the picture and says, "Look, Alex, it's me and you!". And he looks at her with his eyes wide, then he looks at the picture again, and says in a tone that implies that he's a little concerned about how she's not keeping current with her medication, "Yeeeaaahhhh........and we've turned into kangaroos!"

Friday, May 09, 2008

The Java Process That Ate My MacBook Pro

Gotta love the Phenomenal Cosmic Power of virtual memory (the next-to-last column in the following ActivityMonitor screen capture):

Thursday, May 08, 2008

Debugging a Remote Java VM with Eclipse

I (heart) the internet. Why? Well, among other reasons, I ran across this blog post today, which totally saved me a good several hours of frustration and swearing whilst tracking down a thorny problem.

You see, at my day job, I help to develop this webapp that points to a number of Java VMs, running in various combinations of in-Eclipse/not-in-Eclipse. The not-in-Eclipse bits are not run in Eclipse for a reason (read: "I don't care to jump through the hoops necessary to force them to."); however, lamentably, sometimes I get to (read: "have no choice but to") debug those bits too. And so, on the advice of the aforementioned blog post, I added these options to my startup scripts for the to-be-remotely-debugged VMs:
-Xdebug -Xrunjdwp:transport=dt_socket,address=8001,server=y,suspend=n
did some Eclipse magic ('Run | Open Debug Dialog... | (right-click) Remote Java Application | New | (fill in the details)') to point my debugger at the appropriate host and port, and I was off to the races.

The moral of the story: some days you just can get rid of a bomb.

(Author's Note: Bonus points to any commenters who can identify that seriously obscure reference!)

Tuesday, April 29, 2008

In Which I Reconnect With Ruby Just in Time to Finish My Master's Degree

The fates have conspired to force me to end my graduate school career with a bang. Fortunately, the bang is not the sound of my head exploding, as I feared it would be at the beginning of this semester. I'm taking two classes -- Theory of Complexity (about P vs. NP, BPP, #P, complexity of quantum computing...you know the drill; if you don't know the drill, try The Complexity Petting Zoo for an introduction) and Applied Graph Theory. Each is fascinating in its own right, but the graph theory class has really made an impression on me. So much so that I think if I'd taken it earlier on, I probably would have been tempted to do a thesis in that area. As it is, I'm stuck with my lame default choice of the "coursework-only" option for the Master's degree I'll be finishing come mid-May (the 17th, just in case anyone wants to send a present).

However, to my credit, I did manage to complete a significant semester-long project in graph theory, using Ruby as the implementation language. Why Ruby, and not Java (which I use professionally right now) or Scala, or any of the other possibilities I blather about on this blog?

Well, if you're a seasoned Ruby user you'll know why -- there's not much else (that I'm accustomed to) that's suited to the kind of rapid development/iterability I needed to get this thing done on time. My primary concerns throughout were a) to be able to complete the implementation with enough time left over to write up my results and prepare my in-class presentation, and 2) see concern a) above. Sure, Java's static typing or Scala's functional orientation might have given me some (nominally) safer code, but here, speed of development was of the essence. Advantage: Ruby.

The actual project? It's an implementation of an algorithm due to Hermann Stamm-Wilbrandt of the University of Bonn (Google is your friend...) to draw a maximal planar graph in linear time. Actually, the intent of the core algorithm is to "embed", not "draw" the graph; although I also implemented an optional enhancement to assign x-y coordinates to the vertices of the embedded graph for drawing purposes. Using Ruby, I was able to implement the entire project in less than 500 lines -- including blank lines, comments, debug, and other cruft -- of gloriously unoptimized, un-statically-typed, un-refactored, un-IDE'd-to-within-an-inch-of-its-life Ruby code.

I shudder to think what the LOC count would have been for Java.

Even in Ruby, the bulk of the code was either utilitarian in nature (e.g., a Line class and a Triangle class to help with the geometry of deciding where vertices should lie in the plane; some vector math for seeing if two points are on the same side of a line), or was wrapped up in simple one-to-two-liner convenience methods to support the main objective. This stuff accounted for about 120 lines. And the <500 lines of code also includes my from-scratch graph data structure (typically of the adjacency list variety), along with about 35 lines of code to emit the output in displayable format. The guts of the actual implementation of Stamm-Wilbrandt's embedding algorithm took about 130 lines of Ruby code (including blanks and comments), plus another 70 or so to handle a complicated special case of the optional x-y coordinate assignment.

My only regret is that I don't know Python well enough to have done the entire implementation in that language. I say that primarily because I used the totally awesome NodeBox as my drawing solution. NodeBox is written using PyObjC (Mac only -- sorry Windows/*n[i|u]x users!), and uses Python as its scripting language. My Ruby implementation actually emits a Python script which I then open with NodeBox to draw the final graph. If it were implemented in Python, then it could just be a NodeBox library.

The Good News: Now I have an excellent excuse to learn Python...

Thursday, February 07, 2008

IE Misbehaving? Fix It With Prototype!

Disclaimer: Since I specifically make reference to where I work in this post, I thought I should also specifically make reference to the fact that on this blog in general, and in this post in particular, I do not speak for my company in any way shape or form. My opinions are mine. Mine, mine, mine! If my company wants to express its opinions, it can get its own damn blog!

So at my day job we're converting the front end of our product from a Java thick client to a Struts 2 / JSP / several-other-buzzwords webapp. We officially support three browsers (in no particular order other than my blatant preference): Firefox, Safari, and Internet Explorer. We're using a fair amount of Ajax via Prototype and Scriptaculous. Again, no big surprise.

One of the problems we've encountered with our Ajax stuff is that anything we return from a normal Ajax call is subject to caching by the browser. Now I know the standard tricks to defeat caching are to a) submit the request as a POST; and 2) submit as a GET, but append a random string (e.g., a timestamp) to the request string to force the browser to fail on the cache lookup.

Unfortunately, being the curmudgeonly programmer and language maven that I am, I object to both of these approaches. Sometimes (most times) GET is the proper verb to use for my request; it's not changing state on the server, just retrieving it. POST should be used for changing state. The random string hack is just that -- a hack. If the browser is going to cache the results of a single request, it's probably going to cache the result of each "unique" request we create by tacking on this otherwise-irrelevant snippet of "data". I don't want all that unnecessary cruft in my customers' caches if I can help it.

There must be a better way.

Fortunately, there is a better way as of HTTP 1.1, in the form of the Cache-Control response header. See Section 14.9 of the HTTP 1.1 spec for all the gory details. Suffice it to say, including a response header of Cache-Control: no-cache with all of our Ajax responses worked to defeat caching of our Ajax-GET snippets.

Except on IE.

Are you surprised? I was, but only because Cache-Control: no-cache actually works on IE, to a point. So it wasn't obvious at first that IE was screwing up. Fortunately, we have the world's best quality engineering team, so they caught the problem when we lowly developers weren't seeing it.

Long story short: it turns out that (in our application at least; YMMV) the Cache-Control: no-cache response header actually works to prohibit caching in IE. Until the response is > ~8K in size. At which point IE caches it anyway. Which leads to all kinds of fun "but I saved my edits, I know I did" debates between QE and development when the browser returns the cached results instead of the latest and greatest.

This is where Prototype comes in. You see, Prototype already has a set of headers it adds to every Ajax request submitted through it. For example, it sets the header X-Requested-With to XMLHttpRequest. We use this in our app to distinguish between Ajax GETs and non-Ajax (NAjax?) GETs. Comes in handy sometimes. (Note: See Prototype's source file prototype.js, specifically the Ajax.Request.setRequestHeaders() function for the details on this; ~ line 1241 in Prototype

So the trick is to get Prototype to include another header with its Ajax requests: If-Modified-Since. Set If-Modified-Since to some datetime in the past, and the browser should always go to the server instead of the (expired) cache. I could do this by hacking my prototype.js file to include this new header in Ajax.Request.setRequestHeaders(), but then I'd have to remember to re-hack every time I upgrade Prototype. Not fun. I could also submit it as a patch, I suppose, but I don't know that everyone needs this behavior by default.

Enter The Next Best Thing: Functional Programming! Prototype has a wonderful FP-ish function called wrap(), which is defined on Element.Methods (prototype.js, ~ line 1652 in wrap() lets me extend the existing setRequestHeaders() function from the outside thusly:
Ajax.Request.prototype.setRequestHeaders =
function(original) {
// do my stuff first; e.g., set 'If-Modified-Since'
original() // then call the original version
In case this isn't clear, I'm replacing the original definition of the setRequestHeaders() function with a new (anonymous) function that does my stuff first, then does whatever the original was defined to do. To Java programmers circa 2004, this looks kind of like "before advice" in Aspect-Oriented Programming. Without the new-language-compiler-tools-runtime-stack baggage. To functional programming types, it looks like function composition. Without the lambdas and general my-thesis-is-bigger-than-yours snootiness.

To me it looks like a pretty nifty hack, one that plays by everyone's rules.

Well. Except IE's.

But I'm okay with that.

Friday, February 01, 2008

From the Bonehead File: Pragmatic Programmers Books And "Save As PDF"

I (heart) my MacBook Pro.

One of the main reasons I (heart) my MacBook Pro is Mac OS X's built-in "Print... | PDF | Save as PDF..." feature. I've been reading a lot of papers from various online sources recently for my schoolwork, and I love being able to "print" them to a file on my local filesystem for offline reading. HTML, postscript, whatever format you care to publish your paper in, if I can browse it, I can PDF it.

Unfortunately, though, I've gotten so much in the habit of printing to PDF that I've unwittingly given away some of the functionality of some of my documents.

You see, I buy a lot of PDF versions of books from the excellent Pragmatic Programmers catalog. Their PDFs are, without serious exception, among the most informative resources I have at my disposal. But because my browser renders them, and because I'm so used to "printing" my PDFs, I've gotten into the habit of browsing to them and saving them as PDF from the browser. Which, of course, totally wrecks the internal (and external) hyperlinks they have built into the books.


The good news is, the Prags allow one to regenerate purchased PDFs at will (Note: sorry for the spike in regeneration requests this morning, guys! Give the gerbils an extra pellet or two for me.), so I'm back in business, pragmatic-hyperlink-wise.

Saturday, January 19, 2008

Fox/FXRuby/Leopard, Part the Second

As a follow-on to my previous post, I discovered that there's a little more work to be done to actually be able to use my freshly installed FXRuby. I tried using the listexample.rb program from the aforementioned Pragmatic Programmers book, and promptly found that the 'fox16' library couldn't be required. Grumble.

Fortunately, this post on the fxruby-users mailing list (again, courtesy of Lyle Johnson, lead programmer of FXRuby and author of the PragBook) was able to get me going:
a workaround is to use the "gem env" command to identify your Gems installation directory (usually something like /usr/local/lib/ruby/gems/1.8) and switch to the "gems/fxruby-[version]/ext/fox16" directory underneath that:
cd /usr/local/lib/ruby/gems/1.8/gems/fxruby-1.6.0/ext/fox16
and then type:
Note: Since RubyGems comes installed with Leopard, your gem installation directory is more likely to be something like "/Library/Ruby/Gems/1.8", at least if you did a fresh install as I did. YMMV.

But here I encountered the same architecture problem I referenced in my previous post. This time I ended up editing the Makefile and deleting all references to "-arch ppc"; setting the ARCHFLAGS environment variable before running make didn't cut it for me.

Once you've re-made the gem, you should be able to verify your installation in irb:
>> require 'fox16'
=> true
Two final caveats:
  • I had to modify the PragExample with the line "require 'rubygems'" at the top of the file, right before the "require 'fox16'" line. This was because I haven't yet set my RUBYOPT environment variable in Leopard to require rubygems automatically for me.
  • The example program worked fine for me after all this (try holding the shift button to do multiple selections), until I quit, at which point I got:
    X Fatal Error.
    Abort trap
So this FXRuby thing is not an exact science yet. Sigh.

Installing Fox and FXRuby on Mac OS X Leopard (Intel)

I'm planning to start playing with some of the GUI toolkits available for Ruby, and I know there's a Pragmatic Programmers book (currently in beta) for FXRuby, so I thought I'd get the fixin's in place to be able to play with it. Unfortunately, the standard sudo gem install fxruby alone didn't get the job done for me. Even using MacPorts to install Fox first (sudo port install fox) let me down. Here's what (eventually) did work:

  • Download and Install Fox:

    • Download the source. I picked the current stable version from the "Downloads" section, "Linux/Unix" subsection.

    • Set the LDFLAGS environment variable as described in Lyle Johnson's (author of FXRuby and the book) very helpful post:
      export LDFLAGS="-dylib_file \
      Note: There's a typo in Lyle's instructions that will trip you up if you just cut and paste from there; there should be a space between the "-dylib_file" and the first "/System/Library/...". And, in case you're cutting and pasting from here, there should be no space between the colon and the second "/System/Library/...".

    • cd to the expanded Fox source folder.

    • ./configure, with whatever options you would normally use. I didn't specify anything in particular.

    • sudo make install, again with your typical options. The vanilla command worked for me.

  • Install the FXRuby gem:

    • sudo env ARCHFLAGS="-arch i386" gem install fxruby

    • The extra bits about the ARCHFLAGS are a workaround for a problem in ld (and/or lipo) trying to build this gem for both PPC and Intel architectures. As you might guess, this will work for you only if you're on an Intel Mac.

    • From the Credit-Where-Credit-Is-Due department: I cribbed the "env ARCHFLAGS" trick from the most excellent Hivelogic website, specifically this post.

  • Write a cool GUI! (Haven't gotten that far on this item yet...)

Oh, and I'll be looking at Shoes too. No weird Unix/Linux project dependencies for that one, thank goodness. Just a regular .dmg to download and install. Nice.

Thursday, January 17, 2008

Required Reading: The Role of the Study of Programming Languages...

Via the always excellent Patrick Logan -- Daniel Friedman: The Role of the Study of Programming Languages in the Education of a Programmer.

Some key quotes:

  • On the lack of tail call support in Java:
    Guy Steele...was promised back in 1997 that this flaw would be fixed. Here it is 2001 and there is still no resolution of this problem on the horizon.
    Emphasis mine. The more things change...

  • On Friedman's own background and educational goals:
    Later, I wanted to be able to implement a language per week.
    Followed later by:
    I want the student to be able to implement (perhaps crudely) every language that they study...
    Now that's Thinking Different.

  • Friedman quoting Jonathan Sobel, a former student who successfully used (uses?) these concepts in practice:
    Efficiency comes from elegant solutions, not optimized programs. Optimization is just a few correctness-preserving transformations away.

  • Finally, and perhaps my favorite, Patrick Logan's cogent take:
    Probably programming in C itself (or Java or Scala) is a kind of premature optimization.
WARNING: Refers to -- and poses some examples in -- the lambda calculus. Implementations in Scheme. Don't let either of those put you off, though. I don't understand every line of code (yet), but I've seen enough to be inspired to figure it out.

Challenge yourself.

Friday, January 04, 2008

Java Generics Broken? We Report, You Decide.

Since I've been taken to task in the past for my cogent observations of Java's, um, shall we say "unintuitive" behavior, particularly in the era of generics and autoboxing, I'm just going to put this one out there without making any (public (explicit)) value judgments.

So it seems that if you define a method thusly (note: requires Java 5 ("Gangly Geek") or better greater having a numerically higher version number):
public void doSomethingGenerically(Collection<Supertype>){...}
and you attempt to call it thusly:
List<SubtypeOfSupertype> bogus = new ArrayList<SubtypeOfSupertype>();
you get a compiler error saying you can't call that method with those arguments.

So my question here is: why the heck not?

Inheritance 101: a List isa Collection, right? A SubtypeOfSupertype isa Supertype, right? So why am I being told that an instance of type List<SubtypeOfSupertype> isn'ta Collection<Supertype>?

Paging Dr. Liskov...