Including a module in Ruby

18 11 2007

If we define two modules, with methods that have the same names

module M1
  def foo
    puts "M1"
  end
end

module M2
  def foo
    puts "M2"
  end
end

and then include them in a class in a specific order

class C
  include M1
  include M2
end

method from the last included module will be used.

C.new.foo # => "M2"

So it looks like the methods are “copied” into the including class, so that the last definition of “foo” gets precedence. That’s how I thought about including Ruby modules initially.

But if that was the case the following example

module M
  def foo
    puts "M"
  end
end

class C
  def foo
    puts "C"
  end
  include M
end

should print “M”. But it doesn’t.

C.new.foo # => "C"

It calls the class “C” version of the “foo”, so the method can’t be redefined during the include.

What actually happens (and what I learned from “Include” part of Chapter 4 of Ruby Hacking Guide) is that the included module gets injected into the class hierarchy right above “C”.

class C
  def foo
    puts "C"
    super # Calling to see what the superclass defined.
  end
end

Let’s check what the hierarchy looks like before the inclusion of M.

C.ancestors # => [C, Object, Kernel]

Now let’s define “M”

module M
  def foo
    puts "M"
  end
end

and include it in “C”.

class C
  include M
end

Let’s check how it affected the class hierarchy.

C.ancestors # => [C, M, Object, Kernel]

Module “M” got injected as a direct superclass of “C”.

C.new.foo # => "C" then "M"

As C#foo calls super it’s now obvious how we got that output.

Advertisement




Solution to Code Kata Fifteen

5 11 2007

Just felt like doing some programming exercise. My bookmarks led me to the code kata 15. First, the problem:

Think of binary numbers: sequences of 0’s and 1’s. How many n-digit binary numbers are there that don’t have two adjacent 1 bits? For example, for three-digit numbers, five of the possible eight combinations meet the criteria: 000, 001, 010, 011, 100, 101, 110, 111. What is the number for sequences of length 4, 5, 10, n?

Having worked out the pattern, there’s a second part to the question: can you prove why that relationship exists?

Now, the solution.

Let’s call the function that calculate the number of n-digit binary numbers without two adjacent 1 bits a(n).

Now let’s define two helper functions. a0(n) returns number of those binary numbers that end with zero, and a1(n) returns number of those ending with one. Thus, it’s obvious that:

a(n) = a0(n) + a1(n)

Now, suppose we already have a set of (n-1)-bit numbers generated and now, based on that, we want to generate a new set of n-bit numbers. We’ll do that by adding a single bit to the end of each (n-1)-bit number. Because we care only about adjacent 1s, we can add 0s to the end of every (n-1)-bit number. Thus:

a0(n) = a(n-1)

On the other hand we can’t add 1s to each (n-1)-bit number. We can only add 1 to numbers which had 0 at the end. Thus:

a1(n) = a0(n-1)

By simple substitution we can rewrite the last equation into the following one:

a1(n) = a(n-2)

Get back to the definition of a0(n) and a1(n) and make the final substitution:

a(n) = a(n-1) + a(n-2)

Doesn’t it look familiar? Now you only have to say that a(1) = 2 and a(2) = 3 and you’re done.





spec plugin compatible with nose 0.10

12 10 2007

If you use the spec plugin (part of the pinocchio package) and want to upgrade to the new version of nose, you can safely do this now, because here is the new spec plugin, (I hope) fully compatible with the new plugin API. Note that it’s not an official release of pinocchio, but just a testing version for the impatient. I haven’t changed other pinoccho plugins, so you’re safe to upgrade your pinocchio 0.1 installation to this version. Let me know if something doesn’t work as expected.





PVS update

29 07 2007

It’s been quiet here lately, but only because I’m busy with PVS – my SoC project. ;-) PVS stands for Patch Verification System and I’m building it to support patch review process for CPython. There’s not much time left before the end of SoC 2007, so I won’t tell you the whole story now. Instead, I will share with you few insights about development process and tools I’ve used. OK, here we go.

Trac logoSometimes Trac is an overkill. Text files in reST format are often more than enough. You also get a bonus by keeping all your project-related stuff (tests, documentation, todos) in one place (i.e. not scattered among repository, wiki and bugs manager).

Django logoI’m using two ORMs inside PVS: Elixir+SQLAlchemy and Django ORM. Both work great and saved me a lot of tedious work. I like the way SQLAlchemy handles references to other tables, although its select syntax is slightly weird (although surely powerful). Django ORM may not be as functional as SQLAlchemy, but its main advantage is its good integration with the rest of the framework. Tweaking the admin views is both pleasant and addictive (something like customizing desktop settings of your new Ubuntu install ;-). You’ve been warned.

Did I mention that both ORMs work on the same database without any problems at all? A big thanks to both libraries’ authors for not using magic tables/fields or strange implicit conventions.

Ohloh Metric for PythonDuplicating the whole source checkout tree of a project of CPython size (about 100Mb in almost 12.000 files) is quite expensive, as I soon realized (better sooner than later). Hopefully I don’t have to do this – patch has –dry-run option and subversion client supports revert operation. This combination has truly saved me. :-)

Twill rocks. I written a patch reporter for Roundup in less than half an hour. Thanks Titus!

@Python decorators are not used often, but applied carefully can be very powerful. In PVS I defined daemonized decorator which makes decorated function execute in the background as a separate process. It also creates a PID file in a configured directory (like /var/run/pvs/), so you can easily manage the daemon (e.g. send signals to it).

Bazaar logoAfter initially using Subversion I recently switched to Bazaar, mostly for its ability to work offline. It’s been working fine so far. Because I’m working alone I didn’t have occasion to use its merging capabilities, so can’t really comment on those. When it comes to speed, it’s visibly faster than Subversion, mostly because it doesn’t have to process anything over the wire. Making a backup and sharing is easier – just archive the branch directory and you’re done. svn2bzr worked without problems, so if you’re a Subversion user – give Bazaar a try.

There are functions which I use over and over again in different Python applications that I write. Simple ones like read_file_contents/write_file_contents and more complicated beasts like daemonize or run_command. Those get copy&pasted between code repositories, which isn’t really DRY. Yeah, I could clean them up and put mk-utils package on PyPI, but I’m too lazy and this is a stupid idea anyway. A central repository of those functions and a simple way to cherry-pick – now that would make my day. Hey, why do we need whole libraries anyway? ;-)

And finally: grab the code. :-)





Two quotes

16 06 2007

Joel Spolsky:

People should take responsibility and ownership of the things that they specify. If something’s wrong with the spec, there should be a designated spec owner, with their name printed right there on the spec, who is responsible for fixing it.

Venkat Subramaniam and Andy Hunt:

Blame doesn’t fix bugs. Instead of pointing fingers, point to possible solutions. It’s the positive outcome that counts.





PVS architecture draft

28 05 2007

If you’re interested in my Python patch verification system project (or want to get interested :-), check out notes on system architecture I just added. Feel free to comment here or on the wiki, I’d love to hear your feedback.





Minor annoyance

19 05 2007

Map operation on sets isn’t closed, both in Python:

>>> type( map(lambda x: x**2, set([1,2,3,4])) )
<type 'list'>

and Ruby:
>> Set.new([1,2,3,4]).map { |x| x**2 }.class
=> Array

At least Haskell does the right thing:
Main> typeOf( Set.map (\x -> x^2) (Set.fromList([1,2,3,4::Integer])) )
Set Integer

An obvious workaround is to operate on lists and convert to sets once you need them. You have to ask yourself whether it will cause performance problems in your application.





Accepted to Summer of Code 2007!

19 04 2007

It actually happened a week ago, but I was really busy and had no time to share this happy news with the world. But here I am again, a lucky student ready to hack some Python code during summer. This time I will not only write in Python, but also for Python – I’m going to implement a verification system for patches contributed to Python project via its patch tracker. See the application for detailed description. I have already set up a Trac instance for this project, so go ahead and post your comments there.

Last summer I learnt quite a bit about Python and its toolset, made some great friends and got involved into even more projects. I will be happy if this year will be no different.





A Logic File System and the web

1 03 2007

A Logic File System is generally a keywords-based file system extended by good navigation capabilities. There is a official home page with much more information and sample implementations. Although the implementations work nicely with standard UNIX tools, like ls, mkdir or find the concept itself presents a major shift in information management philosophy, which IMHO cannot be introduced overnight. In fact, I don’t think we’ll ever see this on our desktops as too many things rely on hierarchical structure right now (developing applications – along with version control systems – to name one). Current solutions (like Beagle) are simply good enough. What will probably work is creating a new platform which does the right thing from the start. Happy news is that this new platform is being build and (surprisingly!) heavily used already – popular web services like del.icio.us or flickr have these concepts built-in in a form of tags. As we slowly move our data from desktop into the web we’ll use logic file systems more and more, without even knowing it.

Getting back to the original paper – very interesting is the concept of intrinsic and extrinsic keywords. Intrinsic keywords describe an inherent qualities of a file (like size or last modification time), while extrinsic keywords are labels set by the user. By unifying these two properties into a single entity (a keyword) expressiveness of the system rises, while keeping the semantics simple. del.icio.us implemented a small part of this concept in form of system:filetype tags. With these two types of keywords in place you can execute ls length:>20min/type:video/google to list video files about Google longer than 20 minutes. Interesting characteristic of this is the fact that some intrinsic keywords are defined only for specific file types. For example, length keyword can be defined only for media files, like audio or video. By a set of extensions (or plugins if you like) system can incorporate a new set of search and navigation capabilities without requiring any user intervention or a single change in his data.

I hope the way current web applications evolve will eventually lead them to the ideas described in the LISFS paper so all of us can benefit from it without having to struggle with backward-compatibility problems our old hierarchical file systems impose.

BTW, all of this reminds me of an article on platforms and software evolution I read some time ago. Recommended reading.





Free your blog!

27 02 2007

During my search for free blogs today I got surprised by the fact that a really small percent of Python blogs (either on Planet Python or Unofficial Planet Python) is licensed under a free license (full list below). I believe it’s caused mostly by omission or unawareness, as in my example — I added a CC button pretty recently, although my intention was to share my knowledge with others from the very beginning.

Most of you already publish your code in open source projects, so you know the benefits of openness. Next step is freeing your ideas and hard work you’ve put into your blog. Choose a license that work for you and open your blog content for collaboration.

For a quick explanation of CC licensing, watch this video:

What follows is a list of Planet Python and Unofficial Planet Python blogs that are licensed under Creative Commons. If I omitted your blog or you’ve added a CC licensing recently, please let me know in the comments, so I can update this list.