Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using a question mark in ruby methods

Say I have class Player and I want a boolean method to check if a player is attacked:

class Player
  attr_accessor :name, :health, :attacked?

  def initialize(name)
    @name = name
    @health = 100
    @attacked? = false
  end
end

I get a syntax error:

SyntaxError: (irb):14: syntax error, unexpected '='
@attacked? = false
            ^
        from /usr/bin/irb:12:in `<main>'

Removing the question mark from attacked fixes the problem, but I thought it would better follow convention to have attacked? in my code. It's not a big deal to forgo the question mark, but why are zero? and nil? conventions when@variables? and def methods?= are invalid?

like image 467
rubyuser1357796 Avatar asked Dec 22 '12 19:12

rubyuser1357796


2 Answers

Note that if you comment out the line causing your error (@attacked? = false), you will still get an error relating to the question mark:

NameError: invalid attribute name `attacked?'

The problem is that ? is not a valid character in a variable name. The first error (the SyntaxError that you’re seeing) is caused at parse time and caught immediately. The second error is caused when Ruby tries to evaluate the code and cannot create an instance variable with a name containing an invalid character.

A question mark is a valid character at the end of a method name though (actually it’s possible to have a method with a ? anywhere in its name, but you can’t call such a method directly).

One way to achieve what you want is something like this:

class Player
  attr_accessor :name, :health, :attacked
  alias :attacked? :attacked

  def initialize(name)
    @name = name
    @health = 100
    @attacked = false
  end
end

This leaves attacked without the question mark, but adds attacked? as an alias.

like image 92
matt Avatar answered Sep 28 '22 14:09

matt


I've run into the same problem before, and wished that I could make instance variables with a trailing question mark. It seems to be a corner case in Ruby's grammar. Check this out:

>> 1 ? 2 : 3
=> 2
>> 1?2:3
=> 2
>> @a = true
=> true
>> @a?1:2
=> 1
>> a = true
=> true
>> a ? 1 : 2
=> 1
>> a?1:2
SyntaxError: (irb):9: syntax error, unexpected ':', expecting $end

So the ? symbol is overloaded in Ruby's grammar -- it is used for the ternary operator, and as part of valid identifiers for method names. This causes ambiguity in the last case, where Ruby's lexer seems to bite off the a? as a single token, which leaves it unable to parse the rest of the ternary operator properly. With instance variables, this can't happen.

Again, I agree that allowing question marks in instance variable names would be very useful, certainly more valuable than making some obscure uses of the ternary operator non-ambiguous.

like image 24
Alex D Avatar answered Sep 28 '22 16:09

Alex D