At programming big and challenges the considerable quantity of programmers and their such quantity is required has faced an organizational problem. Object-oriented style of programming allows to use only little quantity of functions and not to know the device of the big system.
At early stages of development there were many varieties of such system. Closures were as one function with internal variables. The origin of the term "closure" speaks that closure remembers static links of unrestricted variables and does not allow to influence them external in relation to the given closure to functions. Variable closures cannot be used from the outside of closure, and changes of their values from the outside are not visible.
Object oriented programming where the object is small data structure which can be used by means of a small amount of functions (methods) was further development. Definition of objects is set by means of classes where all objects have identical quantity of internal variables and methods are set in a singular for all objects of the given class.
The object well suits for programming of generators. As the generator understand the object from which it is possible to receive new, distinct from former value. By each call the generator generates value of some type which is somewhat the following one after another. The following feature is inherent in generators: values are generated only at necessity and creation of following value is grounded on the previous. We Will give an example:
>(('natural-number defclass) defvar x) ; definition of an internal variable
natural-number
>('natural-number defmethod natural-number () ('x set 0)) ; constructor
(lambda nil ('x set 0))
>('natural-number defmethod next () ; the method which can be called for all objects
('x set (x + 1)))
(lambda nil ('x set (x + 1)))
>('number set ('natural-number newobject)) ; the new object of the given class
natural-number
The generator of numbers by means of a method next generates by each call an integer on unit more than generated in the previous call.
>(number next)
1
>(number next)
2
It is possible to create various copies of the generator, to give new initial value and to name a copy:
>('natural-number defmethod natural-number (x0) ; the constructor has the class name and is called at creation of the new object
('x set x0))
(lambda (x0) ('x set x0))
>('another-number set ('natural-number newobject 10))
natural-number
>(another-number next)
11
>(number next)
3
The big problem at programming this quantity of the common global variables. If all objects use one set of variables there are many unpleasant surprises, and programming becomes excessively difficult. Probably, "only one little global variable" does not become too uncontrollable, but similar style leads to a code which is useless for everything, except the programmer who has written it.
We can save convenience of a default and avoid troubles because of global variable appearance. The variable which is a class part, but is not a part of the object of this class, is named as a static member. There is exactly one copy of a static member, in difference from usual members when each object of a class has the independent members.
Let's give an example the constructor of the object which uses a default value, using a static member of the object:
>('natural-number defstatic 'initial-value 5)
natural-number
>('natural-number defmethod natural-number ()
('x set initial-value))
(lambda nil ('x set initial-value))
>('number set ('natural-number newobject))
natural-number
>(number next)
6
At implementation of methods the reference to itself is set by a variable this. This variable is required for restart of the method in a method. Also it is possible to give a given data as value of argument to other functions. The given variable unusual, is not recommended to change its value, basically is used for reading.
It is possible in methods to return itself for convenience of records.
>('natural-number defmethod value () x)
(lambda nil x)
>(number value)
6
>('natural-number defmethod ++ ()
('x set (x + 1)) this)
(lambda nil ('x set (x + 1)) this)
>(((number ++) ++) ++)
natural-number
>(number value)
9
Let's accept, we create the program handling the information on employees of the corporation. The following class can be necessary for such program:
>(('employee defclass) defvar name surname date-hiring department)
employee
Then we can try to define the manager:
>(('manager defclass) defvar emp ; data on the manager as about the employee
group ; subordinates
level)
manager
The manager also is the employee; appropriate data are stored in a member emp object manager. To attentively reading person it can be and it is obvious, but here nothing speaks the program, that the manager is at the same time and the employee. The correct approach - obviously to specify, that the manager is the employee.
>(('manager defclass employee) defvar group level)
manager
The class manager is derivative from employee, and employee is a base class for manager. A class manager except own members (group and level) contains members of a class employee ( name, department, etc.).
Simple classes, such as employee and manager, as a rule do not represent the big interest and are not especially useful. That is required to us is a representation of the information in the form of suitable type with an appropriate set of the operations mirroring the concept. We wish to make it, not penetrating in a detail of concrete implementation. For example:
>(('employee defclass) defvar name surname …)
employee
>('employee defmethod complete-name ()
(name + #\space surname))
(lambda nil (name + #\space surname))
>('employee defmethod writeln ()
(cout writeln (this complete-name)))
(lambda nil (cout writeln (this complete-name)))
The member of a derivative class can use methods of a base class as if they are declared in the most derivative class. For example:
('manager defmethod writeln ()
(cout writeln "Name: " (this complete-name))
For convenience it is possible to use methods of a base class, using full method name :
('manager defmethod writeln ()
(cout write "Name: ") (this employee::writeln)
(cout writeln "Level: " level))
For domestic service work of the object methods are necessary gated access. These methods can be called only within the working of method. This feature is implemented only by determining the value of a static member as lambda-list.
('manager defstatic 'private-method '(lambda ()
top-secret)
Calling this function can only work within the method using the eval, funcall, appply.