Friday, January 19, 2007

Accidentally accessing accessors in Ruby

I spent about 30 minutes today trying to determine if I had been misunderstanding basic Ruby syntax for more than a year, or if I had just discovered an undocumented bug in the language. The answer was neither, of course.


Ruby variable naming is straightforward. Class instance variables begin with @, as in @user_name. Local variables are unadorned - just user_name. So, when I came across some code that a co-worker had written that did not follow this convention, and he said that it was working fine, I was initially confused. Here’s an extremely simplified example:




1 class VarTest
2 attr_accessor :instance_var
3
4 def print_it
5 puts "The instance var is #{instance_var}"
6 end
7
8 end
9
10 vt = VarTest.new
11 vt.instance_var = "fred"
12 vt.print_it
13


This code should be spitting out something about the invalid use of the instance variable instance_var, right? That should be @instance_var in that method (line 5). But there it was, working just fine.


So I experimented a bit.




1 class VarTest
2 @instance_var = "some initial value"
3
4 def print_it
5 puts "The instance var is #{instance_var}"
6 end
7
8 end
9
10 vt = VarTest.new
11 vt.print_it
12
13 # ~> -:5:in `print_it': undefined local variable or method `instance_var' for #<VarTest:0x1d4558> (NameError)
14 # ~> from -:11
15


Now that’s what I had expected the first time. After more moments of confusion than I really care to admit, the extremely obvious answer came to me. In the first example, instance_var was the accessor method, NOT the variable. Duh. In the second example, where the error was thrown, instance_var was a local variable, since no accessor had been declared. Hence, the error. Again, duh.


It does bring up an interesting point, however. When I am accessing an instance variable from within a method, I use @varname, never just varname. But, I also frequently create accessor methods in Rails models that manipulate the data in some way. This leads to the possibility of some interesting bugs. Here’s a pretty contrived example.




1 class User
2
3 def lastname=(val)
4 @lastname = val
5 end
6
7 def lastname
8 "Mr. " + @lastname
9 end
10
11 def print_name
12 puts "print_name: #{lastname}"
13 end
14
15 def print_name2
16 puts "print_name2: #{@lastname}"
17 end
18
19 end
20
21 vt = User.new
22 vt.lastname = "Kruger"
23 vt.print_name
24 vt.print_name2
25
26 # >> print_name: Mr. Kruger
27 # >> print_name2: Kruger
28


This is fine, and correct of course, unless what I really wanted was “Mr. Kruger” in both cases.



The lesson here is…


The only real lesson is to be aware of the difference between using @ and not in class methods. Best practice is probably to consistently use @, in part simply because it helps differentiate between local and instance variables. In cases where the accessor really needs to be used, as when the accessor function is performing some sort of processing, its best to use self.varname to make it clear that a function is being called.

Monday, January 1, 2007

New blog

Just moved this from the free wordpress.com account, since it lets me change the CSS without paying a fee :-). The entry Evolution:: (Rails,Ruby) -> Haskell appeared on the wordpress site initially, and was refd on reddit. The version here has some updates based on feedback from some folks.

Thursday, December 28, 2006

Evolution:: (Rails,Ruby) -> Haskell

Apparently, there is a renewed / growing interest in functional languages like Haskell, OCaml, etc. and I am again being accidentally trendy... :-). Here's a bit on how I managed to stumble upon Haskell and how its affecting me as a developer...

Last year, along with thousands of others, I discovered Ruby on Rails, and built the core product for my company using it. It was (and continues to be) a great programming experience. Like everyone else who uses Rails for more than a couple of minutes, I fell in love with Ruby as a programming language. Coming from a background in C/C++ yada yada, Ruby opened up this wonderful world of blocks, closures, lambdas, etc. - concepts that despite 25+ years of programming were new to me. I was so excited, in fact, that I ended up helping to create the Houston Ruby on Rails user group.

Since most of the Rails group members came from similar backgrounds to mine, none of us really had anything more than a superficial understanding the whole lambda thing, so I was elected to give a talk on it. It was in doing my research for the presentation that I came across functional programming (FP) and Haskell.

I've just begun to scratch the surface of Haskell and FP, but its already changed the way I think about things in Ruby. I've been doing OOAD for many, many years, and I approach Ruby from that perspective. I tend to think in terms of OO abstractions, and methods on classes that alter state, i.e., alter the values of variables in an object. In FP, and Haskell in particular since it is the "purest" of the FP languages, there is no such thing (ignoring monads for the time being) as state. "Variables" are really more like constants in other languages - you can assign (aka bind) values to them, but that's it. Functions in FP take inputs and produce outputs, with no "side effects", meaning that they do not alter state or global variables. Since variables can only be assigned to once (like constants), new approaches are required for just about everything. The simplest example is iterating over a collection. In C++, you just do something like

int x[3] = {1,2,3}
for(int i = 0; i < 2; ++i)
{
x[i] = x[i] * 2;
}

and you're done. This can't be done in Haskell, since you would be reassigning values to the variable i. UPDATE: For the sake of clarity, I am not trying to say that you can't iterate in this style - but rather that incrementing a variable (i++) is not allowed in Haskell (although I understand that there are monadic ways of doing this?). In Haskell, you would use a function (map) that applies another function (*2 in this case) to each element in the array or list (x in this case), like this:
map (*2) [1,2,3]

I'm fudging slightly here - the C++ example is of an array, while the Haskell example is really a list. The concept is the same, though.

There are many new concepts in Haskell and FP that I intend to explore over time, but how has this one aspect changed my Ruby programming? I already used Ruby iterators (such as map, inject, etc.) with associated blocks to manipulate arrays. But I also used x.each frequently, essentially taking the same approach that I might have using C. This is not bad, of course, however the FP approach made me take a second look at some of the code that used that idiom, and I quickly realized that I was

(a) not taking full advantage of the Ruby higher level iterators such as map, and

(b) creating local variables all over the place, sometimes without a very good
reason.

Local variables aren't bad either, per se, of course. Sometimes they simply help make the code more readable and easier to debug. But every line of code has a potential for creating a bug, so there is a balance to be sought. So......here's an example of some code from our application that I reworked based on my new found FP sensibilities...

The original code:
html.each do |line|
@search_terms.each do |term|
line.gsub!(/#{term}/i,'<span class="found_text">;\&</span>') unless line =~ /(<|Storage|Towslip)/
end
@results_html

This of course is not bad, and is pretty readable. The general structure is to iterate over each line, then each term, and do a global substitution using a regex. Each line is modified in place using "gsub!". For each term, though, there are actually (potentially) two regex calls - one to determine if the line should be modified, and the other to search for terms to modify. So how would I approach it from a more FP point of view? This is admittedly a naive approach, but just thinking "How could I treat the html as whole and NOT modify values (as in the line.gsub! call)?" proved interesting. The result is below. The regexs are combined into one making it more efficient (although for the non-regex initiated it may seem pretty messy). There are NO explicit intermediate variables.

def highlight_html(html,ht, et)
html.map do |line|
line.gsub(/(?!#{et.join("|")})#{ht.join("|")}/i) \
{ |m| "<span class='found_text'>#{m}</span>" }
end.to_s
end

Some good references


Exploring functional programming, Bruce Tate