6

Can someone more versed in ruby than I please answer why the following returns nothing?

class ThreeAndFive
  def initialize(low_number, high_number)
    @total = 0
    (low_number..high_number).each do |number|
      if (number % 3 == 0 && number % 5 == 0)
        @total += number
      end
    end
    #puts @total here returns value of 33165
    return @total
  end
end

test = ThreeAndFive.new(1,1000)
#This returns nothing but "#<ThreeAndFive:0x25d71f8>"
puts test

shouldn't the result of puts test be the same as if i had called puts on @total directly in the class?

Andrey Deineko
  • 51,333
  • 10
  • 112
  • 145
TheRealMrCrowley
  • 976
  • 7
  • 24
  • I don't know Ruby, but it looks to me as though you're instantiating an object and assigning it to `test`, not calling a function and assigning the return to `test`. – Juan Tomas Oct 07 '16 at 20:49

3 Answers3

12

This is what roughly happens when you call new

def new
  allocate object
  call initialize method on object
  return object
end

This is why you cannot return @total and are instead getting the object itself.

rohit89
  • 5,745
  • 2
  • 25
  • 42
  • 2
    Why "roughly"? Why not spell out *exactly* what happens? `def initialize(*args, &block) object = allocate; object.send(:initialize, *args, &block); return object; end` – Jörg W Mittag Oct 07 '16 at 21:46
  • @JörgWMittag your example throws an exception `undefined local variable or method 'allocate'` and it's probably because you call `allocate` in the context of instance of the class, not class itself. Did you by chance mean to define `self.new`? Most likely there's just something I don't understand, because it is super unlikely that you are mistaken. – Andrey Deineko Oct 07 '16 at 22:50
  • @AndreyDeineko: I'm not sure what you mean. [`new`](http://ruby-doc.org/core/Class.html#method-i-new) is an instance method of [`Class`](http://ruby-doc.org/core/Class.html), and [`allocate`](http://ruby-doc.org/core/Class.html#method-i-allocate) is an instance method of `Class` as well. Surely, you can call other instance method of the same class in an instance method? – Jörg W Mittag Oct 07 '16 at 23:38
  • @JörgWMittag You wrote `def initialize` when you meant `def new` (assuming the definition was in an implied `class Class` context). Alternatively, `def self.new` inside the context of some specific class. – philomory Oct 08 '16 at 02:36
  • @philomory: Oh man. Brain scrambled by sleep deprivation! Thanks. – Jörg W Mittag Oct 08 '16 at 07:31
  • @JörgWMittag yea, the one philomory said is what I meant :) – Andrey Deineko Oct 08 '16 at 08:38
8

Initialize is called from Class#new and it returns the new object, not the (ignored) return value of #initialize.

DigitalRoss
  • 143,651
  • 25
  • 248
  • 329
5

It works correctly:

test = ThreeAndFive.new(1,1000)
#=> #<ThreeAndFive:0x007ff54c5ff610 @total=33165>

Meaning, that you defined instance variable @total in initialize and you have it there.

should or should not "puts test" return the 33165

NO. If you wanted to have @total to be displayed, you would define an attr_reader :total and used it as follows:

test.total
#=> 33165

Another option (if for some reason you did not want to define reader):

test.instance_variable_get :@total
#=> 33165
Andrey Deineko
  • 51,333
  • 10
  • 112
  • 145
  • it doesn't work correctly. As i stated in the question, ruby is returning only the # the return value is nowhere to be found. – TheRealMrCrowley Oct 07 '16 at 20:53
  • @TheRealMrCrowley I tested it in console and it does indeed returns the expected value (shown in my answer). – Andrey Deineko Oct 07 '16 at 20:53
  • the question is pretty clear in my opinion, should or should not "puts test" return the 33165. if the answer is no, then your edit explains that part – TheRealMrCrowley Oct 07 '16 at 20:54
  • thank you. so the only way to immediately assign the value of total is to drop the class and keep only the method e.g. def threeAndFive(..,..)end then call test = threeAndFive(1,1000) – TheRealMrCrowley Oct 07 '16 at 21:05