Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.ruby > #6710

Re: Subtle Bug Reveals Major Design Flaw

From Robert Klemme <shortcutter@googlemail.com>
Newsgroups comp.lang.ruby
Subject Re: Subtle Bug Reveals Major Design Flaw
Date 2012-12-25 00:05 +0100
Message-ID <ajs5dbFqg44U1@mid.individual.net> (permalink)
References <ecf2782f-07a0-4ac5-b093-30ce71b48078@googlegroups.com>

Show all headers | View raw


On 24.12.2012 18:19, rantingrickjohnson@gmail.com wrote:
> Hello folks.
>
> I was hacking away today when i made a stupid mistake that revealed
> a  subtle bug in ruby. Here is a test suite that will expose the problem.
> (be sure to supply a valid folder path on your machine)

It's a subtle bug in _your code_ - not in Ruby.  I wonder why you call 
it "major design flaw" in the subject and now it's a "subtle bug"...

> ## START CODE ##
> def bug
>      path = 'USE A VALID FOLDER PATH HERE!'
>      d = Dir.new(path)
>      files = []
>      folders = []
>      d.entries.each do |x|
>          $stdout.write("--x=#{x}\n")
>          if x == '.' or x == '..'
>              next
>          xpath = File.join(path, x) #<-- ERROR!
>          elsif File.ftype(xpath)=="directory"
>              folders.push(xpath)
>          elsif File.ftype(xpath)=="file"
>              files.push(xpath)
>          end
>      end
>      $stdout.write("files=#{files}\n")
>      $stdout.write("folders=#{folders}\n")
> end
> ## END CODE ##
>
> ## START RESULT ##
> Error: #<TypeError: path/file.rb:14:in `ftype': can't convert nil into String>
> ## END RESULT ##
>
> As you can see i accidentally pasted the line "xpath =
> File.join(path,  x)" INSIDE the conditional. However, for some reason Ruby committed the
> following three crimes:

Hold your horses.  That's way out of proportion.

> ############################################################
> #                         Warning                          #
> ############################################################
> # In the following paragraphs the author has used          #
> # emotional language to describe his mental state whilst   #
> # suffering the affects from a subtle bug. Please read     #
> # this section objectively and do not get offended by      #
> # these words. The author does not intend to offend any    #
> # member of this fine community or the even the language   #
> # designer himself. The author simply wants to understand  #
> # what the heck is going on! Thank you.                    #
> ############################################################

If you do not intend offense then why are you using offensive language? 
  Instead of writing this disclaimer you could have taken the time to 
rid out the offensive bits since you were obviously aware of the effect 
they could have.

> 1. Ruby did not throw a SyntaxError: I guess some might argue that
> the programmer should be responsible breaking syntax, and i agree,
> HOWEVER, syntax error can and will happen and catching this type of
> error at the syntactical level BEFORE it has time to metastasis is
> just good language design.

There is no syntax error.  If you indent line with "ERROR" a bit 
differently you'll probably see it yourself:

         if x == '.' or x == '..'
             next
             xpath = File.join(path, x) #<-- ERROR!
         elsif File.ftype(xpath)=="directory"
             folders.push(xpath)
         elsif File.ftype(xpath)=="file"
             files.push(xpath)
         end

As Christian has written, local variables are known within the scope 
from the point they are defined (first assigned) on - even if that 
statement is not executed:

$ ruby -e '2.times {|x| if false;a=2 else p a;a=2 end}'
nil
nil

Variable a lives inside the scope only which also means it's 
reinitialized on every execution of the block.

> 2. Ruby re-assigned the value of a variable, OR, failed to interpret
> the value correctly and simply defaulted to nil.

There is no reinitialization going on: nil is simply the default value 
for _all_ uninitialized variables.

> I am amazed that
> Ruby would overlook the broken control structure,

It's not broken. (see above)

> okay, maybe this is
> a feature of the language that i was unaware of-- if so i can accept
> that--but why then did Ruby go on to add insult to injury by
> haphazardly assigning "nil" to my variable `xpath`. What possible
> good could come of that?

The way the language is designed there has to be a default value.  nil 
is even more friendly than Java's null which will throw immediately on 
every method invocation.

> 3. Ruby did not throw a NameError: Finally, but worst of all, (and a
> direct result of re-assignment); Ruby did not throw a NameError when
> i tried to access xpath. xpath should never have had existed. I could
> "somewhat" understand allowing the syntactical mistake and just
> ignoring xpath, then, throwing a NameError if i tried to access
> `xpath`. This would make sense at least. But what i uncovered makes
> no sense. It's madness.

People find it strange from time to time that local variables work in 
Ruby the way they do.  If that is madness for you then I suggest you 
simply stop using the language and move on to another one.

> Conclusion: Ruby had three chances to catch my mistake and notify me
> of that mistake but ruby failed all three times. Can someone please
> explain the philosophy behind this design?

Ruby interpreter cannot read your mind.  You can write syntactically 
correct programs which are nonsense nevertheless in every programming 
language.  You better get used to that fact.  There are ways to shoot 
yourself in the foot in every programming language.

> "Errors should never pass silently!"

Well, the error did not pass silently, did it?  You got a response from 
File.ftype().

Plus, Ruby MRI is even smart enough to warn you about the dead code - if 
you chose to use the tools provided (option -w in this case):

$ ruby -w x.rb
x.rb:9: warning: statement not reached
$ cat -n x.rb
      1  def bug
      2      path = 'USE A VALID FOLDER PATH HERE!'
      3      d = Dir.new(path)
      4      files = []
      5      folders = []
      6      d.entries.each do |x|
      7          $stdout.write("--x=#{x}\n")
      8          if x == '.' or x == '..'
      9              next
     10          xpath = File.join(path, x) #<-- ERROR!
     11          elsif File.ftype(xpath)=="directory"
     12              folders.push(xpath)
     13          elsif File.ftype(xpath)=="file"
     14              files.push(xpath)
     15          end
     16      end
     17      $stdout.write("files=#{files}\n")
     18      $stdout.write("folders=#{folders}\n")
     19  end

Cheers

	robert


-- 
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

Back to comp.lang.ruby | Previous | NextPrevious in thread | Next in thread | Find similar | Unroll thread


Thread

Subtle Bug Reveals Major Design Flaw rantingrickjohnson@gmail.com - 2012-12-24 09:19 -0800
  Re: Subtle Bug Reveals Major Design Flaw Christian Neukirchen <chneukirchen@gmail.com> - 2012-12-24 22:29 +0100
  Re: Subtle Bug Reveals Major Design Flaw Robert Klemme <shortcutter@googlemail.com> - 2012-12-25 00:05 +0100
    Re: Subtle Bug Reveals Major Design Flaw Rick Johnson <rantingrickjohnson@gmail.com> - 2012-12-24 20:33 -0800
    Re: Subtle Bug Reveals Major Design Flaw Paul Magnussen <magiconinc@earthlink.net> - 2012-12-25 06:31 -0800

csiph-web