Return Styles: Pseud0ch, Terminal, Valhalla, NES, Geocities, Blue Moon. Entire thread

why do you guys hate c++?

Name: Anonymous 2010-08-27 18:56

apparently one of you was in /v/ a day ago going on a little tirade against c++. why would it be so popular if there was "absolutely nothing good about it" like you said?

Name: Anonymous 2010-08-28 12:25

>>15

Only in languages that have crappy support for multiple inheritance.

(Background: The diamond problem is a simple multiple-inheritance problem. You have 4 classes A,B,C,D. A is a base class, B and C inherit from A and D inherits from both B and C. A has a method, B and C override that method somehow, which method would be used for D? A's, B's or C's?)

In some languages the problem doesn't exist at all. For example, in Common Lisp, you have a variety of options for deciding the effective method. The default behaviour would be to select the most specific method, and use the class order in the inheritance list (for class D) to decide wether to use B or C's (using class A is possible using . Besides that, you can control method combinations in a lot of ways (combinations provided by default), or even define your own combinations which can do just about anything you desire, and if that isn't enough you can rewrite the entire damn object system using the MOP. So the user is given a good default resolution with the option to customize it as much as it wants. The good default is possible because classes and methods are separated (meta) objects (methods can specialize on classes, but classes themselves only contain data, methods are not just directly associated with just one class like in single-inheritance languages (however, if you wish to write in the simple single-inheritance style, nothing prevents you from doing that, it's very simple, just you'll notice there are usually much more flexible ways to do things), instead they can specialize on classes, and even built-in data-types...) each serving different, but interconnected purposes.

Anyways, I was a bit bored, and decided to show off a few such features CL has:


;;; Define the classes, A, B inheriting from A, C inheriting from A,
;;; D inheriting from B and C (or in the latter example, from C and B)

(defclass a () ())
(defclass b (a) ())
(defclass c (a) ())
(defclass d (b c) ())

;;; Define 3 methods on each class

(defmethod meth ((x a)) (print "From A"))
(defmethod meth ((x b)) (print "From B"))
(defmethod meth ((x c)) (print "From C"))

;; Show how the diamond inheritance works by default in CL
;; using standard method combination with no qualifiers
;; or other significant specializers.
;; The order of superclasses is what is used: (b c)

(meth (make-instance 'd)) ; => "From B"

;; Reverse the order and observe new results:

(defclass d (c b) ())

(meth (make-instance 'd)) ; => "From C"

;; what if we want to perform something in `meth' that applies to everything
;; inheriting from A?

(defmethod meth :before ((x a))
  (print "Before A"))

(meth (make-instance 'd)) ; =>
                          ; "Before A"
                          ; "From B"

(meth (make-instance 'c)) ; =>
                          ; "Before A"
                          ; "From C"

(meth (make-instance 'b)) ; =>
                          ; "Before A"
                          ; "From B"

(meth (make-instance 'a)) ; =>
                          ; "Before A"
                          ; "From A"

;;; There are also :after and :around qualifiers for the standard method
;;; combination, which offer you a lot more control
;;; :around allows fully overriding the method, while
;;; :after allows you to run some code after it (like :before)
;;; see the Hyperspec on the exact details on the order of methods

;;; Since we're doing this in a runtime system, we'll remove the :before
;;; method at runtime (you can of course just unintern the class or use
;;; the inspector to do it for you, or just reload everything):

(remove-method #'meth (find-method #'meth '(:before) `(,(find-class 'a))))

(meth (make-instance 'a)) ;=> "From A"

;; a standard way to chain methods using the standard method combination

(defmethod meth ((x b))
  (print "From B")
  (call-next-method))

(defmethod meth ((x c))
  (print "From C")
  (call-next-method))

(meth (make-instance 'd)) ; => "From B" "From C"  "From A"

;; reversing the order the effective method is chosen by using an alternate method combination

(defgeneric meth2 (x)
  (:method-combination or :most-specific-last))

(defmethod meth2 or ((x a)) (print "From A"))
(defmethod meth2 or ((x b)) (print "From B"))
(defmethod meth2 or ((x c)) (print "From C"))

(meth2 (make-instance 'd)) ;=> "From A"

;; a simple, but very violent/destructive way to to call A's
;; method directly (convert the class to a base class):

(defmethod meth ((x d))
  (meth (change-class x 'a)))

(meth (make-instance 'd)) ; => "From A"


;; a proper way to directly call the method specialized on A,
;; bypassing other "next" methods using the MOP:

(require :closer-mop)

(defmethod meth ((x d))
  (funcall (c2mop:method-function
        (find-method #'meth '() (list (find-class 'a))))      
       (list x) '()))

(meth (make-instance 'd))        ; => "From A"

;; What if we want some crazy arbitrary, runtime determined way of picking
;; which method to run? Here's an example which picks
;; a random method to run at runtime!

(define-method-combination :random ()
  ((methods *))
  `(ecase (random ,(length methods))
     ,@(loop for i from 0
         for method in methods
         collect `(,i (call-method ,method ',(remove method methods))))))

(defgeneric meth3 (x)
  (:method-combination :random))

(defmethod meth3 :random ((x a)) (print "From A"))
(defmethod meth3 :random ((x b)) (print "From B"))
(defmethod meth3 :random ((x c)) (print "From C"))

(meth3 (make-instance 'd))
;=> prints "From A", "From B" or "From C", depending on the current random state


;;; Either way I could go on showing standard CL, MOP, method combination,
;;; specializer tricks and many others which show that you have complete
;;; liberty in choosing any method you want despite multiple inheritance,
;;; however such tricks are countless and you could easily see them
;;; by reading the AMOP and a good CL book, so I won't bother showing
;;; any more here.

;;; However, I tend to find the defaults sane, and I can't remember resorting
;;; to most of the tricks I presented here in my day to day coding, but
;;; the point is that these features are there in case you need them
;;; and not only that, you can pretty much redefine the OO system
;;; in itself in almost its entirety using the MOP, if you so need.

Newer Posts
Don't change these.
Name: Email:
Entire Thread Thread List