Electrical engine calculations The ElectricalEngine class responds to the horsepower message. Because efficiency is calculated in percent a programmer can mistakenly initialize it with an integer instead of a float.

class ElectricalEngine
  attr_reader :volts, :current, :efficiency

  def initialize(volts, current, efficiency)
    @volts, @current, @efficiency = volts, current, efficiency
  end

  HP_IN_WATTS = 746
  def horsepower
    (volts * current * efficiency) / HP_IN_WATTS
  end
end

puts ElectricalEngine.new(240, 90, .6).horsepower # correct
puts ElectricalEngine.new(240, 90, 60).horsepower # buggy


How would you handle this scenario?


Do nothing. It's the programmers responsibility to know the right datatype.
Rename efficiency to efficiency_as_float to make it clearer.
Rename efficiency to efficiency_as_percent and adjust horsepower's calculation.
Write a custom efficiency method to check the datatype and convert it accordingly.
Check efficiency type and raise an error if it's not a float.
Other


Solution four might look like this. Of course this conversion can happen in the initialize method too, but I think this is cleaner.

def horsepower
  (volts * current * efficiency_as_float) / HP_IN_WATTS
end

def efficiency_as_float
  if efficiency.is_a?(Integer) # what if 1 is passed in instead of 1.0?
    efficiency / 100.to_f
  else
    efficiency
  end
end


Solution 5 would look something like this:

def initialize(volts, current, efficiency)
  raise "Efficiency must be a float" unless efficiency.is_a?(Float)
  @volts, @current, @efficiency = volts, current, efficiency
end


Should ElectricalEngine own the responsibility of converting incorrect datatypes?
my two cents : use duck-typing.

@efficiency = efficiency.to_f


... if it quacks like a float, then it is a float. This allows to leverage ruby's awesomeness with things like : 

class EfficiencyProfile 
  def initialize(some_data, value)
    @data = some_data
    @efficiency_value = some_value 
  end

  def to_f 
    @efficiency_value.to_f
  end 
end 

e = EfficiencyProfile.new(some_big_chunk_of_data_about_engine_performance, 42)
ElectricalEngine.new(1,2,e) # would work without a complain


Dynamic typing sure is dangerous, but you have to embrace it if you want to benefit from it. 

Checking the type explicitly is an half-arsed solution, because : 


it is cumbersome, and you will never be as good at it than, say, a C compiler is
it will completely remove the sole benefit from dynamic typing : flexibility.