Kameron White
Kameron White

Reputation: 139

How to access instance variable of other object of same class

This is a job interview problem. I'm supposed to create a data structure for a time in seconds and milliseconds, then create two Time objects, and then write a function that can return the difference between the two Times. This is my code:

class Time
  def initialize (sec, milli_sec)
    @sec = sec
    @milli_sec = milli_sec
  end
  def difference(time_2)
    puts @sec.to_i*1000 + @milli_sec.to_i + time_2.@sec
  end
end

time_1 = Time.new('5','30')
time_2 = Time.new('6','40')
time_1.difference(time_2)

This is the error:

syntax error, unexpected tIVAR, expecting '('

I am having a problem accessing the @sec, @milli_sec variables of time_2 passed as time_1.difference(time_2). I think that the syntax is [email protected]_i or time_2.#@sec.to_i, but those return errors. time_2.sec returns uninitialized time, even though it looks like it's been initialized. I would like to know the solution to this problem.

Upvotes: 2

Views: 953

Answers (4)

QASource
QASource

Reputation: 85

The same objective can be achieved in much lesser lines of code using approach as below:-

class MyTime

  attr_accessor :seconds, :milli_seconds

  def initialize(entity={})
    @seconds = entity['seconds']
    @milli_seconds = entity['milli_seconds']
  end

  def difference(obj)
    ms= ((@seconds.to_i*1000+@milli_seconds.to_i)-(obj.seconds.to_i*1000+obj.milli_seconds.to_i))
    secs = ms/1000 
    msecs = ms%1000
    return MyTime.new({'seconds'=> secs,
                        'milli_seconds'=> msecs})
  end

end

time_1 = MyTime.new({'seconds'=> '20',
                        'milli_seconds'=> '100'})
time_2 = MyTime.new({'seconds'=> '10',`enter code here`
                        'milli_seconds'=> '20'})
diff_Obj = time_1.difference(time_2)
puts "Difference is : #{diff_Obj.seconds} Seconds #{diff_Obj.milli_seconds} milliseconds"

Upvotes: 0

Kameron White
Kameron White

Reputation: 139

Here is my final solution:

class Moment
def initialize (sec, milli_sec)
   @sec = sec
   @milli_sec = milli_sec
 end

def sec
   @sec
 end

def milli_sec
  @milli_sec
end

def difference(time_2)
 return ((@sec.to_i*1000 + @milli_sec.to_i) - (time_2.sec.to_i*1000 + time_2.milli_sec.to_i)).abs
 end
end

time_1 = Moment.new('1','300')
time_2 = Moment.new('11','20')

time_1.difference(time_2)

Upvotes: 0

Aetherus
Aetherus

Reputation: 8898

In ruby, every interface is a group of methods. You can't just obj.@var to access instance variables since they are not methods thus not interfaces. If you want to expose instance variables, then create public methods to access them. attr_reader and attr_accessor are simply handy ways to create those methods.

Upvotes: 1

Philip Hallstrom
Philip Hallstrom

Reputation: 19899

@sec and @milli_sec are instance variables of your Time class. This means that unless you do something else only the instance itself has access to them. Other parts of your code can create an instance, but are only able to access the methods you specify. The point of this is so that you can change the underlying implementation without affecting other parts of your code that are using this class.

There are a variety of ways to do this. You could define the following two methods in your Time class:

def sec
  @sec
end

def milli_sec
  @milli_sec
end

These methods are public (by default) so you can now do this:

t = Time.new(1, 2)
puts t.sec # prints 1
puts t.milli_sec # prints 2

A more Ruby-ish way would be to add this line to the top of your class:

attr_reader :sec, :milli_sec

Doing this accomplishes the same thing as defining the two methods above. You might also want to look at attr_accessor.

P.S. Time is a poor choice of class name for your own code as it's already defined by Ruby itself.

Upvotes: 4

Related Questions