ACTUAL Duck Typing Advantages!!

Yes, my friends, I have found what could be a true unique advantage to duck typing. I don’t know why this didn’t occur to me. Everyone else may already realize this, perhaps it’s been diced on ruby-talk already, but it’s just dawned on me. Singletons and duck typing.

Get it in your head: singletons and duck typing. See if you can figure it out. This is a concept that could be a central figure in the way we think as we scrawl out our Ruby.

Open-URI

I’m going to use the open-uri library as an example, because the discussion of this library on the ruby-core list is what made it click for me.

If you haven’t used open-uri, you can read about it in What’s Shiny and New. It’s a little library that allows you to open URIs (http, ftp) as if they were files.

 open( "http://www.whytheluckystiff.net/why.yml" ) do |f|
  feed = YAML::load( f )
 end

The discussion on ruby-core has revolved around adding a progress bar hook to the open-uri library. A recent syntax suggestion looks like this:

 progress = proc { |s| ... }
 open( "http://...", OpenURI::OptProgressProc => progress )

In the example, I’m passing in a proc through an options hash. This is common in many languages. Especially in Perl, you’ll see a hash of options follow the fixed parameters. It’s (sort of) a substite for named parameters.

The above code coats my eyes with sap. My vision could get fully encrusted by that syntax. No criticism to the authors of this code. This is a very common technique in Rubyville. And to its benefit, it can be easy to use.

But when you’re passing procs into hashes into methods, it starts to seem a bit thick.

Singletons and Duck Typing

Lately, I’ve been trying to solve problems with duck typing. Not because I think it’s the universal panacea, but because I’d like to see how far it can stretch. I’ve been sort of skeptical at time and for that I will assuredly pay.

I looked at this progress bar example and it occured to me, “This is a perfect situation for duck typing.” We want to change the behavior of OpenURI. We want it to quack periodically while the file is downloading, right? Why are we embuing behavior through an options hash?!

Behavior is defined by methods in Ruby. They are our stage directions. Procs are a building block of this, but they should exist within methods to perform finer, atomic actions. We shouldn’t be moving our instructions out of methods! Is this correct?

This example is going to start off a little rough. My previous examples used Kernel::open, which open-uri provides. I don’t have an answer for extending Kernel::open to become the ultimate URI/File/mayonaisse jar opener. I think Kernel::open should have it’s functionality limited. But I may address this later as the idea dissipates across the folds of my brain.

Instead, let’s imagine using the URI class, which can be instatiated, to solve our problem.

 uri = URI.parse( "http://whytheluckystiff.net/why.yml" )

We now have a URI object. What if we could just add a new singleton method for a progress bar?

 def uri.progress_bar( percent_done )
  puts "Yeah, we're at " + percent_done + "% now!" 
 end

The URI::progress_bar method would not be built into the URI class. It’s not a required part of processing the transmission. But the URI class could still use respond_to to check for it and use it if available.

So, the class could duck type in case singletons have the method available. Our completed example could be:

 uri = URI.parse( "http://whytheluckystiff.net/why.yml" )
 def uri.progress_bar( percent_done )
  puts "Yeah, we're at " + percent_done + "% now!" 
 end
 uri.open { |f| ... }

Singletons For Hashes

You could also use singletons in lieu of option hashes. This could solve the Kernel::open issue. It feels like a design pattern. Not sure which.

 opts = OpenUriOptions.new
 def opts.progress_bar( percent_done )
  puts "Yeah, we're at " + percent_done + "% now!" 
 end
 open( "http://whytheluckystiff.net/why.yml", opts )

In the Kernel::open code, you could check the ducky opts var:

 if opts.respond_to? :progress_bar
  opts.progress_bar( percent_done )
 end

You may say, well how does this differ from procs? Well, I think methods tend to be a lot more maintainable. If you came up with a robust class for progress bars, a fully featured extension to imaginary OpenUriOptions class, you could include slap the new class on RAA. It is encapsulated. It is reusable. We just don’t do everything in Ruby with procs.

I haven’t milked this idea fully yet. Help me with it. Send me your hybrid ideas and let’s flesh this out fully.

disoriented?

why the lucky stiff
is a fledgling freelance professor, one who will die young and make no lasting impression.

except there was that time when i vacuumed all of Greenland for them.

email? here.

Books:
  • Why's (Poignant) Guide to Ruby (Blixy Tees)

    Blogs:
  • quiet
  • Hackety Org
  • RedHanded COMPLETED!

    Stories:
  • The Bobby Wolves
  • Stunt Runner

    Comics:
  • Holy Bible: one, two, three, four, five, six, seven, eight, nine, ten, eleven, twelve, thirteen, fourteen, fifteen, sixteen
  • The Open Window: one, two, three, four, five, six, seven, eight, nine
  • Lost Children, Lost Children, Lost Children, See Such Feverish Castles: one


  • Incidents: (35) Adventure of the Apple's Mom (34) A Magic Milk (33) The Secret Sandwich (32) A Smart Curtsy (31) The Hand Which Fell Apart (30) Jentle & Pailey (29) The Grieving Boar (28) The Story Life Doesn't Explain (27) The Life Guy (26) The Jump Wanter (25) Kimothy's Mouth (24) Speaking Of Flutes (23) The Advisor (22) Wristwatches (21) The Queen-Sized (20) The Tandem Bicycle (19) The Little Piece of Cloth (18) Milk Powers (17) Javek and the Candle (16) The Skier (15) The Man Who Happened to Have Legs (14) The Man Who Happened to Reach Up (13) Duck Typing (12) The Incident (11) The End (10) Ghosts (9) The Man (8) Waking (7) Water (6) Birthstones (5) Ignored (4) The Berkowitz Manuevre (3) Regrets (2) Emptiness (1) The Milkman Who Couldn't Sleep

    Five-Minute Plays for Twins Who Don't Have Their Other Twin With Them and An Unlimited Supply of Animals: Octopus, Eagle, Swan, Otter

    Quatrains: 0.0, 0.1, 0.2, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5

    Hacking:
  • The Fully Upturned Bin
  • Seeing Metaclasses Clearly
  • What's Shiny and New in Ruby 1.8.0?
  • A Quick Guide to SQLite and Ruby
  • The Little Coder's Predicament
  • Wearing Ruby Slippers To Work

    Feeds:
  • RSS 2.0
  • Atom 0.3
  • !okay/news

    Hobix 0.4 is the white pantsuit underneath it all.