Tuesday, January 30, 2007

A Haskell Epiphanette

A link on reddit led me to this:


I think it’s important/useful to point out that “program flow” in a pure functional language is really a matter of data dependency. The compiler is only free to arbitrarily order computations if there are no data dependencies. Furthermore, monads are not special in any way (they are after all just a useful set of combinators; … they only wind up sequencing computations because they set up a data dependency between the two arguments of the bind operator.
-Jeff [bold added by me]

I’m a newbie to Haskell, and like all Haskell newbies, I’m still working through the Monad fog. On the surface, they appeared to me to be not much more than a way to cheat - to write in an imperative style in Haskell. So, I thought, if in the long run all you are really doing in Haskell is writing a bunch of commands, just as you would in C++ or any other imperative language, then what’s the point? Although you could argue that the net result is the same, i.e., you are effectively giving the computer a specific set of instructions to carry out, and in what order (basically), the quote above gave me a new perspective. Sometimes it just takes a little kick…:-)

Friday, January 26, 2007

Rails Routing Errors: The "diff:{}" Problem

Rails error messages are generally pretty good, but like anything, every once in a while you get one that just makes you go nuts. In creating a new section of our application, I decided to go the RESTy route and use the shiny new magic url thingies. To make life even more interesting, I used nested resources. In particular, I set up one route like this:



map.resources :calls,
:path_prefix => 'call_center',
:controller => 'call_center/calls',
:member => { :close => :get } do |call|
call.resources :call_notes,
:controller => 'call_center/call_notes',
:new => {:add_note => :post}
end


Unfortunately, I immediately got this error when I tried to use my new route:



add_note_new_call_note_url failed to generate from
{:action=>"add_note",
:controller=>"call_center/call_notes"},
expected:
{:action=>"add_note",
:controller=>"call_center/call_notes"},
--> diff: {} <--



Notice the last line: diff: {}. So the difference between what the routing system got and what it wanted was….nothing. The answer, which I found after much gnashing of teeth, turned out to be really simple. I needed to add a parameter to the add_note_new_call_note_url. The call that generated the error was




<% remote_form_for :call_note,
:url => add_note_new_call_note_url, ...




What it needed to be was




:url => add_note_new_call_note_url(@call), ...



The @call provides the url generator with the correct context. I had seen (and used) this parameterized url helper in other places, but had not added it here. In fact, I'm still a little fuzzy on when exactly its needed, since some examples (even in AWDWR) don't use it and some do. At any rate, I now have a first place to look when I get this odd error message again. Lesson learned (I hope…)

Sunday, January 21, 2007

Suppressing link_to_if text when condition is false

The rails link_to_if function is great for, well, creating a link if and only if a condition is true. The prototype is


link_to_if(condition,
name,
options = {},
html_options = {},
*parameters_for_method_reference, &block)

Unfortunately, the default behavior is to put the link text on the page (with no link) if the condition is false. To rid yourself of the pesky text, so that nothing shows up if the condition is false, just add an empty block…


link_to_if(false, "Don't show me",a_fancy_url) {}

Bye Quicksilver, for now at least

I was introduced to Quicksilver last year by someone at the Rails user group. I’m not sure how I survived on the Mac without it. I used it for launching apps, appending to files, and jotting quick notes that went straight to kGTD. Incredible productivity booster.


And I just quit using it, and bought LaunchBar. Why? Stability. QS is great, but it crashes frequently - sometimes 5 or 6 times a day. For no apparent reason. Yes, I know its beta. Yes, I know its free. Yes,yes,yes. LaunchBar is more limited, yes, but it is rock solid. And fast. Seemingly faster than QS (although I have not measured it in any way…). If I can find a script that lets me access kGTD from LaunchBar, it may be a permanent replacement. (The only one I’ve found so far seemed to have a problem on the download page)


UPDATE: ..not that anybody but me really cares... :-)
Going to stick with LaunchBar. No crashes, fast, and the advanced kgtd script works with the new version of LaunchBar as easily as it did with quicksilver.

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.