user9726814
user9726814

Reputation:

Is ruby whitespace sensitive in certain cases?

A single space affects the value returned by *:

rand * 10 #=> 2.7177010707339146
rand *10  #=> 1

I tried to use Ripper to check the tokens produced by those two expressions.

Ripper.lex 'rand *10'
#=> [[[1, 0], :on_ident, "rand", EXPR_CMDARG],
#   [[1, 4], :on_sp, " ", EXPR_CMDARG],
#   [[1, 5], :on_op, "*", EXPR_BEG],
#   [[1, 6], :on_int, "10", EXPR_END|EXPR_ENDARG]]
Ripper.lex 'rand * 10'
#=> [[[1, 0], :on_ident, "rand", EXPR_CMDARG],
#   [[1, 4], :on_sp, " ", EXPR_CMDARG],
#   [[1, 5], :on_op, "*", EXPR_BEG],
#   [[1, 6], :on_sp, " ", EXPR_BEG],
#   [[1, 7], :on_int, "10", EXPR_END|EXPR_ENDARG]]

Except for the second to the fourth element, I see no differences. I thought that the constants on the right would change somehow.

Now with sexp:

Ripper.sexp 'rand *10'
#=> [:program,
# [[:command,
#   [:@ident, "rand", [1, 0]],
#   [:args_add_block, [:args_add_star, [], [:@int, "10", [1, 6]]], false]]]]
Ripper.sexp 'rand * 10'
#=> [:program,
# [[:binary, [:vcall, [:@ident, "rand", [1, 0]]], :*, [:@int, "10", [1, 7]]]]]

One can see there is a big difference.

How and why is it that the expressions return a different value?

Upvotes: 1

Views: 258

Answers (1)

Andrew Marshall
Andrew Marshall

Reputation: 96934

The * in *10 is the unary splat operator, whereas in * 10 it is an overridable binary operator (in this case resolving to Float#*). We can see from the AST as well that, adding parenthesis, the expressions’ equivalencies are:

  • rand *10 is the same as rand(*10) is the same as rand(10).
  • rand * 10 is the same as (rand) * (10) is the same as rand.*(10).

This can also be confirmed at runtime:

def args(*args); p args; end

args *10  # prints [10]
args * 10 # prints []

Upvotes: 3

Related Questions