Programming Language Peculiarities, Part 1: Ruby

DZone 's Guide to

Programming Language Peculiarities, Part 1: Ruby

A few constructs from the Ruby language that can make the code unreadable. The examples given are edge cases but I use them to demonstrate the concept.

· Web Dev Zone ·
Free Resource

So let's talk about Ruby WAT!

In this article I'm going to talk about a few constructs of the Ruby programming language that can make the code unclear / unreadable. 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 decided Ruby is not the language for me. 

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 y == 3 then

also this equivalent form would be valid:

statement1 if y == 3

This form is known as the if-modifier.

Method calls

Method arguments do not have to be wrapped in parentheses:

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

Statements are not required to be terminated with a semicolon 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]

A separator is defined as either a new line or a semicolon.

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"


print "bar"

is followed by


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

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.

language constructs, language design, ruby

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}