Generic function CLOS

as a developer, one way or another faced with object-oriented programming, and tried to understand it, definitely heard of CLOS, the object system of Common Lisp language, one of the fundamental features which are the so-called "generalized functions", or, popularly, "multimethods".

Although many believe that generalized functions is simply the analogue of the static overload of functions, but only in dynamics, this is completely wrong.
Not quite right even to say that this extension dispatch for self/this, that is "virtual functions", for a few arguments.

Of course, multiple dispatching is one of the main chips of generalized functions, but their essence is not only and not so much in this.

Explain with an example — the calculator for simple math expressions.

If we take the language from the "classical" implementation of OOP, such as C#, we have something like the following:
the
interface IExpression
{
int Evaluate();
}

class Negation : IExpression
{
IExpression expr;
public Negation(IExpression e) { expr = e; }
public int Evaluate()
{
return-expr.Evaluate();
}
}

class Addition : IExpression
{
IExpression left, right;
public Addition(IExpression l, IExpression r) { left = l; right = r; }
public int Evaluate()
{
return left.Evaluate() + right.Evaluate();
}
}

class Number : IExpression
{
int value;
public Number(int v) { value = v; } 
public int Evaluate()
{
return value;
}
}


The Lisp code will be:
the
(defstruct (negation
(:constructor negation (expr))
(:conc-name nil))
expr)
(defstruct (addition
(:constructor addition (left right))
(:conc-name nil))
left right)

(defgeneric evaluate (expr)
(:method ((expr negation))
(to (evaluate (expr expr))))
(:method ((expr addition))
(+ (evaluate (left expr))
(evaluate (expr right))))
(:method ((expr number))
expr))

;; (evaluate (addition 5 (negation -5)))
;; ==> 10


The first thing that catches the eye, in addition to reducing the size of the code — methods are separated from data structures and grouped into generic functions.
The second obvious difference is the lack of interfaces as such.
In addition, we did not enter a new class or data structure for representing numbers, and just a specialized evaluate standard class number.

In General, the absence of CLOS concepts of interfaces in OO sense of the word, and abstract classes, pretty much, in my experience, hinders the porting of code with traditional object-oriented languages, and also puts additional obstacles in learning the language and object model for people who are accustomed to this most traditional OO-languages; in addition, problems such people creates a "requirement of the common signatures of a generalized function"(which means that all methods in the group the number of mandatory parameters must be the same), because these people write in traditional OO-style, simply by supplying an alleged "this" as first argument. Perhaps, someone of them also inconvenience the lack of classes access modifiers "properties" and separation of interface inheritance and implementation.

Yes, a direct projection of the classical OOP in CLOS doesn't work, or at least looks bad, but there's a very specific reason, and it consists in the following:

Methods from classes separated not just. The object paradigm CLOS is radically different from classic OOP, tied in the transfer and processing of messages(message passing).

CLOS shifts the emphasis from condition and behavior entity to interactions among themselves and with the outside world.

Above I wrote that interfaces in CLOS no. In fact, it is not so generalized functions is interfaces, and their methods of implementation.

At this point, someone from the adepts of functional programming might ask: "Well, well, what it's all different from the banal pattern-matching?".

You'll be a lot of it. First, specialization of the methods of generalized functions is possible by values and by classes, in the latter case — given inheritance. Secondly, the methods of generalized functions can be added, and even directly in runtime. And third, the dispatch can be arbitrarily manipulated by setting the generalized functions of the so-called "combinatory methods" and this is not to mention :before, :after and :around decorators for standard Combinator.
About combinators techniques I once wrote in his LJ, anyone can read, well, here I will show how using one of the built-in combinators, progn, to implement a sort of "designers" out of the ordinary OO-languages:
the
(defgeneric construct (object &key)
(:method-combination progn :most-specific-last))

(defun new (class &rest args &key &allow-other-keys)
(let ((object (make-instance class)))
(apply #'construct object args)
object))

(defclass superclass ()
(some-slot))
(defclass subclass (superclass)
())

(defmethod construct progn ((object superclass) &key value)
(setf (slot-value object 'some-slot) value)
(write-line "Superclass constructed"))

(defmethod construct progn ((object subclass) &key)
(write-line "Subclass constructed")
(format t "Slot value: ~s~%" (slot-value object 'some-slot)))

;; (new 'subclass :value 123)
;; ==> Superclass constructed
;; Subclass constructed
;; Slot value: 123


In my opinion, the object model of CLOS organically synthesized the best of OOP and functional programming and is still the most perfect realization of an paradigm.
It's a shame that her ideas are mainstream adopts very slowly and reluctantly, and brings to life worse.

Article based on information from habrahabr.ru

Комментарии

Популярные сообщения из этого блога

Why I left Google Zurich

2000 3000 icons ready — become a sponsor! (the table of orders)

New web-interface for statistics and listen to the calls for IP PBX Asterisk