Forum: Ruby undefined method `+' for nil:NilClass (NoMethodError)

399a991530e4bf70b979784f898fbaef?d=identicon&s=25 Paul Robinson (paulr)
on 2014-02-18 20:49
Hello, I'm just setting out on Ruby and my first little program is
generating an error (in the line @allwords = @allwords +
aword.reverse.capitalize + " ")

I'm trying to reverse a name, so it someone enters 'Fred' is will supply
'Derf' and if they enter 'Fred Smith' it will supply 'Derf Htims'

Here's the code in full:


class Jumbler
  #attr_accessor :fullname
  def initialize(fullname)
    @fullname = fullname
  end

  def jumblename
    #if there is more than one word, reverse each one
    if @fullname.split(" ").length > 1
      @fullname = @fullname.split(" ")
      @fullname.each do |aword|
        @allwords = @allwords + aword.reverse.capitalize + " "
      end
      return  @allwords
    else
      #just send back the single word
      return @fullname.reverse.capitalize
    end
  end
end

puts "Please enter your name:"
$stdout.flush
yourname = gets.chomp

jumbleyou = Jumbler.new(yourname)
puts jumbleyou.jumblename


I'm not sure if instance variables that are private to the object should
appear in the initialization method (or whether they need to be denoted
with '@' but that doesn't seen to fix the problem anyway). It seems to
me that the error is because I'm trying to use 'reverse' or 'capitalize'
on a 'nil' value but I can't see why that's happening.

Guidance appreciated, sorry if my code is offensive! :D

Paul
820e01609a9f8f0fc0d5167680625b93?d=identicon&s=25 Harisankar P S (coderhs)
on 2014-02-18 21:02
(Received via mailing list)
This code is the reason for your error
@allwords = @allwords + aword.reverse.capitalize + " "

Since @allwords has no value in it, by default that instance variable is
initialized to nil. Thus creating this error. You need to add @allwords
=
"" before the loop.

 @allwords = ""
 @fullname.each do |aword|
        @allwords = @allwords + aword.reverse.capitalize + " "
 end

There is a simpler method to do the same thing
without initializing @allwords

return @fullname.map { |word| word.reverse.capitalize }.join(' ' )

the above could would yeild the same result.
B078cb4f4fb473c7a54d1fc36d10c70e?d=identicon&s=25 Regis d'Aubarede (raubarede)
on 2014-02-18 21:05
Paul Robinson wrote in post #1137092:

>   def jumblename
>     #if there is more than one word, reverse each one
>     if @fullname.split(" ").length > 1
>       @fullname = @fullname.split(" ")
>       @fullname.each do |aword|
>         @allwords = @allwords + aword.reverse.capitalize + " "
>       end

@allwords is no initialised, so  @allwords + a...try to addition
something to nil

this is perhaps more rubysh :)

       @allwords = @fullname.split(" ").map {|w|
                  w.reverse.capitalize
                 }.join(" ")
399a991530e4bf70b979784f898fbaef?d=identicon&s=25 Paul Robinson (paulr)
on 2014-02-18 21:30
Thank you both, that explains it. I hadn't come across the .map method,
it looks very handy!

Should all variables within an object be prefixed with '@' even if they
are private to it's methods? In this case it doesn't seem to make any
difference whether I use 'allwords'  or '@allwords'.

Thanks for the help, Ruby has been a revelation so far!

Paul
B078cb4f4fb473c7a54d1fc36d10c70e?d=identicon&s=25 Regis d'Aubarede (raubarede)
on 2014-02-18 22:50
Paul Robinson wrote in post #1137106:

> Should all variables within an object be prefixed with '@' even if they
> are private to it's methods?

yes !

> In this case it doesn't seem to make any difference whether I use > 'allwords'
or '@allwords'

without @ , ruby look for a method named 'allwords'
It will found it if you have defined
   attr_accessor :allwords

this call will create this 2 methods:
   def allwords() @allwords end
   def allwords=(v) @allwords=v end

I do not know why, but theses accessors are not accessible
in constructor code.
E088bb5c80fd3c4fd02c2020cdacbaf0?d=identicon&s=25 Jesús Gabriel y Galán (Guest)
on 2014-02-18 23:08
(Received via mailing list)
On Tue, Feb 18, 2014 at 10:50 PM, Regis d'Aubarede
<lists@ruby-forum.com> wrote:
> Paul Robinson wrote in post #1137106:
>
>> Should all variables within an object be prefixed with '@' even if they
>> are private to it's methods?
>
> yes !

The answer to the question I think he is asking should be: no !
I am in the assumption that when you mean "private to it's methods"
you mean variables that are local to a method, that are not used in
any other method in the class. In this case, if you don't use the @
prefix, Ruby will understand that this is a local variable, or a
method if it hasn't found an assignment previously:

allwords = ""

As soon as the parser sees this, from this point on allwords is
considered a local variable.

>
>> In this case it doesn't seem to make any difference whether I use > 'allwords'
> or '@allwords'
>
> without @ , ruby look for a method named 'allwords'

or a local variable, if it has been previously assigned.

Jesus.
399a991530e4bf70b979784f898fbaef?d=identicon&s=25 Paul Robinson (paulr)
on 2014-02-19 08:36
Thank you Regis & Jesus. I should have made the question clearer but,
yes, I meant variables that are local/private to the method in which
they appear.

Paul
399a991530e4bf70b979784f898fbaef?d=identicon&s=25 Paul Robinson (paulr)
on 2014-02-19 19:27
Hmmm, I was reading this page about 'require'...

http://rubylearning.com/satishtalim/including_othe...

... and noticed that @engine_state isn't initialised but the program
still works, presumably because 'nil' is considered to be 'not true' in
this case?

It also has the '@' prefix even though it's not accessible outside the
start_engine method.

Would it be better practice to add

@engine_state = false

to the initialize method or just remove the '@'? I realise this is a
trivial example but I'd like to pick up good habits from the start :D

Paul
B078cb4f4fb473c7a54d1fc36d10c70e?d=identicon&s=25 Regis d'Aubarede (raubarede)
on 2014-02-19 21:14
Paul Robinson wrote in post #1137260:
> Would it be better practice to add
> @engine_state = false
> to the initialize method or just remove the '@'?

aïe aïe aïe...

@var : is variable object instance, value is maintains with object life
var  : method variable , value is lost after each methode evaluation
var=(); var() : method call, if set/return a @var, value are persisted
E088bb5c80fd3c4fd02c2020cdacbaf0?d=identicon&s=25 Jesús Gabriel y Galán (Guest)
on 2014-02-19 21:15
(Received via mailing list)
On Wed, Feb 19, 2014 at 7:27 PM, Paul Robinson <lists@ruby-forum.com>
wrote:
> Hmmm, I was reading this page about 'require'...
>
> http://rubylearning.com/satishtalim/including_othe...
>
> ... and noticed that @engine_state isn't initialised but the program
> still works, presumably because 'nil' is considered to be 'not true' in
> this case?
>

This is exactly the case.

> It also has the '@' prefix even though it's not accessible outside the
> start_engine method.

This is not true. Precisely due to having the '@' prefix it is
accesible in other methods of the same class.
If you modify the example like this:

class MotorCycle
  def initialize(make, color)
    # Instance variables
    @make = make
    @color = color
  end
  def engine_status
    @engine_state
  end
  def start_engine
    if @engine_state
      puts 'Engine is already Running'
    else
      @engine_state = true
      puts 'Engine Idle'
    end
  end
end

You could do:

m = MotorCycle.new("honda", "red")
puts m.engine_status #=> nil
m.start_engine
puts m.engine_status #=> true

> Would it be better practice to add
>
> @engine_state = false
>
> to the initialize method

It depends. In this example, it might make sense and make everything
clearer. If the engine_state is better defined as always being true or
false, it would be better to initialize it to false in the
constructor, I agree.


> or just remove the '@'?

This will impact the function of the variable. If you remove the @,
then it's simple local variable within the method. With the @, it's an
instance variable that lives as long as the object to which it
belongs.

> I realise this is a
> trivial example but I'd like to pick up good habits from the start :D

That's a good thing, and I think you should read a little bit about
instance variables and object oriented programming in general to have
a clear understanding on the implications of being a local variable vs
an instance variable.

Jesus.
399a991530e4bf70b979784f898fbaef?d=identicon&s=25 Paul Robinson (paulr)
on 2014-02-19 21:40
Great thank you both (again!). I'm ok with variable scope and object
orientation in general (Java etc) but this is a rather different!

Paul
15000f55138ae94b0f362ed7c625461a?d=identicon&s=25 unknown (Guest)
on 2014-02-19 22:14
(Received via mailing list)
Am 19.02.2014 19:27, schrieb Paul Robinson:
> ... and noticed that @engine_state isn't initialised but the program
> still works, presumably because 'nil' is considered to be 'not true' in
> this case?

Not only "in this case".
In Ruby, exactly two things are considered false: `false' and `nil'.

Regards,
Marcus
399a991530e4bf70b979784f898fbaef?d=identicon&s=25 Paul Robinson (paulr)
on 2014-02-19 22:52
Thanks Marcus.

Paul
Please log in before posting. Registration is free and takes only a minute.
Existing account

NEW: Do you have a Google/GoogleMail, Yahoo or Facebook account? No registration required!
Log in with Google account | Log in with Yahoo account | Log in with Facebook account
No account? Register here.