X-Git-Url: http://matita.cs.unibo.it/gitweb/?a=blobdiff_plain;f=helm%2FDEVEL%2Fpxp%2Fpxp%2Fdoc%2Fmanual%2Fhtml%2Fx1439.html;fp=helm%2FDEVEL%2Fpxp%2Fpxp%2Fdoc%2Fmanual%2Fhtml%2Fx1439.html;h=26773057472438634725337ac1d3b979822fe8f5;hb=c03d2c1fdab8d228cb88aaba5ca0f556318bebc5;hp=0000000000000000000000000000000000000000;hpb=758057e85325f94cd88583feb1fdf6b038e35055;p=helm.git diff --git a/helm/DEVEL/pxp/pxp/doc/manual/html/x1439.html b/helm/DEVEL/pxp/pxp/doc/manual/html/x1439.html new file mode 100644 index 000000000..267730574 --- /dev/null +++ b/helm/DEVEL/pxp/pxp/doc/manual/html/x1439.html @@ -0,0 +1,464 @@ +The class type extension
The PXP user's guide
PrevChapter 3. The objects representing the documentNext

3.3. The class type extension

class type [ 'node ] extension =
+  object ('self)
+    method clone : 'self
+      (* "clone" should return an exact deep copy of the object. *)
+    method node : 'node
+      (* "node" returns the corresponding node of this extension. This method
+       * intended to return exactly what previously has been set by "set_node".
+       *)
+    method set_node : 'node -> unit
+      (* "set_node" is invoked once the extension is associated to a new
+       * node object.
+       *)
+  end
+ +This is the type of classes used for node extensions. For every node of the +document tree, there is not only the node object, but also +an extension object. The latter has minimal +functionality; it has only the necessary methods to be attached to the node +object containing the details of the node instance. The extension object is +called extension because its purpose is extensibility.

For some reasons, it is impossible to derive the +node classes (i.e. element_impl and +data_impl) such that the subclasses can be extended by new +new methods. But +subclassing nodes is a great feature, because it allows the user to provide +different classes for different types of nodes. The extension objects are a +workaround that is as powerful as direct subclassing, the costs are +some notation overhead.

Figure 3-6. The structure of nodes and extensions

The picture shows how the nodes and extensions are linked +together. Every node has a reference to its extension, and every extension has +a reference to its node. The methods extension and +node follow these references; a typical phrase is + +

self # node # attribute "xy"
+ +to get the value of an attribute from a method defined in the extension object; +or + +
self # node # iter
+  (fun n -> n # extension # my_method ...)
+ +to iterate over the subnodes and to call my_method of the +corresponding extension objects.

Note that extension objects do not have references to subnodes +(or "subextensions") themselves; in order to get one of the children of an +extension you must first go to the node object, then get the child node, and +finally reach the extension that is logically the child of the extension you +started with.

3.3.1. How to define an extension class

At minimum, you must define the methods +clone, node, and +set_node such that your class is compatible with the type +extension. The method set_node is called +during the initialization of the node, or after a node has been cloned; the +node object invokes set_node on the extension object to tell +it that this node is now the object the extension is linked to. The extension +must return the node object passed as argument of set_node +when the node method is called.

The clone method must return a copy of the +extension object; at least the object itself must be duplicated, but if +required, the copy should deeply duplicate all objects and values that are +referred by the extension, too. Whether this is required, depends on the +application; clone is invoked by the node object when one of +its cloning methods is called.

A good starting point for an extension class: + +

class custom_extension =
+  object (self)
+
+    val mutable node = (None : custom_extension node option)
+
+    method clone = {< >} 
+
+    method node =
+      match node with
+          None ->
+            assert false
+        | Some n -> n
+
+    method set_node n =
+      node <- Some n
+
+  end
+ +This class is compatible with extension. The purpose of +defining such a class is, of course, adding further methods; and you can do it +without restriction.

Often, you want not only one extension class. In this case, +it is the simplest way that all your classes (for one kind of document) have +the same type (with respect to the interface; i.e. it does not matter if your +classes differ in the defined private methods and instance variables, but +public methods count). This approach avoids lots of coercions and problems with +type incompatibilities. It is simple to implement: + +

class custom_extension =
+  object (self)
+    val mutable node = (None : custom_extension node option)
+
+    method clone = ...      (* see above *)
+    method node = ...       (* see above *)
+    method set_node n = ... (* see above *)
+
+    method virtual my_method1 : ...
+    method virtual my_method2 : ...
+    ... (* etc. *)
+  end
+
+class custom_extension_kind_A =
+  object (self)
+    inherit custom_extension
+
+    method my_method1 = ...
+    method my_method2 = ...
+  end
+
+class custom_extension_kind_B =
+  object (self)
+    inherit custom_extension
+
+    method my_method1 = ...
+    method my_method2 = ...
+  end
+ +If a class does not need a method (e.g. because it does not make sense, or it +would violate some important condition), it is possible to define the method +and to always raise an exception when the method is invoked +(e.g. assert false).

The latter is a strong recommendation: do not try to further +specialize the types of extension objects. It is difficult, sometimes even +impossible, and almost never worth-while.

3.3.2. How to bind extension classes to element types

Once you have defined your extension classes, you can bind them +to element types. The simplest case is that you have only one class and that +this class is to be always used. The parsing functions in the module +Pxp_yacc take a spec argument which +can be customized. If your single class has the name c, +this argument should be + +

let spec =
+  make_spec_from_alist
+    ~data_exemplar:            (new data_impl c)
+    ~default_element_exemplar: (new element_impl c)
+    ~element_alist:            []
+    ()
+ +This means that data nodes will be created from the exemplar passed by +~data_exemplar and that all element nodes will be made from the exemplar +specified by ~default_element_exemplar. In ~element_alist, you can +pass that different exemplars are to be used for different element types; but +this is an optional feature. If you do not need it, pass the empty list.

Remember that an exemplar is a (node, extension) pair that serves as pattern +when new nodes (and the corresponding extension objects) are added to the +document tree. In this case, the exemplar contains c as +extension, and when nodes are created, the exemplar is cloned, and cloning +makes also a copy of c such that all nodes of the document +tree will have a copy of c as extension.

The ~element_alist argument can bind +specific element types to specific exemplars; as exemplars may be instances of +different classes it is effectively possible to bind element types to +classes. For example, if the element type "p" is implemented by class "c_p", +and "q" is realized by "c_q", you can pass the following value: + +

let spec =
+  make_spec_from_alist
+    ~data_exemplar:            (new data_impl c)
+    ~default_element_exemplar: (new element_impl c)
+    ~element_alist:            
+      [ "p", new element_impl c_p;
+        "q", new element_impl c_q;
+      ]
+    ()
+ +The extension object c is still used for all data nodes and +for all other element types.


PrevHomeNext
The class type nodeUpDetails of the mapping from XML text to the tree representation
\ No newline at end of file