Unintelligible

Sunday, March 8, 2009

Rubyists and Photographers, slight return

A few months ago, I posted an entry on how Rubyists sometimes get distracted by the power of the language, preferring lengthy debates on programming aesthetics to actually writing (efficient) code. I compared this to photography, in which aspiring photographers sometimes get lost in technical discussions rather than focussing on the work they produce. Then I came across this quote, which concisely expresses in 3 sentences what I hadn’t managed in an entire post:

Every medium suffers from its own particular handicap. Photography’s greatest handicap is the ease with which the medium as such can be learned. As a result, too many budding neophytes learn to speak the language too long before they have anything to say.

(Will Connell, 1949, via Brendan MacRae, via Tim Bray)

The point of my original post was that the same may apply to Ruby; the language’s power and accessibility makes everything seem so easy, that it becomes tempting to engage in discussions about the finer points of programming aesthetics rather than focussing what one has to say (i.e. the problems one chooses to solve.)

posted by Nick at 1:15 pm - filed in ruby  

Monday, February 2, 2009

Mona Lisa image evolution in Ruby (JRuby)

Like several other people, I was fascinated by Roger Alsing’s post shortly before Christmas describing his program to evolve an image look like Leonardo’s Mona Lisa, using only semi-transparent polygons. This uses genetic programming (or perhaps more accurately, simulated annealing, a Monte Carlo method) to evolve an image, comparing each evolved image to its parent and deciding whether it is closer to the target image; if it is closer to the target, the image is retained and then evolved further.

Since Roger released his source code, there have been several other implementations in different languages, such as Javascript and Clojure. I thought that converting the program to another language would be an excellent way to understand how it works; so, I converted it to Ruby (actually JRuby, as Swing is used for drawing the images and the user interface).

I’ve uploaded the code to GitHub; my implementation is pretty much a straight port of Roger Alsing’s original code though, and generally speaking it’s a little quick and dirty; I may eventually spend a little time tidying and/or optimising it, but as of yet it isn’t either elegant or fast.

This short clip shows the evolution of the selected candidates over 75000 generations (around four hours on my machine).

posted by Nick at 8:50 pm - filed in java, ruby  

Thursday, August 16, 2007

One line Ruby memoization

Memoization is a functional programming technique used to cache the result of expensive method calls for later re-use; this allows us to avoid repeatedly performing an expensive calculation when the result has already been calculated once. Today I stumbled accross an interesting method of achieving memoization in Javascript for nullary functions (i.e. functions taking no arguments); the author was re-defining the method called to perform the calculation to return the computed result, meaning the repeated invocations of the method would return the computed value once the initial calculation had been performed. This seemed like an elegant way to achieve result caching; I was curious to see if the same could be achieved with Ruby.

The standard method of result caching in Ruby might be:

class Cached
  def cached_method
    return @cache unless @cache.nil?
    puts 'computing expensive value'
    sleep(2)
    @cache= "hello world"
  end
end
 
c=Cached.new
10.times do
  puts 'result: ' + c.cached_method
end

Using memoization:

class Memoized
  def memoized_method
      #expensive computation goes here
      puts 'computing expensive value'
      sleep(2)
      cache="hello world"
      self.class.send(:define_method, :memoized_method, lambda{cache}).call
  end
end
 
m=Memoized.new
10.times do
  puts 'result: ' + m.memoized_method
end

Here, we are re-defining memoized_method within the function itself so that it returns the computed value once it has been invoked. Disappointingly though, this isn’t much of an improvement line-count wise - the result is slightly less readable too, mainly because define_method is private (which is why we need to use the self.class.send hack above). What about performance (over 50000 iterations)?

nick@unintelligible:~/Desktop$ ruby perf.rb
Rehearsal ---------------------------------------------
cached:    0.120000   0.020000   0.140000 (  2.135206)
memoised:  0.110000   0.020000   0.130000 (  2.139923)
------------------------------------ total: 0.270000sec
                    user     system      total        real
cached:    0.100000   0.040000   0.140000 (  0.134768)
memoised:  0.130000   0.020000   0.150000 (  0.144927)

Nope - it’s roughly equivalent (very slightly slower in fact, presumably due to the extra cost of routing the method through define_method). So, although memoization is definitely a useful technique, result caching yields is still more readable and slightly more performant for nullary functions in Ruby than this particular implementation.

posted by Nick at 1:09 pm - filed in ruby  

Friday, July 13, 2007

Rubyists and Photographers

I was browsing the net the other day, minding my own business, when I came across this:

https://giantrobots.thoughtbot.com/2007/5/1/coding-without-ifs

In summary, Jared Carroll is proposing to replace

def update_subscriptions
  Subscription.find(:all).each do |each|
    if each.expired?
      each.renew!
    else
      each.update!
    end
  end
end

with

def update_subscriptions
  subscriptions = Subscription.find :all
  expired = subscriptions.select {|each| each.expired?}
  expired.each {|each| each.renew!}
  active = subscriptions.reject {|each| each.expired?}
  active.each {|each| each.update!}
end

in the name of avoiding conditionals in Ruby. You’ll notice that the second version loops through the ’subscriptions’ array 3 times rather than one. In the comments (which span 9 A4 pages) follows a lengthy discussion on the aesthetics and validity of the design of the second solution. It struck me then that Ruby gives you power, a lot of power - perhaps, sometimes, too much power.

I’m reading Paul Graham’s Hackers and Painters at the moment, and continue with his “hacking is like a visual art” analogy, I’d like to propose the following: Ruby is to Java (or C#) what photography is to oil painting. As with all analogies, it has its limitations, but the logic is as follows:

  • creating an image using oil painting is long and hard
  • creating an image using photography is quick and easy
  • because creating an image is quicker with photography, the amount of time spent actually creating the image becomes a proportionally smaller part of the artistic process than it is with oil painting
  • as a result, the percentage of time spent on ’secondary’ considerations (lenses, film types, darkroom exposure techniques, filters, etc.) becomes a proportionally larger part of the artistic process

Most of the professional photographers I know actually spend little time thinking about the secondary considerations such as lenses, film types etc. - they seem to find something they like and stick with it, reviewing their choices only occasionally. However, some get tempted into spending a lot of time and energy debating the relative merits of different lenses, film types, darkroom exposure techniques etc. These items are still only a minor factor of a good picture; the most important element in a good picture is unarguably its content (in a studio picture, this could be the subject, angle, background, lighting, pose etc.)

The similarity here, I think, is that Ruby has empowered programmers to think about the lenses, film types etc. a lot more because taking a picture has just become so much easier. There is not doubt in my mind, however, that whether to use conditional logic or closures is a minor consideration compared to the main (and hardest to attain) aim of the hacker, which is the beauty of the resulting solution; as tempting as it may be to debate the best polarizing filter, debates about language constructs are only as valuable as their contribution to achieving that aim is (which in this case would probably be minor).

P.S. I’m not at all arguing that Jared Carroll or any of the commenters in his blog are bad programmers (most of them are probably more experienced and talented than I am), or that debating about lenses and cameras is pointless - it isn’t, but spending more time thinking about them than actually taking pictures is counter-productive for a photographer. I’m just reminding myself how easy it it to get sidetracked.

posted by Nick at 12:53 pm - filed in ruby  

Friday, June 1, 2007

Microsoft and Ruby

Martin Fowler’s post on Microsoft and Ruby reflects some of my recent thoughts on MS closely. As he points out, MS is a large company made up of individuals rather than single-minded giant; and as such, there are bound to be differences of opinion within the company as to the direction it should be taking, and how it should approach different situations.

My impressions is that there are two main currents within Microsoft at the moment: those who favour openness and dialogue, who show an understanding of developers’ concerns and who think that discussing these issues and their solutions openly will help Microsoft stay ahead of the pack; and those who seem more intent on responding to managers’ concerns, and who think that Microsoft’s innovations are precious IP and should be kept as far from potential competitors as possible.

Microsoft at the moment seems torn between these two currents, as the difficulties in the inception of Channel 9 (for example) illustrates. The problem for Ruby developers is to figure out which side is going to prevail; if the “open” side does, the result of collaboration with Microsoft could be a strong Ruby implementation on the Windows platform and possibly also good integration with MS’s own technologies, both of which would help further Ruby cause; if it doesn’t on the other hand, the result could be a lot of wasted time and effort which could have been spent more productively elsewhere, and possibly also a dilution of Ruby in a similar way that happened to Java with the MS Java Runtime and J#, which Ruby could take a while to recover from.

So, what to do from Ruby’s point of view? In the current situation, it’s hard to say; ideally, the best would probably be to wait for Microsoft to make its intentions clearer, which it could to by committing to implement a Ruby interpreter fully compatible with the MRI, by opening up the source code for the Iron Ruby implementation, or perhaps by issuing a Patent Non-Assertion Covenant on any Ruby-related technologies it develops. None of these may be realistic for Microsoft in the short term; efforts at openness are still relatively new at MS, and pushing through this type of measure internally probably takes a lot of time and determination. Perhaps the competition from Sun (one of MS’s traditional rivals) via JRuby combined with a better understanding of how Ruby could benefit MS could help move things forwards.

Update 4/7/2007: Martin Fowler’s post seems to have gotten those involved in Ruby implementations talking:
John Lam (IronRuby lead): Microsoft and IronRuby
Ola Bini (JRuby committer): There can be only one, a tale about Ruby, IronRuby, MS and whatnot
Charles O. Nutter (JRuby lead): A Response to Ola’s IronRuby Post

posted by Nick at 10:12 am - filed in ruby