If you have a problem or need to report a bug please email : support@dsprobotics.com
There are 3 sections to this support area:
DOWNLOADS: access to product manuals, support files and drivers
HELP & INFORMATION: tutorials and example files for learning or finding pre-made modules for your projects
USER FORUMS: meet with other users and exchange ideas, you can also get help and assistance here
NEW REGISTRATIONS - please contact us if you wish to register on the forum
Users are reminded of the forum rules they sign up to which prohibits any activity that violates any laws including posting material covered by copyright
[Ruby] How to call back from superclass to subclass?
6 posts
• Page 1 of 1
[Ruby] How to call back from superclass to subclass?
Ok, it isn't obvious what I'm looking for. So I try to use an example that is as close to a real world issue, as I can think of, while keeping it simple.
You have a class for centered coordinates. It defines a setter method.
A second class inherits A and uses x to calculate the top-left position.
Now, to actually do the update, I have to wait for x to change. If that happens, update is called afterwards. And here's where it gets ugly. Implementation:
I don't like that for two reasons:
1) defining x=(value) two times (I think it's called monkey patching) shouldn't be necessary in such an elegant language.
2) The update method in reality is a general updater, that not only updates @l, but some other variables as well. The superclass does not just host @x, but a lot of other variables. In effect, I need to define the setter two times for each of them, always with a call of update()
What I'm looking for, is a way to signalize the subclass, that a superclass method has been called, so that I can run update()
PSEUDOCODE!
Any ideas?
You have a class for centered coordinates. It defines a setter method.
- Code: Select all
class A
def initialize
@x = 0.0
end
def x=(value)
@x = value
end
end
A second class inherits A and uses x to calculate the top-left position.
- Code: Select all
class B < A
def initialize
@l = 0.0
end
def update
@l = @x - 2
end
end
Now, to actually do the update, I have to wait for x to change. If that happens, update is called afterwards. And here's where it gets ugly. Implementation:
- Code: Select all
class B < A
def initialize
@l = 0.0
end
def update
@l = @x - 2
end
def x=(value)
super(value)
update
end
end
I don't like that for two reasons:
1) defining x=(value) two times (I think it's called monkey patching) shouldn't be necessary in such an elegant language.
2) The update method in reality is a general updater, that not only updates @l, but some other variables as well. The superclass does not just host @x, but a lot of other variables. In effect, I need to define the setter two times for each of them, always with a call of update()
What I'm looking for, is a way to signalize the subclass, that a superclass method has been called, so that I can run update()
PSEUDOCODE!
- Code: Select all
class B < A
def initialize
@l = 0.0
end
def update
@l = @x - 2
end
def message_from_super
update()
end
end
Any ideas?
"There lies the dog buried" (German saying translated literally)
- tulamide
- Posts: 2714
- Joined: Sat Jun 21, 2014 2:48 pm
- Location: Germany
Re: [Ruby] How to call back from superclass to subclass?
Define a dummy update method in the parent and include it in each setter. Then you only need to modify the update method in the subclasses:
That is the simplest most elegant solution.
Alternatively, you may automate the monkey-patching by iterrating trough the parent's methods and declaring new method with the same name for each setter (name should match /^\w+=$/ or in english a nonzero-length word character (numbers/letters/_) string ending with "="). This has the added benefit, that it will also work with setter methods declared with attr_writer and attr_accessor methods. In the previous solution this would not be the case.
Note, you will have to update the specific ruby component for changes to apply, if you create new setters elsewhere.
Or you may list specific method names to for which this applies, if you're uncomfortable with relying on automatically detecting relevant method names.
EDIT: setters should always return the modified value. If they don't you can quickly run into problems.
- Code: Select all
class A
def update;end
def x=(v)
@x=v
update()
return v
end
end
class B < A
def update
@l=@x-2
end
end
That is the simplest most elegant solution.
Alternatively, you may automate the monkey-patching by iterrating trough the parent's methods and declaring new method with the same name for each setter (name should match /^\w+=$/ or in english a nonzero-length word character (numbers/letters/_) string ending with "="). This has the added benefit, that it will also work with setter methods declared with attr_writer and attr_accessor methods. In the previous solution this would not be the case.
Note, you will have to update the specific ruby component for changes to apply, if you create new setters elsewhere.
- Code: Select all
class B < A
A.instance_methods.select{
|name| name.to_s=~/^\w+=$/ #matches setter method names
}.each{|name|
#defines new method in B with identical name
define_method(name){|v| super(v);update();v}
}
end
Or you may list specific method names to for which this applies, if you're uncomfortable with relying on automatically detecting relevant method names.
- Code: Select all
class B < A
[:x=,:y=,:w=,:h=].each{|name|
#defines new method in B with identical name
define_method(name){|v| super(v);update();v}
}
end
EDIT: setters should always return the modified value. If they don't you can quickly run into problems.
- KG_is_back
- Posts: 1196
- Joined: Tue Oct 22, 2013 5:43 pm
- Location: Slovakia
Re: [Ruby] How to call back from superclass to subclass?
Reversing the monkey patching. Such a brilliant, yet simple solution. I wonder why this next logical step didn't occur to me. It is not a callback, but it makes the most sense (when reading the code sometime in the future, it is still obvious)KG_is_back wrote:Define a dummy update method in the parent and include it in each setter. Then you only need to modify the update method in the subclasses
I like this second most. Using a block, it even comes close to callbacks. However, since it is runtime code, it may confuse me, if I go back to the code in the future.KG_is_back wrote:Or you may list specific method names to for which this applies, if you're uncomfortable with relying on automatically detecting relevant method names.
- Code: Select all
class B < A
[:x=,:y=,:w=,:h=].each{|name|
#defines new method in B with identical name
define_method(name){|v| super(v);update();v}
}
end
What makes you think so? Or do you mean, when using iterating to create the methods? I don't use the return value in the original code example, but access @x directly from the subclass. That's what inheritance is all about (having access to all variables/methods of the superclass). So I hope there isn't a bug hidden somewhere?KG_is_back wrote:EDIT: setters should always return the modified value. If they don't you can quickly run into problems.
"There lies the dog buried" (German saying translated literally)
- tulamide
- Posts: 2714
- Joined: Sat Jun 21, 2014 2:48 pm
- Location: Germany
Re: [Ruby] How to call back from superclass to subclass?
I just stumbled upon this on stackoverflow. It is a very similar question, and the answer is not only preferring your solution 1 (so we all three agree), it is also stating why that is the ONLY solution, one should think of!
https://stackoverflow.com/a/4846249
https://stackoverflow.com/a/4846249
"There lies the dog buried" (German saying translated literally)
- tulamide
- Posts: 2714
- Joined: Sat Jun 21, 2014 2:48 pm
- Location: Germany
Re: [Ruby] How to call back from superclass to subclass?
tulamide wrote:What makes you think so? Or do you mean, when using iterating to create the methods? I don't use the return value in the original code example, but access @x directly from the subclass. That's what inheritance is all about (having access to all variables/methods of the superclass). So I hope there isn't a bug hidden somewhere?
It makes a difference when you stack assignment or use it inside other statements. Here is a simple scenario which would yield incorrect behavior:
- Code: Select all
#stacked assignment
var=obj.x=5 #you would expect var to receive same value as x. In reality it receives the return value of .x= method, which may be different if you implement .x= method incorrectly.
tulamide wrote:KG_is_back wrote:
Or you may list specific method names to for which this applies, if you're uncomfortable with relying on automatically detecting relevant method names.
CODE: SELECT ALL
class B < A
[:x=,:y=,:w=,:h=].each{|name|
#defines new method in B with identical name
define_method(name){|v| super(v);update();v}
}
end
I like this second most. Using a block, it even comes close to callbacks. However, since it is runtime code, it may confuse me, if I go back to the code in the future.
It will confuse the hell out of you. Especially if you are not careful with the order in which ruby components are loaded. The runtime code is only executed once exactly when the component loads. Shenanigans may occur, especially with the first version, when setters of the parent class get defined after this runtime auto-definer for the child class runs. You may easily end up with code working, saving the schematic and be broken or spammed with exceptions when loading the schematic later...
- KG_is_back
- Posts: 1196
- Joined: Tue Oct 22, 2013 5:43 pm
- Location: Slovakia
Re: [Ruby] How to call back from superclass to subclass?
I see what you mean regarding return value! In my case it doesn't have any impact, but if you create code that might be extended by others, it makes sense to keep that in mind.
For me the lesson was, that I should never try to let the superclass know of functionality of the subclass.
For me the lesson was, that I should never try to let the superclass know of functionality of the subclass.
"There lies the dog buried" (German saying translated literally)
- tulamide
- Posts: 2714
- Joined: Sat Jun 21, 2014 2:48 pm
- Location: Germany
6 posts
• Page 1 of 1
Who is online
Users browsing this forum: No registered users and 35 guests