In reference to a famous talk that went viral on the web, so lets talk about Ruby WAT! In this article I’m going to talk about a few of the problems with the Ruby programming language.

In reference to a famous talk that went viral on the web, so lets talk about Ruby WAT!

In this article I’m going to talk about a few of the problems with the Ruby programming language. The examples I will give are fairly edge cases but I use them purely to demonstrate the concept.

In the past I was asked to write a parser for Ruby, after having written it I vowed never to use Ruby again. This may seem quite harsh but let me explain why I made this decision.

First of all I want to give you some examples of valid ruby constructs before going on to explain what is wrong with the fact that these constructs are valid.

The if-modifier statement

if-modifier-statement ::
    statement [ no line-terminator here ] if expression<

The above definition means that instead of a normal if statement e.g.

if x < 5 then
    statement1 
end

also this form would be valid:

statement1 if y == 3 

The third form of the if statement seen here is known as the if-modifier.

Method calls

Method arguments do not have to be wrapped in parenthesis:

method-invocation-expression ::= primary-method-invocation 
    | method-invocation-without-parentheses 
    | local-variable-identifier 

In line 2 we see a reference to the method-invocation-without-parentheses construct below.

method-invocation-without-parentheses :: command 
    | chained-command-with-do-block        
    | chained-command-with-do-block ( . | :: ) method-name 
    | argument-without-parentheses 
    | return-with-argument     
    | break-with-argument      
    | next-with-argument 

In line 4 we can see a reference to the argument-without-parentheses construct below:

argument-without-parentheses :: [ lookahead ∈/ { { } ] 
    [ no line-terminator here ] argument-list
argument-list :: block-argument 
    | splatting-argument ( , block-argument )?      
    | operator-expression-list [ no line-terminator here ] 
        , association-list 
        ( [no line-terminator here] , splatting-argument )? 
        ( [no line-terminator here ] , block-argument )? 
    | ( operator-expression-list | association-list )       
        ( [no line-terminator here] , splatting-argument )? 
        ( [no line-terminator here ] , block-argument )? 
    | command 

Statements are not required to be terminated with a semi colon unless on a single line. However an if statement can be written all on one line and begin can be substituted with a separator as the following grammar snippet shows:

    
if-expression :: if expression then-clause 
    elsif-clause else-clause? end

The elseif-clause and the else-clause are not obligatory.

then-clause :: separator compound-statement 
    | separator ? then compound-statement 

A then-clause may or may not include a then.

separator :: ; 
    | [line-terminator here]

Given the above information, how would you interpret the following given that examplePrint is the name of a method as is isFalse:

print "foo"; if isTrue; print "bar" end

This is a valid line of code but it is very unclear here what the expected behaviour is for someone reading the code. Obviously this would print either foo, bar or both.

So lets look at it in detail:

print "foo" 

is a statement, as mentioned previously

if isTrue 

could apply to this statement. However in this case

if isTrue 

applies to

print "bar" 

because print “bar” is followed by

end

Another example where the language may be misunderstood, is when a variable and a function have the same name but the method takes no arguments. An example of this would be:

number = 3
sum = 0

def number()
  return 6
end

sum = number

print sum
print number()
print number

The output when the code is run is as follows: 363

In line 8 it is not clear if we are referring to number the variable or number the function. In this case it is virtually impossible to understand what the identifier is referring to because a method or function call does not requires the parenthesis to be present. Obviously this makes the code very difficult to read and maintain.

Here I have just outlined two of the cases I found while writing a parser for Ruby. Obviously it would not be a best practice to program in this way, so it is unlikely to be a problem.None the less, these issues make it very difficult to understand and maintain these languages. If the language treated whitespace as important as Python does this would be less of an issue.

Call me old fashioned but an if belongs before the statements it affects. I also think some form of statement terminator should always be used and only used, to terminate statements. These small things make a language much cleaner and clearer.

Next week I’ll cover another language.