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?
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With