Enumerations: Difference between revisions

From m204wiki
Jump to navigation Jump to search
mNo edit summary
 
(46 intermediate revisions by 6 users not shown)
Line 7: Line 7:
they would be set to values like <code>'True'</code> or <code>'False'</code>.
they would be set to values like <code>'True'</code> or <code>'False'</code>.
Or they could be
Or they could be
defined with a numeric datatype like Float, in which case they would
defined with a numeric datatype like <var>Float</var>, in which case they would
be set to values like <code>0</code> or <code>1</code>.
be set to values like <code>0</code> or <code>1</code>.
Both of these options are unappealing:
Both of these options are unappealing:
Line 16: Line 16:
readily apparent.
readily apparent.
<li>Neither strings nor numbers provide any compile-time validation of values.
<li>Neither strings nor numbers provide any compile-time validation of values.
That is, if the value of a property can be either <code><code>'True'</code></code>
That is, if the value of a property can be either <code>'True'</code>
or <code><code>'False'</code></code>,
or <code>'False'</code>,
the compiler will allow the property to be set to <code><code>'True'</code></code>,
the compiler will allow the property to be set to <code>'True'</code>,
or <code><code>'False'</code></code>, or anything else, for that matter.
or <code>'False'</code>, or anything else, for that matter.
</ul>
</ul>
   
   
Line 28: Line 28:
Since values are syntactically nouns, as are objects, enumeration handling is very
Since values are syntactically nouns, as are objects, enumeration handling is very
similar to object handling.
similar to object handling.
<var class="product">Sirius Mods</var> version 7.1 introduced support for User Language enumerations, that is, enumerations
<var class="product">SOUL</var> supports '''system enumerations''' (pre-defined
that are defined in User Language.
in the <var class="product">Model 204</var> nucleus) as well as
Before that release, only system enumerations (those defined
'''user enumerations''' (defined within a <var class="product">SOUL</var> request.
in the <var class="product">Model 204</var> nucleus) were supported.
 
 
Enumeration variables are declared very much like objects.
==Declaring enumeration variables==
==Enumeration variable declaration syntax==
Enumeration variables are declared very much like objects:
<p class="pre"> {variable} [Is] Enumeration <className> [Initial(<value>)]
<p class="syntax"><span class="term">variable</span> <span class="squareb">[</span><span class="literal">Is</span><span class="squareb">]</span> <span class="literal">Enumeration</span> <span class="term">className</span> <span class="squareb">[</span>Initial<span class="squareb">(</span><span class="term">value</span><span class="squareb">)]</span>
</p>
</p>
The Boolean enumeration is so heavily used that, as of <var class="product">Sirius Mods</var> 7.0, the keyword
The <var>Boolean</var> enumeration is so heavily used that the keyword
Enumeration is optional for Boolean enumeration variables:
<var>Enumeration</var> is optional for <var>Boolean</var> enumeration variables:
==Boolean enumeration variable declaration syntax==
<p class="syntax"><span class="term">variable</span> <span class="squareb">[</span><span class="literal">Is</span><span class="squareb">]</span> <span class="literal">Boolean</span> <span class="squareb">[</span>Initial<span class="squareb">(</span><span class="term">value</span><span class="squareb">)]</span>
<p class="pre"> {variable} [Is] Boolean [Initial(<value>)]
</p>
</p>
For example:
For example:
<p class="code"> %myAim  is boolean
<p class="code">%myAim  is boolean
</p>
</p>
   
   
An Enumeration variable, like an Object variable can be null;
An <var>Enumeration</var> variable, like an <var>Object</var> variable can be null;
in fact this the the default initial value for all enumeration variables.
in fact this the the default initial value for all enumeration variables.
This means that certain operations on enumeration variables can result
This means that certain operations on enumeration variables can result
in null-pointer reference errors.
in null-pointer reference errors.
It also means that, in some sense, all enumerations contain a special value
It also means that, in some sense, all enumerations contain a special value
of Null (though Null behaves somewhat differently from other values).
of <var>Null</var> (though <var>Null</var> behaves somewhat differently from other values).
This means that caution should be used for inequality tests on enumeration
This means that caution should be used for inequality tests on enumeration
variables as a null will satisfy an inequality test.
variables as a null will satisfy an inequality test.
   
   
As of <var class="product">Sirius Mods</var> 7.1, enumeration variables, including Booleans, can have a
Enumeration variables, including <var>Booleans</var>, can have a
compile-time initial value as specified by an Initial clause:
compile-time initial value as specified by an <var>Initial</var> clause:
<p class="code"> %myAim  is boolean initial(true)
<p class="code">%myAim  is boolean initial(true)
</p>
</p>
Such a clause can also be placed on variables in a class Public, Private, or
Such a clause can also be placed on variables in a class <var>Public</var>, <var>Private</var>, or
Shared block:
<var>Shared</var> block:
<p class="code"> class alison
<p class="code">class alison
  public
  public
      variable myaim  is boolean initial(true)
    variable myaim  is boolean initial(true)
      ...
    ...
  end public
  end public
  ...
  ...
end class
end class
</p>
</p>
   
   
As with other variable types, an Initial clause in a Public or Private block
As with other variable types, an <var>Initial</var> clause in a <var>Public</var> or <var>Private</var> block
sets the initial value for the variable when the containing object is
sets the initial value for the variable when the containing object is
instantiated.
instantiated.
Line 79: Line 79:
context of the (typically one) system class method
context of the (typically one) system class method
that uses the enumeration.
that uses the enumeration.
==Using enumerations==
==Using enumerations==
An explicit New method is not allowed for enumeration variables.
An explicit <var>New</var> method is '''not''' allowed for enumeration variables.
Instead, they must be set from the possible values for the enumeration:
Instead, they must be set from the possible values for the enumeration:
<p class="code"> %well  is enumeration boolean
<p class="code">%well  is enumeration boolean
  ...
...
%well = %(boolean):true
%well = %(boolean):true
  ...
...
%well = %(boolean):false
%well = %(boolean):false
</p>
</p>
   
   
Line 92: Line 93:
as with other shared properties, an enumeration variable can be used instead
as with other shared properties, an enumeration variable can be used instead
of the class name to reference the shared properties:
of the class name to reference the shared properties:
<p class="code"> %well  is enumeration boolean
<p class="code">%well  is enumeration boolean
  ...
...
%well = %well:true
%well = %well:true
  ...
...
%well = %well:false
%well = %well:false
</p>
</p>
   
   
Or, because the class can be inferred from the target,
Or, because the class can be inferred from the target,
enumerations can be set using just the value name:
enumerations can be set using just the value name:
<p class="code"> %well  is enumeration boolean
<p class="code">%well  is enumeration boolean
  ...
...
%well = true
%well = true
  ...
...
%well = false
%well = false
</p>
</p>
   
   
You can also use just the value name
You can also use just the value name
when a method parameter is an enumeration:
when a method parameter is an enumeration:
<p class="code"> class customer
<p class="code">class customer
    public
  public
      subroutine setActive(%active is enumeration boolean)
      subroutine setActive(%active is enumeration boolean)
      ...
      ...
    end public
  end public
    ...
  ...
end class
end class
  ...
...
%myCustomer  is object customer
%myCustomer  is object customer
  ...
...
%myCustomer:setActive(false)
%myCustomer:setActive(false)
</p>
</p>
   
   
Line 126: Line 127:
parameter.
parameter.
The previous example would probably be recast as:
The previous example would probably be recast as:
<p class="code"> class customer
<p class="code">class customer
    public
  public
      property active is enumeration boolean
      property active is enumeration boolean
      ...
      ...
    end public
  end public
    ...
  ...
end class
end class
  ...
...
%myCustomer  is object customer
%myCustomer  is object customer
  ...
...
%myCustomer:active = false
%myCustomer:active = false
</p>
</p>
   
   
System enumerations
System enumerations
can be declared with an explicit &ldquo;system:&rdquo; on their declaration:
can be declared with an explicit "system" on their declaration:
<p class="code"> %active is enumeration system:boolean
<p class="code">%active is enumeration system:boolean
</p>
</p>
   
   
Enumerations have a ToString method that returns the
Enumerations have a <var>ToString</var> method that returns the
string form of a value:
string form of a value:
<p class="code"> %active is enumeration boolean
<p class="code">%active is enumeration boolean
   
   
%active = true
%active = true
   
   
print %active:toString
print %active:toString
</p>
</p>
'''Note:'''
 
Prior to <var class="product">Sirius Mods</var> version 7.3,
<div id="imp2str"></div>
explicitly calling the ToString method was required to
<blockquote class="note">'''Note:'''
<!-- Prior to <var class="product">Sirius Mods</var> version 7.3 -->
Explicitly calling the <var>ToString</var> method was formerly required to
display the string form of an enumeration value, and simply
display the string form of an enumeration value, and simply
specifying <code>print %active</code> in the example above was an error,
specifying <code>print %active</code> in the example above was an error,
because %active is an object, not a string.
because <code>%active</code> is an object, not a string.  
<p>
However,
However, now that explicitly specifying
as of <var class="product">Sirius Mods</var> 7.3, explicitly specifying
<var>ToString</var> is optional, a statement like <code>print %active</code>
ToString is optional, and a statement like <code>print %active</code>
automatically implies <code>print %active:toString</code>.
automatically implies <code>print %active:toString</code>.
This is described further in ??[[#ToString property|ToString property]].
This is described further in [[#Calling ToString implicitly|Calling ToString implicitly]], below. </p>
</blockquote>
 
Enumerations can also have other methods.
Enumerations can also have other methods.
One class of such methods are &ldquo;Is&rdquo; methods that return
One class of such methods are "Is" methods that return
<code>0</code> or <code>1</code> depending on whether the method has a particular
<code>0</code> or <code>1</code> depending on whether the method has a particular
value.
value.
   
   
For example, the following method tests if
For example, the following method tests if
the value of %active is <code>True</code>:
the value of <code>%active</code> is <code>True</code>:
<p class="code"> %active is enumeration boolean
<p class="code">%active is enumeration boolean
  ...
...
if %active:isTrue then
if %active:isTrue then
</p>
</p>
   
   
This is almost exactly equivalent to the following:
This is almost exactly equivalent to the following:
<p class="code"> %active is enumeration boolean
<p class="code">%active is enumeration boolean
  ...
...
if %active eq true then
if %active eq true then
</p>
</p>
   
   
The one difference between the two forms is that the former would cause
The one difference between the two forms is that the former would cause
a null-pointer-reference request cancellation if %active had never
a null-pointer-reference request cancellation if <code>%active</code> had never
been set, while the latter would simply evaluate <code>%active eq true</code>
been set, while the latter would simply evaluate <code>%active eq true</code>
as false, since a Null value is not equal to <code>True</code>.
as false, since a <var>Null</var> value is not equal to <code>True</code>.
'''Note:'''
<p class="note">'''Note:'''
An alternative to using these Is methods for Boolean enumerations
There is an alternative to using these <var>Is</var> methods for <var>Boolean</var> enumerations
in the context of an If statement was introduced in <var class="product">Sirius Mods</var> version 6.7:
in the context of an <var>If</var> statement:
automatic conversion of
automatic conversion of
a Boolean <code>True</code> to a 1, and of a <code>False</code> to a 0.
a <var>Boolean</var> <var>True</var> to a 1, and of a <var>False</var> to a 0.
See [[#Using Boolean enumerations|Using Boolean enumerations]].
See [[#Using Boolean enumerations|Using Boolean enumerations]]. </p>
   
   
It is possible to use enumerations without ever declaring a variable
It is possible to use enumerations without ever declaring a variable
with that enumeration.
with that enumeration.
For example, one can set the UseDefault property of a NamedArraylist
For example, one can set the <var>UseDefault</var> property of a
(?? <var>[[NamedArraylist class|NamedArraylist]]</var>) just using the enumeration value:
<var>[[NamedArraylist class|NamedArraylist]]</var> by just using the enumeration value:
<p class="code"> %description is collection NamedArraylist of string len 64
<p class="code">%description is collection NamedArraylist of string len 64
  ...
  ...
%description:useDefault = true
%description:useDefault = true
</p>
</p>
==Common Enumeration methods==
 
The methods described in this section are available to all system enumerations.
==Common enumeration methods==
The methods listed below are available to all system enumerations. The individual method descriptions follow.
The versatile Boolean enumeration (??[[#Using Boolean enumerations|Using Boolean enumerations]]) has additional methods available.
<ul class="nobul">
<li><var>[[#Copy function|Copy]]</var>
<li><var>[[#DeepCopy function|DeepCopy]]</var>
<li><var>[[#FromString function|FromString]]</var>
<li><var>[[#ToString property|ToString]]</var>
</ul>
 
The [[#Using Boolean enumerations|versatile]] <var>Boolean</var> enumeration has additional methods available.
 
===Copy function===
===Copy function===
This function returns an exact copy of the method object.
This function returns an exact copy of the method object.
It is identical to the DeepCopy method (??[[#DeepCopy function|DeepCopy function]]).
It is identical to the <var>[[#DeepCopy function|DeepCopy]]</var> method.
Since enumeration variables simply have values, a Copy or DeepCopy is no
Since enumeration variables simply have values, a <var>Copy</var> or <var>DeepCopy</var> is no
different from an assignment, so enumerations are always copyable and deep
different from an assignment, so enumerations are always copyable and deep
copyable, as described in ??[[Copying objects]].
copyable, as described in [[Copying objects|"Copying objects"]].
As such, there is no real reason to do a Copy or DeepCopy of an
As such, there is no real reason to do a <var>Copy</var> or <var>DeepCopy</var> of an
enumeration variable, and the presence of these methods simply
enumeration variable, and the presence of these methods simply
makes the copyability of enumeration variables explicit.
makes the copyability of enumeration variables explicit.
==Copy syntax==
 
<p class="pre"> %cop = enum:Copy
====Copy syntax====
<p class="syntax"><span class="term">%cop</span> <span class="literal">=</span> <span class="term">enum</span><span class="literal">:Copy</span>
</p>
</p>
   
   
===Syntax terms===
====Syntax terms====
<table class="syntaxTable">
<table>
<tr><th><i><b>%cop</b></i></th>
<tr><th>%cop</th>
<td>An enumeration variable to contain the copy of ''enum''.
<td>An enumeration variable to contain the copy of ''enum''. <var class="term">%cop</var> does not have to be [[XmlDoc API#XmlDoc states|empty]].
''%cop'' does not have to be empty (??[[??]]XmlDoc API#XmlDoc states|]]).
</td></tr>
</td></tr>
<tr><th>enum</th>
<tr><th>enum</th>
<td>An enumeration variable or an expression that results
<td>An enumeration variable or an expression that results in an enumeration.
in an enumeration.
</td></tr></table>
</td></tr></table>
   
   
The method object (''enum'') may be null.
The method object (<var class="term">enum</var>) may be <var>Null</var>.
The output of a copy of a null object is a null object.
The output of a copy of a <var>Null</var> object is a <var>Null</var> object.
 
===DeepCopy function===
===DeepCopy function===
This function returns an exact copy of the method object.
This function returns an exact copy of the method object.
It is identical to the Copy method (??[[#Copy function|Copy function]]).
It is identical to the <var>[[#Copy function|Copy]]</var> method.
Since enumeration variables simply have values, a Copy or DeepCopy is no
Since enumeration variables simply have values, a <var>Copy</var> or <var>DeepCopy</var> is no
different from an assignment, so enumerations are always copyable and deep
different from an assignment, so enumerations are always copyable and deep
copyable, as described in ??[[Copying objects]].
copyable, as described in [[Copying objects|"Copying objects"]].
As such, there is no real reason to do a Copy or DeepCopy of an
As such, there is no real reason to do a <var>Copy</var> or <var>DeepCopy</var> of an
enumeration variable, and the presence of these methods simply
enumeration variable, and the presence of these methods simply
makes the copyability of enumeration variables explicit.
makes the copyability of enumeration variables explicit.
==DeepCopy syntax==
 
<p class="pre"> %dcop = enum:DeepCopy
====DeepCopy syntax====
<p class="syntax"><span class="term">%dcop</span> <span class="literal">=</span> <span class="term">enum</span><span class="literal">:DeepCopy</span>
</p>
</p>
   
   
===Syntax terms===
====Syntax terms====
<table class="syntaxTable">
<table>
<tr><th><i><b>%dcop</b></i></th>
<tr><th>%dcop</th>
<td>An enumeration variable to contain the deep copy of ''enum''.
<td>An enumeration variable to contain the deep copy of <var class="term">enum</var>. <var class="term">%dcop</var> does not have to be [[XmlDoc API#XmlDoc states|empty]].
''%dcop'' does not have to be empty (??[[??]]XmlDoc API#XmlDoc states|]]).
</td></tr>
</td></tr>
<tr><th>enum</th>
<tr><th>enum</th>
Line 255: Line 266:
</td></tr></table>
</td></tr></table>
   
   
The method object (''enum'') may be null.
The method object (<var class="term">enum</var>) may be <var>Null</var>.
The output of a deep copy of a null object is a null object.
The output of a deep copy of a <var>Null</var> object is a <var>Null</var> object.
 
===FromString function===
<var>FromString</var> is a [[Notation conventions for methods#Shared methods|shared]] function that converts a string argument into a value of the specified enumeration type.
This is the opposite of the enumeration <var>ToString</var> method, which converts an enumeration value to its <var>String</var> representation.
<!-- <var>FromString</var> is available as of <var class="product">Sirius Mods</var> Version 7.8. -->
====FromString syntax====
<p class="syntax"><span class="term">%enum</span> <span class="literal">= [%(</span><span class="term">enumType</span><span class="literal">):]</span><span class="literal">FromString(</span><span class="term">string</span><span class="literal">)</span></p>
====Syntax terms====
<table>
<tr><th>%enum</th>
<td>An enumeration variable or expression.  </td></tr>
<tr><th><var class="nobr">%(<i>enumType</i>)</var> </th>
<td>This explicit specification of the enumeration type in parentheses denotes a [[Object variables#Virtual Constructor methods|virtual constructor]]. See [[#Usage notes|"Usage notes"]], below, for more information about invoking this function. </td></tr>
 
<tr><th>string</th>
<td>A [[Longstrings|longstring]] variable that is assigned the current string value of <var class="term">enum</var>.
</td></tr>
</table>
 
====Usage Notes====
<ul>
<li>As an example, consider the following user-defined enumeration:
<p class="code">enumeration Animal
    public
      value cat
      value dog
      value gecko
      value parrot
    end public
end enumeration
</p>
 
You can populate an <code>Animal</code> enumeration variable with one of the <code>Animal</code> enumeration values by making a call to <var>FromString</var>:
<p class="code">%pet is enumeration animal
%pet = fromString('gecko')
</p>
The result of a <var>Print</var> of <code>%pet</code> above is <code>gecko</code>.
<blockquote class="note">'''Note:''' In the method call, <code>fromString</code> might but does '''not''' have to be preceded by <code>%(Animal):</code> to identify the type of enumeration, because the type is determined from the result variable. You could also get the same result from invoking with an already defined enumeration variable, as in:
<p class="code">%pet = %pet:fromString('gecko')</p>
</blockquote>
<li>Only strings that match a value of the particular enumeration type
can be converted. If a string cannot be converted to an enumeration
value, <var>FromString</var> throws an <var>[[InvalidValue class|Invalidvalue]]</var> exception:
<p class="code">%pet = fromString('alien')
<nowiki>***</nowiki>  1  CANCELLING REQUEST: MSIR.0750: Class Animal, function
FromString: InvalidValue exception: ALIEN is not a valid enumeration
value in line 84, procedure ENUM, file MYPROC
</p>
</ul>
 
===ToString property===
===ToString property===
This non-shared non-settable property examines an enumeration
This non-settable property examines an enumeration
and returns a printable or testable string representation of its value.
and returns a printable or testable string representation of its value.
==ToString syntax==
 
<p class="pre"> %ls = enum:ToString
====ToString syntax====
<p class="syntax"><span class="term">%ls</span> <span class="literal">=</span> <span class="term">enum</span><span class="literal">:ToString</span>
</p>
</p>
   
   
===Syntax terms===
====Syntax terms====
<table class="syntaxTable">
<table>
<tr><th><i><b>%ls</b></i></th>
<tr><th>%ls</th>
<td>If specified, a longstring variable that is assigned the
<td>A [[Longstrings|longstring]] variable that is assigned the current string value of <var class="term">enum</var>.
current string value of ''enum''.
</td></tr>
</td></tr>
<tr><th>enum</th>
<tr><th>enum</th>
<td>An enumeration variable or an expression that results in an enumeration.
<td>An enumeration variable or an expression that results in an enumeration.
</td></tr></table>
</td></tr></table>
==Usage Notes==
 
<div id="printenum"></div>
====Calling ToString implicitly====
<!-- As of <var class="product">Sirius Mods</var> 7.3 -->To return a string representation of the value of a <var class="product">SOUL</var> system or user-defined enumeration, you can do either of the following:
<ul>
<ul>
<li>Prior to <var class="product">Sirius Mods</var> version 7.3, the ToString method was the only way to
<li>Explicitly specify the <var>ToString</var> method.
return a string representation of the value of a [[Janus SOAP ULI]] enumeration.
 
As of <var class="product">Sirius Mods</var> 7.3, however, you no longer need to explicitly specify
<li>Print (or audit) the value of an enumeration, and <var>ToString</var> is implied,
ToString to print the value of a system or user-defined enumeration.
You can simply print (or audit) the value of an enumeration, and ToString is implied,
as shown in the following example:
as shown in the following example:
<p class="code"> begin
<p class="code">begin
enumeration color
enumeration color
    public
  public
      value red
      value red
      value white
      value white
      value blue
      value blue
      value green
      value green
    end public
  end public
end enumeration
end enumeration
   
   
%x  is boolean initial(true)
%x  is boolean initial(true)
%z  is enumeration color initial(blue)
%z  is enumeration color initial(blue)
%daem is object daemon
%daem is object daemon
   
   
%daem = new
%daem = new
   
   
print %x with ' ' %z
print %x with ' ' %z
printText {~} = {%x}, {~} = {%z}
[[PrintText statement|printText]] {~} = {%x}, {~} = {%z}
print %daem:haveDaemon
print %daem:haveDaemon
printText {~} = {%daem:haveDaemon}
printText {~} = {%daem:haveDaemon}
end
end
</p>
</p>
   
   
The Print and PrintText statements above produce these results:
The <var>Print</var> and <var>PrintText</var> statements above produce these results:
<p class="code"> True blue
<p class="code">True blue
%x = True, %z = blue
%x = True, %z = blue
True
True
%daem:haveDaemon = True
%daem:haveDaemon = True
</p>
</p>
'''Note:'''
 
In addition, the implicit ToString feature extends beyond enumerations:
<blockquote class="note">'''Note:'''
upon any attempt to print or audit any object value, [[Janus SOAP ULI]] will try to apply a
In addition, the implicit <var>ToString</var> feature extends beyond enumerations:
ToString method to the object.
upon any attempt to print or audit any object value, <var class="product">SOUL</var> will try to apply a
<var>ToString</var> method to the object.
If the object is an enumeration (as shown above) or is an
If the object is an enumeration (as shown above) or is an
instance of a system or user-defined class that has a ToString method,
instance of a system or user-defined class that has a <var>ToString</var> method,
a ToString is implicitly
a <var>ToString</var> is implicitly
applied and the result is a successful print or audit of the object value.
applied and the result is a successful print or audit of the object value.
<p>
For example, the user-defined class in the following request includes a
For example, the user-defined class in the following request includes a
ToString method.
<var>ToString</var> method.
The request's printText statement prints <code>%x = a=11, b=22</code>.
The request's <code>printText</code> statement prints <code>%x = a=11, b=22</code>. </p>
<p class="code"> begin
<p class="code">begin
class mumble
class mumble
  public
  public
    variable  a is float
    variable  a is float
    variable  b is float
    variable  b is float
    constructor new(%a is float nameRequired, %b is float)
    constructor new(%a is float nameRequired, %b is float)
    function tostring is longstring
    function tostring is longstring
  end public
  end public
  constructor new(%a  is float nameRequired, %b is float)
  constructor new(%a  is float nameRequired, %b is float)
    %this:a = %a
    %this:a = %a
    %this:b = %b
    %this:b = %b
  end constructor
  end constructor
  function tostring is longstring
  function tostring is longstring
    return 'a=' with %a with ', b=' with %b
    return 'a=' with %a with ', b=' with %b
  end function
  end function
end class
end class
   
   
    %x  is object mumble
  %x  is object mumble
    %x = new(a=11, b=22)
  %x = new(a=11, b=22)
    printText {~} = {%x}
  printText {~} = {%x}
end
end
</p>
</p>
<p>
If the object you try to print or audit directly is not an enumeration or is
If the object you try to print or audit directly is not an enumeration or is
an instance of a class that does not have a ToString method (system or
an instance of a class that does not have a <var>ToString</var> method (system or
user-written), you receive a compilation error.
user-written), you receive a compilation error.
For example, if %sl is a Stringlist object, no user ToString method exists,
For example, if <code>%sl</code> is a <var>Stringlist</var> object, no user <var>ToString</var> method exists,
and your request contains a <code>Print %sl</code> statement, you get a message
and your request contains a <code>Print %sl</code> statement, you get a message
like the following:
like the following: </p>
<p class="code"> ***  1  MSIR.0733: Member TOSTRING not found in class STRINGLIST
<p class="code">&#42;**  1  MSIR.0733: Member TOSTRING not found in class STRINGLIST
  print %sl
  print %sl
  (FILE = JALWORK, PROCEDURE = FOO, LINE = 28)
  (FILE = JALWORK, PROCEDURE = FOO, LINE = 28)
***  M204.1042: COMPILATION ERRORS
&#42;**  M204.1042: COMPILATION ERRORS
</p>
</p>
<p>
Finally, if the object you try to print directly is a Unicode variable
Finally, if the object you try to print directly is a <var>Unicode</var> variable,
under <var class="product">Sirius Mods</var> 7.6 and higher,
<!-- under <var class="product">Sirius Mods</var> 7.6 and higher -->
the implicit ToString method returns an EBCDIC character-encoded value for
the implicit <var>ToString</var> method returns an EBCDIC character-encoded value for
Unicode characters that do not translate to EBCDIC.
Unicode characters that do not translate to EBCDIC.
This is described further in ??[[??]]Unicode#Implicit Unicode conversions|]].
This is described further in [[Unicode#Implicit Unicode conversions|"Implicit Unicode conversions"]]. </p>
</blockquote>
</ul>
</ul>
==Using Boolean enumerations==
 
The system Boolean enumeration values (shared
==Boolean enumeration==
properties) are:
The [[Boolean enumeration]] is probably the most commonly used, and so the most important enumeration class. Because of its importance, it is treated specially by <var class="product">SOUL</var>, and is a topic unto itself.
<ul>
 
<li><b>True</b>
==User enumerations==
<li><b>False</b>
</ul>
Many methods, for example the [[Janus SOAP]] XML Exists function
(??[[Exists (XmlDoc/XmlNode function)]]), return a Boolean enumeration.
Unlike other [[Janus SOAP ULI]] enumerations, Boolean enumeration values
are usable (as of <var class="product">Sirius Mods</var> version 6.7) as the condition in an If statement:
<p class="code"> %recset  is object recordSet in file sirfiled
  ...
find records to %recset
    rectype = 'FILE'
end find
  ...
if %recset:isEmpty then
    print 'No records found!'
end if
</p>
In the above example, the IsEmpty method returns a Boolean enumeration value.
Strictly speaking, the If clause expects a numeric zero or non-zero value as
its operand, but in this context [[Janus SOAP ULI]] automatically converts
a <code>True</code> to a 1 and a <code>False</code> to a 0.
Other places where a Boolean value can be used, that is, where it's automatically
converted to the 0 or 1 that User Language expects are:
<ul>
<li>As a Repeat statement operand.
<li>As an operand for a logical operator such as Not, And, or Or.
This would usually be in an If or Repeat statement.
</ul>
You can also use Boolean literals in these contexts, but they must be
completely qualified as Booleans: otherwise there is a syntactic
ambiguity between the values <code>True</code> or <code>False</code> and
fields by the name of <code>True</code> or <code>False</code>.
The following is syntactically valid:
<p class="code"> if %(boolean):true then
    print 'Truth be told'
end if
</p>
Besides the common enumeration methods (??[[#Common Enumeration methods|Common Enumeration methods]]), the
system Boolean enumeration has additional methods available, which are
described in the following sections.
===IsFalse function===
This function examines a Boolean enumeration and returns an integer (0 or 1)
according to the Boolean value (True or False).
==IsFalse syntax==
<p class="pre"> %num = bool:IsFalse
</p>
===Syntax terms===
<table class="syntaxTable">
<tr><th>%num</th>
<td>If specified, a number variable that is assigned the value <code>0</code>
if the value of ''bool'' is True, and <code>1</code> if
''bool'' is False.
</td></tr>
<tr><th>bool</th>
<td>A Boolean enumeration variable or an expression that results
in a Boolean enumeration.
</td></tr></table>
===IsTrue function===
This function examines a Boolean enumeration and returns an integer (1 or 0)
according to the Boolean value (True or False).
==IsTrue syntax==
<p class="pre"> %num = bool:IsTrue
</p>
===Syntax terms===
<table class="syntaxTable">
<tr><th>%num</th>
<td>If specified, a number variable that is assigned the value <code>1</code>
if the value of ''bool'' is True, and <code>0</code> if
''bool'' is False.
</td></tr>
<tr><th>bool</th>
<td>A Boolean enumeration variable or an expression that results
in a Boolean enumeration.
</td></tr></table>
==User Language Enumerations==
While there are a wide variety of system enumerations that can be useful in
While there are a wide variety of system enumerations that can be useful in
many contexts (especially the Boolean enumeration), as of <var class="product">Sirius Mods</var> 7.1, it is
many contexts (especially the <var>Boolean</var> enumeration), it is
also possible to define enumerations in User Language.
also possible to define user enumerations in <var class="product">SOUL</var>.
This is done via the Enumeration statement/block, which is very similar to the
This is done via the <var>Enumeration</var> statement/block, which is very similar to the
Class statement/block (??[[Classes and objects]]).
<var>Class</var> statement/block (as in [[Classes and Objects|"Classes and objects"]]).
'''Note:'''
 
Just as for class blocks as of <var class="product">Sirius Mods</var> version 7.3,
===The Enumeration block===
an enumeration block you declare inside a method or complex subroutine
The <var>Enumeration</var> block can contain <var>Public</var>, <var>Private</var>, <var>Public</var> <var>Shared</var>, and <var>Private</var> <var>Shared</var> blocks, just like any other class.
must be preceded by the keyword <code>Local</code>.
For more information about locally-scoped classes and enumerations,
see [[??]]Local and Common entities#Local classes, enumerations, and structures|]].
The Enumeration block can contain Public, Private, Public Shared, and Private
Shared blocks, just like any other class.
However, because enumeration classes don't really describe objects, there
However, because enumeration classes don't really describe objects, there
can be no instance variables.
can be no instance variables.
That is, the Public and Private blocks cannot contain Variable declarations.
That is, the <var>Public</var> and <var>Private</var> blocks cannot contain <var>Variable</var> declarations.
   
   
==Value declaration syntax==
Instead, the <var>Public</var> block must contain one or more <var>Value</var> declarations
<p class="pre"> Instead, the Public block must contain one or more Value declarations:
whose syntax is:
:fig place=inline
<p class="syntax"><span class="literal">Value</span> <span class="term">value</span> <span class="squareb">[</span><span class="term">attribute</span><span class="squareb">]</span>
value <value>
</p>
</p>
   
   
Each value declared by a Value declaration becomes one of the values
Each value declared by a <var>Value</var> declaration becomes one of the values of the enumeration.  
of the enumeration.
 
No values are allowed in the Private or Shared blocks.
One or more '''attributes''' (a constant datum of type <var>String</var>, <var>Float</var>, or <var>Enumeration</var>) can be attached to an enumeration value. <!-- (as of <var class="product">Sirius Mods</var> version 7.8) -->
'''Note:'''
 
The value in a value clause is unusual in that the case (lower or upper)
No values or attributes are allowed in the <var>Private</var> or <var>Shared</var> blocks.
of the characters in its value are saved and used in the implicit ToString method.
 
<p class="note">'''Note:''' The value in a <var>Value</var> clause is unusual in that the case (lower or upper)
of the characters in its value are saved and used in the implicit <var>ToString</var> method. The same is true for the values in an <var>Attribute</var> clause. </p>
   
   
The following is an example of a simple enumeration:
The following is an example of a simple enumeration:
<p class="code"> enumeration shape
<p class="code">enumeration shape
    public
  public
      value triangle
      attribute code is string
      value square
 
      value rhombus
      value triangle     (code='31')
      value rectangle
      value square       (code='44')
      value quadrilateral
      value rhombus       (code='42')
      value pentagon
      value rectangle     (code='41')
      value circle
      value quadrilateral (code='40')
    end public
      value pentagon     (code='50')
  end enumeration
      value circle       (code='01')
  end public
end enumeration
</p>
 
All attributes must be declared before any value is declared. In a given <var>Value</var> clause:
<ul>
<li>A specification for each attribute must be explicitly present.  
<li>An attribute may be specified by name or by position; and like a method [[Methods#Named_parameters|named parameter]], an attribute specified with its name may not precede an attribute specified only by position.
<li>An attribute name may not repeat.
</ul>
 
<p class="note">'''Note:'''
Just as for <var>Class</var> blocks, <!-- as of <var class="product">Sirius Mods</var> version 7.3 -->
an <var>Enumeration</var> block you declare inside a method or complex subroutine
must be preceded by the keyword <var>Local</var>.
For more information about locally-scoped classes and enumerations,
see [[Local and Common entities#Local classes, enumerations, and structures|"Local classes, enumerations, and structures"]].
</P>
===Using user enumerations===
You can use user-defined enumerations just like system enumerations.
That is, variables are declared with the <var>Enumeration</var> keyword and class name:
<p class="code">%cookieShape is enumeration shape
</p>
</p>
   
   
User Language defined enumerations can be used just like system enumerations.
Enumeration values may be assigned to an enumeration variable:
That is, variables can be declared with the enumeration class:
<p class="code">%cookieShape = circle
<p class="code"> %cookieShape is enumeration shape
</p>
</p>
   
   
And enumeration values can be assigned to an enumeration variable:
Such a variable may be printed (<code>Print %cookieShape</code>), and it may be used to access an enumeration attribute:
<p class="code"> %cookieShape = circle
<p class="code">Print %cookieShape:code
</p>
</p>
 
More commonly, enumerations can be used as method parameters:
More commonly, enumerations may be used as method parameters:
<p class="code"> class cookie
<p class="code">class cookie
    ...
  ...
    subroutine cut(%shape is enumeration shape)
  subroutine cut(%shape is enumeration shape)
    ...
  ...
end class
end class
</p>
</p>
   
   
And, typically, literal values are used as the arguments when invoking
And, typically, literal values are used as the arguments when invoking
such a method:
such a method:
<p class="code"> %biscuit  is object cookie
<p class="code">%biscuit  is object cookie
  ...
...
%biscuit:cut(pentagon)
%biscuit:cut(pentagon)
</p>
</p>
   
   
Line 524: Line 525:
from context, the class name can always be explicitly specified for a
from context, the class name can always be explicitly specified for a
value:
value:
<p class="code"> %cookieShape = %(shape):circle
<p class="code">%cookieShape = %(shape):circle
  ...
...
%biscuit:cut(%(shape):pentagon)
%biscuit:cut(%(shape):pentagon)
</p>
</p>
   
   
Like system enumerations, User Language enumeration variables can be in a state where
Like system enumerations, user enumeration variables can be in a state where
they have no value, that is, they can be null.
they have no value, that is, they can be null.
In fact, that is the initial value of any enumeration variable.
In fact, that is the initial value of any enumeration variable.
==Initial value clause==
 
<p class="pre"> As with system enumerations (as of <var class="product">Sirius Mods</var> 7.1), this default initial value
As with system enumerations, you can change the default initial value
can be changed with the Initial clause on the variable declaration:
with the <var>Initial</var> clause on the variable declaration:
:fig place=inline
<p class="syntax"><span class="term">variable</span> <span class="squareb">[</span><span class="literal">Is</span><span class="squareb">]</span> <span class="literal">Enumeration</span> <span class="term">enumerationName</span> <span class="squareb">[</span><span class="literal">Initial</span><span class="squareb">(</span><span class="term">value</span><span class="squareb">)]</span>
<variable> [is] enumeration <enumerationName> -
                [Initial(value)]
</p>
</p>
 
This can be done for local variables:
You can set the default initial value for local variables:
<p class="code"> %cutout is enumeration shape initial(square)
<p class="code">%cutout is enumeration shape initial(square)
</p>
</p>
   
   
as well as for variables in class blocks:
And you can set it for variables in class blocks:
<p class="code"> class cookie
<p class="code">class cookie
    public
  public
      variable shape is enumeration shape initial(round)
      variable shape is enumeration shape initial(round)
      ...
      ...
    end public
  end public
    ...
  ...
end class
end class
</p>
</p>
   
   
Of course, instance-specific (non-Shared) initial values are set
Of course, instance-specific (non-<var>Shared</var>) initial values are set
for each instance of the class when it is created.
for each instance of the class when it is created.
===Enumeration methods===
===Enumeration methods===
Enumeration classes can also contain methods that operate on
Enumeration classes can also contain methods that operate on
or are related to the enumeration values.
or are related to the enumeration values.
For example, the Shapes class can have a method that returns the number
For example, the <code>Shape</code> enumeration can have a method that returns the number
of sides in a shape:
of sides in a shape:
<p class="code"> enumeration shape
<p class="code">enumeration shape
    public
  public
      ...
      ...
      function sides is float
      function sides is float
    end public
  end public
    function sides is float
  function sides is float
      if %this eq circle then
      if %this eq circle then
          return 0
        return 0
      end if
      end if
      if %this eq triangle then
      if %this eq triangle then
          return 3
        return 3
      end if
      end if
      ...
      ...
    end function
  end function
end enumeration
end enumeration
</p>
</p>
   
   
As this example illustrates, the implicit %this variable for enumeration
As this example illustrates, the implicit <code>%this</code> variable for enumeration
methods contains not an object reference but an enumeration value.
methods contains not an object reference but an enumeration value.
   
   
Enumeration methods can be applied to enumeration values as well as
Enumeration methods can be applied to enumeration values as well as enumeration variables.
enumeration variables.
This is one case, however, where the enumeration value '''must'''
This is one case, however, where the enumeration value '''must'''
be qualified with the class name, because it appears in a context where
be qualified with the class name, because it appears in a context where
the class cannot be determined otherwise:
the class cannot be determined otherwise:
<p class="code"> print %(shape):rhombus:sides
<p class="code">print %(shape):rhombus:sides
</p>
</p>
   
   
And, as with objects, an enumeration method could be applied to the output
And, as with objects, an enumeration method could be applied to the output
of another method that returns an enumeration value.
of another method that returns an enumeration value.
For example, if the PickCookie method of the Jar class returns a
For example, if the <code>PickCookie</code> method of the <code>Jar</code> class returns a
Cookie object, and the Shape method of the Cookie class returns a
<code>Cookie</code> object, and the <code>Shape</code> method of the <code>Cookie</code> class returns a
Shape enumeration value, the following prints the number of sides of
<code>Shape</code> enumeration value, the following prints the number of sides of
a picked cookie:
a picked cookie:
<p class="code"> %jar  is object jar
<p class="code">%jar  is object jar
  ...
...
print %jar:pickCookie:shape:sides
print %jar:pickCookie:shape:sides
</p>
 
===Inverse attribute methods===
Inverse attribute methods let you derive an enumeration <var>Value</var> based on the value of one of
its <var>[[#The Enumeration block|Attributes]]</var>. To do so, you declare an <code>inverse</code> method at the end of an <var>Attribute</var> declaration, then you invoke the method, as is shown with the <code>fromOz</code> method in this example:
<p class="code">enumeration coffee                                                     
    public
      attribute oz is float inverse fromOz 
 
      value tall  (12)
      value grande (16)
      value venti  (20)
    end public 
end enumeration           
 
%order is enumeration coffee
 
%order = fromOz(16) 
Print %order
</p>
</p>
<p>
The result is: </p>
<p class="code">grande</p>
====Usage notes====
<ul>
<li>Inverse attribute calls throw an <var>[[InvalidValue class|InvalidValue]]</var> exception if the given value cannot be inverted.
<li>Since the same attribute value may appear in more than one <var>Value</var> specification,
inverse attribute calls are checked at compile time for such ambiguous
value parameters. If you try to invert an attribute value that has multiple possible inverses,
you receive <code>MSIR.1029: Attribute error: Duplicate values specified for
invertible attribute</code> when you attempt to compile the offending enumeration.
</ul>
===Automatic methods===
===Automatic methods===
Several methods are automatically provided for User Language enumeration
Several methods are automatically provided for <var class="product">SOUL</var> enumeration
classes.
classes.
Some of these are identical to common methods available in most system
Some of these are identical to common methods available in most system
enumerations.
enumerations.
These methods are:
These methods are:
<dl>
<table class="thJustBold">
<dt>Copy
<tr>
<dd>Performs a &ldquo;copy&rdquo; of the enumeration value.
<th>Copy</th>
Since enumeration variables simply have values, a Copy or DeepCopy is no
<td>Performs a &ldquo;copy&rdquo; of the enumeration value. Since enumeration variables simply have values, a <var>Copy</var> or <var>DeepCopy</var> is no different from an assignment, so enumerations are always copyable and deep
different from an assignment, so enumerations are always copyable and deep
copyable, as described in [[Copying objects|"Copying objects"]]. As such, there is no real reason to do a <var>Copy</var> or <var>DeepCopy</var> of an enumeration variable, and the presence of these methods simply makes the copyability of enumeration variables explicit.</td>
copyable, as described in ??[[Copying objects]].
</tr>
As such, there is no real reason to do a Copy or DeepCopy of an
<tr>
enumeration variable, and the presence of these methods simply
<th>DeepCopy</th>
makes the copyability of enumeration variables explicit.
<td>Performs a &ldquo;copy&rdquo; of the enumeration value. Since enumeration variables simply have values, a <var>Copy</var> or <var>DeepCopy</var> is no different from an assignment, so enumerations are always copyable and deep
<dt>DeepCopy
copyable, as described in [[Copying objects|"Copying objects"]]. As such, there is no real reason to do a <var>Copy</var> <var>Or</var> DeepCopy of an enumeration variable, and the presence of these methods simply makes the copyability of enumeration variables explicit.</td>
<dd>Performs a &ldquo;copy&rdquo; of the enumeration value.
</tr>
Since enumeration variables simply have values, a Copy or DeepCopy is no
<tr>
different from an assignment, so enumerations are always copyable and deep
<th>FromOrdinal</th>
copyable, as described in ??[[Copying objects]].
<td>This shared method is the inverse of the <var>Ordinal</var> method and converts an ordinal number to an enumeration value. The class specified in the shared method invocation determines the class of the result enumeration value.
As such, there is no real reason to do a Copy or DeepCopy of an
By default, the <var>FromOrdinal</var> method behaves as if it is a private method. That is, it can only be accessed inside the class. This can be overridden by specifying <code>Allow Ordinal</code> in the <var>Public</var> block.
enumeration variable, and the presence of these methods simply
 
makes the copyability of enumeration variables explicit.
This method was introduced in <var class="product">[[Sirius Mods]]</var> Version 8.1.</td>
<dt>Ordinal
</tr>
<dd>Returns the ordinal position of the Value clause associated with
<tr>
the value of the enumeration.
<th>NumberOfValues</th>
For example, if an enumeration was declared as
<td>This shared method returns the number of values in the enumeration class. The class specified in the shared method invocation determines the class whose value count is returned.
<p class="code"> enumeration shot
By default, the <var>NumberOfValues</var> method behaves as if it is a private method. That is, it can only be accessed inside the class. This can be overridden by specifying <code>Allow Ordinal</code> in the <var>Public</var> block.
    public
 
      value rock
This method was introduced in <var class="product">[[Sirius Mods]]</var> Version 8.1.</td>
      value paper
</tr>
      value scissors
<tr>
    end public
<th>Ordinal</th>
end enumeration
<td>Returns the ordinal position of the <var>Value</var> clause associated with the value of the enumeration. For example, if an enumeration was declared as follows:
<p class="code">enumeration shot
  public
      value rock
      value paper
      value scissors
  end public
end enumeration
</p>
</p>
The ordinal for a value of <var>Rock</var> is 1, for <var>Paper</var> 2, and <var>Scissors</var> 3.
the ordinal for a value of Rock is 1, for Paper 2, and Scissors 3.
By default, the <var>Ordinal</var> method behaves as if it is a private method. That is, it can only be accessed inside the class. This can be overridden by specifying <code>Allow Ordinal</code> in the <var>Public</var> block, as described below.</td>
By default, the Ordinal method behaves as if it is a private method.
</tr>
That is, it can only be accessed inside the class.
<tr>
This can be overridden by specifying <code>Allow Ordinal</code> in the Public block.
<th>ToString</th>
<dt>ToString
<td>Returns a string representation of the enumeration value.
<dd>Returns a string representation of the enumeration value.
The value returned uses the same case for the characters as was used on the <var>Value</var> declaration.</td>
The value returned uses the same case for the characters as was used on
</tr>
the Value declaration.
</table>
</dl>
 
====Using the Ordinal method====
The Ordinal method, especially, bears a bit more discussion.
The <var>Ordinal</var> method, especially, bears further discussion.
It can be very useful in writing enumeration methods, especially in
It can be very useful in writing enumeration methods, especially in
conjunction with the Jump statement.
conjunction with the <var>Jump</var> statement.
For example, the Sides method in the Shapes class above could have been
For example, the <code>Sides</code> method in the <code>Shape</code> enumeration above could have been
written like:
written like:
<p class="code"> function sides is float
<p class="code">function sides is float
    jump to (three, four, four, four, four, five, none) -
  jump to (three, four, four, four, four, five, none) %this:ordinal
            %this:ordinal
  three: return 3
    three: return 3
  four:  return 4
    four:  return 4
  five:  return 5
    five:  return 5
  none:  return 0
    none:  return 0
end function
end function
</p>
</p>
   
   
Line 666: Line 704:
dependent on the order of the value declarations.
dependent on the order of the value declarations.
This means that it becomes difficult to rearrange the value declarations,
This means that it becomes difficult to rearrange the value declarations,
or to insert one into the list after there is code that uses the Ordinal
or to insert one into the list after there is code that uses the <var>Ordinal</var>
method on an enumeration class.
method on an enumeration class.
For this reason, the Ordinal method behaves like a private method, by
For this reason, the <var>Ordinal</var> method behaves like a private method, by
default.
default.
That is, it is only available to methods inside the Enumeration class
That is, it is only available to methods inside the <var>Enumeration</var> class
block.
block.
   
   
One use of the Ordinal method that you might want to make public occurs
One use of the <var>Ordinal</var> method that you might want to make public occurs
when the enumeration values have a natural ordering.
when the enumeration values have a natural ordering.
Consider, for example, the following enumeration:
Consider, for example, the following enumeration:
<p class="code"> enumeration volume
<p class="code">enumeration volume
    public
  public
      value low
      value low
      value medium
      value medium
      value high
      value high
      value deafening
      value deafening
    end public
  end public
end enumeration
end enumeration
</p>
</p>
   
   
With such an enumeration, one might want to use an enumeration value's
With such an enumeration, one might want to use an enumeration value's
ordinality in comparisons.
ordinality in comparisons.
To allow this to be done, the Allow Ordinal directive must be placed in
To allow this to be done, the <var>Allow Ordinal</var> directive must be placed in
the Public block of the enumeration definition:
the <var>Public</var> block of the enumeration definition:
<p class="code"> enumeration volume
<p class="code">enumeration volume
    public
  public
      allow ordinal
      allow ordinal
      value low
      value low
      value medium
      value medium
      value high
      value high
      value deafening
      value deafening
    end public
  end public
end enumeration
end enumeration
</p>
</p>
   
   
Then, code like the following can be used outside the class:
Then, code like the following can be used outside the class:
<p class="code"> %leftSpeakerVolume  is enumeration volume
<p class="code">%leftSpeakerVolume  is enumeration volume
%rightSpeakerVolume is enumeration volume
%rightSpeakerVolume is enumeration volume
  ...
...
if %leftSpeakerVolume:ordinal gt -
if %leftSpeakerVolume:ordinal gt -
    %rightSpeakerVolume:ordinal then
  %rightSpeakerVolume:ordinal then
    ...
  ...
end if
end if
</p>
</p>
   
   
Of course, the same effect could be achieved by adding a different method
Of course, the same effect could be achieved by adding a different method
to the enumeration, called perhaps Level, that returned a non-ordinal value
to the enumeration, called perhaps <code>Level</code>, that returned a non-ordinal value
that could still be used for comparisons:
that could still be used for comparisons:
<p class="code"> %leftSpeakerVolume  is enumeration volume
<p class="code">%leftSpeakerVolume  is enumeration volume
%rightSpeakerVolume is enumeration volume
%rightSpeakerVolume is enumeration volume
  ...
...
if %leftSpeakerVolume:level gt -
if %leftSpeakerVolume:level gt -
    %rightSpeakerVolume:level then
  %rightSpeakerVolume:level then
    ...
  ...
end if
end if
</p>
</p>
   
   
Line 729: Line 767:
enumeration is to provide a comparison method to compare two enumeration
enumeration is to provide a comparison method to compare two enumeration
values.
values.
====Using the FromOrdinal and NumberOfValues methods====
The <var>FromOrdinal</var> and <var>NumberOfValues</var> methods were introduced in <var class="product">Sirius Mods</var> version 8.1.
These two methods make it easy to enumerate all the values in an enumeration class without having to maintain code that has a list of all the values. Because these methods could be used to build an equivalent to the automatic <var>Ordinal</var> method, they require <var>Allow Ordinal</var> to be set in the enumeration class against which they are used (see example below).
The <var>FromOrdinal</var> method is a [[Shared_class_members|shared method]] and has a single input argument: the ordinal number of the value to which to set the target enumeration variable. For example, if one has a <var>Stooge</var> enmeration:
<p class="code">enumeration stooge
  public
      value moe
      value larry
      value curly
      value shemp
      allow ordinal
  end public
end enumeration
</p>
then the following sequence:
<p class="code">%favorite is enumeration stooge
%favorite = %(stooge):fromOrdinal(3)
printText {~=%favorite}
</p>
would print:
<p class="code">%favorite=curly
</p>
If an invalid ordinal number is specified as input to the <var>FromOrdinal</var> method, an <var>[[InvalidValue_class|InvalidValue]]</var> exception is thrown. For example, the following:
<p class="code">%favorite = %(stooge):fromOrdinal(-5)
</p>
would result in the following request canceling error message:
<p class="code">MSIR.0750: Class Stooge, function FromOrdinal: InvalidValue exception: -5 is not -
a valid ordinal number for class Stooge ...
</p>
You can catch such an exception to produce a list of all values in an enumeration class:
<p class="code">for %i from 1 to 99999999
  try printText {%(stooge):fromOrdinal(%i)}
  catch invalidValue; loop end
  end try
end for
</p>
This outputs:
<p class="code">moe
larry
curly
shemp
</p>
The <var>NumberOfValues</var> automatic method for enumerations lets you do this a little more tidily:
<p class="code">for %i from 1 to %(stooge):numberOfValues
  printText {%(stooge):fromOrdinal(%i)}
end for
</p>
The <var>NumberOfValues</var> method has no parameters.
<var>NumberOfValues</var> and <var>FromOrdinal</var> can be used to build an [[Arraylist_class|Arraylist]] that contains one item for each value in the enumeration class:
<p class="code">%stoogeValues    is arraylist of enumeration stooge
...
%stoogeValues = new
for %i from 1 to %(stooge):numberOfValues
  %stoogeValues:add(%(stooge):fromOrdinal(%i))
end for
</p>
One advantage of having such an <var>Arraylist</var> is that it can easily be sorted or searched. For example, the following displays the stooge values sorted in ascending character order:
<p class="code">%stoogevalues:[[SortNew_(GenericNamedArraylist_function)|sortNew]](ascending(toString)):print
</p>
This displays:
<p class="code">1: curly
2: larry
3: moe
4: shemp
</p>
==See also==
<ul>
<li>[[Lists of classes and methods#Enumerations|List of system enumerations]] </li>
<li>[[Object oriented programming in SOUL]] </li>
</ul>
[[Category:SOUL object-oriented programming topics]]

Latest revision as of 19:42, 30 June 2014


Objects may have properties that can have relatively few values, such as True or False; Yes, No, or Maybe; Red, Green, or Blue; or Small, Medium, Large, SuperSize. These properties could be defined with a string datatype, in which case they would be set to values like 'True' or 'False'. Or they could be defined with a numeric datatype like Float, in which case they would be set to values like 0 or 1. Both of these options are unappealing:

  • Using strings ties you to a particular case-sensitive representation of the values.
  • Using numbers makes the code unclear, as the meaning of, say, 2 is not readily apparent.
  • Neither strings nor numbers provide any compile-time validation of values. That is, if the value of a property can be either 'True' or 'False', the compiler will allow the property to be set to 'True', or 'False', or anything else, for that matter.

The special type of class called enumerations solves these problems. An enumeration class doesn't actually describe a set of objects but a set of values or, more specifically, names for a set of values. Since values are syntactically nouns, as are objects, enumeration handling is very similar to object handling. SOUL supports system enumerations (pre-defined in the Model 204 nucleus) as well as user enumerations (defined within a SOUL request.


Declaring enumeration variables

Enumeration variables are declared very much like objects:

variable [Is] Enumeration className [Initial(value)]

The Boolean enumeration is so heavily used that the keyword Enumeration is optional for Boolean enumeration variables:

variable [Is] Boolean [Initial(value)]

For example:

%myAim is boolean

An Enumeration variable, like an Object variable can be null; in fact this the the default initial value for all enumeration variables. This means that certain operations on enumeration variables can result in null-pointer reference errors. It also means that, in some sense, all enumerations contain a special value of Null (though Null behaves somewhat differently from other values). This means that caution should be used for inequality tests on enumeration variables as a null will satisfy an inequality test.

Enumeration variables, including Booleans, can have a compile-time initial value as specified by an Initial clause:

%myAim is boolean initial(true)

Such a clause can also be placed on variables in a class Public, Private, or Shared block:

class alison public variable myaim is boolean initial(true) ... end public ... end class

As with other variable types, an Initial clause in a Public or Private block sets the initial value for the variable when the containing object is instantiated.

The sections that follow describe how to use enumerations, including the methods that may be applied to them. Most of the individual enumeration classes are documented elsewhere: in the context of the (typically one) system class method that uses the enumeration.

Using enumerations

An explicit New method is not allowed for enumeration variables. Instead, they must be set from the possible values for the enumeration:

%well is enumeration boolean ... %well = %(boolean):true ... %well = %(boolean):false

Enumeration values are similar to shared properties of an object class and, as with other shared properties, an enumeration variable can be used instead of the class name to reference the shared properties:

%well is enumeration boolean ... %well = %well:true ... %well = %well:false

Or, because the class can be inferred from the target, enumerations can be set using just the value name:

%well is enumeration boolean ... %well = true ... %well = false

You can also use just the value name when a method parameter is an enumeration:

class customer public subroutine setActive(%active is enumeration boolean) ... end public ... end class ... %myCustomer is object customer ... %myCustomer:setActive(false)

Often, though, an enumeration will be a property rather than a parameter. The previous example would probably be recast as:

class customer public property active is enumeration boolean ... end public ... end class ... %myCustomer is object customer ... %myCustomer:active = false

System enumerations can be declared with an explicit "system" on their declaration:

%active is enumeration system:boolean

Enumerations have a ToString method that returns the string form of a value:

%active is enumeration boolean %active = true print %active:toString

Note:

Explicitly calling the ToString method was formerly required to display the string form of an enumeration value, and simply specifying print %active in the example above was an error, because %active is an object, not a string.

However, now that explicitly specifying ToString is optional, a statement like print %active automatically implies print %active:toString. This is described further in Calling ToString implicitly, below.

Enumerations can also have other methods. One class of such methods are "Is" methods that return 0 or 1 depending on whether the method has a particular value.

For example, the following method tests if the value of %active is True:

%active is enumeration boolean ... if %active:isTrue then

This is almost exactly equivalent to the following:

%active is enumeration boolean ... if %active eq true then

The one difference between the two forms is that the former would cause a null-pointer-reference request cancellation if %active had never been set, while the latter would simply evaluate %active eq true as false, since a Null value is not equal to True.

Note: There is an alternative to using these Is methods for Boolean enumerations in the context of an If statement: automatic conversion of a Boolean True to a 1, and of a False to a 0. See Using Boolean enumerations.

It is possible to use enumerations without ever declaring a variable with that enumeration. For example, one can set the UseDefault property of a NamedArraylist by just using the enumeration value:

%description is collection NamedArraylist of string len 64 ... %description:useDefault = true

Common enumeration methods

The methods listed below are available to all system enumerations. The individual method descriptions follow.

The versatile Boolean enumeration has additional methods available.

Copy function

This function returns an exact copy of the method object. It is identical to the DeepCopy method. Since enumeration variables simply have values, a Copy or DeepCopy is no different from an assignment, so enumerations are always copyable and deep copyable, as described in "Copying objects". As such, there is no real reason to do a Copy or DeepCopy of an enumeration variable, and the presence of these methods simply makes the copyability of enumeration variables explicit.

Copy syntax

%cop = enum:Copy

Syntax terms

%cop An enumeration variable to contain the copy of enum. %cop does not have to be empty.
enum An enumeration variable or an expression that results in an enumeration.

The method object (enum) may be Null. The output of a copy of a Null object is a Null object.

DeepCopy function

This function returns an exact copy of the method object. It is identical to the Copy method. Since enumeration variables simply have values, a Copy or DeepCopy is no different from an assignment, so enumerations are always copyable and deep copyable, as described in "Copying objects". As such, there is no real reason to do a Copy or DeepCopy of an enumeration variable, and the presence of these methods simply makes the copyability of enumeration variables explicit.

DeepCopy syntax

%dcop = enum:DeepCopy

Syntax terms

%dcop An enumeration variable to contain the deep copy of enum. %dcop does not have to be empty.
enum An enumeration variable or an expression that results in an enumeration.

The method object (enum) may be Null. The output of a deep copy of a Null object is a Null object.

FromString function

FromString is a shared function that converts a string argument into a value of the specified enumeration type. This is the opposite of the enumeration ToString method, which converts an enumeration value to its String representation.

FromString syntax

%enum = [%(enumType):]FromString(string)

Syntax terms

%enum An enumeration variable or expression.
%(enumType) This explicit specification of the enumeration type in parentheses denotes a virtual constructor. See "Usage notes", below, for more information about invoking this function.
string A longstring variable that is assigned the current string value of enum.

Usage Notes

  • As an example, consider the following user-defined enumeration:

    enumeration Animal public value cat value dog value gecko value parrot end public end enumeration

    You can populate an Animal enumeration variable with one of the Animal enumeration values by making a call to FromString:

    %pet is enumeration animal %pet = fromString('gecko')

    The result of a Print of %pet above is gecko.

    Note: In the method call, fromString might but does not have to be preceded by %(Animal): to identify the type of enumeration, because the type is determined from the result variable. You could also get the same result from invoking with an already defined enumeration variable, as in:

    %pet = %pet:fromString('gecko')

  • Only strings that match a value of the particular enumeration type can be converted. If a string cannot be converted to an enumeration value, FromString throws an Invalidvalue exception:

    %pet = fromString('alien') *** 1 CANCELLING REQUEST: MSIR.0750: Class Animal, function FromString: InvalidValue exception: ALIEN is not a valid enumeration value in line 84, procedure ENUM, file MYPROC

ToString property

This non-settable property examines an enumeration and returns a printable or testable string representation of its value.

ToString syntax

%ls = enum:ToString

Syntax terms

%ls A longstring variable that is assigned the current string value of enum.
enum An enumeration variable or an expression that results in an enumeration.

Calling ToString implicitly

To return a string representation of the value of a SOUL system or user-defined enumeration, you can do either of the following:

  • Explicitly specify the ToString method.
  • Print (or audit) the value of an enumeration, and ToString is implied, as shown in the following example:

    begin enumeration color public value red value white value blue value green end public end enumeration %x is boolean initial(true) %z is enumeration color initial(blue) %daem is object daemon %daem = new print %x with ' ' %z printText {~} = {%x}, {~} = {%z} print %daem:haveDaemon printText {~} = {%daem:haveDaemon} end

    The Print and PrintText statements above produce these results:

    True blue %x = True, %z = blue True %daem:haveDaemon = True

    Note:

    In addition, the implicit ToString feature extends beyond enumerations: upon any attempt to print or audit any object value, SOUL will try to apply a ToString method to the object. If the object is an enumeration (as shown above) or is an instance of a system or user-defined class that has a ToString method, a ToString is implicitly applied and the result is a successful print or audit of the object value.

    For example, the user-defined class in the following request includes a ToString method. The request's printText statement prints %x = a=11, b=22.

    begin class mumble public variable a is float variable b is float constructor new(%a is float nameRequired, %b is float) function tostring is longstring end public constructor new(%a is float nameRequired, %b is float) %this:a = %a %this:b = %b end constructor function tostring is longstring return 'a=' with %a with ', b=' with %b end function end class %x is object mumble %x = new(a=11, b=22) printText {~} = {%x} end

    If the object you try to print or audit directly is not an enumeration or is an instance of a class that does not have a ToString method (system or user-written), you receive a compilation error. For example, if %sl is a Stringlist object, no user ToString method exists, and your request contains a Print %sl statement, you get a message like the following:

    *** 1 MSIR.0733: Member TOSTRING not found in class STRINGLIST print %sl (FILE = JALWORK, PROCEDURE = FOO, LINE = 28) *** M204.1042: COMPILATION ERRORS

    Finally, if the object you try to print directly is a Unicode variable, the implicit ToString method returns an EBCDIC character-encoded value for Unicode characters that do not translate to EBCDIC. This is described further in "Implicit Unicode conversions".

Boolean enumeration

The Boolean enumeration is probably the most commonly used, and so the most important enumeration class. Because of its importance, it is treated specially by SOUL, and is a topic unto itself.

User enumerations

While there are a wide variety of system enumerations that can be useful in many contexts (especially the Boolean enumeration), it is also possible to define user enumerations in SOUL. This is done via the Enumeration statement/block, which is very similar to the Class statement/block (as in "Classes and objects").

The Enumeration block

The Enumeration block can contain Public, Private, Public Shared, and Private Shared blocks, just like any other class. However, because enumeration classes don't really describe objects, there can be no instance variables. That is, the Public and Private blocks cannot contain Variable declarations.

Instead, the Public block must contain one or more Value declarations whose syntax is:

Value value [attribute]

Each value declared by a Value declaration becomes one of the values of the enumeration.

One or more attributes (a constant datum of type String, Float, or Enumeration) can be attached to an enumeration value.

No values or attributes are allowed in the Private or Shared blocks.

Note: The value in a Value clause is unusual in that the case (lower or upper) of the characters in its value are saved and used in the implicit ToString method. The same is true for the values in an Attribute clause.

The following is an example of a simple enumeration:

enumeration shape public attribute code is string value triangle (code='31') value square (code='44') value rhombus (code='42') value rectangle (code='41') value quadrilateral (code='40') value pentagon (code='50') value circle (code='01') end public end enumeration

All attributes must be declared before any value is declared. In a given Value clause:

  • A specification for each attribute must be explicitly present.
  • An attribute may be specified by name or by position; and like a method named parameter, an attribute specified with its name may not precede an attribute specified only by position.
  • An attribute name may not repeat.

Note: Just as for Class blocks, an Enumeration block you declare inside a method or complex subroutine must be preceded by the keyword Local. For more information about locally-scoped classes and enumerations, see "Local classes, enumerations, and structures".

Using user enumerations

You can use user-defined enumerations just like system enumerations. That is, variables are declared with the Enumeration keyword and class name:

%cookieShape is enumeration shape

Enumeration values may be assigned to an enumeration variable:

%cookieShape = circle

Such a variable may be printed (Print %cookieShape), and it may be used to access an enumeration attribute:

Print %cookieShape:code

More commonly, enumerations may be used as method parameters:

class cookie ... subroutine cut(%shape is enumeration shape) ... end class

And, typically, literal values are used as the arguments when invoking such a method:

%biscuit is object cookie ... %biscuit:cut(pentagon)

Enumeration values are not strings, so they are case insensitive. While the class of an enumeration value can almost always be determined from context, the class name can always be explicitly specified for a value:

%cookieShape = %(shape):circle ... %biscuit:cut(%(shape):pentagon)

Like system enumerations, user enumeration variables can be in a state where they have no value, that is, they can be null. In fact, that is the initial value of any enumeration variable.

As with system enumerations, you can change the default initial value with the Initial clause on the variable declaration:

variable [Is] Enumeration enumerationName [Initial(value)]

You can set the default initial value for local variables:

%cutout is enumeration shape initial(square)

And you can set it for variables in class blocks:

class cookie public variable shape is enumeration shape initial(round) ... end public ... end class

Of course, instance-specific (non-Shared) initial values are set for each instance of the class when it is created.

Enumeration methods

Enumeration classes can also contain methods that operate on or are related to the enumeration values. For example, the Shape enumeration can have a method that returns the number of sides in a shape:

enumeration shape public ... function sides is float end public function sides is float if %this eq circle then return 0 end if if %this eq triangle then return 3 end if ... end function end enumeration

As this example illustrates, the implicit %this variable for enumeration methods contains not an object reference but an enumeration value.

Enumeration methods can be applied to enumeration values as well as enumeration variables. This is one case, however, where the enumeration value must be qualified with the class name, because it appears in a context where the class cannot be determined otherwise:

print %(shape):rhombus:sides

And, as with objects, an enumeration method could be applied to the output of another method that returns an enumeration value. For example, if the PickCookie method of the Jar class returns a Cookie object, and the Shape method of the Cookie class returns a Shape enumeration value, the following prints the number of sides of a picked cookie:

%jar is object jar ... print %jar:pickCookie:shape:sides

Inverse attribute methods

Inverse attribute methods let you derive an enumeration Value based on the value of one of its Attributes. To do so, you declare an inverse method at the end of an Attribute declaration, then you invoke the method, as is shown with the fromOz method in this example:

enumeration coffee public attribute oz is float inverse fromOz value tall (12) value grande (16) value venti (20) end public end enumeration %order is enumeration coffee %order = fromOz(16) Print %order

The result is:

grande

Usage notes

  • Inverse attribute calls throw an InvalidValue exception if the given value cannot be inverted.
  • Since the same attribute value may appear in more than one Value specification, inverse attribute calls are checked at compile time for such ambiguous value parameters. If you try to invert an attribute value that has multiple possible inverses, you receive MSIR.1029: Attribute error: Duplicate values specified for invertible attribute when you attempt to compile the offending enumeration.

Automatic methods

Several methods are automatically provided for SOUL enumeration classes. Some of these are identical to common methods available in most system enumerations. These methods are:

Copy Performs a “copy” of the enumeration value. Since enumeration variables simply have values, a Copy or DeepCopy is no different from an assignment, so enumerations are always copyable and deep copyable, as described in "Copying objects". As such, there is no real reason to do a Copy or DeepCopy of an enumeration variable, and the presence of these methods simply makes the copyability of enumeration variables explicit.
DeepCopy Performs a “copy” of the enumeration value. Since enumeration variables simply have values, a Copy or DeepCopy is no different from an assignment, so enumerations are always copyable and deep copyable, as described in "Copying objects". As such, there is no real reason to do a Copy Or DeepCopy of an enumeration variable, and the presence of these methods simply makes the copyability of enumeration variables explicit.
FromOrdinal This shared method is the inverse of the Ordinal method and converts an ordinal number to an enumeration value. The class specified in the shared method invocation determines the class of the result enumeration value.

By default, the FromOrdinal method behaves as if it is a private method. That is, it can only be accessed inside the class. This can be overridden by specifying Allow Ordinal in the Public block.

This method was introduced in Sirius Mods Version 8.1.
NumberOfValues This shared method returns the number of values in the enumeration class. The class specified in the shared method invocation determines the class whose value count is returned.

By default, the NumberOfValues method behaves as if it is a private method. That is, it can only be accessed inside the class. This can be overridden by specifying Allow Ordinal in the Public block.

This method was introduced in Sirius Mods Version 8.1.
Ordinal Returns the ordinal position of the Value clause associated with the value of the enumeration. For example, if an enumeration was declared as follows:

enumeration shot public value rock value paper value scissors end public end enumeration

The ordinal for a value of Rock is 1, for Paper 2, and Scissors 3.

By default, the Ordinal method behaves as if it is a private method. That is, it can only be accessed inside the class. This can be overridden by specifying Allow Ordinal in the Public block, as described below.
ToString Returns a string representation of the enumeration value. The value returned uses the same case for the characters as was used on the Value declaration.

Using the Ordinal method

The Ordinal method, especially, bears further discussion. It can be very useful in writing enumeration methods, especially in conjunction with the Jump statement. For example, the Sides method in the Shape enumeration above could have been written like:

function sides is float jump to (three, four, four, four, four, five, none) %this:ordinal three: return 3 four: return 4 five: return 5 none: return 0 end function

While this might justifiably be disparaged as questionable programming technique, it is very efficient and simple.

One disadvantage of such a technique is that the code is now highly dependent on the order of the value declarations. This means that it becomes difficult to rearrange the value declarations, or to insert one into the list after there is code that uses the Ordinal method on an enumeration class. For this reason, the Ordinal method behaves like a private method, by default. That is, it is only available to methods inside the Enumeration class block.

One use of the Ordinal method that you might want to make public occurs when the enumeration values have a natural ordering. Consider, for example, the following enumeration:

enumeration volume public value low value medium value high value deafening end public end enumeration

With such an enumeration, one might want to use an enumeration value's ordinality in comparisons. To allow this to be done, the Allow Ordinal directive must be placed in the Public block of the enumeration definition:

enumeration volume public allow ordinal value low value medium value high value deafening end public end enumeration

Then, code like the following can be used outside the class:

%leftSpeakerVolume is enumeration volume %rightSpeakerVolume is enumeration volume ... if %leftSpeakerVolume:ordinal gt - %rightSpeakerVolume:ordinal then ... end if

Of course, the same effect could be achieved by adding a different method to the enumeration, called perhaps Level, that returned a non-ordinal value that could still be used for comparisons:

%leftSpeakerVolume is enumeration volume %rightSpeakerVolume is enumeration volume ... if %leftSpeakerVolume:level gt - %rightSpeakerVolume:level then ... end if

The advantage of this approach is that a non-ordinal value is less likely to be misused for computed jumps, and the levels leave space to add values associated with new enumeration values. Another approach that avoids exposing the ordinal values of an enumeration is to provide a comparison method to compare two enumeration values.

Using the FromOrdinal and NumberOfValues methods

The FromOrdinal and NumberOfValues methods were introduced in Sirius Mods version 8.1.

These two methods make it easy to enumerate all the values in an enumeration class without having to maintain code that has a list of all the values. Because these methods could be used to build an equivalent to the automatic Ordinal method, they require Allow Ordinal to be set in the enumeration class against which they are used (see example below).

The FromOrdinal method is a shared method and has a single input argument: the ordinal number of the value to which to set the target enumeration variable. For example, if one has a Stooge enmeration:

enumeration stooge public value moe value larry value curly value shemp allow ordinal end public end enumeration

then the following sequence:

%favorite is enumeration stooge %favorite = %(stooge):fromOrdinal(3) printText {~=%favorite}

would print:

%favorite=curly

If an invalid ordinal number is specified as input to the FromOrdinal method, an InvalidValue exception is thrown. For example, the following:

%favorite = %(stooge):fromOrdinal(-5)

would result in the following request canceling error message:

MSIR.0750: Class Stooge, function FromOrdinal: InvalidValue exception: -5 is not - a valid ordinal number for class Stooge ...

You can catch such an exception to produce a list of all values in an enumeration class:

for %i from 1 to 99999999 try printText {%(stooge):fromOrdinal(%i)} catch invalidValue; loop end end try end for

This outputs:

moe larry curly shemp

The NumberOfValues automatic method for enumerations lets you do this a little more tidily:

for %i from 1 to %(stooge):numberOfValues printText {%(stooge):fromOrdinal(%i)} end for

The NumberOfValues method has no parameters.

NumberOfValues and FromOrdinal can be used to build an Arraylist that contains one item for each value in the enumeration class:

%stoogeValues is arraylist of enumeration stooge ... %stoogeValues = new for %i from 1 to %(stooge):numberOfValues %stoogeValues:add(%(stooge):fromOrdinal(%i)) end for

One advantage of having such an Arraylist is that it can easily be sorted or searched. For example, the following displays the stooge values sorted in ascending character order:

%stoogevalues:sortNew(ascending(toString)):print

This displays:

1: curly 2: larry 3: moe 4: shemp

See also