Search code examples
javarubyvariablesdynamic-typing

type of object references in ruby


I am new to Ruby and currently trying a few examples from the Ruby book I am using as a guide:

    class Account
attr_accessor :balance
def initialize(balance)
  @balance = balance
end  
end

class Transaction
def initialize(account_a, account_b)
@account_a = account_a
@account_b = account_b  
end  

def debit(account,amount)
  account.balance -= amount
end
    def credit(account,amount)
        account.balance += amount
    end

  def transfer(amount)
      debit(@account_a, amount)
      credit(@account_b, amount)    
  end

end

savings = Account.new(100)
checking = Account.new(200)
trans = Transaction.new(checking, savings)
trans.transfer(60)

puts savings.balance
puts checking.balance

This is a pretty straightforward example containing two classes within the same script file. I am confused about the type of the argument I am passing to the credit and debit methods. Coming from Java, I am still thinging in terms of types, so obviously the type of the account variable i am passing to,say the debit method, has to be of type Account.

Since ruby is dynamically typed and is not checking for type, how can I safely operate on the argument I am passing, and define the rest of the method by saying: account.balance -+ amount ?

I am trying to understand, what kind of safety is there if I pass to the debit method a reference to an object other than Account?

When the body of the method below is defined, it uses the given parameter account. Now, I guess I am repeating myself because I still can't grasp the idea... How can I take the argument account (which can be of any type, since no-one is checking) and build some logic by using the dot operator, ask for its instance variable, or call its other methods, and perform calculations on an object which might, or might-not be, the correct kind (or type)? Of course, implicitely, I want it to be of type Account.

def credit(account,amount)
        account.balance += amount
    end

Also, how would the same example work if I declared the two classes in different files?

Sincere apologies in advance for the newbie questions, I just find it hard to wrap my mind around the dynamic typing -- or better, no type checking. The book is either a bit vague on this, or I can't shake my tunnel-vision by thinking only in java.

Any practical explanations would be greatly appreciated.


Solution

  • You don't have any type safety in Ruby. All that matters to Ruby is whether an object can respond to the messages it's receiving. You can pass in something completely nonsensical and Ruby won't do anything to stop you at that point. But if you pass in an object that doesn't respond to the messages you're sending (+ and - in this case), you'll get a NoMethodError when your code tries to send the invalid message.

    In general, the solution to this is: Don't pass in the wrong type. It know it sounds weak, but that's pretty much what you need to do — ensure you're passing the right thing. Write tests for your programs to make sure you're doing what you mean to do. Ruby is very big on unit-testing. If you're really worried about an argument being the correct kind of thing, you can either explicitly check its class (raise 'WTF?' unless object.class == String) or you can try to convert it to the right class (by defining a to_foo-type method).

    In return for this, you're largely freed from caring about types. As long as the object responds to the messages you send, it doesn't matter what you pass in. This makes things like mocks and proxies really easy.