-
Notifications
You must be signed in to change notification settings - Fork 50
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
can we do multiple inheritance in euslisp? #454
Comments
No, EusLisp do not support multiple inheritance and it is not possible to implement it without changing the fundamentals of how methods are searched for in the language. Message forwarding acts as pseudo multiple inheritance only for non-conflicting methods. (defclass foo :super object :slots (a))
(defmethod foo
(:test-foo (val) (1+ val)))
(defclass bar :super object :slots (b))
(defmethod bar
(:test-bar (val) (* val 2)))
(defclass foobar :super foo :slots ((bar-inst :forward (:test-bar))))
(defmethod foobar
(:init () (setq bar-inst (instance bar))))
irteusgl> (defvar c (instance foobar :init))
c
irteusgl> (send c :test-foo 1)
2
irteusgl> (send c :test-bar 2)
4 As for 'dynamically changing the method name', it seems that it may be sufficient to overwrite the metaclass irteusgl> (send foo :get-val 'methods)
((:test-foo (val) (1+ val)))
irteusgl> (send foo :set-val 'methods '((:test-foo-2 (val) (1+ val))))
((:test-foo-2 (val) (1+ val)))
irteusgl> (send c :test-foo-2 1)
2 |
This is another example of how to change the method name. |
Thank you for the answers. |
I found out that method-name changing approach have problems with #!/usr/bin/env roseus
(require :pr2-interface "package://pr2eus/pr2-interface.l")
(if (not (assoc :start-grasp-org (send pr2-interface :methods)))
(rplaca (assoc :start-grasp (send pr2-interface :methods)) :start-grasp-org))
(defmethod pr2-interface
(:start-grasp
(&optional (arm :arms) &key ((:objects objs) nil) &rest args)
(send* self :start-grasp-org arm args))) when I try to do
|
Makes sense, and thanks for the heads up! It is also interesting to notice that this seems to work for compiled code (?) ;; test.l
(defclass foo :super object)
(defmethod foo
(:test-foo () (return-from :test-foo :none)))
(rplaca (assoc :test-foo (send foo :methods)) :test-bar)
(setq c (instance foo)) Then (load "test.so")
(send c :test-bar) ;; :none If your objective is to ornament an existing method, though, why don't you use (standard single) inheritance? (require :pr2-interface "package://pr2eus/pr2-interface.l")
(defclass awesome-pr2-interface :super pr2-interface)
(defmethod awesome-pr2-interface
(:start-grasp
(&optional (arm :arms) &key ((:objects objs) nil) &rest args)
(send-super* :start-grasp arm args))) |
this is just a simple example and we can avoid this error when i use single inheritance. |
Oh, ok. By the way is the below fairly close to what you would want to achieve with 'multiple-inheritance'? If you could give us more details it would be easier to find better work-arounds. (defclass foo :super object :slots (a))
(defmethod foo
(:test-foo (val) (1+ val)))
(defclass bar :super object :slots (b))
(defmethod bar
(:test-foo (val) (* val 2)) ;; overlapping method
(:test-bar (val) (* val 10)))
(eval `(defclass foobar :super foo
:slots ((bar-inst :forward ,(mapcar #'car (send bar :all-methods))))))
(defmethod foobar
(:init () (setq bar-inst (instance bar)))
(:test-foo-bar (a) (send bar-inst :test-foo a)))
(defvar c (instance foobar :init))
(send c :test-foo 10) ;; 11
(send c :test-bar 10) ;; 100
(send c :test-foo-bar 10) ;; 20 |
@Affonso-Gui probably, your example is what I want to do. Thanks you. |
@Affonso-Gui (defclass foo :super object :slots (a))
(defmethod foo
(:test-foo (val) (1+ val)))
(defclass bar :super object :slots (b))
(defmethod bar
(:init (setq b 10))
(:test-foo (val) (* val (send self :test-bar val))) ;; overlapping method
(:test-bar (val) (* val b)))
(eval `(defclass foobar :super foo
:slots ((bar-inst :forward ,(mapcar #'car (send bar :all-methods)))))
(defmethod foobar
(:init () (setq bar-inst (instance bar)))
(:test-foo-bar (a) (send bar-inst :test-foo a)))
(defvar c (instance foobar :init))
(print (send c :test-foo 10)) ;; 11
(print (send c :test-bar 10)) ;; 100
(print (send c :test-foo-bar 10)) ;; 20 |
I am not sure why you are getting this result. When I try to run your code I get some errors regarding the parenthesis mismatch and faulty initialization, and when I correct them to what I think you were running then the code seems to execute normally. (defclass foo :super object :slots (a))
(defmethod foo
(:test-foo (val) (1+ val)))
(defclass bar :super object :slots (b))
(defmethod bar
(:init () (setq b 10))
(:test-foo (val) (* val (send self :test-bar val))) ;; overlapping method
(:test-bar (val) (* val b)))
(eval `(defclass foobar :super foo
:slots ((bar-inst :forward ,(mapcar #'car (send bar :all-methods))))))
(defmethod foobar
(:init () (setq bar-inst (instance bar :init)))
(:test-foo-bar (a) (send bar-inst :test-foo a)))
(defvar c (instance foobar :init))
(print (send c :test-foo 10)) ;; 11
(print (send c :test-bar 10)) ;; 100
(print (send c :test-foo-bar 10)) ;; 1000 Note:
|
Ok, I think I solved this. You were probably running your code after executing the sample I posted. This method should work just fine with slot variables as well. |
@Affonso-Gui sorry, it was my typo. and there is also a typo in |
@Affonso-Gui In that case, slot variable will not be shared, so we should take care of it. (defclass foo :super object :slots (b))
(defmethod foo
(:test-foo (val) (1+ val))
(:test-b () (setq b 10)))
(defclass bar :super object :slots (b))
(defmethod bar
(:init ())
(:test-foo (val) (* val (send self :test-bar val))) ;; overlapping method
(:test-b () (setq b 20))
(:test-bar (val) (send self :test-b) (* val b)))
(eval `(defclass foobar :super foo
:slots ((bar-inst :forward ,(mapcar #'car (send bar :all-methods))))))
(defmethod foobar
(:init () (setq bar-inst (instance bar :init)))
(:test-foo-bar (a) (send bar-inst :test-foo a)))
(defvar c (instance foobar :init))
(print (send c :test-foo 10)) ;; 11
(print (send c :test-bar 10)) ;; 200
(print (send c :test-foo-bar 10)) ;; 2000 |
maybe this example is better. (defclass foo :super object :slots (b))
(defmethod foo
(:test-foo (val) (1+ val))
(:test-b () (setq b 10)))
(defclass bar :super object :slots (b))
(defmethod bar
(:init ())
(:test-foo (val) (* val (send self :test-bar val))) ;; overlapping method
(:test-bar (val) (* val b))
(:test-b () (setq b 20)))
(eval `(defclass foobar :super foo
:slots ((bar-inst :forward ,(mapcar #'car (send bar :all-methods))))))
(defmethod foobar
(:init () (setq bar-inst (instance bar :init)))
(:test-foo-bar (val) (send bar-inst :test-foo val)))
(defvar c (instance foobar :init))
(print (send c :test-foo 10)) ;; 11
(send c :test-b)
(print (send c :test-bar 10)) ;; error
(print (send c :test-foo-bar 10)) ;; error |
Sharing slot variables is much more challenging. Actually in CLOS the |
can we do multiple inheritance in euslisp?
or can we dynamically change method name to avoid method name collision?
in euslisp doc, message forwarding is using pseudo multiple inheritance, but I could not find the code.
The text was updated successfully, but these errors were encountered: