Index: doc/next-tutorial/next-tutorial.txt =================================================================== diff -u -r26480a59b14cf250904da0cdc7d895f21b0ed5fd -rc2374366bcb47c70ebd33cb16c8152eba783987f --- doc/next-tutorial/next-tutorial.txt (.../next-tutorial.txt) (revision 26480a59b14cf250904da0cdc7d895f21b0ed5fd) +++ doc/next-tutorial/next-tutorial.txt (.../next-tutorial.txt) (revision c2374366bcb47c70ebd33cb16c8152eba783987f) @@ -1,7 +1,7 @@ Tutorial for the Next Scripting Language ========================================== Gustaf Neumann , Stefan Sobernig -v2.1, March 2011: +v2.0b5, June 2013: Written for the Initial Release of the Next Scripting Framework. :Author Initials: GN :toc: @@ -39,7 +39,7 @@ the universal method combinator "next", which was introduced in XOTcl. The combinator "next" serves as a single instrument for method combination with filters, per-object and transitive per-class mixin -classes, per-object methods and multiple inheritance. +classes, object methods and multiple inheritance. The definition of NX is fully scripted (e.g. defined in +nx.tcl+). The Next Scripting Framework is shipped with three language @@ -87,7 +87,7 @@ examples. In later sections we introduce the more advanced concepts of the language. Conceptually, most of the addressed concepts are very similar to XOTcl. Concerning the differences between NX and XOTcl, -please refer to the "Migration Guide for the Next Scripting Language". +please refer to the _Migration Guide for the Next Scripting Language_. == Introductory Overview Example: Stack @@ -255,30 +255,28 @@ In our next example, we introduce _generic objects_ and _object specific methods_. With NX, we can define generic objects, which are instances of the most generic class +nx::Object+ (sometimes called -"common root class"). +nx::Object+ is predefined and contains a -minimal set of methods applicable to all NX objects. +_common root class_). +nx::Object+ is predefined and contains a +minimal set of methods applicable to all NX objects. In this example, +we define a generic object named +stack+ and provide methods for this +object. The methods defined above were methods provided by a class for +objects. Now we define object specific methods, which are methods +applicable only to the object for which they are defined. -In our second example, we will define a generic object named +stack+ -and provide methods for this object. The methods defined in our first -example were methods provided by a class for objects. Now we defined -object specific methods, which are methods applicable only to the -object for which they are defined. - [[xmp-object-stack]] .Listing {counter:figure-number}: Object stack {set:xmp-object-stack:Listing {figure-number}} [source,tcl,numbers] -------------------------------------------------- nx::Object create stack { - :variable things {} + :object variable things {} - :public method push {thing} { + :public object method push {thing} { set :things [linsert ${:things} 0 $thing] return $thing } - :public method pop {} { + :public object method pop {} { set top [lindex ${:things} 0] set :things [lrange ${:things} 1 end] return $top @@ -293,12 +291,14 @@ - First, we use +nx::Object+ instead of +nx::Class+ to denote that we want to create a generic object, not a class. -- As in the example above, we use +:variable+ to define the - instance variable +things+ for this object (the object +stack+). +- We use +:object variable+ to define the variable +things+ just for + this single instance (the object +stack+). -The definition for the methods +push+ and +pop+ are the same as -before, but this times these methods are object-specific (in general, -all methods defined for an object are object-specific). In order to use +- The definition for the methods +push+ and +pop+ are the same as + before, but here we defined these with +object method+. Therefore, + these two methods +push+ and +pop+ are object-specific. + +In order to use the stack, we can use directly the object +stack+ in the same way as we have used the object +s1+ in <> (e.g. +stack push a+). <> shows @@ -311,7 +311,7 @@ A reader might wonder when to use a class +Stack+ or rather an object +stack+. A big difference is certainly that one can define easily multiple instances of a class, while the object is actually a -singleton. The concept of the object +stack+ is similar to a module, +single, tailored entity. The concept of the object +stack+ is similar to a module, providing a certain functionality via a common interface, without providing the functionality to create multiple instances. The reuse of methods provided by the class to objects is as well a difference. If @@ -402,7 +402,7 @@ ::Safety % Stack create s1 ::s1 -% Stack create s2 -mixin Safety +% Stack create s2 -object-mixin Safety ::s2 % s2 push a a @@ -428,8 +428,9 @@ mixin class +Safety+ generates an error message (raises an exception), and does not invoke the method of the +Stack+. -The last two commands in <> use introspection to query for the objects +The last two commands in +<> +use introspection to query for the objects +s1+ and +s2+ in which order the involved classes are processed. This order is called the +precedence order+ and is obtained via +info precedence+. We see that the mixin class +Safety+ is only in use for @@ -440,15 +441,15 @@ image::per-object-mixin.png[title="Per-object Mixin",align="center"] {set:img-per-object-mixin:Figure {figure-number}} -Note that the class +Safety+ is only mixed into a single object (here +Note that in <>, +the class +Safety+ is only mixed into a single object (here +s2+), therefore we refer to this case as a _per-object mixin_. <> shows the class diagram, where the class +Safety+ is used as a per-object mixin for +s2+. -The class +Safety+ can be used as well in other ways, such as e.g. for -defining classes for safe stacks <>. +The mixin class +Safety+ can be used as well in other ways, such as e.g. for +defining classes of safe stacks: [[xmp-class-safestack]] .Listing {counter:figure-number}: Class SafeStack @@ -464,17 +465,20 @@ SafeStack create s3 -------------------------------------------------- -The difference to the case with the per-object mixin is that now, -+Safety+ is mixed into the definition of +SafeStack+. Therefore, all -instances of the class +SafeStack+ (here the instance +s3+) will be -using the safety definitions. -<> shows the class diagram -for this definition. +The difference of a per-class mixin and an per-object mixin is that +the per-class mixin is applicable to all instances of the +class. Therefore, we call these mixins also sometimes instance mixins. +In our example in <>, ++Safety+ is mixed into the definition of ++SafeStack+. Therefore, all instances of the class +SafeStack+ (here +the instance +s3+) will be using the safety definitions. [[img-per-class-mixin]] image::per-class-mixin.png[title="Per-class Mixin",align="center"] {set:img-per-class-mixin:Figure {figure-number}} +<> shows the class diagram +for this definition. Note that we could use +Safety+ as well as a per-class mixin on +Stack+. In this case, all stacks would be safe stacks and we could not provide a selective feature selection (which might be perfectly @@ -501,7 +505,7 @@ # to check the type of entries # - :public method push {thing:integer} { + :public object method push {thing:integer} { next } } @@ -545,25 +549,22 @@ +IntegerStack+ is defined, using the same method definition as +s4+, this time on the class level. -=== Define Class Specific Methods +=== Define Object Specific Methods on Classes In our previous examples we defined methods provided by classes (applicable for their instances) and object-specific methods (methods defined on objects, which are only applicable for these objects). In -this section, we introduce methods that are defined on classes. These -method are only applicable for the class objects. Such methods are -sometimes called _class methods_ or _static methods_. +this section, we introduce methods that are defined on the class +objects. Such methods are sometimes called _class methods_ or +_static methods_. -In NX classes are objects with certain properties. The classes are -objects providing methods for instance and which are managing the -life-cycles of the objects (we will come to this point in later -sections in more detail). Since classes are objects, it is also -possible to define object-specific methods for the class -objects. However, since +:method+ applied on classes defines methods -for instances, we have to use the method-modifier +class+ to denote -methods to be applied on the class itself. Note that instances do not -inherit class methods. The methods defined on the class object are -actually exactly same as the object-specific methods shown in the +In NX classes are objects, they are specialized objects with +additional methods. Methods for classes are often used for managing +the life-cycles of the instances of the classes (we will come to this +point in later sections in more detail). Since classes are objects, we +can use exactly the same notation as above to define class methods by +using +object method+. The methods defined on the class object are +in all respects identical with object specific methods shown in the examples above. [[xmp-stack2]] @@ -573,7 +574,7 @@ -------------------------------------------------- nx::Class create Stack2 { - :public class method available_stacks {} { + :public object method available_stacks {} { return [llength [:info instances]] } @@ -621,7 +622,7 @@ create or modify variables on the fly by using for example the Tcl commands +set+ and +unset+. Depending on the variable name (or more precisely, depending on the variable name's prefix consisting of -colons +:+) a variable is either local to a method, or it is an +colons "+:+") a variable is either local to a method, or it is an instance variable, or a global variable. The rules are: - A variable without any colon prefix refers typically to a method @@ -662,33 +663,40 @@ of some class +Foo+ referring to differently scoped variables. -==== Properties: Instance Variables with Accessors +==== Properties: Configurable Instance Variables -Generally, there is no need to define or declare instance variables in -NX. In some cases, however, a definition of instance variables is -useful. NX allows us to define instances variables as _properties_ on -classes, which are inherited to subclasses. Furthermore, the -definition of properties can be used the check permissible values for -instance variables or to initialize instance variables from default -values during object initialization. +As described above, there is no need to declare instance variables in +NX. In many cases, a developer might want to define some value +constraints for variables, or to provide defaults, or to make +variables configurable upon object creation. Often, variables are +"inherited", meaning that the variables declared in a general class +are also available in a more specialized class. For these purposes NX +provides _variable handlers_ responsible for the management of +instance variables. We distinguish in NX between configurable +variables (called +property+) and variables that are not configurable +(called +variable+). ========================================= -A *property* is a definition of an attribute (an instance variable) -with accessor methods. A property definition might carry -value-constraints and a default value. +A *property* is a definition of a configurable instance variable. ========================================= +The term configurable means that (a) one can provide at creation time of +an instance a value for this variable, and (b), one can query the +value via the accessor function +cget+ and (c), one can change the +value of the variable via +configure+ at runtime. Since the general +accessor function +cget+ and +configure+ are available, an application +developer does not have to program own accessor methods. When value +checkers are provided, each time, the value of the variable is to be +changed, the constrained are checked as well. + [[img-person-student]] image::person-student.png[align="center",title="Classes Person and Student"] {set:img-person-student:Figure {figure-number}} The class diagram above defines the classes +Person+ and -+Student+. For both classes, accessor methods are specified with the -same names as the attributes. (Note that we show the accessor methods -only in this example, we omit it in later ones). By defining -properties we can use the name of the attribute as method name to -access the attributes. The listing below shows an implementation of this -conceptual model in NX. ++Student+. For both classes, configurable instance variable are +specified by defining these as properties. The listing below shows +an implementation of this conceptual model in NX. [[xmp-properties]] .Listing {counter:figure-number}: Properties @@ -714,22 +722,23 @@ } # -# Create instances using object parameters +# Create instances using configure parameters # for the initialization # Person create p1 -name Bob Student create s1 -name Susan -matnr 4711 # Access property value via accessor method -puts "The name of s1 is [s1 name]" +puts "The name of s1 is [s1 cget -name]" -------------------------------------------------- -By defining +name+ and +birthday+ as properties of +Person+, NX -provides automatically accessor methods with the same name. The -accessors methods (or shortly called "accessors") provide read and -write access to the underlying instance variables. In our example, the -class +Person+ has two methods implied by the +property+ definition: -the method +name+ and the method +birthday+. +By defining +name+ and +birthday+ as properties of +Person+, NX makes +these configurable. When we create an instance of +Person+ named ++p1+, we can provide a value for e.g. the name by specifying +-name+ +during creation. The properties result in non-positional configure parameters +which can be provided in any order. In our listing, we create an instance of ++Person+ using the configure parameter +name+ and provide the value of ++Bob+ to the instance variable +name+. The class +Student+ is defined as a specialization of +Person+ with two additional properties: +matnr+ and +oncampus+. The property @@ -738,28 +747,41 @@ default set to +true+. Note that the class +Student+ inherits the properties of +Person+. So, +Student+ has four properties in total. -The property definitions are also used to providing +object -parameters+. These are typically non-positional parameters, which are -used during object creation to supply values to the instance -variables. In our listing, we create an instance of +Person+ using the -object parameter +name+ and provide the value of +Bob+ to the instance -variable +name+. Similarly, we create an instance of +Student+ using -the two object parameters +name+ and +matnr+. Finally, we use the -accessor method +name+ to obtain the value of the instance variable -+name+ of object +s1+. +The property definitions provide the +configure parameters+ for +instance creation. Many other languages require such parameters to be +passed via arguments of a constructor, which is often error prone, +when values are to be passed to superclasses. Also in dynamic +languages, the relationships between classes can be easily changed, +and different superclasses might have different requirements in their +constructors. The declarative approach in NX reduces the need for +tailored constructor methods significantly. +Note, that the property +matnr+ of class +Student+ is required. This +means, that if we try to create an instance of +Student+, a runtime +exception will be triggered. The property +oncamups+ is boolean and +contains a default value. Providing a default value means that +whenever we create an instance of this class the object will contain +such an instance variable, even when we provide no value via the +configure parameters. -==== Instance Variables without Accessors +In our listing, we create an instance of +Student+ using the two +configure parameters +name+ and +matnr+. Finally, we use method +cget+ +to obtain the value of the instance variable +name+ of object +s1+. -To define instances variables with default values without accessors -the predefined method +variable+ can be used. Such instance variables -are often used for e.g. keeping the internal state of an object. The + +==== Non-configurable Instance Variables + +In practice, not all instance variables should be configurable. But +still, we want to be able to provide defaults similar to +properties. To define non-configurable instance variables the +predefined method +variable+ can be used. Such instance variables are +often used for e.g. keeping the internal state of an object. The usage of +variable+ is in many respects similar to +property+. One difference is, that +property+ uses the same syntax as for method -parameters, whereas +variable+ receives the default value as a separate -argument (similar to the +variable+ command in Tcl). The introductory -Stack example in <> uses already -the method +variable+. +parameters, whereas +variable+ receives the default value as a +separate argument (similar to the +variable+ command in plain +Tcl). The introductory Stack example in <> uses already the method +variable+. [[xmp-variable]] .Listing {counter:figure-number}: Declaring Variables @@ -787,7 +809,10 @@ properties. The example in <> shows a class +Derived+ that inherits from +Base+. When an instance +d1+ is created, it will contain the two instance variables +x+ and +y+. +Note that the variable declarations from +property+ and +variable+ are +used to initialize (and to configure) the instances variables of an object. + [[xmp-constructor]] .Listing {counter:figure-number}: Setting Variables in the Constructor {set:xmp-constructor:Listing {figure-number}} @@ -821,6 +846,12 @@ requires an explicit method chaining between the constructors and is less declarative than the approach in NX using +property+ and +variable+. +Both, +property+ and +variable+ provide much more functionalities. One +can for example declare +public+, +protected+ or +private+ accessor +methods, or one can define variables to be incremental (for +e.g. adding values to a list of values), or one can define variables +specific behavior. + === Method Definitions The basic building blocks of an object oriented program are object and @@ -892,16 +923,19 @@ _aliases_. =========================================== -An *accessor method* is in most cases a C-implemented method that -accesses instance variables of an object. A call to an accessor +An *accessor method* is a method that accesses instance +variables of an object. A call to an accessor without arguments uses the accessor as a getter, obtaining the actual value of the associated variable. A call to an accessor with an argument uses it as a setter, setting the value of the associated variable. =========================================== -Accessors have already been discussed in the section about properties, -in which the accessors were created automatically. +NX provides support for C-implemented accessor methods. Accessors have +already been mentioned in the section about properties. When +the option +-accessor public|protected|private+ is provided to a ++variable+ or +property+ definition, NX creates automatically a +same-named accessors method. [[xmp-fido2]] .Listing {counter:figure-number}: Accessor Methods @@ -914,7 +948,7 @@ } nx::Class create Tail { - :property {length:double 5} + :property -accessor public {length:double 5} :public method wag {} {return Joy} } @@ -941,7 +975,8 @@ full name of the subobject +fido::tail+. The method +length+ is an C-implemented accessor, that enforces the value constraint (here a floating point number, since length uses the value constraint -+double+). ++double+). Line 25 will therefore raise an exception, since the +provided values cannot be converted to a double number. [[xmp-fido3]] .Listing {counter:figure-number}: Forwarder Methods @@ -952,12 +987,12 @@ :public method bark {} { puts "[self] Bark, bark, bark." } :method init {} { Tail create [self]::tail - :public forward wag [self]::tail wag + :public object forward wag [self]::tail wag } } nx::Class create Tail { - :property {length 5} + :property -accessor public {length 5} :public method wag {} {return Joy} } @@ -1026,7 +1061,7 @@ -------------------------------------------------- <> extends the last example by defining an -alias for the method "bark". The example only shows the bare +alias for the method +bark+. The example only shows the bare mechanism. In general, method aliases are very powerful means for reusing pre-existing functionality. The full object system of NX and XOTcl2 is built from aliases, reusing functionality provided by the @@ -1133,10 +1168,10 @@ all other purposes, the private methods are "invisible" in all situations, e.g., when mixins are used, or within the +next+-path, etc. -By using the +-local+ flag at the call site it is possible to invoce +By using the +-local+ flag at the call site it is possible to invoke only the local definition of the method. If we would call the method without this flag, the resolution order would be the standard -resolution order, starting with filters, mixins, per-object methods +resolution order, starting with filters, mixins, object methods and the full intrinsic class hierarchy. NX supports the modifier +private+ for methods and properties. In all @@ -1146,9 +1181,9 @@ locality of the code e.g. for compositional operations. In order to improve locality for properties, a private property -defines therfore internally a variable with a different name to avoid +defines therefore internally a variable with a different name to avoid unintended interactions. The variable should be accessed via the -private accessor, which can be invoved with the +-local+ flag. In the +private accessor, which can be invoked with the +-local+ flag. In the following example class +D+ introduces a private property with the same name as a property in the superclass. @@ -1158,10 +1193,10 @@ [source,tcl,numbers] -------------------------------------------------- # -# Define a class C with a (public) property "x" +# Define a class C with a property "x" and a public accessor # nx::Class create C { - :property {x c} + :property -accessor public {x c} } # @@ -1170,7 +1205,7 @@ # the private property. # nx::Class create D -superclass C { - :private property {x d} + :property -accessor private {x d} :public method bar {p} {return [: -local $p]} } @@ -1227,29 +1262,29 @@ ==== Object Methods =========================================== -Methods defined on objects are *per-object methods*. Per-object +Methods defined on objects are *object methods*. Object methods are only applicable on the object, on which they are defined. -Per-object methods cannot be inherited from other objects. +Object methods cannot be inherited from other objects. =========================================== -The following example defines an object specific method +bar+ on the +The following example defines an object method +bar+ on the instance +c1+ of class +C+, and as well as the object specific method -+baz+ defined on the object +o1+. An object-specific method is defined -simply by defining the method on an object. ++baz+ defined on the object +o1+. An object method is defined +via +object method+. -Note that we can define a per-object method that shadows (redefines) -for this object an intrinsic instance method. +Note that we can define a object method that shadows (redefines) +for this object methods provided from classes. [[xmp-object-applicable1]] -.Listing {counter:figure-number}: Per-object Method +.Listing {counter:figure-number}: Object Method {set:xmp-object-applicable1:Listing {figure-number}} [source,tcl,numbers] -------------------------------------------------- nx::Class create C { :public method foo {} {return 1} :create c1 { - :public method foo {} {return 2} - :public method bar {} {return 3} + :public object method foo {} {return 2} + :public object method bar {} {return 3} } } @@ -1261,7 +1296,7 @@ # Method "baz" is an object specific method of "o1" nx::Object create o1 { - :public method baz {} {return 4} + :public object method baz {} {return 4} } o1 baz -------------------------------------------------- @@ -1270,8 +1305,8 @@ ========================================= A *class method* is a method defined on a class, which is only -applicable to the class object itself. The class method is a -per-object method of the class object. +applicable to the class object itself. The class method is actually +an object method of the class object. ========================================= In NX, all classes are objects. Classes are in NX special kind of @@ -1281,7 +1316,7 @@ this later). The following example defines a public class method +bar+ on class -+C+. The class method is specified by using the modifier +class+ in ++C+. The class method is specified by using the modifier +object+ in front of +method+ in the method definition command. [[xmp-object-applicable2]] @@ -1294,7 +1329,7 @@ # Define a class method "bar" and an instance # method "foo" # - :public class method bar {} {return 2} + :public object method bar {} {return 2} :public method foo {} {return 1} # @@ -1321,7 +1356,7 @@ === Ensemble Methods -NX provides "ensemble methods" as a means to structure the method name +NX provides _ensemble methods_ as a means to structure the method name space and to group related methods. Ensemble methods are similar in concept to Tcl's ensemble commands. @@ -1354,7 +1389,7 @@ :public method "string length" {x} {....} :public method "string tolower" {x} {...} :public method "string info" {x} {...} - ... + #... :create c1 } @@ -1373,11 +1408,12 @@ ++++ In the case, no mixins are involved, first the object is searched for -a per-object method with the given name, and then the class hierarchy +an object method with the given name, and then the class hierarchy of the object. The method can be defined multiple times on the search path, so some of these method definitions might be _shadowed_ by the more specific definitions. + [[xmp-method-resolution]] .Listing {counter:figure-number}: Method Resolution with Intrinsic Classes {set:xmp-method-resolution:Listing {figure-number}} @@ -1392,7 +1428,7 @@ :public method foo {} { return "D foo: [next]"} :create d1 { - :public method foo {} { return "d1 foo: [next]"} + :public object method foo {} { return "d1 foo: [next]"} } } @@ -1406,9 +1442,9 @@ -------------------------------------------------- Consider the example in -<>. When the method -+foo+ is invoked on object +d1+, the per-object method has the highest -precedence and is therefore invoked. The per-object methods shadows +<>. When the method ++foo+ is invoked on object +d1+, the object method has the highest +precedence and is therefore invoked. The object methods shadows the same-named methods in the class hierarchy, namely the method +foo+ of class +D+ and the method +foo+ of class +C+. The shadowed methods can be still invoked, either via the primitive +next+ or via method @@ -1438,7 +1474,7 @@ # "d1" is created based on the definitions of the last example # # Add the methods from "M1" as per-object mixin to "d1" -d1 mixin M1 +d1 object mixin M1 # # Add the methods from "M2" as per-class mixin to class "C" @@ -1453,7 +1489,7 @@ # result: "::M1 ::M2 ::D ::C ::nx::Object" -------------------------------------------------- -The example in <> is +The example in <> is an extension of the previous example. We define here two additional classes +M1+ and +M2+ which are used as per-object and per-class mixins. Both classes define the method +foo+, these methods shadow @@ -1471,10 +1507,10 @@ # "d1" is created based on the definitions of the last two examples, # the mixins "M1" and "M2" are registered. # -# Define a public per-object method "bar", which calls the method +# Define a public object method "bar", which calls the method # "foo" which various invocation options: # -d1 public method bar {} { +d1 public object method bar {} { puts [:foo] puts [: -local foo] puts [: -intrinsic foo] @@ -1495,8 +1531,8 @@ The invocation flag +-local+ means that the method has to be resolved from the same place, where the current method is defined. Since the -current method is defined as a per-object method, +foo+ is resolved as -a per-object method. The effect is that the mixin definitions are +current method is defined as a object method, +foo+ is resolved as +a object method. The effect is that the mixin definitions are ignored. The invocation flag +-local+ was already introduced int the section about method protection, where it was used to call _private_ methods. @@ -1512,7 +1548,7 @@ no definitions of +foo+ on the base clases, therefore an error message is returned. -The output of <> is: +The output of <> is: ---- M1 foo: M2 foo: d1 foo: D foo: C foo: d1 foo: D foo: C foo: @@ -1525,7 +1561,7 @@ NX provides a generalized mechanism for passing values to either methods (we refer to these as _method parameters_) or to objects -(these are called _object parameters_). Both kind of parameters +(these are called _configure parameters_). Both kind of parameters might have different features, such as: - Positional and non-positional parameters @@ -1536,7 +1572,7 @@ TODO: complete list above and provide a short summary of the section -Before we discuss method and object parameters in more detail, we +Before we discuss method and configure parameters in more detail, we describe the parameter features in the subsequent sections based on method parameters. @@ -1562,22 +1598,22 @@ # # Method foo has positional parameters: # - :public method foo {x y} { + :public object method foo {x y} { puts "x=$x y=$y" } # # Method bar has non-positional parameters: # - :public method bar {-x -y} { + :public object method bar {-x -y} { puts "x=$x y=$y" } # # Method baz has non-positional and # positional parameters: # - :public method baz {-x -y a} { + :public object method baz {-x -y a} { puts "x? [info exists x] y? [info exists y] a=$a" } } @@ -1642,15 +1678,15 @@ # Method foo has one required and one optional # positional parameter: # - :public method foo {x:required y:optional} { + :public object method foo {x:required y:optional} { puts "x=$x y? [info exists y]" } # # Method bar has one required and one optional # non-positional parameter: # - :public method bar {-x:required -y:optional} { + :public object method bar {-x:required -y:optional} { puts "x=$x y? [info exists y]" } } @@ -1699,15 +1735,15 @@ # # Positional parameter with default value: # - :public method foo {x:required {y 101}} { - puts "x=$x y? [info exists y]" + :public object method foo {{x 1} {y 2}} { + puts "x=$x y=$y" } # # Non-positional parameter with default value: # - :public method bar {{-x 10} {-y 20}} { - puts "x=$x y? [info exists y]" + :public object method bar {{-x 10} {-y 20}} { + puts "x=$x y=$y" } } @@ -1716,9 +1752,9 @@ o3 bar -------------------------------------------------- -In order to define a default value, the parameter specification must -be of the form of a 2 element list, where the second argument is the -default value. See for an example in +In order to define a default value for a parameter, the parameter +specification must be of the form of a 2 element list, where the +second argument is the default value. See for an example in <>. ==== Value Constraints @@ -1749,7 +1785,7 @@ <> shows the built-in general applicable value checkers available in NX, which can be used -for all method and object parameters. In the next step, we show how to +for all method and configure parameters. In the next step, we show how to use these value-checkers for checking permissible values for method parameters. Then we will show, how to provide more detailed value constraints. @@ -1764,19 +1800,20 @@ # # Positional parameter with value constraints: # - :public method foo {x:integer o:object,optional} { + :public object method foo {x:integer o:object,optional} { puts "x=$x o? [info exists o]" } # # Non-positional parameter with value constraints: # - :public method bar {{-x:integer 10} {-verbose:boolean false}} { - puts "x=$x y=$y" + :public object method bar {{-x:integer 10} {-verbose:boolean false}} { + puts "x=$x verbose=$verbose" } } -# The following invocation raises an exception +# The following invocation raises an exception, since the +# value "a" for parameter "x" is not an integer o4 foo a -------------------------------------------------- @@ -1805,7 +1842,7 @@ # # Parameterized value constraints # - :public method work { + :public object method work { -person:object,type=Person -project:object,type=Project } { @@ -1885,11 +1922,14 @@ D create d1 -# testing "groupsize" +# testing "groupsize"; +# the second call (with value 10) will raise an exception: d1 foo 2 d1 foo 10 # testing "choice" +# the second call (with value pink for parameter a) +# will raise an exception: d1 bar green good d1 bar pink bad -------------------------------------------------- @@ -1953,23 +1993,23 @@ # Positional parameter with an possibly empty # single value # - :public method foo {x:integer,0..1} { + :public object method foo {x:integer,0..1} { puts "x=$x" } # # Positional parameter with an possibly empty # list of values value # - :public method bar {x:integer,0..n} { + :public object method bar {x:integer,0..n} { puts "x=$x" } # # Positional parameter with a non-empty # list of values # - :public method baz {x:integer,1..n} { + :public object method baz {x:integer,1..n} { puts "x=$x" } } @@ -2006,7 +2046,7 @@ ... -=== Details on Method and Object Parameters +=== Details on Method and Configure Parameters The parameter specifications are used in NX for the following purposes. They are used for @@ -2016,7 +2056,7 @@ - the specification for the initialization of objects. We refer to the first two as method parameters and the last one as -object parameters. The examples in the previous sections all parameter +configure parameters. The examples in the previous sections all parameter specification were specifications of method parameters. ***************************************************************************** @@ -2029,12 +2069,11 @@ and what kind of checks should be performed on these. ***************************************************************************** -*Object parameters* are parameters that specify, with what values -instance variables of objects are initialized and how these objects -could be parameterized. +*Configure parameters* are parameters that specify, how objects +can be parameterized upon creation. ***************************************************************************** -Syntactically, object parameters and method parameters are the same, +Syntactically, configure parameters and method parameters are the same, although there are certain differences (e.g. some parameter options are only applicable for objects parameters, the list of object parameters is computed dynamically from the class structures, object @@ -2043,7 +2082,7 @@ application classes +Person+ and +Student+ with a few properties. [[xmp-object-parameters]] -.Listing {counter:figure-number}: Object Parameters +.Listing {counter:figure-number}: Configure Parameters {set:xmp-object-parameters:Listing {figure-number}} [source,tcl,numbers] -------------------------------------------------- @@ -2066,14 +2105,14 @@ } # -# Create instances using object parameters +# Create instances using configure parameters # for the initialization # Person create p1 -name Bob Student create s1 -name Susan -matnr 4711 -# Access property value via accessor method -puts "The name of s1 is [s1 name]" +# Access property value via "cget" method +puts "The name of s1 is [s1 cget -name]" -------------------------------------------------- The class +Person+ has two properties +name+ and +birthday+, where the @@ -2084,27 +2123,27 @@ {xmp-object-parameters}>>). The class diagram below visualizes these definitions. -[[img-object-parameters]] -image::object-parameter.png[align="center",title="System and Application Classes"] -{set:img-object-parameters:Figure {figure-number}} +[[img-configure-parameters]] +image::configure-parameter.png[align="center",title="System and Application Classes"] +{set:img-configure-parameters:Figure {figure-number}} In NX, these definitions imply that instances of the class of +Person+ have the properties +name+ and +birthday+ as _non-positional object parameters_. Furthermore it implies that instances of +Student+ will -have the object parameters of +Person+ augmented with the object +have the configure parameters of +Person+ augmented with the object parameters from +Student+ (namely +matnr+ and +oncampus+). Based on -these object parameters, we can create a +Person+ named +Bob+ and a +these configure parameters, we can create a +Person+ named +Bob+ and a +Student+ named +Susan+ with the matriculation number +4711+ (see line 23 and 24 in <>). After the object +s1+ is created it has the +{xmp-configure-parameters}>>). After the object +s1+ is created it has the instance variables +name+, +matnr+ and +oncampus+ (the latter is initialized with the default value). -==== Object Parameters for all NX Objects +==== Configure Parameters available for all NX Objects -The object parameters are not limited to the application defined +The configure parameters are not limited to the application defined properties, also NX provides some predefined definitions. Since -+Person+ is a subclass of +nx::Object+ also the object parameters of ++Person+ is a subclass of +nx::Object+ also the configure parameters of +nx::Object+ are inherited. In the introductory stack example, we used +-mixin+ applied to an object to denote per-object mixins (see <>). Since +mixin+ @@ -2119,40 +2158,40 @@ <> or <>). The scripted block and its meaning are as well defined by the means of -object parameters. However, this object parameter is positional (last +configure parameters. However, this configure parameter is positional (last argument) and optional (it can be omitted). The following listing shows -(simplified) the object parameters of +Person p1+ and +Student s1+. +(simplified) the configure parameters of +Person p1+ and +Student s1+. [[xmp-object-parameter-list]] -.Listing {counter:figure-number}: Computed Actual Object Parameter (simplified) +.Listing {counter:figure-number}: Computed Actual Configure Parameter (simplified) {set:xmp-object-parameter-list:Listing {figure-number}} [source,tcl,numbers] -------------------------------------------------- -Object parameter for Person p1: +Configure parameter for Person p1: -name:required -birthday ... -mixin:mixinreg,alias,1..n -filter:filterreg,alias,1..n _:initcmd,optional -Object parameter for Student s1: +Configure parameter for Student s1: -matnr:required {-oncampus:boolean true} -name:required -birthday ... -mixin:mixinreg,alias,1..n -filter:filterreg,alias,1..n _:initcmd,optional -------------------------------------------------- The actual values can be obtained via introspection via +Person info -parameter definition+. The object parameter types +mixinreg+ and +parameter definition+. The configure parameter types +mixinreg+ and +filterreg+ are for converting definitions of filters and mixins. The -object parameter type +initcmd+ says that the content of this variable +configure parameter type +initcmd+ says that the content of this variable will be executed in the context of the object being created (before -the constructor +init+ is called). More about the object parameter +the constructor +init+ is called). More about the configure parameter types later. -==== Object Parameters for all NX Classes +==== Configure Parameters available for all NX Classes Since classes are certain kind of objects, classes are parameterized in the same way as objects. A typical parameter for a class definition is the relation of the class to its superclass.In our example, we have specified, that +Student+ has +Person+ as superclass via the -non-positional object parameter +-superclass+. If no superclass is +non-positional configure parameter +-superclass+. If no superclass is specified for a class, the default superclass is +nx::Object+. Therefore +nx::Object+ is the default value for the parameter +superclass+. @@ -2163,8 +2202,8 @@ the same way. Since +Student+ is an instance of the meta-class +nx::Class+ it -inherits the object parameters from +nx::Class+ (see class diagram -<>). Therefore, one can +inherits the configure parameters from +nx::Class+ (see class diagram +<>). Therefore, one can use e.g. +-superclass+ in the definition of classes. Since +nx::Class+ is a subclass of +nx::Object+, the meta-class @@ -2181,7 +2220,7 @@ {set:xmp-class-parameter-list:Listing {figure-number}} [source,tcl,numbers] -------------------------------------------------- -Object parameter for Class Student: +Configure parameter for Class Student: -mixin:mixinreg,alias,1..n -filter:filterreg,alias,1..n ... {-superclass:class,alias,1..n ::nx::Object} ... -------------------------------------------------- @@ -2192,15 +2231,15 @@ ==== User defined Parameter Types -More detailed definition of the object parameter types comes here. +More detailed definition of the configure parameter types comes here. ==== Slot Classes and Slot Objects In one of the previous sections, we defined scripted (application defined) checker methods on a class named +nx::Slot+. In general NX offers the possibility to define value checkers not only for all usages of parameters but as well differently for method parameters or -object parameters +configure parameters [[img-slots]] image::slots.png[align="center",title="Slot Classes and Objects"] @@ -2220,8 +2259,10 @@ - incremental slots == Miscellaneous +... === Profiling +... === Unknown Handlers @@ -2243,7 +2284,7 @@ [source,tcl,numbers] -------------------------------------------------- ::nx::Object create o { - :method unknown {called_method args} { + :object method unknown {called_method args} { puts "Unknown method '$called_method' called" } } @@ -2272,7 +2313,7 @@ {set:xmp-unknown-class:Listing {figure-number}} [source,tcl,numbers] -------------------------------------------------- -::nx::Class public class method __unknown {name} { +::nx::Class public object method __unknown {name} { # A very simple unknown handler, showing just how # the mechanism works. puts "***** __unknown called with <$name>" @@ -2285,11 +2326,11 @@ ::nx::Object create o { # The class M is unknown at this point - :mixin add M + :object mixin add M # The line above has triggered the unknown class handler, # class M is now defined - puts [:info mixin classes] + puts [:info object mixin classes] # The output will be: # ***** __unknown called with <::M> # ::M