Mastodon

Duck typing in Ruby: thoughts on checking argument types.

It doesn’t take much time in the Ruby world to hear the term duck typing. It wasn’t until I was writing a method for a recent project that was to accept either one or many ids that I actually stopped and actually investigated it. I knew what most people know about it: “If it walks like a duck and quacks like a duck, then it’s a duck” and that in actual practice this means you call call respond_to? to see if a method exists.

But as I was working on the code I found I kept wanting to type object.kind_of?(Array) but since this seemed to clash with the idea of duck typing I thought it was time to investigate a little bit.

The reason the type of an object using #kind_of? is not that useful is that Ruby supports multiple inheritance via the inclusion of modules. Since an object’s methods may have come from either a parent class or an included module, knowing the objects class doesn’t provide much information. If Tiger.new.kind_of?(Felidae) just returned true, is it safe to call the #domesticated? method? Calling #kind_of? just doesn’t help you make that decision.

module Wild
  def domesticated?
    false
  end
end

class Felidae
  def claws?
    true
  end
end

class Tiger < Felidae
  include Wild
end

It seems that there are two schools of thought on duck typing. First, “soft” duck typing. Paraphrasing an example from Dave Thomas’ pickaxe book shows the standard approach:

def some_method param
  if param.respond_to? :<<
    # must be something we can write to!
    param << "a string to be added"
  end
end

The difficulty here is that respond_to? famously fails when you are using method_missing to catch and respond to method calls. The only way to be sure that respond_to? is not deceiving you is to go ahead and call the method. It is this approach that people call “hard” duck typing:

def some_method param
  param << "a string to be added"
end

As Dave explains:

“You don’t need to check the type of the arguments. If they support << (in the case of result) or title and artist (in the case of song), everything will just work. If they don’t, your method will throw an exception anyway (just as it would have done if you’d checked the types). But without the check, your method is suddenly a lot more flexible: you could pass it an array, a string, a file, or any other object that appends using <<, and it would just work.”
— Programming Ruby second edition pg 355 – Dave Thomas

The interesting thing to me here, is the rationale for just calling the method instead of doing something like this:

def some_method param
  begin
    param &lt;&lt; &quot;a string to be added&quot;
  rescue NoMethodError =&gt; e
    raise ArgumentError, &quot;Needs to support the &lt;&lt; method&quot;
  end
end

Constantly wrapping method calls in begin/rescue/end is pretty heinous from any angle; aesthetics, readability or performance. While hard duck-typing might come off as a little cavalier, it’s pretty much assumed in the Ruby community you have a test suite to make sure none of these NoMethod exceptions end up in production.

Another interesting take on the issue is the approach taken by Jeremy Kemper, the top commiter to the Rails framework. With commit 609c1988d2e274b he added the #acts_like? method to Object:

class Object
  # A duck-type assistant method. For example, Active Support extends Date
  # to define an acts_like_date? method, and extends Time to define
  # acts_like_time?. As a result, we can do &quot;x.acts_like?(:time)&quot; and
  # &quot;x.acts_like?(:date)&quot; to do duck-type-safe comparisons, since classes that
  # we want to act like Time simply need to define an acts_like_time? method.
  def acts_like?(duck)
    respond_to? :&quot;acts_like_#{duck}?&quot;
  end
end

and then to each of the core classes in the standard library he added an acts_like_x? method. Here is what the one for Date looks like:

class Date
  # Duck-types as a Date-like class. See Object#acts_like?.
  def acts_like_date?
    true
  end
end

These were added to ActiveSupport back in 2009 but for some reason they don’t seem to be widely used in the codebase. This surprises me because this approach seems to avoid NoMethodErrors without cluttering your code with rescue statements. On top of that it has none of the problems inherent in respond_to?.

I hope that helps people out a little. I know it has helped clarify my thoughts. Just one more reason to go and read the source.

Steam on Linux is a very big deal

Two years after writing that Steam on Linux would be a big deal, I got to play Team Fortress 2 on Linux. Steam on Linux is finally no longer vapourware and it is a very big deal. It was pretty amazing to see it running natively on Linux after all this time.

Screenshot from 2012-12-20 14:38:55
While it certainly did run, for me it was largely unplayable. On the few instances were I was able to connect to a server and join a game it was incredibly laggy. Most of the time it would freeze and crash.  I suspect my experience is not the norm because this was pretty bad even by Beta standards.  My individual issues aside, Steam coming to Linux has already already pushed Nvidia to double the speed of their Linux drivers and have already gotten Left for Dead 2 running faster on Linux than on Windows.  I think it safe to say that we can expect many more improvements as other companies start taking Linux seriously as well.

2012-12-20_00001

Canonical, the company behind Ubuntu, is working closely with Valve and game engine developer Unity to make Ubuntu a solid gaming platform. This focus on gaming is evident all over the Ubuntu blog and is clearly transforming the company. With all this activity going on its interesting to remember that it all started with moves by Microsoft to start closing their platform (perhaps prompted by their first loss?).

The opening move from Microsoft was to force developers using the new Windows 8 “metro” interface to sell their software through the new Microsoft app store so they can take a cut of the transaction. I guess nobody likes being reminded that they are only a sharecropper because the reaction was fierce. Former Microsoft employee and now Valve CEO Gabe Newell called Windows 8 “a catastrophe for everyone in the PC space”,  a sentiment that was echoed by Blizzard’s CEO, Minecraft creator Notch and Croteam developer Alen Ladavac who explained:

Gabe Newell did not overreact. What you don’t see here is that, under the hood, the new tiled UI is a means for Microsoft to lock Windows applications into a walled garden, much like the one on iOS. There is this “small detail” that Microsoft is not advertising anywhere, but you can find it dug deep in the developer documentation: One cannot release a tiled UI application by any other means, but only through Windows Store!
While, theoretically, desktop applications are exempt from these requirements, it looks more and more like just a foot-in-the-door technique. A large number of developers have expressed their concern with possibility that, probably in Windows 9 or something like that, the ability to get even desktop apps in any other way than through Windows app store may very well be removed. When that happens it will be too late.

The effect of this according to Newell is that “margins will be destroyed for a bunch of people” as Microsoft claims an Apple-like 30% from each sale. Moving to Linux for him was a “hedging strategy”. The silence from other quarters of the software industry has been interesting but I am sure they are all watching carefully what is going on. So thanks to Microsoft I am now playing Team Fortress 2 on Linux with a 50% faster drivers. How’s that for a Cobra effect?

All that said, Steam, the games it runs and the Nvidia drivers are all just binary blobs being loaded onto my computer. While I am happy to have them, none of this represents knowedge/code entering the public domain for others to build on… so the big question that needs to be answered now was asked by Richard Stallman:

I suppose that availability of popular nonfree programs on GNU/Linux can boost adoption of the system. However, our goal goes beyond making this system a “success”; its purpose is to bring freedom to the users. Thus, the question is how this development affects users’ freedom.

Learning to code

I just read an interesting post by Rob Johnson called Why is Learning to Code So Hard?. With seven teachers in my immediate family and a little experience passing on what I have learned, this is a question I find really interesting.

One of the things that stood out to me was list list of “how developers spend their time”:

  1. Fixing bugs and making minor changes to an existing code base
  2. Adding new features to an existing code base
  3. Writing new software from scratch
  4. Refactoring (making a material architectural change to a code base without changing the functionality – very difficult)

When you look at that list, imagine the knowledge that is required to perform each task. Every one of them requires you to read someone else’s code and understand what it does.
Reflecting back on my own schooling, the emphasis was on writing; our assignments were little snippets of code in the language of the day. The other thing that stands out is that we never stuck with any language very long; a little C++, a smattering to Java, some Oracle style SQL, C# and two weeks of Perl.

I think I know why schools teach this way; businesses want people who write code and need their new hires to be flexible. Consequently the focus is on writing and you keep moving between languages to prevent a deep attachment to any particular one. The goal for the school is to produce a pool of fresh graduates that are going to pick up whatever is used by their employer quickly and without complaint without flooding the market in any particular niche. Turning out highly opinionated students who already wedded to the latest and greatest language/tool is not what most employers want from a school (unless maybe you live in Silicon Valley). Here in Ottawa most of the jobs are working with .Net, Java or Cobol (imagine learning Rails or Node.js in school and then landing a job at Revenue Canada only to realize they use Cobol!).

The problem here is that Rob’s list (and my own experience) suggests that most of the time what is required is to read code not write it. To me that indicates that learning to code might best be tackled as a literacy problem, rather than a complicated case of writers block. If that’s true the process should probably be: pick a language and read about it, and read code written in it until you have a solid idea of the mechanics of the language. Once you are able to read, then you can try your hand at writing. The drawback of course is that you won’t be able to avoid going deep enough into the language to develop an attachment to it which means a big school would be in danger of flooding a particular market.

I am pretty sure that anyone who teaches ESL or reading to kids would find the process we use to “learn to code” pretty strange; roughly the equivalent of teaching kids to read via writing short paragraphs. Focusing on literacy first would probably go a long way to addressing the barriers to learning that were pointed out, specifically the “leap in difficulty”.

While I think that there are certainly better/faster ways to learn computer programming than traditional schools I also feel like the recent wave of “0 to Rails dev” private schools like Rob’s MakerAcademy, App Academy, CodeFellows, GSchool and Bitmakers all rely heavily (probably to heavily) on the encapsulation of knowledge that tools like Git and Rails represent to ramp up students in such a short time. I suspect that such a method will probably create a crop of junior developers that are destined to remain junior developers.

While its certainly good for addressing a certain niche (like the current shortage of Rails developers) it will be interesting to see if what’s going on in those schools will make a broader impact on the field of education. In the mean time, my focus will be on code fluency.

cannot load such file — taps/operation

I am an eternal optimist. With very few exceptions I will upgrade to the latest version of just about anything. Beta versions are close to being my norm and deprecation warnings are like nails on a chalkboard to me. A while ago I got deprecation warning while using one of my favorite heroku commands, heroku db:pull

The `heroku` gem has been deprecated and replaced with the Heroku Toolbelt. Download and install from: https://toolbelt.heroku.com

Obviously I installed the toolbelt. Of course everything looks find until I am trying to get some work done and try my next db:pull:


mike@sleepycat:~/projects/capoeiraottawa.ca$ heroku db:pull
! Taps Load Error: cannot load such file -- taps/operation
! You may need to install or update the taps gem to use db commands.
! On most systems this will be:
!
! sudo gem install taps

Taps is already installed but I humour them and install it again. Same deal. Purge and reinstall the Toolbelt. Same deal.
For the moment my solution is to back out of the toolbelt thing and use the gem again. Grr.
To do that I just did sudo apt-get purge heroku-toolbelt heroku. Keep in mind that heroku’s repo is still in the list of places apt will search. If you want to get rid of it you will have to delete /etc/apt/sources.list.d/heroku.list.

The last bit of the cleanup is removing the stuff heroku added to your path in your ~/.bashrc:


### Added by the Heroku Toolbelt
export PATH="/usr/local/heroku/bin:$PATH"

Then reopen your terminal. After that you are ready to install the gem as usual with gem install heroku


mike@sleepycat:~/projects/capoeiraottawa.ca☺ heroku db:pull
Loaded Taps v0.3.24
...
The 'heroku' gem has been deprecated and replaced with the Heroku Toolbelt, download and install from https://toolbelt.heroku.com.

Receiving schema
...

Sigh.

Ruby redo’s: The Rails router

One of the things that Ruby is famous for is the ease with which you can build Domain Specific Languages (DSLs). The routing DSL in Rails is one of the more recognizable features of the framework and a good example of a Ruby DSL. If you’ve worked with Rails at all you have seen this in config/routes.rb:

MyApp::Application.routes.draw do
  match &quot;/foo&quot;, to: &quot;foo#bar&quot;
end

I’ve worked with Rails a fair bit and had a pretty good understanding of how to use the DSL but there is always more to be learned by implementing it (or something like it) yourself. So what are we implementing? We want something that behaves like the ActionDispatch Routeset:

[27] pry(main)&gt; Rails.application.routes
=&gt; #&lt;ActionDispatch::Routing::RouteSet:0x0000000232c588&gt;
[28] pry(main)&gt; Rails.application.routes.draw do
[28] pry(main)*   match &quot;/foo&quot;, to: &quot;bar#baz&quot;, via: :get
[28] pry(main)* end
=&gt; nil

So we can see that it has a draw method that accepts a block. That block contains a call to the method “match” and accepts a string and a hash of arguments. We called the match method in our code block above and passed that block to the draw methods. When match is evaluated it adds the given route to the set of routes for the application. Which means that if we dig into the routes we should find our path we specified (/foo). Sure enough:

[29] pry(main)&gt; Rails.application.routes.router.routes.each{|r| puts r.path.spec};nil;
/assets
/foo(.:format)
/rails/info/properties(.:format)

As with most things in Ruby, its actually surprisingly little code to get such a thing working:

class RouteSet

  def initialize(routes = {})
    @routes = routes
  end

  def match(path, options)
    @routes[path]= options
  end

  def draw(&amp;block)
    instance_eval &amp;block
  end

  def to_s
    puts @routes.inspect
  end

end

We can play with it in Pry:

mike@sleepycat:~/projects/play$ pry -I.
[1] pry(main)&gt; load 'routes.rb'
=&gt; true
[2] pry(main)&gt; routeset = RouteSet.new
{}
=&gt; #&lt;RouteSet:0x1561598&gt;
[3] pry(main)&gt; routeset.draw do
[3] pry(main)*   match &quot;/foo&quot;, to: &quot;bar#baz&quot;, via: :get
[3] pry(main)* end
=&gt; {:to=&gt;&quot;bar#baz&quot;, :via=&gt;:get}
[4] pry(main)&gt; routeset.to_s
{&quot;/foo&quot;=&gt;{:to=&gt;&quot;bar#baz&quot;, :via=&gt;:get}}
=&gt; nil

The secret DSL sauce is all in the draw method. Notice the ampersand in front of the block parameter:

  def draw(&amp;block)
    instance_eval &amp;block
  end

That ampersand operator wraps an incoming block in a Proc and then binds it to a local variable named block. The same operator is used to reverse that process, turning the contents of the block variable from a Proc back into a block. That block is then fed into instance_eval which evaluates the block in the context of the current object. The net effect is the same as if you had just written this:

  def draw
    match &quot;/foo&quot;, to: &quot;bar#baz&quot;, via: :get
  end

This process of taking a block of code defined somewhere and evaluating it in some other context is the key to DSLs in Ruby. Understanding the ampersand operator and its conversion between blocks and Procs is really important since this is really common in Ruby code. While is may be common, its not cheap. All that “binding to variables” stuff can be slow so in those moments where you care about speed you will want to use this instead:

  def draw
    instance_eval &amp;Proc.new
  end

Playing with this stuff has really helped my understanding of both Ruby and Rails. I hope it helps you too.

Getting to know SQLite3

I’m finding SQLite3 super useful lately. Its great for any kind of experimentation and quick and painless way to persist data. There are just a few things I needed to wrap my head around to start to feel commfortable with it.

As with most things on Debian based systems, installing is really easy:
sudo apt-get install sqlite3 libsqlite3-dev

My first real question was about datatypes. What does SQLite support? It was a bit mysterious to read that SQLite has 5 datatypes (null, integer, real(float), text, blob) but then see a MySQL style create table statement like this work:

create table people(
  id integer primary key autoincrement,
  name varchar(30),
  age integer,
  awesomeness decimal(5,2)
);

How are varchar and decimal able to work? Worse still, why does something like this work:

create table people(
  id integer primary key autoincrement,
  name foo(30),
  age bar(100000000),
  awesomeness baz
);

As it happens SQLite maps certain terms to its internal datatypes:

If the declared type contains the string “INT” then it is assigned INTEGER affinity.

If the declared type of the column contains any of the strings “CHAR”, “CLOB”, or “TEXT” then that column has TEXT affinity. Notice that the type VARCHAR contains the string “CHAR” and is thus assigned TEXT affinity.

If the declared type for a column contains the string “BLOB” or if no type is specified then the column has affinity NONE.

If the declared type for a column contains any of the strings “REAL”, “FLOA”, or “DOUB” then the column has REAL affinity.

Otherwise, the affinity is NUMERIC.

So the foo, bar and baz columns above, being unrecognized, would have received an affinity of numeric, and would try to convert whatever was inserted into them into a numeric format. You can read more about the in’s and outs of type affinities in the docs, but the main thing to grasp up front is that syntax-wise you can usually write whatever you are comfortable with and it will probably work, just keep in mind that affinities are being set and you will know where to look when you see something strange happening. For the most part this system of affinities does a good job of not violating your expectations regardless of what database you are used to using.

The other thing to get is that SQLite determines the datatype from the values themselves. Anything in quotes is assumed to be a string, unquoted digits are integers, or if they have a decimal, a “real” while a blob is a string of hex digits prefixed with an x: x’00ff’.

So the safest/easiest thing might just be to leave the column definitions out altogether so they will all have an affinity of none and let the values speak for themselves.

The rest of my learning about SQLite is really a grab bag of little goodies:

Getting meta info about tables, indexes or the database itself is done with a pragma statement.
For example, if I want information about the table data:

sqlite&gt; pragma table_info(people);
0|id|integer|0||1
1|name|foo(30)|0||0
2|age|bar(100000000)|0||0
3|awesomeness|baz|0||0

You can get that same list of info within Ruby like so (after running “gem install sqlite3”):

require 'sqlite3'
@db = SQLite3::Database.new(&quot;cats.db&quot;)
table_name = &quot;cats&quot;
@db.table_info(table_name)

A complete list of pragma statements can be found in the docs.

To open or create a database simply run sqlite3 with the name of the file:

mike@sleepycat:~☺ sqlite3 cats.db

And finally if you have a file with sql statements you would like to run on a database:

mike@sleepycat:~☺ sqlite3 cats.db &lt; insert_all_the_cats.sql

Its been good to get to know SQLite3 a little better. Before this I had only really come in contact with it through my Rails development work and knew it only as the in-memory test database or the one I would use when I couldn’t be bothered to set up a “real” database. The more I look at it the more its seems like a really powerful and useful tool.

Ruby redo’s: IRB

I have come to the realization that the best thing you can do to advance your Rails knowledge is to get better at Ruby. Rails development tends to keep you in one particular corner of the language. To see the other parts you really need to step off Rails’ golden path and try writing something from scratch yourself.

To push myself into some interesting territory I have taken to creating toy implementations of some of the programs I use but have never really understood the internals of. Every time I do this I find I learn something new… sometimes something big, sometimes something small.

One of the small ones actually started with switching from IRB to Pry, and seeing the mind blowing simplicity of Josh Cheek’s example Read Evaluate Print Loop (REPL):

loop do
  puts eval gets
end

When he showed that I nearly fell out of my chair. I’ve been using the Rails console for years now and had never really stopped to consider how it actually did what it does. Obviously IRB is a bit more more involved than a one-liner and a gemspec but this is one of those magic code examples that gets the concept across with searing clarity.

A learning opportunity is not far off either since its not long before you will get the urge to improve it after fat-fingering something and the having it exit. If you don’t know about Ruby’s Exception hierarchy, or like me needed a reminder because you have spent to much time with Rails, try adding some error handling catching the Exception class:

loop do
  begin
    puts eval gets
  rescue Exception =&gt; e #Not a good idea!
    puts e.message
  end
end

Of course you will soon realize that you can’t end the program since it turns out that Kernel#abort just calls Kernel#exit and that actually exits the program by raising a SystemExit Error… which we just caught. Oops.
After discovering the joy of Kernel#exit! and doing some reading about the Exception hierarchy (Ahhaa StandardError!) I have to say that redoing even seven lines of IRB taught me a lot.

Sikuli tips

Lately I have been working alot with Sikuli. In case you have not heard of it, its a project that uses the computer vision library OpenCV to automate GUI interactions. While Sikuli itself is new to me, this also marks my first exposure to the underlying language of Python.

For the most part its nice to use an has some decent documentation, but there have been a few things that I have tripped over; some related to Sikuli itself and some due to my lack of familiarity with Python. So here is a compilation of a bunch of those little things that I had to stop and scratch my head over.

Java 7:

Don’t. It crashes every time you click one of the image functions in the IDE. Use Java 6 and life is good.

Special Keys:

All the special keys can be accessed through the Key class.

type('Sikuli rocks' + Key.ENTER)

The rest of the keys follow the same pattern… Key.TAB, Key.BACKSPACE and so on.
All that leads you to believe that to copy some text is going to use Key.CTRL, but you actually need to use the KeyModifier class instead. So Ctrl+C looks like this:

type('c', KeyModifier.CTRL)

Killing a script:

You will run your script a lot and when it goes badly you need to kill it but there is no obvious way to do that since the IDE disappears when you run the script. Kill your script with this:

Alt+Shift+c

Screenshots:
Sometimes you need to capture a image of a menu (like a context menu) that disappears when you move away. To catch an image of the menu use the shorcut:

Ctrl+Shift+2

Launching an app:
Sure you could doubleclick some icon somewhere but its much faster to launch most apps with a command. To save yourself from having to escape all the slashes in a path you should use Pythons raw string (note the r in from of the path):


firefox = App(r'C:\Program Files\Mozilla\firefox.exe')

Sikuli has some pretty good documentation but there are some areas where it feels a little thin. Specifically finding a complete list of methods for a particular class. Fortunately Pythons dir() function does that job.


firefox = App(r'C:\Program Files\Mozilla\firefox.exe')
screenRegion = firefox.window()
print dir(screenRegion)

[‘ROI’, ‘above’, ‘autoWaitTimeout’, ‘below’, ‘bottomLeft’, ‘bottomRight’…]

Child windows:
Lets say that Firefox opens a child window, like the downloads window. To get a handle on that you just need to do this:


downloadsWindow = firefox.window(0)

Unfortunately what you will find in downloadsWindow is an object of Region class. I was expecting to be able to get an App instance so I could call methods like focus() on it. It does the job though.

One other thing is that sometimes you will want to check that a region actually contains what you think it does. For that you will probably want to capture an image of that area during execution. I drop in code like this when ever I need to get a visual of a region:


import shutil
captureimage = capture(resultsBox)
shutil.move(captureimage, r'C:\somefolder\bounds.png')

These are a few of the things I have bumped into so far and I wanted to put them up here so I don’t forget them. Hopfully I’ll get to do more work with Sikuli. I think with a little practice I could make some scripts that are pretty resiliant to a lot of the changes that normally break these types of scripts (unexpected popups for instance, or slow networks). I’m looking forward to learning more about it.

Getting to know rbenv

I’ve been flirting with switching to rbenv for a while now. Updating RVM recently left me with a strange and annoying error (rubygems_bundler_installer LoadError) that I decided was best fixed by finally moving to rbenv.
The setup was pretty painless but after installing ruby 1.9.3 I thought I would install bundler and get to some coding. So I ran “gem install bundler” which went fine and then “bundle install”. What I got was:

mike@sleepycat:~/projects/capoeiraottawa.ca☺ bundle install
The program 'bundle' is currently not installed. You can install it by typing:
sudo apt-get install ruby-bundler

After a little reading rehashing was suggested and solved the problem:

mike@sleepycat:~/projects/capoeiraottawa.ca☺ rbenv rehash
mike@sleepycat:~/projects/capoeiraottawa.ca☺ bundle install
Fetching gem metadata from http://rubygems.org/......

Since I had no idea what rehash meant, or why I would need to use it. Since rehash seems to be a big thing with rbenv this gave me a good reason to get to know rbenv a little better. It actually works by prepending ~/.rbenv/shims and ~/.rbenv/bin to your path so its binaries are found first. Those binaries are shims based on the rubies and gems in the ~/.rbenv/versions directory. Rehash calls the following instructively named function to do create them:


make_shims ../versions/*/bin/*

The result is a shims directory full of shims. I’ve heard the term used many times but I have to admit I had a pretty shaky understanding of what a shim actually was. Taking a look in the directory helped…


mike@sleepycat:~/.rbenv☺ ls shims/
ast bundle erb gem irb jgem jirb jirb_swing jruby jrubyc rake rdoc ri ruby testrb update_rubygems

Even better is seeing the code:


mike@sleepycat:~/.rbenv☺ cat shims/bundle
#!/usr/bin/env bash
set -e
export RBENV_ROOT="/home/mike/.rbenv"
exec rbenv exec "${0##*/}" "$@"

So all that’s happening is setting an environmental variable and then execute some other command. OK, suddenly its clear what a shim is. As it happens rbenv exec is basically the same thing, setting some variables and then executing the actual command.

So when I install new gems, and those gems have a bin directory I need to call “rbenv rehash” to have rbenv generate new shims for the binaries they contain. Curiosity satisfied.