From: Benoit Daloze Date: 2010-01-24T02:36:16+09:00 Subject: Writing proper getter in a Ruby way Hi Rubyists ! While writing a 'getter'(it actually does more than just getting a @var's value) method, I was wondering what was the most ruby-way to write it. The 'issue' is if the @var is not initialized in constructor, and you access it directly like "@var", Ruby gives you a warning(only if you enable them of course) : "warning: instance variable @value not initialized" While "@var" returns nil as expected, it still show this warning. Well, I know you would probably not care too much about warnings(do you?), but how would you deal to make it disappear? If you use attr_* methods, you'll never see this warning, because it's "cheating" (For what I understood of the C code, it checks if defined). In fact, a ruby equivalent(for the user) of attr_reader :var is def var instance_variable_defined?(:@var) ? @var : nil end and not just "@var" (because of the warning). I think you will agree with me, using #instance_variable_defined? is not very nice. Now I begin to describe the real code, because abstract examples would be hard. Here it is: class Variable attr_accessor :name, :proc attr_writer :value # Create a new Variable, with optional name, value and proc def initialize(*args, &proc) args.each do |arg| case arg when Numeric then @value = arg when String, Symbol then @name = arg.to_s else raise ArgumentError, "..." end end @proc = proc end def value @value or @proc && @proc.call.value end def to_s name || 'unnamed_variable' end end So the constructor have optional *args, and so we are not sure if a String or Symbol will be given for the name, neither if the value will be provided. For #to_s, I used the accessor(getter) of @name ("name"), that avoid me the warning(instead of @name || ...) But for value, it's a bit complicated. Because we want to return or the value if given, or the result of the proc. I can't use the accessor of value, because we are in a method with the same name ... There are then many possibles: 1) Initialize @value in #initialize : "@value = nil" or "@value = unnamed_variable" (but it looks so old school) 2) Verify if @value is defined with #instance_variable_defined? : instance_variable_defined?(:@value) ? @value : @proc && @proc.call.value (but it's awful to read, btw #defined? still show the warning) 3) We don't care about warnings ! 4) bad names involve this conflict, we should rename @value (we can't change the name of the method), and then use his accessor. The main problem is we'll have then something like var.val = 2, which is less easy to understand than var.value = 2. 5) Another idea ? :D Excuse me if I'm writing very much for a very small problem, but I thank you already if you take time to read and/or reply ;) Regards, B.D.