You should explicitly use @foo in the original, aliased setter; which will add just one line to your code.
- Notice that, as you made
A superclass, generally you would
want to validate before setting some variables, such as @bar. This the reason why the validation function was added to the code below (just to reflect this idea).
Also, as attr s declarations will be translated to methods, methods are the ones that master the final behaviour and, therefore, in general, it is better to use alias_method over alias (please, see this widely accepted answer).
I would dare say this is the simplest way to go:
module Aside
class A
attr_reader :bar
# as mentioned, preferable to use alias_method
alias_method :foo, :bar
alias_method :foo=, :bar=
def initialize
# use setter method to keep @bar and @foo in sync
self.bar = 'hello'
end
def bar=(value)
@bar = nil
@bar = value if some_validation?(value)
@foo = @bar
end
private
def some_validation?(value)
value.is_a?(String)
end
end
class B < A
def try_alias
puts @foo
end
end
end
Aside::B.new.try_alias #=> "hello"
Please, observe that the initialize of the class A, uses the setter method, rather than the direct assignment (as in your example), to initialize @bar.
This is because after aliasing this way, to keep in sync @bar and @foo, you should avoid direct variable assignment everywhere other than the bar setter itself (aside note: that is good practice anyway, because you centralize all the validation of @foo to one single point).
In other words, when you want to use this approach:
- do not use
direct assignment : @bar = value or @foo = value, and
- use
setter methods instead : self.bar = value or self.foo = value (as shown in the class A initializer).