A major ruby annoyance!

Jim F. wrote:

Try unit testing for a while and you will see. After doing

  1. write code
  2. write test
  3. run test and see it succeed

Perhaps it’s me, but it doesn’t make much sense to write your code
BEFORE your test. How do you know that the code is operating right if
you write it before your test?

My suggestion: write your unit tests first, they don’t take much
time, so if you find you need to change things a little, having to
rewrite one unit test isn’t a big loss.

On May 7, 2006, at 9:56 PM, Roy S. wrote:

I’m not sure why everyone automatically assumed he did not use unit
testing. Unit testing certainly can point out there -is- an
error. The fix he proposes for his problem (typoing variable
names) tells him -where- the problem is. Unit tests can tell you
generally where you problem is but it still takes the debugging
work to step in and find out what -caused- the problem.

When you get better and better at testing your methods get smaller
and smaller. That’s why we call them “unit” tests. You just want to
test one small piece of the code, or one unit, at a time. When you
only have to search three lines of code for a misspelled variable,
you can find it pretty darn quick.

James Edward G. II

On May 7, 2006, at 10:48 PM, Jeremy T. wrote:

if you write it before your test?
Yes. that is what I was trying to point out. Maybe I didn’t succeed.
Most people do 1,2,3; 1,2,3; 1,2,3. If they are lucky and no tests
break, then they go back to one of the previous three iterations
and break 1 then run 3, see it fail, and say to themselves, “ok, my
tests are working”, go back, fix 1, and continue on.

It is best to do the following:

  1. write test
  2. run test and see it fail
  3. write code
  4. run test and see it succeed (hopefully) :slight_smile:

Jim F.

From: “Roy S.” [email protected]

Unit testing certainly can point out there -is- an error. The
fix he proposes for his problem (typoing variable names) tells him
-where- the problem is. Unit tests can tell you generally where you
problem is but it still takes the debugging work to step in and find out
what -caused- the problem.

Hi,

I’m not sure how many people might know about this (or
how many might care ) but: The state of the art in
Test Driven Development has come pretty far. Drop by a
TDD mailing list and ask folks how many minutes a year
they spend stepping through code anymore; or indeed, if
they even use a debugger at all.

Most TDD folk are likely to say they use a debugger rarely,
if ever. Maybe to deal with weird interactions with a
third party module to which they don’t have tests. But on
the TDD codebase? I rarely if ever use a debugger in my C++
TDD code and never in Ruby, nor do I miss it.

Stepping through code in the debugger is inefficient
because it doesn’t buy any security for the future. The
debugger is a great tool when needed–this is definitely
not some anti-debugger rant–but the key difference of
unit tests is that, once written, they are automated
tests, where using the debugger is a wholly manual
process each time.

State-of-the-art TDD uses One Button Testing(*) where
you bind a key in your editor to run your tests, and
without interrupting your flow. You get to keep coding,
while your tests are running, but if the tests don’t
pass, you get results that allow you to easily navigate
to the failure point. If you’re running your tests
frequently, chances are the failure relates to code you
just typed moments ago.

(*) Hmm - I see I’m behind the times. Some folks were
already pushing toward Zero Button Testing three years
ago. :slight_smile:
http://www.testdriven.com/modules/newbb/viewtopic.php?topic_id=412&forum=6

Well anyway: I’d been programming for about 18 years
before I first tried TDD; and I’d gotten damn good at
writing fairly bug-free code in C/C++. However, I did used
to fear refactoring my bug-free code, for fear of having
to thoroughly manually test it again in the debugger.
In TDD, by contrast, refactoring is an integral part of
the process - with the network of tests catching refactoring
errors the same way it catches other errors while coding.
(Such as the misspellings mentioned in this thread.)

This isn’t meant to preach some sort of silver bullet.
But modern TDD is pretty neat. And it seems like time
much better spent than the stepping-through-code in the
debugger I do on a few regrettably-non-TDD projects.

Regards,

Bill

On 8-May-06, at 12:44 AM, Jim F. wrote:

Perhaps it’s me, but it doesn’t make much sense to write your code
BEFORE your test. How do you know that the code is operating right
if you write it before your test?

Yes. that is what I was trying to point out.

Ah, my apologies, I must have deleted your original message since I
only saw this when quoted by someone else… I’m guessing what would
have led me to your intent was clipped.

On 5/8/06, Frank H. [email protected] wrote:

language like Ruby with STATIC TYPING???
…and also if you were to add a preprocessor to provide the other
three I wonder if you wouldn’t be happier with some other language?
I read over here: http://www.joelonsoftware.com/articles/Wrong.html
the useful rule: “Don’t use macros to create your own personal
programming language”

Python would be the place to go if you want significant whitespaces.
C# would be good for the braces and variable declarations.

Hal F. wrote:

I am not trying to say your concerns are not valid. But every
newbie comes to Ruby and wants to change it.

Hey, not true! I didn’t say a thing! :slight_smile:

The top things, as I recall, that people insist Ruby absolutely
HAS TO HAVE are:

  1. significant whitespace as in Python
  2. braces instead of keyword…end
  3. static typing
  4. variable declarations

Actually, apart from 3, all of those could easily be handled with
a preprocessor. Shouldn’t be more than a few days work, I suppose.
But, who the friggin heck would want to break a perfectly beautiful
language like Ruby with STATIC TYPING???

Regards, 0ffh

2006/5/8, Jim F. [email protected]:

Try unit testing for a while and you will see. After doing

  1. write code
  2. write test
  3. run test and see it succeed

you start to get paranoid that your tests aren’t being run. :slight_smile:
Seeing them fail, then succeed has a euphoric effect.

That’s why with “Test Driven Development”, it goes like this:

  1. write test
  2. write code
  3. run test and see it succeed

(Well really it is more like:

  1. write test
  2. if test_fails
  3. write code
  4. else
  5. go back to 1
  6. end

but the picture looks nicer: http://www.agiledata.org/essays/tdd.html )

Douglas

It may also be worth noting two additional points:

First, to be fair, the reason that perl has the my keyword for
declaring a variable is to make it a lexically scoped variable. If
you don’t declare a variable with my and you aren’t using the
strict pragma, you get a non-lexical global package variable. Ruby
defaults to lexically scoped variable anyway.

When you want to do some cool magic tricks in perl you need to turn of
strictures to do it. Ruby make it easy to extend classes and other
advanced things in a safe way. Perl makes you mess around with its
symbol table.

Second, what perl buys you on one end, bites you in another. Unless
you jump through a bunch of hoops and use inside-out objects all of
your perl objects will probably be hashed based. Since hash keys are
strings and aren’t checked in the compile stage you can still shoot
yourself in the foot. It will operate in exactly the same manner in
ruby:

$self->{'hard_to_speel_instance_variable'}  # !! not caught by 

strict !!

And actually, this turns out to be better in ruby because you can set
the hash miss behaivor to whatever you want:

hash = Hash.new { |k,v| fail 'You mispeeeled a key ;)' }

which will catch half of your errors.

I think it all boils down, as usual, to flexability vs safety. Ruby
is nice because it lets you do things quickly and it requires less
code. On the other hand, having a good test suite–as others have
said–becomes all the more important.

If not, you can always write rubylint :wink:

Hi –

On Mon, 8 May 2006, Logan C. wrote:

@something = exp
it does, but there’s no reason that should be viewed as the only or
best or likeliest use of instance variables. It’s layered on top of
a subsystem (instance variables) that have other uses too.

David

I wans’t suggesting only using ivars for accessors, but I believe strongly in
the uniform access principle. Even if you using ivars for something
completely internal that no one sees, you should still wrap the accesses to
them in methods (private ones).

But then you are suggesting that they only be used for accessors :slight_smile:

I can’t help feeling it’s a lot of trouble to do this:

class C
def initialize
self.container = []
end

 private
 attr_writer :container

end

rather than:

class C
def initialize
@container = []
end
end

if you’re just using @container as a state variable here and there.

I think the role of the uniform access principle here is open to
question. As I understand it, that principle states that the outside
user shouldn’t be able to tell whether a value is stored or calculated
– essentially, an attribute vs. the return value of a method call.
But instance variables are neither attributes nor methods; so they’re
not really candidates for being evaluated for uniform/non-uniform
access. And Ruby’s attributes are methods. To that extent, Ruby
actually enforces the UA principle; when you do this:

obj.something

you know that you’ve called a method. There’s no other possibility,
so there’s no opportunity for divergence of the interface.

David

On May 6, 2006, at 4:00 PM, Talha O. wrote:

Allow me to rearrange your statements a bit.

thing and
to work for me.
Yes, you can. I do.

Last several hours I spent debugging a malfunctioning code just
to see mistyped variable name was causing all the problem. I had to
put many log statements which polluted to the code.

Or, you could have written some tests that wouldn’t have polluted
your code and saved yourself several hours (and having to pull out
all those log statements).


Eric H. - [email protected] - http://blog.segment7.net
This implementation is HODEL-HASH-9600 compliant

http://trackmap.robotcoop.com

On May 7, 2006, at 4:18 PM, Talha O. wrote:

If you mistyped an instance variable name in a method, probably the
one you had properly initialized in your constructor, oops, sorry,
you just created a new variable and had a brand new bug. If you are
agile guy, and spent double time writing test for every little
functionality, hopefully you would find it soon.

Well, either you can be an agile guy and type twice as much or you
can do it your way and spend several hours debugging malfunctioning
code and adding log statements.

I’ve found its easier to be an agile guy and spend my time doing a
little more typing.

Rather than chasing down the same errors over and over why not write
some tests. I don’t like to repeat my mistakes and a solid test
suite keeps that from happening.


Eric H. - [email protected] - http://blog.segment7.net
This implementation is HODEL-HASH-9600 compliant

http://trackmap.robotcoop.com

On May 8, 2006, at 4:10 PM, [email protected] wrote:

accessors for any case where you might need to access an
best or likeliest use of instance variables. It’s layered on top of

user shouldn’t be able to tell whether a value is stored or calculated

David


David A. Black ([email protected])

Well at least if you do it my way, you don’t get tripped up by typos, :wink:

On May 7, 2006, at 7:56 PM, Roy S. wrote:

generally where you problem is but it still takes the debugging
work to step in and find out what -caused- the problem. I think
people are doing Talha a disservice by assuming that if he just
tested better his problems would go away.

My unit tests typically tell me which line my errors are on. You
probably haven’t written enough tests for your code or aren’t writing
small enough chunks of code.

The biggest change writing tests has done for my coding is to give me
smaller more descriptive methods rather than large methods that do
too much. A method that is more than 10 lines long is probably
wrong. A method that is more than 25 is most definitely wrong.


Eric H. - [email protected] - http://blog.segment7.net
This implementation is HODEL-HASH-9600 compliant

http://trackmap.robotcoop.com

On 5/8/06, Eric H. [email protected] wrote:

repeating yourself. Writing tests keeps your from duplicating work
that should be automatic.

Also not to mention that debuggers modify your code, thus potentially
opening up an entire new can of worms [1]

[1] Heisenbug - Wikipedia

On May 7, 2006, at 10:01 PM, Bill K. wrote:

the TDD codebase? I rarely if ever use a debugger in my C++
TDD code and never in Ruby, nor do I miss it.

Stepping through code in the debugger is inefficient
because it doesn’t buy any security for the future. The
debugger is a great tool when needed–this is definitely
not some anti-debugger rant–but the key difference of
unit tests is that, once written, they are automated
tests, where using the debugger is a wholly manual
process each time.

Not to mention that using a debugger to find bugs is a case of you
repeating yourself. Writing tests keeps your from duplicating work
that should be automatic.

already pushing toward Zero Button Testing three years
ago. :slight_smile:
http://www.testdriven.com/modules/newbb/viewtopic.php?
topic_id=412&forum=6

autotest in ZenTest gives you Zero Button Testing (well, you have to
save the file, does that count?)


Eric H. - [email protected] - http://blog.segment7.net
This implementation is HODEL-HASH-9600 compliant

http://trackmap.robotcoop.com

On 5/8/06, Ryan D. [email protected] wrote:

I’ve also taken it a step further by integrating autotest into emacs.
It allows you to run autotest in the background and click on errors
to go right to the issue. Works pretty well. I’ll be releasing it in
the next ZenTest release.

What about us Vim users? :frowning:

I guess we’ll have to hack it up ourselves…

Ryan

On Tue, 9 May 2006, Ryan L. wrote:

Ryan

i think the point is that vim users don’t make mistakes and therfore
don’t
need it (ducks) :wink:

-a

On May 8, 2006, at 1:51 PM, Eric H. wrote:

to save the file, does that count?)
I’ve also taken it a step further by integrating autotest into emacs.
It allows you to run autotest in the background and click on errors
to go right to the issue. Works pretty well. I’ll be releasing it in
the next ZenTest release.

On May 7, 2006, at 16:18, Talha O. wrote:

First of all, I would like to say that the problem is valid for all
types of
variables. You can mistype a local variable name in the same block and
you
just create a second variable instantly.

Not necessarily. You have to mistype a local variable name IN AN
ASSIGNMENT.

I loved Pascal’s requirement of pre-declaring variables. It seemed a
very sensible practice to me, and forced other people’s code to be more
readable to me, as well as making my own current code more readable to
my future self.

“So why,” I asked myself, “haven’t I had more problems with variable
name typos in Ruby?”

In point of fact, I do have a lot of problems with getting the name
wrong, especially since Ruby, like most primitive computer systems but
unlike the standard behavior of people, thinks that an “A” is
fundamentally different than an “a”. That one causes me constant
irritation.

But it’s easy to spot and fix, because the error message is almost
always “NIL doesn’t have a .whatever method.” And lo and behold, it’s
because I got my variable name wrong.

I think, Talha, that it’s not “Unit testing” that would alleviate your
problems. I think that what would help the most is if you used fewer
variables in the first place. One of my favorite ‘tricks’ in Ruby is
being able to stack method calls up. In the process of doing that, I
eliminate the need for a lot of intermediate variables.

increase the complexity of the code.
But any means of adding declarations is going to be a “custom
solution.” I mean, there’s absolutely no way that variable declaration
would become a required component of Ruby. At best, it would be an
option. So if somebody wants to use it, first they have to enable it,
probably by including the module that causes it to be possible. Then
each module or class that wants to enforce it has to mix it in, because
all the existing Ruby code would immediately break if it’s required
globally. Then there are the new declarations themselves.

How did you imagine this could be added to Ruby without doing something
“ugly?”

On the other hand, for the problem that I
present in my post, I am required to implement custom solutions which
partially solve the problem. The problem that I stated here is one of
the
biggest sources of unintentional bugs. Ruby is supposed to cut down
development time and reduce the unintentional complexity dramatically.
It is
one of most high level languages I have encountered. So I believe ruby
should have not missed this feature.

I’m not sure you’d get consensus that variable declaration is a
feature. :slight_smile:

I prefer a language that loudly shouts at with discriptive information
when
I do something wrong instead of running but producing erroneous
results.

Probably the #1 reason why, having tried using C, I have no intention
of ever exposing myself to such a poorly designed language again.

I really hope to see that ruby language
supports these with a new set of keywords in its next releases.

What kind of keywords would you want, and how would they work?