Classes and Objects: Difference between revisions

From m204wiki
Jump to navigation Jump to search
mNo edit summary
Line 11: Line 11:
The description of a class, all variables, and all methods of the class
The description of a class, all variables, and all methods of the class
must be contained inside one or more <var>Class</var> blocks:
must be contained inside one or more <var>Class</var> blocks:
<pre>
<p class="code">
begin
begin
   ...
   ...
Line 23: Line 23:
   ...
   ...
end
end
</pre>
</p>
This is slightly different from most other object-oriented languages, which require an entire class definition to be within a single class block (though sometimes a keyword other than <var>Class</var> is used to mark the start of the class definition).
This is slightly different from most other object-oriented languages, which require an entire class definition to be within a single class block (though sometimes a keyword other than <var>Class</var> is used to mark the start of the class definition).
The main reason for allowing multiple class blocks is that they let you selectively include methods in a class as they are needed in a request, rather than having to compile all the methods in a class if any one is needed.
The main reason for allowing multiple class blocks is that they let you selectively include methods in a class as they are needed in a request, rather than having to compile all the methods in a class if any one is needed.
Line 29: Line 29:
For example, <code>Subroutine Paint</code> for <code>Class Car</code> could be kept in a procedure
For example, <code>Subroutine Paint</code> for <code>Class Car</code> could be kept in a procedure
as follows:
as follows:
<pre>
<p class="code">PROCEDURE CLASS.CAR.PAINT
PROCEDURE CLASS.CAR.PAINT
!dupexit
!dupexit
class car
class car
Line 38: Line 37:
end class
end class
END PROCEDURE
END PROCEDURE
</pre>
</p>
<code>!dupexit</code> causes the procedure to be exited on all but the first <var>Include</var>, which ensures that the subroutine is only defined once.
<code>!dupexit</code> causes the procedure to be exited on all but the first <var>Include</var>, which ensures that the subroutine is only defined once.
Attempting to define it more than once would result in compilation errors, of course.
Attempting to define it more than once would result in compilation errors, of course.
   
   
Given the above procedure, code that needs to use <code>Subroutine Paint</code> in class <code>Car</code> could simply <var>Include</var> procedure <code>CLASS.CAR.PAINT</code>:
Given the above procedure, code that needs to use <code>Subroutine Paint</code> in class <code>Car</code> could simply <var>Include</var> procedure <code>CLASS.CAR.PAINT</code>:
<pre>
<p class="code">include class.car.paint
include class.car.paint
  ...
  ...
%chevy    is object car
%chevy    is object car
  ...
  ...
%chevy:paint('Teal')
%chevy:paint('Teal')
</pre>
</p>
Subroutine <code>Paint</code> can only be defined '''after''' it has been declared inside a [[#Declaration blocks|declaration block]] for class <code>Car</code>. If a class is broken up in such a way that some methods are in their own procedures, it is likely that the class's declaration blocks would all be contained in another procedure, called something like <code>CLASS.CAR</code> in this example. And that procedure would have to be <var>Included</var>'ed '''before''' the procedure that defines the <code>Paint</code> method:
Subroutine <code>Paint</code> can only be defined '''after''' it has been declared inside a [[#Declaration blocks|declaration block]] for class <code>Car</code>. If a class is broken up in such a way that some methods are in their own procedures, it is likely that the class's declaration blocks would all be contained in another procedure, called something like <code>CLASS.CAR</code> in this example. And that procedure would have to be <var>Included</var>'ed '''before''' the procedure that defines the <code>Paint</code> method:
<pre>
<p class="code">include class.car
include class.car
include class.car.paint
include class.car.paint
  ...
  ...
Line 58: Line 55:
  ...
  ...
%chevy:paint('Teal')
%chevy:paint('Teal')
</pre>
</p>
 
===Class block syntax===
===Class block syntax===
The full syntax of the Class block is:
The full syntax of the Class block is:
<p class="pre">
<p class="syntax"><span class="squareb">[</span>Local<span class="squareb">]</span> Class <span class="term">className</span> <span class="squareb">[</span>Abstract<span class="squareb">]</span>            -
[Local] Class className [[Abstract]] -
                         <span class="squareb">[</span>Alias=<span class="term">aliasList</span><span class="squareb">]</span>      -
                         [[Alias (Class and Structure)|[Alias=aliasList]]] -
                         <span class="squareb">[</span>Extends=<span class="term">extendList</span><span class="squareb">]</span>  -
                         [Extends=extendList] -
                         <span class="squareb">[</span>RequiredSuffix=<span class="term">suffix</span><span class="squareb">]</span>
                         [[RequiredSuffix (Class and Structure)|[RequiredSuffix=suffix]]]
                        <span class="squareb">[</span><span class="term">declaration blocks</span><span class="squareb">]</span>
          [[#Declaration blocks|[declaration blocks]]]
                        <span class="squareb">[</span><span class="term">method definitions</span><span class="squareb">]</span>
          [[Methods#Method definition syntax|[method definitions]]]
         End Class <span class="squareb">[</span><span class="term">className</span><span class="squareb">]</span>
         End Class [className]
</p>
</p>


===Syntax terms===
===Syntax terms===
<table class="syntaxTable">
<table class="syntaxTable">
<tr><th>Local</th><td>Indicates that the class can only be referenced inside the containing [[scope]]. A class declared inside a method or complex subroutine '''must''' be <var>Local</var>. A class in the outermost (<var>Begin</var>/<var>End</var>) scope can be either ''local'', in which case it cannot be referenced in other scopes such as methods or complex subroutines, or not local, in which case it can be referenced anywhere in the request.</td></tr>   
<tr><th><var>Local</var></th><td>Indicates that the class can only be referenced inside the containing [[scope]]. A class declared inside a method or complex subroutine '''must''' be <var>Local</var>. A class in the outermost (<var>Begin</var>/<var>End</var>) scope can be either ''local'', in which case it cannot be referenced in other scopes such as methods or complex subroutines, or not local, in which case it can be referenced anywhere in the request.</td></tr>   
<tr><th>Abstract</th><td>Indicates that the class is ''abstract'', that is, no instance of the class can be created unless it is an instance of a non-abstract extension class.</td></tr>
 
<tr><th>className</th><td>Consists of any valid alphanumeric and other non-separator characters.
<tr><th>className</th><td>Consists of any valid alphanumeric and other non-separator characters.
<tr><th>aliasList</th><td>A list of aliases for the class, with each alias separated by the word <var>And</var>. Class aliases are only available in Sirius Mods 7.8 and later.</td></tr>
 
<tr><th>extendList</th><td>A list of classes that this class extends.</td></tr>
<tr><th><var>Abstract</var></th><td>Indicates that the class is ''abstract'', that is, no instance of the class can be created unless it is an instance of a non-abstract extension class.</td></tr>
<tr><th>suffix</th><td>A non-quoted string of characters that must end the name of any object variable being declared for the class.</td></tr>
 
<tr><th><var>Alias=</var>aliasList</th><td>A list of aliases for the class, with each alias separated by the word <var>And</var>. See [[#Aliases for class names|"Aliases for class names"]].</td></tr>
 
<tr><th><var>Extends=</var>extendList</th><td>A list of classes that this class extends.</td></tr>
 
<tr><th><var>RequiredSuffix=</var>suffix</th><td>A non-quoted string of characters that must end the name of any object variable being declared for the class; provides a way of enforcing naming standards for class variable names. </td></tr>
 
<tr><th>declaration blocks</th>
<td>See [[#Declaration blocks|"Declaration blocks"]]. </td></tr>
<tr><th>method definition</th>
<td>See [[Methods#Method definition syntax|"Method definition syntax"]]. </td></tr>
</table>  
</table>  
The (one or more) class blocks for a class contain the declaration blocks and method definitions for the class, which together comprise the ''class definition''.
The (one or more) class blocks for a class contain the declaration blocks and method definitions for the class, which together comprise the ''class definition''.
The class definition consists of zero or more ''declaration blocks'' and zero or more ''method definitions''.
The class definition consists of zero or more ''declaration blocks'' and zero or more ''method definitions''.
Line 89: Line 97:
   
   
Once a class is declared, you use the <var>Object</var> keyword on variable declarations to declare objects as instances of a class:
Once a class is declared, you use the <var>Object</var> keyword on variable declarations to declare objects as instances of a class:
<pre>
<p class="code">%malibu  is object car
%malibu  is object car
%outback  is object car
%outback  is object car
</pre>
</p>
 
===Colons in class names===
===Colons in class names===
The colon character (:) is allowed in User Language class names.
The colon character (:) is allowed in User Language class names.
The following, for example, is a valid class declaration:
The following, for example, is a valid class declaration:
<pre>
<p class="code">class customer:order
class customer:order
</p>  
</pre>  
No colon-demarcated part of a class name can be the word <var>System</var>.
No colon-demarcated part of a class name can be the word <var>System</var>.
For example, <code>System</code>, <code>System:foo</code>, <code>Foo:system</code>, and <code>Foo:system:bar</code> are all '''invalid''' class names.
For example, <code>System</code>, <code>System:foo</code>, <code>Foo:system</code>, and <code>Foo:system:bar</code> are all '''invalid''' class names.
Line 106: Line 113:
This grouping, itself, falls under the larger grouping of <code>MiddleEarth</code>.
This grouping, itself, falls under the larger grouping of <code>MiddleEarth</code>.
Using the colon in this way is likely to make it easier to take advantage of future class management features that depend on a hierarchical, colon-based, class naming scheme.
Using the colon in this way is likely to make it easier to take advantage of future class management features that depend on a hierarchical, colon-based, class naming scheme.
===Aliases for class names===
As of <var class="product">Sirius Mods</var> Version 7.8, you can define an alias name for an existing user class.
You do so by specifying an <var>Alias</var> parameter setting on the existing class declaration. For example,
you are changing a naming convention for some code, and you want to refer to user-defined class <code>Blue</code> by another name, say <code>Indigo</code>. Your class declaration would be:
<p class="code">class blue alias indigo
</p>
You can then use either the primary class name or the alias when declaring objects of the class:
<p class="code">%foo    is object blue
%bar    is object indigo
</p>
An object of the alias class is compiled as an object
of the primary class, and the runtime class of an
object variable that was defined using an alias is the primary class.
Consequently, all system messages you receive will specify the primary class.
For example, given the declarations above, if you call method <code>TouchUp</code> for an object declared for the Indigo class:
<p class="code">%bar:touchUp
</p>
And method <code>TouchUp</code> does not exist in the class, the error message you receive is:
<p class="code">MSIR.0733: Member TOUCHUP not found in class Blue
</p>
While this might seem potentially confusing, aliases are intended primarily for migrating class names, so any confusion will be limited to this migration period. In addition, only the owner of a class can declare an alias, so aliases are not likely to proliferate in your site's code.


==Declaration blocks==
==Declaration blocks==
Line 129: Line 159:
The Shared blocks contain members that are shared among '''all''' instances of the class and so are able to be referenced independent of any instance of the class.
The Shared blocks contain members that are shared among '''all''' instances of the class and so are able to be referenced independent of any instance of the class.
<var>Public Shared</var> members are available to all users of the class, and <var>Private Shared</var> members are available only within the class definition.
<var>Public Shared</var> members are available to all users of the class, and <var>Private Shared</var> members are available only within the class definition.
<var>Shared</var> variables and methods are discusssed in more detail in [[Shared class members]].
<var>Shared</var> variables and methods are discussed in more detail in [[Shared class members]].
   
   
The declaration blocks contain declarations for all variables and methods in a class, and they must appear before any method definitions.
The declaration blocks contain declarations for all variables and methods in a class, and they must appear before any method definitions.
===Declaration block syntax===
===Declaration block syntax===
The format of the declarations blocks is:
The format of the declarations blocks is:
Line 143: Line 174:
<table class="syntaxTable">
<table class="syntaxTable">
<tr><th>Public&nbsp;|&nbsp;Private</th><td>Indicates whether the block describes members that can be referenced outside the class (<var>Public</var>) or members that can only be referenced inside the class (<var>Private</var>).</td></tr>
<tr><th>Public&nbsp;|&nbsp;Private</th><td>Indicates whether the block describes members that can be referenced outside the class (<var>Public</var>) or members that can only be referenced inside the class (<var>Private</var>).</td></tr>
<tr><th>End</th><td>Marks the end of the declaration block. It must be followed immediately by <var>Public</var> or <var>Private</var> which is then possibly followed by <var>Shared</var>. The keywords following <var>End</var> must exactly match the block type: for a <var>Public</var> block, <var>End Public</var> is required; for a <var>Private Shared</var> block, <var>End Private Shared</var> is required.
<tr><th>End</th><td>Marks the end of the declaration block. It must be followed immediately by <var>Public</var> or <var>Private</var> which is then possibly followed by <var>Shared</var>. The keywords following <var>End</var> must exactly match the block type: for a <var>Public</var> block, <var>End Public</var> is required; for a <var>Private Shared</var> block, <var>End Private Shared</var> is required.
The class name can, optionally, be indicated after the block type on the <var>End</var> clause.</td></tr>
The class name can, optionally, be indicated after the block type on the <var>End</var> clause.</td></tr>
<tr><th>Allow clauses</th><td>Indicate special operations allowed by the class. It can only be specified in a <var>Public</var> (non-shared) block, and consist of the <var>Allow</var> keyword followed by <var>Auto</var>, <var>Copy</var>, <var>DeepCopy</var>, or <var>Narrow</var>.
<tr><th>Allow clauses</th><td>Indicate special operations allowed by the class. It can only be specified in a <var>Public</var> (non-shared) block, and consist of the <var>Allow</var> keyword followed by <var>Auto</var>, <var>Copy</var>, <var>DeepCopy</var>, or <var>Narrow</var>.
There can be multiple <var>Allow</var> clauses in a declaration block.  
There can be multiple <var>Allow</var> clauses in a declaration block.  
<var>Allow</var> clauses are optional and can be interspersed with <var>Disallow</var> clauses and member declarations.</td></tr>
<var>Allow</var> clauses are optional and can be interspersed with <var>Disallow</var> clauses and member declarations.</td></tr>
<tr><th>Disallow clauses</th><td>Indicate operations not allowed by the class. It can only be specified in a <var>Public</var> (non-shared) block, and consist of the <var>Disallow</var> keyword followed by <var>Discard</var>, or <var>New</var>.
<tr><th>Disallow clauses</th><td>Indicate operations not allowed by the class. It can only be specified in a <var>Public</var> (non-shared) block, and consist of the <var>Disallow</var> keyword followed by <var>Discard</var>, or <var>New</var>.
There can be multiple <var>Disallow</var> clauses in a declaration block.  
There can be multiple <var>Disallow</var> clauses in a declaration block.  
<var>Disallow</var> clauses are optional and can be interspersed with <var>Allow</var> clauses and member declarations.</td></tr>  
<var>Disallow</var> clauses are optional and can be interspersed with <var>Allow</var> clauses and member declarations.</td></tr>  
<tr><th>member declarations</th><td>Declare variables or methods in the class. These are described in following subsections.
<tr><th>member declarations</th><td>Declare variables or methods in the class. These are described in following subsections.
While member declarations are optional, they tend to appear in almost all declarations blocks and a class without member declarations in '''some''' declaration blocks would be pretty much useless.
While member declarations are optional, they tend to appear in almost all declarations blocks and a class without member declarations in '''some''' declaration blocks would be pretty much useless.
Line 160: Line 195:
<table class="syntaxTable">
<table class="syntaxTable">
<tr><th>Allow Auto</th><td>Indicates that an <var>Auto New</var> clause may be used on the declaration of variables of the type of the class being defined. If the class is an extension class, <var>Allow Auto</var> must also be specified on the class's base class(es).</td></tr>
<tr><th>Allow Auto</th><td>Indicates that an <var>Auto New</var> clause may be used on the declaration of variables of the type of the class being defined. If the class is an extension class, <var>Allow Auto</var> must also be specified on the class's base class(es).</td></tr>
<tr><th>Allow&nbsp;Copy or
<tr><th>Allow&nbsp;Copy or
Allow&nbsp;DeepCopy</th><td>Makes available the system <var>Copy</var> or <var>DeepCopy</var> method, respectively, for objects in the class.</td></tr>
Allow&nbsp;DeepCopy</th><td>Makes available the system <var>Copy</var> or <var>DeepCopy</var> method, respectively, for objects in the class.</td></tr>
<tr><th>Allow Narrow</th><td>Permits narrowing assignments for objects in the class.</td></tr>
<tr><th>Allow Narrow</th><td>Permits narrowing assignments for objects in the class.</td></tr>
</table>
</table>
====Allow Auto and constructors====
====Allow Auto and constructors====
Prior to version 7.6 of the Sirius Mods, a class defined with <var>Allow Auto</var> is not allowed to contain a constructor. As of version 7.6, <var>Allow Auto</var> is allowed in a class that has a constructor. However, for an object variable declared with <var>Auto New</var> in such a class, an automatic instantiation of the object does '''not''' call any of the constructors in the class, even if the class has defined an explicit constructor with the name <var>New</var>.
Prior to version 7.6 of the Sirius Mods, a class defined with <var>Allow Auto</var> is not allowed to contain a constructor. As of version 7.6, <var>Allow Auto</var> is allowed in a class that has a constructor. However, for an object variable declared with <var>Auto New</var> in such a class, an automatic instantiation of the object does '''not''' call any of the constructors in the class, even if the class has defined an explicit constructor with the name <var>New</var>.


For example, the following request prints <code>%y:b = 0</code> &mdash; the class's <code>New</code> constructor does '''not''' get called by <code>%y:b</code>:
For example, the following request prints <code>%y:b = 0</code> &mdash; the class's <code>New</code> constructor does '''not''' get called by <code>%y:b</code>:
b
<p class="code">b
class y
class y
    public
  public
      allow auto
      allow auto
      variable  b is float
      variable  b is float
      constructor new
      constructor new
    end public
  end public
    &nbsp;
  &nbsp;
    constructor new
  constructor new
      %this:b = 1234
      %this:b = 1234
    end constructor
  end constructor
    &nbsp;
  &nbsp;
end class
end class
&nbsp;
&nbsp;
%y is object y auto new
%y is object y auto new
[[Targeted Text statements|printText]] {~} = {%y:b}
[[Targeted Text statements|printText]] {~} = {%y:b}
end
end
</p>
 
===Disallow clause===
===Disallow clause===
As the name suggests, the <var>Disallow</var> clause indicates things that one is not allowed to do with the object instances of the class that ordinarily '''would'''  be allowed:
As the name suggests, the <var>Disallow</var> clause indicates things that one is not allowed to do with the object instances of the class that ordinarily '''would'''  be allowed:
Line 205: Line 245:
</ul>
</ul>
An example follows of a class block with some variable declarations:
An example follows of a class block with some variable declarations:
<pre>
<p class="code">class car
class car
   public
   public
       variable    price      is fixed  dp 2
       variable    price      is fixed  dp 2
Line 213: Line 252:
   end public
   end public
end class
end class
</pre>
</p>
Class variables can be referenced via an instance of that class, that is,
Class variables can be referenced via an instance of that class, that is,
via an ''object variable'', like <code>%gremlin</code> below:
via an ''object variable'', like <code>%gremlin</code> below:
<pre>
<p class="code">%gremlin  is object car
%gremlin  is object car
   ...
   ...
printText The price is {%gremlin:price}
printText The price is {%gremlin:price}
</pre>  
</p>  
The colon (<code>:</code>) that separates the object variable <code>%gremlin</code>
The colon (<code>:</code>) that separates the object variable <code>%gremlin</code>
and the class member variable <code>price</code>, above, may alternatively be
and the class member variable <code>price</code>, above, may alternatively be
Line 257: Line 295:
<table class="syntaxTable">
<table class="syntaxTable">
<tr><th><var>Functions</var></th><td>Methods that produce an output value.</td></tr>
<tr><th><var>Functions</var></th><td>Methods that produce an output value.</td></tr>
<tr><th><var>Subroutines</var></th><td>Methods that produce no output value.</td></tr>
<tr><th><var>Subroutines</var></th><td>Methods that produce no output value.</td></tr>
<tr><th><var>Properties</var></th><td>Methods that sometimes produce an output value and that can sometimes be set to a value, that is, be on the left side of an assignment statement.</td></tr>
<tr><th><var>Properties</var></th><td>Methods that sometimes produce an output value and that can sometimes be set to a value, that is, be on the left side of an assignment statement.</td></tr>
<tr><th><var>Constructors</var></th><td>Methods that process objects immediately after the objects are instantiated. Constructors produce no output value.</td></tr>
<tr><th><var>Constructors</var></th><td>Methods that process objects immediately after the objects are instantiated. Constructors produce no output value.</td></tr>
</table>  
</table>  
====Method declaration syntax====
====Method declaration syntax====
The declarations for these methods are very similar:
The declarations for these methods are very similar:
Function <name>                                                  -
<p class="code">Function <name>                                                  -
          [(parameters)] [Is] <datatype>                              -
        [(parameters)] [Is] <datatype>                              -
          [AllowNullObject] [CurrentRecord <context>] [Callable]  -
        [AllowNullObject] [CurrentRecord <context>] [Callable]  -
        [Public | Private [Shared] ]
&nbsp;
Subroutine <name>                                                -
          [(parameters)]                                        -
          [AllowNullObject] [CurrentRecord <context>]            -
           [Public | Private [Shared] ]
           [Public | Private [Shared] ]
&nbsp;
&nbsp;
Subroutine <name>                                                -
Property <name>                                                  -
          [(parameters)]                                        -
        [(parameters)] [Is] <datatype>                              -
          [AllowNullObject] [CurrentRecord <context>]            -
        [ReadWrite | ReadOnly | WriteOnly]                      -
          [Public | Private [Shared] ]
        [AllowNullObject] [CurrentRecord <context>]            -
&nbsp;
        [Public | Private [Shared] ]
Property <name>                                                  -
&nbsp;
          [(parameters)] [Is] <datatype>                              -
Constructor <name>                                              -
          [ReadWrite | ReadOnly | WriteOnly]                      -
            [(parameters)]                                      -
          [AllowNullObject] [CurrentRecord <context>]            -
            [Public | Private]
          [Public | Private [Shared] ]
</p>
&nbsp;
Constructor <name>                                              -
            [(parameters)]                                      -
            [Public | Private]


====Syntax terms====
====Syntax terms====
Line 316: Line 359:
%hybridMileage = %civic:mileage + 19
%hybridMileage = %civic:mileage + 19
</p></ul>
</p></ul>
<li>The ''''Optional'''' keyword indicates that a parameter may be specified on the method invocation or not. Alternatively, ''''Default'''' lets you provide a default parameter value.
<li>The ''''Optional'''' keyword indicates that a parameter may be specified on the method invocation or not. Alternatively, ''''Default'''' lets you provide a default parameter value.
<li>The ''''AllowNullObject'''' keyword on a method declaration indicates that, even though the method operates on an instance of the class (an object), the method may be invoked with a null object variable. Ordinarily, a non-shared method referenced by a null object variable causes a (null-object reference) request cancellation error. Invoking a method even when the object variable is null may be useful in diagnostic code that displays object status or cleanup code.<br/><br/>Since a constructor will always receive the just-created object as the object variable, AllowNullObject is ''not'' allowed on constructor declarations.
<li>The ''''AllowNullObject'''' keyword on a method declaration indicates that, even though the method operates on an instance of the class (an object), the method may be invoked with a null object variable. Ordinarily, a non-shared method referenced by a null object variable causes a (null-object reference) request cancellation error. Invoking a method even when the object variable is null may be useful in diagnostic code that displays object status or cleanup code.<br/><br/>Since a constructor will always receive the just-created object as the object variable, AllowNullObject is ''not'' allowed on constructor declarations.
<li>The ''''CurrentRecord'''' clause (''CurrentRecord In File <name>'', or ''CurrentRecord In Group <name>'') on a method declaration indicates that the method may only be invoked in a record context (established by a ''For Each Record'' loop, for example) for the declared file or group. Furthermore, ''CurrentRecord'' establishes a record context '''within''' the method, so method statements may reference a record field without having to be wrapped inside a record For loop (such as a For Record CurrentRecord loop).
<li>The ''''CurrentRecord'''' clause (''CurrentRecord In File <name>'', or ''CurrentRecord In Group <name>'') on a method declaration indicates that the method may only be invoked in a record context (established by a ''For Each Record'' loop, for example) for the declared file or group. Furthermore, ''CurrentRecord'' establishes a record context '''within''' the method, so method statements may reference a record field without having to be wrapped inside a record For loop (such as a For Record CurrentRecord loop).
<div id="callable"></div>
<div id="callable"></div>
<li>The ''''Callable'''' keyword, available only on Function declarations, indicates that the function can be Called, that is, invoked without a target for the result. Such a function may be Called even though it returns a value, and the Call may be explicit or implicit.
<li>The ''''Callable'''' keyword, available only on Function declarations, indicates that the function can be Called, that is, invoked without a target for the result. Such a function may be Called even though it returns a value, and the Call may be explicit or implicit.
    class car
<p class="code">class car
      public
  public
          ...
      ...
          function wash is float callable
      function wash is float callable
          ...
      ...
      end public
  end public
    end class
end class
    ...
...
    %beetle  is object car
%beetle  is object car
    ...
...
    %beetle:wash
%beetle:wash
</p>
The last line can also be written:
The last line can also be written:
    call %beetle:wash
<p class="code">call %beetle:wash</p>
<var>Callable</var> is typically to be used on Functions that perform some action but also return a status or informational value. Since the caller might not care about the informational value, the <var>Callable</var> keyword allows the caller to invoke the Function without a target for the return value.<br/><br/>Without the <var>Callable</var> keyword, an attempt to invoke a Function without a target for the result (the target of an assignment or input to another method or subroutine) causes a compilation error. Not having the <var>Callable</var> option makes sense for Functions whose chief purpose is to return a value, since invoking them without a return value defeats the purpose. For example, if you had:
<var>Callable</var> is typically to be used on Functions that perform some action but also return a status or informational value. Since the caller might not care about the informational value, the <var>Callable</var> keyword allows the caller to invoke the Function without a target for the return value.<br/><br/>Without the <var>Callable</var> keyword, an attempt to invoke a Function without a target for the result (the target of an assignment or input to another method or subroutine) causes a compilation error. Not having the <var>Callable</var> option makes sense for Functions whose chief purpose is to return a value, since invoking them without a return value defeats the purpose. For example, if you had:
    class cat
<p class="code">class cat
      public
  public
          function weight is float
      function weight is float
          ...
      ...
      end public
  end public
    end class
end class
</p>
It probably wouldn't make sense to do:
It probably wouldn't make sense to do:
    %misha  is object cat
<p class="code">%misha  is object cat
    ...
...
    %misha:weight
%misha:weight
</p>
In this case, it is probably best not to put the <var>Callable</var> keyword on the function declaration, and to catch likely typos or misunderstandings at compile-time.
In this case, it is probably best not to put the <var>Callable</var> keyword on the function declaration, and to catch likely typos or misunderstandings at compile-time.
<div id="readWrite"></div>  
<div id="readWrite"></div>  
<li>Properties behave very much like variables, with the exception that they have code that is run when their value is set or retrieved. This behavioral similarity between properties and variables can be formally described as an ''isomorphism'' between properties and variables. Practically, this means that a variable can be changed to a property, and vice versa, without worrying about how the member is used outside the class.<br/><br/>The keywords '''ReadWrite''', '''ReadOnly''', and '''WriteOnly''' indicate the type of access allowed for the property. The default, <var>ReadWrite</var>, indicates that the property can be both set and retrieved. <var>ReadOnly</var> properties can only be retrieved, and <var>WriteOnly</var> properties can only be set.<br/><br/><var>ReadOnly</var> properties are functionally equivalent to non-<var>Callable</var> Functions: one can think of a <var>ReadOnly</var> Property as a non-<var>Callable</var> Function, and vice versa, with no change to how the method can be used in applications. This makes the naming of such a method a <var>ReadOnly</var> Property or non-<var>Callable</var> Function primarily a hint to the users or maintainers of a class &mdash; a <var>ReadOnly</var> Property, as the name suggests, is a static attribute of an object, while a non-<var>Callable</var> Function is thought of as performing some dynamic operation. Any method that is to be <var>Callable</var> must be a Function rather than a Property.
<li>Properties behave very much like variables, with the exception that they have code that is run when their value is set or retrieved. This behavioral similarity between properties and variables can be formally described as an ''isomorphism'' between properties and variables. Practically, this means that a variable can be changed to a property, and vice versa, without worrying about how the member is used outside the class.<br/><br/>The keywords '''ReadWrite''', '''ReadOnly''', and '''WriteOnly''' indicate the type of access allowed for the property. The default, <var>ReadWrite</var>, indicates that the property can be both set and retrieved. <var>ReadOnly</var> properties can only be retrieved, and <var>WriteOnly</var> properties can only be set.<br/><br/><var>ReadOnly</var> properties are functionally equivalent to non-<var>Callable</var> Functions: one can think of a <var>ReadOnly</var> Property as a non-<var>Callable</var> Function, and vice versa, with no change to how the method can be used in applications. This makes the naming of such a method a <var>ReadOnly</var> Property or non-<var>Callable</var> Function primarily a hint to the users or maintainers of a class &mdash; a <var>ReadOnly</var> Property, as the name suggests, is a static attribute of an object, while a non-<var>Callable</var> Function is thought of as performing some dynamic operation. Any method that is to be <var>Callable</var> must be a Function rather than a Property.
<li>The ''''Public'''', ''''Private'''', and ''''Shared'''' keywords are optional, but, if present, must match the declaration block type. That is, in a Private block, ''Private'' must be indicated; in a Public Shared block, ''Public Shared'' must be indicated; and so on.
<li>The ''''Public'''', ''''Private'''', and ''''Shared'''' keywords are optional, but, if present, must match the declaration block type. That is, in a Private block, ''Private'' must be indicated; in a Public Shared block, ''Public Shared'' must be indicated; and so on.
<li>Constructors behave like subroutines but cannot be called directly. Instead, they are called by the Janus SOAP User Language Interface when an object is first created.
<li>Constructors behave like subroutines but cannot be called directly. Instead, they are called by the Janus SOAP User Language Interface when an object is first created.
</ul>
</ul>
Line 356: Line 409:
contains one variable declaration, one method (subroutine) declaration,
contains one variable declaration, one method (subroutine) declaration,
and a disallow clause:
and a disallow clause:
    class stooge
<p class="code">class stooge
      public
  public
          variable funniness is float
      variable funniness is float
          subroutine slap(%howHard is float)
      subroutine slap(%howHard is float)
          disallow new
      disallow new
      end public
  end public
    end class
end class
</p>
 
==The Auto keyword on object declarations==
==The Auto keyword on object declarations==
While it is not a daunting task to create an instance of an object,
While it is not a daunting task to create an instance of an object,
Line 370: Line 425:
This chore can be simplified by placing the object instantiation
This chore can be simplified by placing the object instantiation
statement immediately after the declaration:
statement immediately after the declaration:
    %stringArray    is object stringList
<p class="code">%stringArray    is object stringList
    %stringArray = new
%stringArray = new
</p>
But this mixes code with variable declarations,
But this mixes code with variable declarations,
which might be deemed ugly, at best, and doesn't work, anyway,
which might be deemed ugly, at best, and doesn't work, anyway,
Line 378: Line 434:
Shared block.
Shared block.
   
   
To get around these issues, the ''''Auto'''' keyword was introduced
To get around these issues, you can use the ''''Auto'''' keyword
for object variable declarations in Sirius Mods version 6.6.
for object variable declarations.
For example:
For example:
    %stringArray  is object stringList  auto new
<p class="code">%stringArray  is object stringList  auto new </p>
   
   
An Auto keyword may be followed by either:
An Auto keyword may be followed by either:
Line 404: Line 460:
For example, it might seem natural to be able to start adding immediately
For example, it might seem natural to be able to start adding immediately
to a stringlist without actually instantiating it:
to a stringlist without actually instantiating it:
    %colors  is object stringlist  auto new
<p class="code">%colors  is object stringlist  auto new
   
   
    %colors:add('Turquoise')
%colors:add('Turquoise')
    %colors:add('Amber')
%colors:add('Amber')
    ...
... </p>
   
   
Collections seem particularly suited for being immediately added to:
Collections seem particularly suited for being immediately added to:
    %itemPrice  is collection namedArraylist of float auto new
<p class="code">%itemPrice  is collection namedArraylist of float auto new
   
   
    %itemPrice('Widget')  =  22.34
%itemPrice('Widget')  =  22.34
    %itemPrice('Thingy')  =    9.84
%itemPrice('Thingy')  =    9.84
    %itemPrice('Whatsit') =  64.18
%itemPrice('Whatsit') =  64.18
      ...
  ... </p>
   
   
The Auto keyword can also be quite useful for [[Enumerations|enumerations]].
The Auto keyword can also be quite useful for [[Enumerations|enumerations]].
An Auto keyword on an enumeration variable acts very much like
An Auto keyword on an enumeration variable acts very much like
an Initial clause on a String, Float, or Fixed variable:
an Initial clause on a String, Float, or Fixed variable:
    %haveWarned    is enumeration boolean auto false
<p class="code">%haveWarned    is enumeration boolean auto false </p>
   
   
While it might be tempting to think about the Auto clause as
While it might be tempting to think about the Auto clause as
Line 430: Line 486:
That is, the following declarations do not cause three Stringlist
That is, the following declarations do not cause three Stringlist
instances to be created:
instances to be created:
    %red      is object stringList
<p class="code">%red      is object stringList
    %white    is object stringList
%white    is object stringList
    %blue    is object stringList
%blue    is object stringList </p>
   
   
But if somewhat further down, the following statement is executed,
But if somewhat further down, the following statement is executed,
a Stringlist instance is automatically created before the Add
a Stringlist instance is automatically created before the Add
method is invoked:
method is invoked:
    %blue:add('Azure')
<p class="code">%blue:add('Azure') </p>
   
   
If the first reference to an Auto object is an assignment:
If the first reference to an Auto object is an assignment:
    %red = %blue
<p class="code">%red = %blue </p>
   
   
the Auto attribute will never be exercised, even if the assignment
the Auto attribute will never be exercised, even if the assignment
source is Null, and even if the object is subsequently discarded.
source is Null, and even if the object is subsequently discarded.


Note: the effect of Auto is restricted to the first reference to a variable
'''Note:''' the effect of Auto is restricted to the first reference to a variable
in a request.
in a request.


Line 561: Line 617:
<p class="code"><span class="literal">If</span> <span class="term">object</span> <span class="term">eqOrNe</span> <span class="term">constructor</span> <span class="literal">Then</span>
<p class="code"><span class="literal">If</span> <span class="term">object</span> <span class="term">eqOrNe</span> <span class="term">constructor</span> <span class="literal">Then</span>
</p>
</p>
Note:
'''Note:'''
<ul>
<ul>
<li><code>object</code> must be an object
<li><code>object</code> must be an object

Revision as of 16:35, 20 June 2012

Classes

A class is a collection of attributes that describe an object and of operations that may be performed on an object. The attributes of an object are formally declared as variables, while the operations are declared as methods. In the Janus SOAP User Language Interface, there are four types of methods: subroutines, functions, properties, and constructors. While a class describes general attributes and methods, a specific instance of the class is called an object, and variables that refer to those instances are called object variables.

The description of a class, all variables, and all methods of the class must be contained inside one or more Class blocks:

begin ... class car ... end class ... class car ... end class car ... end

This is slightly different from most other object-oriented languages, which require an entire class definition to be within a single class block (though sometimes a keyword other than Class is used to mark the start of the class definition). The main reason for allowing multiple class blocks is that they let you selectively include methods in a class as they are needed in a request, rather than having to compile all the methods in a class if any one is needed.

For example, Subroutine Paint for Class Car could be kept in a procedure as follows:

PROCEDURE CLASS.CAR.PAINT !dupexit class car subroutine paint(%color is string len 32) ... end subroutine end class END PROCEDURE

!dupexit causes the procedure to be exited on all but the first Include, which ensures that the subroutine is only defined once. Attempting to define it more than once would result in compilation errors, of course.

Given the above procedure, code that needs to use Subroutine Paint in class Car could simply Include procedure CLASS.CAR.PAINT:

include class.car.paint ... %chevy is object car ... %chevy:paint('Teal')

Subroutine Paint can only be defined after it has been declared inside a declaration block for class Car. If a class is broken up in such a way that some methods are in their own procedures, it is likely that the class's declaration blocks would all be contained in another procedure, called something like CLASS.CAR in this example. And that procedure would have to be Included'ed before the procedure that defines the Paint method:

include class.car include class.car.paint ... %chevy is object car ... %chevy:paint('Teal')

Class block syntax

The full syntax of the Class block is:

[Local] Class className [Abstract] - [Alias=aliasList] - [Extends=extendList] - [RequiredSuffix=suffix] [declaration blocks] [method definitions] End Class [className]

Syntax terms

LocalIndicates that the class can only be referenced inside the containing scope. A class declared inside a method or complex subroutine must be Local. A class in the outermost (Begin/End) scope can be either local, in which case it cannot be referenced in other scopes such as methods or complex subroutines, or not local, in which case it can be referenced anywhere in the request.
classNameConsists of any valid alphanumeric and other non-separator characters.
AbstractIndicates that the class is abstract, that is, no instance of the class can be created unless it is an instance of a non-abstract extension class.
Alias=aliasListA list of aliases for the class, with each alias separated by the word And. See "Aliases for class names".
Extends=extendListA list of classes that this class extends.
RequiredSuffix=suffixA non-quoted string of characters that must end the name of any object variable being declared for the class; provides a way of enforcing naming standards for class variable names.
declaration blocks See "Declaration blocks".
method definition See "Method definition syntax".

The (one or more) class blocks for a class contain the declaration blocks and method definitions for the class, which together comprise the class definition. The class definition consists of zero or more declaration blocks and zero or more method definitions. It is valid to define a class with no declarations and no methods, though such a class is not going to be particularly useful.

Multiple class blocks for a class are, in effect, combined to form one class definition. Class blocks after the first may exactly repeat any of the Alias, Extends, or RequiredSuffix clauses from the first block for a class, but they may not change these clauses.

Classes must be declared outside of any other block structures such as For loops, If blocks, or other Class blocks.

Once a class is declared, you use the Object keyword on variable declarations to declare objects as instances of a class:

%malibu is object car %outback is object car

Colons in class names

The colon character (:) is allowed in User Language class names. The following, for example, is a valid class declaration:

class customer:order

No colon-demarcated part of a class name can be the word System. For example, System, System:foo, Foo:system, and Foo:system:bar are all invalid class names.

While there is no special meaning to the colon-demarcated parts of a class name, the intent is that the colons be used to group classes, and that higher-level qualifiers come before lower-level ones. For example, in class name MiddleEarth:rohan:rider, a Rider class falls under a grouping of classes qualified by Rohan. This grouping, itself, falls under the larger grouping of MiddleEarth. Using the colon in this way is likely to make it easier to take advantage of future class management features that depend on a hierarchical, colon-based, class naming scheme.

Aliases for class names

As of Sirius Mods Version 7.8, you can define an alias name for an existing user class. You do so by specifying an Alias parameter setting on the existing class declaration. For example, you are changing a naming convention for some code, and you want to refer to user-defined class Blue by another name, say Indigo. Your class declaration would be:

class blue alias indigo

You can then use either the primary class name or the alias when declaring objects of the class:

%foo is object blue %bar is object indigo

An object of the alias class is compiled as an object of the primary class, and the runtime class of an object variable that was defined using an alias is the primary class. Consequently, all system messages you receive will specify the primary class.

For example, given the declarations above, if you call method TouchUp for an object declared for the Indigo class:

%bar:touchUp

And method TouchUp does not exist in the class, the error message you receive is:

MSIR.0733: Member TOUCHUP not found in class Blue

While this might seem potentially confusing, aliases are intended primarily for migrating class names, so any confusion will be limited to this migration period. In addition, only the owner of a class can declare an alias, so aliases are not likely to proliferate in your site's code.

Declaration blocks

Declaration blocks are another feature of the Janus SOAP User Language Interface that is unusual among object-oriented languages. Declaration blocks describe all the variables and methods that make up a class, but they contain no code.

Most object-oriented languages allow variable declarations of all types to be mixed arbitrarily with method definitions of all types. Though this appears to be very convenient, it can make it difficult for users or maintainers of a class to determine the general framework of the class. The Janus SOAP User Language Interface requires all variables and methods of a class to be declared in a few blocks, and in those blocks, to be organized in ways that are significant to their behavior.

The Janus SOAP User Language Interface allows no more than one of each of four declaration blocks:

  • Public
  • Private
  • Public Shared
  • Private Shared

The Public block contains the declaration of all class members (variables that are associated with an instance of the class, and methods that operate on an instance of the class) that are "public", that is available to users of the class. The Private block contains the declaration of all members that are "private", that is available only to methods inside a class definition.

The Shared blocks contain members that are shared among all instances of the class and so are able to be referenced independent of any instance of the class. Public Shared members are available to all users of the class, and Private Shared members are available only within the class definition. Shared variables and methods are discussed in more detail in Shared class members.

The declaration blocks contain declarations for all variables and methods in a class, and they must appear before any method definitions.

Declaration block syntax

The format of the declarations blocks is:

{Public | Private} [Shared]
   [Allow clauses]
   [Disallow clauses]
   [member declarations]
End {Public | Private} [Shared] [className]

Syntax terms

Public | PrivateIndicates whether the block describes members that can be referenced outside the class (Public) or members that can only be referenced inside the class (Private).
EndMarks the end of the declaration block. It must be followed immediately by Public or Private which is then possibly followed by Shared. The keywords following End must exactly match the block type: for a Public block, End Public is required; for a Private Shared block, End Private Shared is required. The class name can, optionally, be indicated after the block type on the End clause.
Allow clausesIndicate special operations allowed by the class. It can only be specified in a Public (non-shared) block, and consist of the Allow keyword followed by Auto, Copy, DeepCopy, or Narrow.

There can be multiple Allow clauses in a declaration block.

Allow clauses are optional and can be interspersed with Disallow clauses and member declarations.
Disallow clausesIndicate operations not allowed by the class. It can only be specified in a Public (non-shared) block, and consist of the Disallow keyword followed by Discard, or New.

There can be multiple Disallow clauses in a declaration block.

Disallow clauses are optional and can be interspersed with Allow clauses and member declarations.
member declarationsDeclare variables or methods in the class. These are described in following subsections.

While member declarations are optional, they tend to appear in almost all declarations blocks and a class without member declarations in some declaration blocks would be pretty much useless.

Member declaration clauses can be interspersed with Allow and Disallow clauses.

Allow clause

As the name suggests, the Allow clause indicates things one is allowed to do with the object instances of the class that one ordinarily would be allowed to do:

Allow AutoIndicates that an Auto New clause may be used on the declaration of variables of the type of the class being defined. If the class is an extension class, Allow Auto must also be specified on the class's base class(es).
Allow Copy or Allow DeepCopyMakes available the system Copy or DeepCopy method, respectively, for objects in the class.
Allow NarrowPermits narrowing assignments for objects in the class.

Allow Auto and constructors

Prior to version 7.6 of the Sirius Mods, a class defined with Allow Auto is not allowed to contain a constructor. As of version 7.6, Allow Auto is allowed in a class that has a constructor. However, for an object variable declared with Auto New in such a class, an automatic instantiation of the object does not call any of the constructors in the class, even if the class has defined an explicit constructor with the name New.

For example, the following request prints %y:b = 0 — the class's New constructor does not get called by %y:b:

b class y public allow auto variable b is float constructor new end public   constructor new %this:b = 1234 end constructor   end class   %y is object y auto new printText {~} = {%y:b} end

Disallow clause

As the name suggests, the Disallow clause indicates things that one is not allowed to do with the object instances of the class that ordinarily would be allowed:

Disallow DiscardIndicates that objects of the class cannot be explicitly discarded outside the class. Objects of the class can still be explicitly Discarded inside the class. For more about discarding objects, see "Discarding objects"
Disallow NewIndicates that explicit construction of instances of the class using the New constructor is not allowed outside the class. Objects of the class can still be explicitly created with New inside the class, and other public constructors for the class can be invoked outside the class. For more about object constructors, see "Creating object instances"

Variable declarations

Variable declarations in a class declaration block must begin with Variable followed by the variable name (without a percent sign). This is followed by any standard User Language variable declaration, with the exception that:

  • Static is not valid in a non-Shared block.
  • Global is not valid in a non-Shared block and requires the global name in a Shared block.
  • Common is not allowed.
  • The keywords to indicate “publicity” (Private, Private Shared, Public, and Public Shared) are allowed. If specified, they must match the publicity of the enclosing declaration block.
  • Auto followed by New or an enumeration value is allowed.
  • ReadOnly and Protected are allowed in Sirius Mods 7.2 and later. Like standard Model 204 variable declarations, the keyword Is immediately after the variable name on variable declarations is optional.

An example follows of a class block with some variable declarations:

class car public variable price is fixed dp 2 variable make is string len 32 variable description is longstring end public end class

Class variables can be referenced via an instance of that class, that is, via an object variable, like %gremlin below:

%gremlin is object car ... printText The price is {%gremlin:price}

The colon (:) that separates the object variable %gremlin and the class member variable price, above, may alternatively be specified with a one or more blanks before and/or after it.

In Sirius Mods 7.2 and later, it is possible to to declare a variable as ReadOnly or Protected. A ReadOnly variable can be examined by code outside the class, but it can only be updated inside the class. A Protected variable can be examined by code outside the class, but it can only be updated inside the class or by code inside an extension class. Since a ReadOnly or Protected variable must be accessible outside the class, it would make no sense for such a variable to be in a Private section, so this is not allowed.

ReadOnly and Protected variables are useful for providing an efficient means of accessing relatively static information about objects in a class. Unlike a property, retrieving ReadOnly or Protected variables requires no code to be run in the class.

The term Protected is something of a misnomer. In a very real sense, Protected variables aren't protected, at all. After all, they can be updated by extension classes. Their real purpose is to act as a sort of overridable variable, that is, a value that can be overridden by an extension class.

For example, suppose a class has a ReadOnly variable called PartNumber. Perhaps PartNumber is set by the class's constructor, and then it is never set again (for a particular object instance). Now, suppose this class wants to allow extension classes to set a different PartNumber, probably in their constructors. One approach would be to make PartNumber an Overridable ReadOnly property. But this is a somewhat heavyweight approach, as it requires a bit of code (the property Get method) for each extension class, and this code has to be run every time PartNumber is retrieved. Instead, PartNumber could be made a Protected variable, and an extension class's constructor could simply set it after calling the base class constructor. This allows the extension classes to override the base class's PartNumber using little extra code and using a very efficient access path for the value.

Protected variables differ from Overridable ReadOnly properties, however, in that an Overridable ReadOnly property always guarantees that the extension class's code is run, so it overrides the base class's properties. With a Protected variable, it would be possible for an extension class to set it, and for the base class to then set it to something else, undoing the extension class action.

Because they can be updated by both base and extension classes, Protected variables are probably most useful for very static values, like values that are only set by the constructors. Use of Protected variables that can be set throughout the life of objects of a class is likely to be error-prone, as it requires careful coordination of updates between the base and extension classes.

Method declarations and method types

In addition to variable declarations, a declaration block can also contain method declarations. There are four basic types of methods:

FunctionsMethods that produce an output value.
SubroutinesMethods that produce no output value.
PropertiesMethods that sometimes produce an output value and that can sometimes be set to a value, that is, be on the left side of an assignment statement.
ConstructorsMethods that process objects immediately after the objects are instantiated. Constructors produce no output value.

Method declaration syntax

The declarations for these methods are very similar:

Function <name> - [(parameters)] [Is] <datatype> - [AllowNullObject] [CurrentRecord <context>] [Callable] - [Public | Private [Shared] ]   Subroutine <name> - [(parameters)] - [AllowNullObject] [CurrentRecord <context>] - [Public | Private [Shared] ]   Property <name> - [(parameters)] [Is] <datatype> - [ReadWrite | ReadOnly | WriteOnly] - [AllowNullObject] [CurrentRecord <context>] - [Public | Private [Shared] ]   Constructor <name> - [(parameters)] - [Public | Private]

Syntax terms

  • The 'name' for Functions, Subroutines, Properties, and Constructors must follow the same rules as variable names and cannot be the same as another member of the class, whether a variable or method, public or private, shared or non-shared.
  • The 'parameters' have the same format as the parameter declarations of complex subroutines. For example:

    class car public ... subroutine wash(%detergent is string len 16, - %howLong is float, - %howClean is fixed output) ... end public end class

  • Functions and properties require a 'datatype', that is, an Is clause (though the keyword Is is optional).
    • For functions, the datatype is the datatype returned by the function.
    • For properties, the datatype is both the datatype returned by the property (when the property is used as an input) and the datatype to which the property is set. For example, suppose class Car had a mileage property:

      class car public ... property mileage is float ... end public end class

      You could do:

      %civic is object car ... %civic:mileage = 32.6 ... %hybridMileage = %civic:mileage + 19

  • The 'Optional' keyword indicates that a parameter may be specified on the method invocation or not. Alternatively, 'Default' lets you provide a default parameter value.
  • The 'AllowNullObject' keyword on a method declaration indicates that, even though the method operates on an instance of the class (an object), the method may be invoked with a null object variable. Ordinarily, a non-shared method referenced by a null object variable causes a (null-object reference) request cancellation error. Invoking a method even when the object variable is null may be useful in diagnostic code that displays object status or cleanup code.

    Since a constructor will always receive the just-created object as the object variable, AllowNullObject is not allowed on constructor declarations.
  • The 'CurrentRecord' clause (CurrentRecord In File <name>, or CurrentRecord In Group <name>) on a method declaration indicates that the method may only be invoked in a record context (established by a For Each Record loop, for example) for the declared file or group. Furthermore, CurrentRecord establishes a record context within the method, so method statements may reference a record field without having to be wrapped inside a record For loop (such as a For Record CurrentRecord loop).
  • The 'Callable' keyword, available only on Function declarations, indicates that the function can be Called, that is, invoked without a target for the result. Such a function may be Called even though it returns a value, and the Call may be explicit or implicit.

    class car public ... function wash is float callable ... end public end class ... %beetle is object car ... %beetle:wash

    The last line can also be written:

    call %beetle:wash

    Callable is typically to be used on Functions that perform some action but also return a status or informational value. Since the caller might not care about the informational value, the Callable keyword allows the caller to invoke the Function without a target for the return value.

    Without the Callable keyword, an attempt to invoke a Function without a target for the result (the target of an assignment or input to another method or subroutine) causes a compilation error. Not having the Callable option makes sense for Functions whose chief purpose is to return a value, since invoking them without a return value defeats the purpose. For example, if you had:

    class cat public function weight is float ... end public end class

    It probably wouldn't make sense to do:

    %misha is object cat ... %misha:weight

    In this case, it is probably best not to put the Callable keyword on the function declaration, and to catch likely typos or misunderstandings at compile-time.

  • Properties behave very much like variables, with the exception that they have code that is run when their value is set or retrieved. This behavioral similarity between properties and variables can be formally described as an isomorphism between properties and variables. Practically, this means that a variable can be changed to a property, and vice versa, without worrying about how the member is used outside the class.

    The keywords ReadWrite, ReadOnly, and WriteOnly indicate the type of access allowed for the property. The default, ReadWrite, indicates that the property can be both set and retrieved. ReadOnly properties can only be retrieved, and WriteOnly properties can only be set.

    ReadOnly properties are functionally equivalent to non-Callable Functions: one can think of a ReadOnly Property as a non-Callable Function, and vice versa, with no change to how the method can be used in applications. This makes the naming of such a method a ReadOnly Property or non-Callable Function primarily a hint to the users or maintainers of a class — a ReadOnly Property, as the name suggests, is a static attribute of an object, while a non-Callable Function is thought of as performing some dynamic operation. Any method that is to be Callable must be a Function rather than a Property.
  • The 'Public', 'Private', and 'Shared' keywords are optional, but, if present, must match the declaration block type. That is, in a Private block, Private must be indicated; in a Public Shared block, Public Shared must be indicated; and so on.
  • Constructors behave like subroutines but cannot be called directly. Instead, they are called by the Janus SOAP User Language Interface when an object is first created.

Declaration block example

In the following example, a class block consists of one public block which contains one variable declaration, one method (subroutine) declaration, and a disallow clause:

class stooge public variable funniness is float subroutine slap(%howHard is float) disallow new end public end class

The Auto keyword on object declarations

While it is not a daunting task to create an instance of an object, sometimes it can be unclear exactly where to instantiate an object. Furthermore, certain objects just do not make sense as nulls, so instantiating them is simply a chore. This chore can be simplified by placing the object instantiation statement immediately after the declaration:

%stringArray is object stringList %stringArray = new

But this mixes code with variable declarations, which might be deemed ugly, at best, and doesn't work, anyway, if the object is actually inside a class — code can't be placed in side a Public, Private, Public Shared, or Private Shared block.

To get around these issues, you can use the 'Auto' keyword for object variable declarations. For example:

%stringArray is object stringList auto new

An Auto keyword may be followed by either:

  • An enumeration value, for enumeration variables.
  • An instantiation method, which currently can only be 'New' (with no parameters), for object

and collection variables (for classes for which New is valid). Any instantiation that requires parameters must be done programmatically rather than on the variable declaration (for more information, see :hdref refid=newcons.).

The automatic instantiation of an object for a variable whose declaration includes Auto New does not use any constructor that may be defined for the object class, even a constructor named 'New'. The instantiation is generic, so to speak.

Auto New is valid for user-defined class object variables only if the class definition includes Allow Auto.

The Auto keyword can be very useful for array-like objects, especially collections. For example, it might seem natural to be able to start adding immediately to a stringlist without actually instantiating it:

%colors is object stringlist auto new %colors:add('Turquoise') %colors:add('Amber') ...

Collections seem particularly suited for being immediately added to:

%itemPrice is collection namedArraylist of float auto new %itemPrice('Widget') = 22.34 %itemPrice('Thingy') = 9.84 %itemPrice('Whatsit') = 64.18 ...

The Auto keyword can also be quite useful for enumerations. An Auto keyword on an enumeration variable acts very much like an Initial clause on a String, Float, or Fixed variable:

%haveWarned is enumeration boolean auto false

While it might be tempting to think about the Auto clause as doing the instantiation or assignment — as if an assignment immediately followed the declaration — this is not quite the way Auto works. Auto waits until the first reference to the variable, as long as it is not an assignment to the variable, before assigning to it. That is, the following declarations do not cause three Stringlist instances to be created:

%red is object stringList %white is object stringList %blue is object stringList

But if somewhat further down, the following statement is executed, a Stringlist instance is automatically created before the Add method is invoked:

%blue:add('Azure')

If the first reference to an Auto object is an assignment:

%red = %blue

the Auto attribute will never be exercised, even if the assignment source is Null, and even if the object is subsequently discarded.

Note: the effect of Auto is restricted to the first reference to a variable in a request.

Member reference

As described (in the object-oriented terminology list), defining a class entails defining its members, that is, variables and methods. In order to access one of those variables or invoke one of those methods, an expression must identify the member, and:

  • an object instance, for a non-shared, non-constructor member
  • the member's class, for a constructor or shared member (as described below, in some circumstances the class is implicit in the expression)

Here are three typical examples of member reference:

  • print %doc:value

    The Value function is invoked using the object %doc.

  • %slis = New

    A new instance object of the Stringlist class is assigned to the object variable %slis. Note that here the class identification is implicit.

  • %num = %(daemon):parentNumber

    The shared ParentNumber property is invoked to return the user number of the parent of the current thread. %(daemon) identifies the class of the shared property.

All of the above cases use the following syntax:

[identifyingPhrase:]member

The colon (:) preceding the member may optionally be preceded or followed by any number of blanks; here are some examples:

%str = %doc:Value('/order/cust/@name') %name = %custInfo : name %addr = %custInfo: - address %phone = %custInfo - :phone

The 'identifyingPhrase:' phrase is optional when invoking a Constructor or virtual constructor, in some circumstances, as described below.

  • If 'identifyingPhrase:' is present, the member phrase may either be a member name or a method variable.
  • If 'identifyingPhrase:' is not present, the member phrase must be a member name.

Non-shared, non-constructor members

For class members that are neither shared nor constructors, the member name (or method variable) must be preceded by an expression that denotes an object of the class, and a colon. The immediately preceeding examples are all of non-shared/non-constructor method invocation (...:Value...) or class variable access (%custInfo:...). For method invocation, the object instance (above, %doc) is the method object input to the method. For variable access, the class variable (name, address, phone) for the object instance (%custInfo) is accessed.

Constructors or shared members

Since neither a constructor nor a shared member operates on an object instance, referencing a constructor or a shared member requires identifying only the class to which the member belongs. For constructors and shared members, either of the following two syntax forms can always be used:

  1. %(className):member

    For example:

    %tok = %(system):arguments:stringTokenizer

  2. object:member

    For example:

    %daem object daemon if %daem:amDaemon then ...

    In this form of identifying the class, note that since no specific object instance is operated upon, the value of the method object (%daem) may be Null.

In addition to the above two syntax forms for identifying the class, in some circumstances the class can be implicitly identified for a Constructor or virtual constructor (a shared Function, Property, or Variable whose type is an object in the class):

  • The first, most common, set of circumstances is when the constructor is on the right hand side of an assignment statement:

    %var = constructor

    Note that %var must be an object variable, and constructor must be a Constructor or virtual constructor in the class of %var.

    For example, using the New Constructor:

    %strLis object stringlist %strLis = new

    A shared Function example is:

    %doc object xmlDoc ... for each record ... %doc = newFromRecord

  • The class identification may also be omitted before a constructor if the constuctor's result is an argument (but not the method object) of another method. For example:

    %origLis:copyItems(list('a', 'b', 'c'))

    In this example, the result of the virtual constructor List is the Stringlist argument of the CopyItems method.

  • A final, albeit rare, set of circumstances is when the result of the constructor is the right-hand comparand, for example in an If statement:

    If object eqOrNe constructor Then

    Note:

    • object must be an object expression, and constructor must be a Constructor or virtual constructor in the class of object.
    • The comparison operator (eqOrNe) must be one of Eq, =, or Ne.
    • object may not itself be a constructor without a preceding identifyingPhrase and colon.
    • Only the second operand in a comparison may use implicit class specification, that is, you may not do:

      If constructor eqOrNe object Then

Base class members

If an object expression is for an extension class, and you want to refer to a non-inherited member of a base class, you must specify the parenthesized base class name before the member name (or method variable). For example:

class ropeList extends stringList ... end class %rope object ropeList %rope = new %rope:(stringlist)add('sisal')

Intrinsic methods

As with non-intrinsic methods, you use the following syntax to invoke an intrinsic method:

identifyingPhrase:method

For intrinsic methods, however, the identifyingPhrase and colon (:) are always required; there is no circumstance that allows implicit class identification.

An example of invoking an intrinsic method is:

%sqrt = 169:SquareRoot

In addition, there are certain unusual syntax rules for invoking intrinsic methods, as described in "Intrinsic method syntax: special cases".

See also