Operator Overloading Stupidity

I’m back in .NET land after living, pretty much exclusively, for the last two years in Java-and-Ruby land and while I generally like C#, I ran across something today that is really stupid. It involves operator overloading. While I actually like operator overloading and think it can be a powerful thing, the implementation of one facet of it in C# is just wrong. The problem is that they force you to override certain operators in pairs instead of defining them in terms of each other or in terms of a single method. In other words, if I define == to check equality then I also have to define != to check inequality! Why in the world should I have to do that since inequality is the opposite of equality and can be defined in terms of the equality operator? The same holds true for < & > and <= & >=. What you end up with is something like this:

   1  public class Foo   2  {   3      private int val;   4   5      public Foo(int val)   6      {   7          this.val = val;   8      }   9  10      public static bool operator==(Foo lhs, Foo rhs)  11      {  12          return lhs.val == rhs.val;  13      }  14  15      public static bool operator!=(Foo lhs, Foo rhs)  16      {  17          return ! (lhs == rhs);  18      }  19  }  

where the != operator just negates a call to ==. You would repeat this process for the other two pairs if you wanted to provide them. (And yes, I know if you provide your own == then you have to also provide a GetHashCode method.) There is no reason that the developer should have to do anything more than provide a comparison operator and then let the system define the other methods in terms of that comparison…

And that’s exactly what Ruby does. If you include the module called “Comparable” in your class, and provide a comparison method called (called the “spaceship method” because that’s what it looks like) then you get ==, !=, <, and >= for free! That’s right, by defining one method you get six defined in terms of it automatically. Now that’s how it should be done! Which results in code like this:

   1  class Foo   2      include Comparable  # Here's where the majic starts   3   4      attr_accessor :val   5   6      def initialize(val)   7          self.val = val   8      end   9  10      # comparison method; all others defined in terms of this  11      def (other)  12          val  other.val  13      end  14  end  

Obviously these are both trivial classes but I think you get the point. There is no reason why you should have to define more than one method to get all the normal comparisons that you would expect in a language.

Word Annoys Me

I spent quit a bit of time today updating my resume, in Microsoft Word. What an absolute pain in the keester! I spent so much time just trying to make the stupid bullet points line up it wasn’t even remotely funny. I swear I could have done it in far less time in LaTeX except for the fact that I needed to give it to people who only have Word. For public consumption I just may convert it to LaTeX and be done with it. Does anyone know of a free program to convert a .dvi file into a Word document? That would be sweet. I can do PDF with the built in DVI converters, but not Word, as far as I know.

New “Reading Room” Blosxom Plugin

I’ve just released a new plugin for Blosxom called Reading_Room. It is what I used to produce the “Reading Room” box at the bottom of the page on the left.

The idea was to automate the creation of these boxes so I could do it for books, records, films, etc. without having to write HTML each time. What I ended up with is a data file + template setup where you put the important information in a data file that you associate with a template. At page load time the data are read from the file, replacing the appropriate bits in the template for each record, and the output shows up where you specify on your page. This is an example data file called reading.dat:

  reading  Author|Title|ISBN|Rank  J.R.R. Tolkien|The Lord of the Rings|0618260587|5  Fred Rogers|The World According to Mr. Rogers|1401301061|4  Richard Condon|The Manchurain Candidate|1568582706|2  Michael Crichton|Prey|0061015725|4  Andrew Burgess|A Clockwork Orange|0393312836|-1  

The first line is the name of the template to use (it will have .tpl appended to its name). The second line lists the columns that will make up the following lines, in this case separated by a pipe. Each additional line is one book, giving the author, title, the ISBN and a ranking, which will be converted to stars. A 0 ranking will be replaced with “Stinks!” and a -1 will be replaced with “Rating Pending.” Both of these are configurable, as is the graphic to use for the stars.

The template file, called reading.tpl, looks like this:

  
$reading_room::Author
$reading_room::Title
$reading_room::Rank

And you can see that in the template each column’s name shows up, spelled and capitalized exactly as it is in the data file.

A variable with the same name as the data file, without the .dat extension, will be created in the $reading_room package, so to get our “reading” list, we would add $reading_room::reading somewhere in our blosxom flavour files, probably in head.html. Similarly if we had a data file called “movies”, then this HTML would be in the $reading_room::movies variable.

I don’t know if anyone other than me will find this useful or amusing, but if you are game to give it a go, you can download it here. The archive comes with the plugin itself, reading.dat and reading.tpl as examples, and star.gif to get you started. Please let me know if you find it useful and, more importantly, if you find bugs or have problems with it.

Update: I’ve now packaged the distro up as a zip file for those of you who may be having problems with the tarball. Get it here.

Lego Mindstorms Are Very Cool

I got some cash for Christmas, bought a Lego Mindstorms robotics kit and It arrived yesterday via UPS truck. Ooo boy, this thing is cool. So far I’ve built the starter robot (see the photos; click to get larger view) and gone through the tutorials. The RCX ‘language’ and the development environment is very well done, if a bit too 4GL for my tastes. I will say that this environment is going to be great for my wonderful Thomas, who is five years old, and terribly excited about the robot. To program the robot you drag program blocks around that look like Lego blocks and connect them together. You can do quite a bit without any reading, which is good for a youngster.

For me, though, I want more. So I’ve already installed a bunch of stuff that should give me more. I’ve installed and played a bit with NQC (Not Quite C) which is a C-like language. I’ve installed two IDEs for NQC; one called NQCEdit, and the other called Bricx Command Center. Both are fairly nice if a bit crude. And of course VIm groks NQC source code, so I can always use it and the command line compiler. I’ve installed a Java API called RCXJava and Shashank Date’s API written in Ruby. (His powerpoint slides from RubyConf2003 are available here.) Needless to say, I’m set for a while now with stuff to do…

SSH Util Ruby Script

OpenSSH, that ships with Cygwin has a nice utility called ssh-agent. This program is a daemon that will hold on to your keys so that hosts you are authorized to log on to will not continually ask for your password. This is especially useful when working with CVS repositories over SSH. When you run ssh-agent, it spits out text that should be evaluated to set two environment variables that you will need in order to run ssh-add, to actually add your keys to it. That output looks like this:

  
SSH_AUTH_SOCK=/tmp/ssh-mjKjm512/agent.512; 
export SSH_AUTH_SOCK;  
SSH_AGENT_PID=1600; 
export SSH_AGENT_PID;  
echo Agent pid 1600;

On a Unix system, it’s easy to capture the output of ssh-agent and evaluate it, but under the ‘command shell’ that ships with Windows systems, which is so pathetically crippled that my old Commodore 64’s BASIC-based shell is looking pretty good, you can’t do that.

So what are those poor saps, myself included, who are using Windows systems to do? Ruby to the rescue. I wrote a simple script that executes ssh-agent, capturing the output, massaging it a little, and then creating a batch file that I can run to set the necessary variables. Simply redirecting the output to a batch file won’t work because there are some Unix-isms, such as exporting the variables, that don’t work on Windows. So, here’s the script:

#!ruby   
lines = %x{ssh-agent}   
File.open("c:/tmp/sde.bat", "w") do |file|   
  lines.each do |line|   
    chunks = line.chomp.split ';'   
    if chunks[0] =~ /^SSH/  
      file.puts "SET #{chunks[0]}"  
    end  
  end  
end  

You can see that the script sends the captured and massaged output to a batch file called “sde.bat” located in C:/tmp. You can change both of these to suit your preference. Once the script runs, I simply execute the generated batch file and then run ssh-add. The nice thing about the generated batch file is that it lingers until the next time I run the Ruby script. Thus as I open new console Windows I can re-run it to get the environment variables set properly in each one.

New Version of My Google Blosxom Plugin

I’ve finally gotten around to updating my Google plugin for Blosxom that’s been languishing for several months now. No longer must you use the cheesy ‘KW:’ style keywords; I now use the Meta plugin, so you can add a meta-google_keywords: line in your meta area and get the same effect. I’ve left the old style support in, so if you’ve been using it, you don’t have to go through and change all your stories to the new format.

Thus, the old style was:

and the new-and-improved style is:

meta-google_keywords: comment spam

One caveat: make certain that the meta plugin runs before this one or your google links will show up one story too late. That took a while to track down. I renamed my meta plugin to 00meta and now all is well.

Get it here and please let me know if you have problems with it.

VirtualPC Spanks The Monkey’s Hiney

Today I was working from home when my friend got peeved that I kept dropping off of IM to VPN in to the office, because the Nortel VPN client shuts down all non-VPN network routes on your computer while you are connected. It’s annoying, but what are you going to do? The answer is VirtualPC, formerly from Connectix, now from Microsoft. I installed the 45 day trial version, loaded Windows98 (blech!) on to it, then the VPN client, Microsoft LookOut and GAIM. Now I can fire up the virtual PC and stay connected to the office all day through the VPN with access to our Exchange server and the Jabber server that I maintain for the team. This is seriously cool since it leaves me free to get to the Internet while connected to the VPN, which I couldn’t do before. I don’t know how much Microsoft is going to charge for it, but whatever it is, I’m willing to pay it. This is going to make my life a whole lot easier.

But wait! There’s more! At this precise moment I am installing Red Hat Linux 9 on another virtual machine. This will save me from needing to buy another computer just for Linux testing of my JRuby work.

Mixer Remixed

After reading several threads about the text scrmabler and various implementations, I revised my Ruby version and it’s now 21 lines shorter and much more Ruby-like. It makes far less of an attempt to deal with punctuation, but I think that’s OK. This is just a lark, after all.

  1  class Mixer  2      private  3      def randomize(str)  4          return str if str.length < 4  5  6          str =~ /B.*B/  7          first = $`  8          last = $'  9          first + ($&.split(//).sort_by {rand}.join) + last 10      end 11 12      public 13      def mix_file(filename) 14          lines = IO.readlines(filename) 15 16          mix_lines(lines) 17      end 18 19      def mix_string(str) 20          mix_lines(str.split).join(" ") 21      end 22 23      def mix_lines(lines) 24          lines.collect! do |line| 25              words = Array.new 26 27              line.split(/W/).each do |word| 28                  words << randomize(word) 29              end 30 31              words.join(" ") 32          end 33      end 34  end 

By Popular Demand, I Give You… Mixer!

“Popular demand,” yeah… right… That’s the ticket. Anyway, I saw this blog entry by Jamie this morning which caused me to write a Ruby program to mix up the letters of words, leaving the first and last letter as they were. I started out with a simple script, then I added better punctuation support, then I converted it to a class, then I wrote unit tests to run it. Anyway, somebody wanted to see it, so here it is. Is it great code? Probably not. Do I care? Not really.

  1  class Mixer  2      private  3      def randomize(str)  4          if str.length < 4  5              return str  6          end  7  8          letters = str.split(//)  9 10          first = letters[0] 11          mid = letters[1..(letters.length - 2)] 12          last = letters[letters.length - 1] 13 14          new_letters = "" 15 16          while mid && mid.length > 0 17              len = mid.length 18              r = rand(len) 19              new_letters << mid.delete_at(r) 20          end 21 22          first + new_letters + last 23      end 24 25      public 26      def mix_file(filename) 27          lines = IO.readlines(filename) 28 29          mix_lines(lines) 30      end 31 32      def mix_string(str) 33          new_str = "" 34 35          mix_lines(str.split).each do |line| 36              new_str << line 37          end 38 39          new_str 40      end 41 42      def mix_lines(lines) 43          lines.collect! do |line| 44              new_line = "" 45 46              line.split(/s+|,|.|!|(|)|"|'/).each do |word| 47                  new_line << randomize(word) << " " 48              end 49 50              new_line 51          end 52 53          lines 54      end 55  end 

And the unit tests, which don’t actually test anything.

  1  require 'test/unit'  2  require 'mix'  3  4  class MixTest < Test::Unit::TestCase  5      def setup()  6          @mixer = Mixer.new  7      end  8  9      def test_word() 10          x = @mixer.mix_string("testing") 11          puts x 12          assert_not_equal("testing", x, "String not randomized") 13      end 14 15      def test_string() 16          x = @mixer.mix_string("this is a humongous test, dangit") 17          puts x 18      end 19 20      def test_file() 21          article = @mixer.mix_file("testfile.txt") 22          #puts article 23      end 24  end 

I’m sure someone will find this useful… Again, “yeah, right.” Ah well, it was a mildly amusing diversion…

I’m Presenting at NFJS: Atlanta

If anyone will be in or around Atlanta, GA, October 24 – 26, you should think about attending the Atlanta Java Software Symposium which is part of the No Fluff, Just Stuff symposium series. I’ll be presenting a session entitled “Scripting on the JVM” in which I will present various scripting languages like Python and Ruby running on top of the Java virtual machine and trying to explain why that’s cool. The session abstract is located on the sessions listing page; I’m about 1/3 of the way down the page.

I attended this symposium last year and had an excellent experience. The ratio of useful information to vendor-specific sales-weasel crap was extremely high, which is a good thing. I wrote about it in the February Java Developer’s Journal if you want to read about it. There is also a review of one of the other symposia in the series in the current issue.

I’m really looking forward to presenting at it this year’s symposium.