Index: doc/next-tutorial.html =================================================================== diff -u -r7201909d5ab73f0ca37e62bc5cf727e0be968faf -rb50f8e334d3abf7e807e63be3fc292af69a77d73 --- doc/next-tutorial.html (.../next-tutorial.html) (revision 7201909d5ab73f0ca37e62bc5cf727e0be968faf) +++ doc/next-tutorial.html (.../next-tutorial.html) (revision b50f8e334d3abf7e807e63be3fc292af69a77d73) @@ -1796,18 +1796,432 @@

3.2. Method Definitions

+

The basic building blocks of an object oriented program are objects, +classes, which contain named pieces of code, the methods.

+
+
+

Methods are subroutines (pieces of code) associated with objects +and/or classes. Every method has a name, it receives arguments and +returns a value.

+
+

There are as well other program units, which are not associated with +objects or classes. Examples for such units are Tcl procs or Tcl +commands.

+

Methods might have different scopes, defining, on which kind of +objects these methods are applicable. We describe this later in more +detail. For the time being, we deal here with methods defined on +classes, which are applicable for the instance of these classes.

3.2.1. Scripted Methods

+

Since NX is a scripting language, most methods are most likely +scripted methods, where the method body contains Tcl code.

+
Listing 20: Scripted method

+
+
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+
# Define a class
+nx::Class create Dog {
+
+  # Define a scripted method for the class
+  :public method bark {} {
+    puts "[self] Bark, bark, bark."
+  }
+}
+
+# Create an instance of the class
+Dog create fido
+
+# The following line prints "::fido Bark, bark, bark."
+fido bark
+

In the example above we create a class Dog with a scripted method +named bark. The method body defines the code, which is executed when +the method is invoked. In this example, the method bar will print +out a line on the terminal starting with the object name (determined +by the built in command self followed by "Bark, bark, bark.". +This method is defined on a class (the class contains the method) and +applicable to instances of the class (here the instance fido).

3.2.2. C-implemented Methods

+

Not all of the methods usable in NX are scripted methods. There are +for example predefined methods, that we used already in our examples, +which are implemented in C. For example, in Listing 20 +we used the method create to create the class Dog and to create +the dog instance fido.

+

Also application developer might define their own functions in C, but +this is an advanced topic, not covered here. However, application +developer might reuse some generic C code to define their own +C-implemented methods. Such methods are for example accessors, +forwarders and aliases.

+
+
+

An accessor is a (in most cases) C-implemented method to access +instance variables of an object. A call to an accessor with no arguments +uses the accessor as a getter, obtaining the 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.

+
+

We used accessors as well already in the section about properties, +which define accessors automatically.

+
Listing 21: Accessor Methods

+
+
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+
nx::Class create Dog {
+ :public method bark {} { puts "[self] Bark, bark, bark." }
+ :method init {} { Tail create [self]::tail}
+}
+
+nx::Class create Tail {
+  :property {length:double 5}
+  :public method wag {} {return Joy}
+}
+
+# Create an instance of the class
+Dog create fido
+
+# Use the accessor "length" as a getter, to obtain the value
+# of a property. The following call returns the length of the
+# tail of fido
+fido::tail length
+
+# Use the accessor "length" as a setter, to alter the value
+# of a property. The following call changes the length of
+# the tail of fido
+fido::tail length 10
+
+# Proving an invalid values will raise an error
+fido::tail length "Hello"
+

Listing 21 shows an extended example, where every doc +has a tail. The object tail is created as a subobject of the dog in +the constructor init. The subobject can be accessed by providing the +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).

+
Listing 22: Forwarder Methods

+
+
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+
nx::Class create Dog {
+  :public method bark {} { puts "[self] Bark, bark, bark." }
+  :method init {} {
+    Tail create [self]::tail
+    :public forward wag [self]::tail wag
+  }
+}
+
+nx::Class create Tail {
+  :property {length 5}
+  :public method wag {} {return Joy}
+}
+
+# Create an instance of the class
+Dog create fido
+
+# The invocation of "fido wag" is delegated to "fido::tail wag".
+# Therefore, the following method returns "Joy".
+fido wag
+

Listing 22 again extends the example by adding a +forwarder named wag to the object (e.g. fido) that redirects all +calls of the form fido wag with arbitrary arguments to the subobject +fido::tail.

+
+
+

A forwarder is a +C-implemented method to redirect an invocation for a certain method +to either a method of other object or to some other method of the +same object. Forwarding an invocation of a method to some other +object is a means of delegation.

+
+

The functionality of the forwarder can be certainly as well be +implemented as a scripted method, but for the most common cases, the +forward implementation is more efficient, and the forward method +expresses the intention of the developer.

+

The forwarder have several options to change e.g. the order of the +arguments, to substitute certain patterns in the argument list +etc. This will be described in later sections.

3.2.3. Method-Aliases

+
+
+

A method alias is a means to register an existing method, a Tcl proc or +command under as a method with a certain name on a class or object.

+
+

In some way, the method alias is a restricted form of a forwarder, but +it does not support delegation to different objects and argument +reordering. The advantage of the method alias is it has close to zero +overhead, especially for aliasing c-implemented methods, since the +methods are simple registered under a different name.

+
Listing 23: Method-Alias

+
+
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+
nx::Class create Dog {
+  :public method bark {} { puts "[self] Bark, bark, bark." }
+
+  # Define a public alias for the method "bark"
+  :public alias warn [:info method handle bark]
+  # ...
+}
+
+# Create an instance of the class
+Dog create fido
+
+# The following line prints "::fido Bark, bark, bark."
+fido warn
+

Listing 23 extends the last example by defining an +alias for the method "bark". The example just shows the bare +mechanism. In general, method aliases are a very powerful means +for reusing pre-existing functionality. The full object system of NX +and XOTcl2 is built from aliases, where e.g. the same functionality is +available in NX and XOTcl2 under different names. Method aliases are +as well a means for implementing traits in NX.

3.3. Method Protection

+

All kinds of methods might have different kind of protections in NX. +The call-protection defines from which calling context methods might +be called. The Next Scripting Framework supports as well redefinition +protection for methods.

+

NX distinguished between public, protected and private methods, +where the default call-protection is "protected".

+
+
+

A public method can be +called from every context. A protected method can only be invoked +from the same object. A private method can be only invoked from +methods defined on the same entity (e.g. defined on the same class) +via my -local.

+
+

All kind of methods protection are applicable for all kind of methods, +either scripted or C-implemented.

+

The distinction between public and protected is an instrument to +define an interface for classes. Public methods are for consumer of +the classes. Public methods define the intended ways of reusing +classes and objects for consumers. Protected methods are intended for +the implementor of the class or subclasses and not for public +usage. The distinction between protected and public reduces the +coupling between consumers and the implementation and offers more +flexibility to the developer.

+
Listing 24: Protected Methods

+
+
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+
nx::Class create Foo {
+
+  # Define a public method
+  :public method foo {} {
+    # ....
+    return [:helper]
+  }
+
+  # Define a protected method
+  :method helper {} {
+     return 1
+  }
+}
+
+# Create an instance of the class:
+Foo create f1
+
+# The invocation of the public method "foo" returns 1
+f1 foo
+
+# The invocation of the protected method "helper" raises an error:
+f1 helper
+

Note that we could have as well used :protected method helper … +in the above example, but we can omit protected, since it is the default +method call protection.

+

The method call-protection of private goes one step further and +helps to hide implementation details also for implementors of +subclasses. Private methods are a means for avoiding unanticipated name +clashes. Consider the following example:

+
Listing 25: Private Methods

+
+
+
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+
nx::Class create Base {
+  :private method helper {a b} { expr {$a + $b} }
+  :public method foo {a b} { my -local helper $a $b }
+}
+
+nx::Class create Sub -superclass Base {
+  :public method bar {a b} { my -local helper $a $b }
+  :private method helper {a b} { expr {$a * $b} }
+  :create s1
+}
+
+s1 foo 3 4     ;# returns 7
+s1 bar 3 4     ;# returns 12
+s1 helper 3 4  ;# raises error: unable to dispatch method helper
+

The base class implements a public method foo using the helper +method named helper. Also the derived class implements a public +method bar, which is also using a helper method named helper. When +we create an instance s1 from the derived class, we can call the +method foo which uses in turn the private method of the base +class. Therefore, foo called with the arguments 3 and 4 returns its +sum. If we would not have used my -local for invoking the helper, +s1 would have tried to call the helper of Sub, which would be +incorrect. For all other purposes, the private methods are "invisible" +in all situations, e.g. when mixins are used, or within the +next-path, etc.

3.4. Scopes of Methods

@@ -1822,7 +2236,11 @@
-

3.5. Parameters

+

3.5. Ensemble Methods

+

+
+
+

3.6. Parameters

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 @@ -1859,7 +2277,7 @@ describe the parameter features in the subsequent sections based on method parameters.

-

3.5.1. Positional and Non-Positional Parameters

+

3.6.1. Positional and Non-Positional Parameters

If the position of a parameter in the list of formal arguments (e.g. passed to a function) is significant for its meaning, this is a positional parameter. If the meaning of the parameter is independent @@ -1869,7 +2287,7 @@ determined by its position. When we call a method with non-positional parameters, their meaning is determined via a name passed with the argument during invocation.

-
Listing 20: Positional and Non-Positional Method Parameters

+
Listing 26: Positional and Non-Positional Method Parameters