Thursday, April 05, 2007

make a change to Ruby

OK, I can't resist Pat Eyler's "Bloggin Contest"

I started programming in Ruby after having programmed in Perl for a while. There is not very much I miss about Perl, but there is one thing: in Perl, you can locate a subroutine anywhere in the script; in Ruby, any call to a method has to be located physically below the definition of the method. (Yes I know that there are reasons that Ruby's interpreter does it that way, but still...)

I write a lot of scripts that are run by non-technical non-programming users, like QA people and business analysts. The nice way to set up such scripts is to put all of the editable bits right up at the very top of the page, so that the users can ignore all of the programming guts below the important variables and such. This is easy in Perl. In Ruby, I am forced to either put all of the editable parts at the very bottom of the page, so the non-technical user has to scroll through a lot of intimidating code to get to the important stuff; or I have to distribute a separate library file and use 'require'.


Here's examples:

########################
#Perl
sub i_am_at_the_top {
print "I'm at the top\n";
}

i_am_at_the_top();
i_am_at_the_bottom();

sub i_am_at_the_bottom {
print "I'm at the bottom\n";
}
#########################
yields:
>perl -w subs.pl
I'm at the top
I'm at the bottom

#########################
#Ruby
def i_am_at_the_top
puts "I'm at the top"
end

i_am_at_the_top
i_am_at_the_bottom

def i_am_at_the_bottom
puts "I'm at the bottom"
end
#############################
yields:
>ruby defs.rb
I'm at the top
defs.rb:7: undefined local variable or method `i_am_at_the_bottom' for main:Object (NameError)
>Exit code: 1

If Ruby's interpreter would make all methods available for use at runtime, it would make communication with non-technical script users a lot more appealing.

10 comments:

zenspider said...

I've got to say... EWW.

Having a straight-forward interpreter that does what you say when you say it makes a lot more sense and clears up any philosophical questions you might have about what is defined and when.

def x; p :x1; end
x
def x; p :x2; end
x

What should output in your version of ruby? More importantly why? And if you say it should work exactly the same way that ruby currently works, then even more importantly, HOW?

Now, for the fun part (and actually addressing your concerns), put an x at the top and tell me what THAT is supposed to do.

P.S. why I can't use code or pre tags is totally beyond me. how usable.

Chris McMahon said...

Yikes.

def x
p "one thing"
end

def x
p "a different thing"
end

I think is crazy on the face of it. While I can imagine it happening, it just screams "maintenance nightmare"

Rubén said...

I agree, that leads to madness indeed.
But... how about

Foo.class_eval "def #{name_your_method}; end"

It's another gate to madness, but it can be useful under some circunstances. I think telling Ruby to find the definition of a method can hurt metaprogramming -if did wrong-.

Chris McMahon said...

Ruby already has a feature define_method that is really useful: http://testingjeff.wordpress.com/2007/01/27/creating-methods-on-the-flyand-bugs-in-google-phonebook/
and methods not defined at runtime certainly should not cause errors.

What I'm after is the ability only to look a little way into the future, so I can tell my users what it is that they'll have to know.

Paul said...

Hear, Hear! The positioning of methods has been bugging me too. This would be a great addition to the Ruby interpreter.

Bret said...

The proposal, as it stands, would never happen in Ruby. Ruby evaluates code as it is loaded. Unlike other languages (like perl), it does not compile first, then execute. In effect you are asking Ruby to turn from a single-pass language to a double-pass language. Not going to happen.

But i would like to know more about the original problem. The example you give, which demonstrates what you are asking for, does not actually demonstrate the original problem. Can you give us an example of a script that has stuff you want users to edit and which you want to put at the top, but can't figure out how with Ruby?

I bet there is a way. Here's one suggestion.

def main
# stuff for users to edit
$name = 'foo'

# calls to methods later in the file
stuff
end

def stuff
puts 'foo'
end

main

Chris McMahon said...

Bret, good point. I hadn't thought of doing it that way. I'll have to poke around and see if I can come up with a counter-example.

GnikDrazil said...

I'm still trying to understand why you wouldn't prefer to move the configurable stuff intended for non-techs to fiddle with into another file.

Keeping non-programmers away from source code is a good thing.

Chris McMahon said...

gnikdrazil:
One of the cornerstones of my career is to demonstrate to non-programmers that they can accomplish amazing things by becoming modest programmers with modest ambitions with only a modest investment of time and energy in programming.

Clearly, I'm somewhere on that curve myself, as the comments demonstrate.

DevDanke said...

i second or third or wherever i am in the order, your idea to improve ruby so that you can define methods anywhere in your file and call them from anywhere in the file and ruby will do what you asked.

this ease-of-use feature will benefit many ruby scripters.