Object variables: Difference between revisions

From m204wiki
Jump to navigation Jump to search
 
(14 intermediate revisions by 3 users not shown)
Line 25: Line 25:
The following is an example of assignment of an object reference, rather
The following is an example of assignment of an object reference, rather
than an object:
than an object:
<pre>
 
class pet
<p class="code">class pet
   public
   public
       variable type  is string len 16
       variable type  is string len 16
Line 39: Line 39:
%fluffy:type = 'Cat'
%fluffy:type = 'Cat'
print %rover:type
print %rover:type
</pre>
</p>
 
Because the statement <code>%fluffy = %rover</code> assigns to %fluffy a reference
Because the statement <code>%fluffy = %rover</code> assigns to %fluffy a reference
to the same object as %rover, both variables end up referring
to the same object as %rover, both variables end up referring
Line 54: Line 55:


Consider the following example::
Consider the following example::
<pre>
<p class="code">class pet
class pet
   public
   public
       variable type  is string len 16
       variable type  is string len 16
Line 69: Line 69:
%fluffy:type = 'Dog'
%fluffy:type = 'Dog'
if %fluffy eq %rover then
if %fluffy eq %rover then
   print 'They''re equal!'
   print 'They&apos;&apos;re equal!'
end if
end if
</pre>
</p>
 
This will not print <code>They're equal</code>.
This will not print <code>They're equal</code>.
Even though the objects
Even though the objects
Line 77: Line 78:
are different objects, so %fluffy is not equal to %rover.
are different objects, so %fluffy is not equal to %rover.
However, if the code were changed:
However, if the code were changed:
<pre>
 
class pet
<p class="code">class pet
   public
   public
       variable type  is string len 16
       variable type  is string len 16
Line 90: Line 91:
%rover = %fluffy
%rover = %fluffy
if %fluffy eq %rover then
if %fluffy eq %rover then
   print 'They''re equal!'
   print 'They&apos;&apos;re equal!'
end if
end if
</pre>
</p>
 
<code>They're equal</code> will be printed, because <code>%rover = %fluffy</code>
<code>They're equal</code> will be printed, because <code>%rover = %fluffy</code>
sets <code>%rover</code> to point to the same object as <code>%fluffy</code>, making them equal.
sets <code>%rover</code> to point to the same object as <code>%fluffy</code>, making them equal.
<br>'''Note:'''
 
<p class="note>'''Note:'''
Since order comparisons (GE, LE, GT, and LT) are meaningless for references &mdash;
Since order comparisons (GE, LE, GT, and LT) are meaningless for references &mdash;
when is a reference to one object greater than a reference to another? &mdash;
when is a reference to one object greater than a reference to another? &mdash;
only equality and inequality (EQ and NE) comparisons are allowed for objects.
only equality and inequality (EQ and NE) comparisons are allowed for objects. </p>


Despite the foregoing remarks, for most purposes, one can still think of
Despite the foregoing remarks, for most purposes, one can still think of
Line 104: Line 107:
the objects themselves, rather than references to the object.
the objects themselves, rather than references to the object.
For example, in the statement:
For example, in the statement:
<pre>
 
%rover:type = 'Ferret'
<p class="code">%rover:type = 'Ferret'
</pre>
</p>
 
it is quite natural to think of the statement as setting %rover's Type to
it is quite natural to think of the statement as setting %rover's Type to
"ferret," rather than as setting the type of the object referenced
"ferret," rather than as setting the type of the object referenced
Line 112: Line 116:


==Creating object instances==
==Creating object instances==
Since object variables are references to objects, two questions naturally
Since object variables are references to objects, two questions naturally
arise: what object does an object variable refer to initially, and
arise: what object does an object variable refer to initially, and
Line 119: Line 122:
points to ''no'' object.
points to ''no'' object.
So, the following program would cause a request cancellation error:
So, the following program would cause a request cancellation error:
<pre>
 
class pet
<p class="code">class pet
   public
   public
       variable type  is string len 16
       variable type  is string len 16
Line 129: Line 132:
   
   
%rover:type = 'Dog'
%rover:type = 'Dog'
</pre>
</p>
 
The statement <code>%rover:type = 'Dog'</code> attempts to set the object's
The statement <code>%rover:type = 'Dog'</code> attempts to set the object's
type to "Dog," but there is no instance of an object for
type to "Dog," but there is no instance of an object for
Line 140: Line 144:


===Using New or other Constructors===
===Using New or other Constructors===
When you invoke a <var>Constructor</var> method, the <var class="product">Janus SOAP ULI</var> creates an object instance which is available to the <var>Constructor</var> code. The <var>Constructor</var>:
When you invoke a <var>Constructor</var> method, <var class="product">SOUL</var> creates an object instance which is available to the <var>Constructor</var> code. The <var>Constructor</var>:
<ul>
<ul>
<li>Operates on the new instance (which is the value of <code>%this</code> within the <var>Constructor</var>)
<li>Operates on the new instance (which is the value of <code>%this</code> within the <var>Constructor</var>)
<p>Unlike a shared method, a <var>Constructor</var> operates on an object instance.</p>
<p>Unlike a shared method, a <var>Constructor</var> operates on an object instance.</p>
<li>Returns the value of <code>%this</code> as the result.  
<li>Returns the value of <code>%this</code> as the result.  
<p>
<p>
Like a <var>Subroutine</var>, the <var>Constructor</var>'s <var>Return</var> statement may not specify a value, but like a <var>Function</var>, the <var>Constructor</var> does produce a result.</p>
Like a <var>Subroutine</var>, the <var>Constructor</var>'s <var>Return</var> statement may not specify a value, but like a <var>Function</var>, the <var>Constructor</var> does produce a result.</p>
</ul>
</ul>
In any non-<var>[[Dynamic dispatch#Overridable versus Abstract methods|Abstract]]</var> class, you can invoke a default <var>Constructor</var>, named <var>New</var>, which operates no further on <code>%this</code> and simply returns a new instance for explicit or implicit assignment. As described below, you can explicitly define <var>New</var> to operate on the new instance, you can define other constructors in addition to New, and you can also [[#Private constructors|"disallow"]] New from use outside the class definition.
 
In any non-<var>[[Dynamic dispatch#Overridable versus Abstract methods|Abstract]]</var> class, you can invoke a default <var>Constructor</var>, named <var>New</var>, which operates no further on <code>%this</code> and simply returns a new instance for explicit or implicit assignment. As described below, you can explicitly define <var>New</var> to operate on the new instance, you can define other constructors in addition to <var>New</var>, and you can also [[#Private constructors|"disallow"]] <var>New</var> from use outside the class definition.


====Syntax for Constructors====
====Syntax for Constructors====
Line 276: Line 282:
parameter list.
parameter list.


The <var class="product">Janus SOAP User Language Interface</var> supports '''multiple constructors''':
<var class="product">SOUL</var> supports '''multiple constructors''':
<p class="code">class resource
<p class="code">class resource
   public
   public
Line 321: Line 327:
<var>Public</var> block.
<var>Public</var> block.


===Virtual Constructor methods===
===<b id="Virtual Constructor methods"></b>Virtual constructors===
 
It is possible to have a non-constructor shared function return an
It is possible to have a non-constructor shared function return an
instance of a class:
instance of a class:
<pre>
 
class resource
<p class="code">class resource
   public shared
   public shared
       function newFromUrl(%url is string len 255) -
       function newFromUrl(%url is string len 255) -
Line 345: Line 350:
   ...
   ...
%res = %res:newFromUrl('http://nfl.com/score')
%res = %res:newFromUrl('http://nfl.com/score')
</pre>
</p>
 
Such functions are often called '''factory methods''' or
Such functions are often called '''factory methods''' or
virtual constructors.
virtual constructors.
Line 354: Line 360:
<li>They might not actually instantiate an object but return a reference to an existing instance. Such a method may not truly be a factory method.
<li>They might not actually instantiate an object but return a reference to an existing instance. Such a method may not truly be a factory method.
</ul>
</ul>
The support for multiple constructors means that <var class="product">Janus SOAP User Language Interface</var>
The support for multiple constructors means that <var class="product">SOUL</var>
users need factory methods less than those using
users need factory methods less than those using
most other object-oriented programming languages.
most other object-oriented programming languages.
Line 360: Line 366:
Virtual constructors can be invoked in much the same way that regular constructors are invoked, that is, without specifying the class name if the class name can be determined from context.
Virtual constructors can be invoked in much the same way that regular constructors are invoked, that is, without specifying the class name if the class name can be determined from context.
For example, the above example of the NewFromUrl virtual constructor can be changed to the following:
For example, the above example of the NewFromUrl virtual constructor can be changed to the following:
<pre>
 
%res  is object resource
<p class="code">%res  is object resource
   ...
   ...
%res = newFromUrl('http://nfl.com/score')
%res = newFromUrl('http://nfl.com/score')
</pre>
</p>
 
Similarly, if a method called Send in class Coworker took a resource
Similarly, if a method called Send in class Coworker took a resource
object as an input parameter, the NewFromUrl virtual constructor could
object as an input parameter, the NewFromUrl virtual constructor could
also be used as follows:
also be used as follows:
<pre>
 
%sufjan  is object coworker
<p class="code">%sufjan  is object coworker
  ...
  ...
%sufjan:send(newFromUrl('http://asthmatickitty.com'))
%sufjan:send(newFromUrl('http://asthmatickitty.com'))
</pre>
</p>


Because the naming rules for virtual constructors are now
Because the naming rules for virtual constructors are now
Line 380: Line 387:


==Object variables within class definitions==
==Object variables within class definitions==
Classes can, themselves, contain object variables:
Classes can, themselves, contain object variables:
<pre>
<p class="code">class pet
class pet
   public
   public
     ...
     ...
Line 391: Line 396:
  ...
  ...
end class
end class
</pre>
</p>
 
Remember that an object variable is not really the object itself but
Remember that an object variable is not really the object itself but
a reference to an underlying object so, in the case of an object
a reference to an underlying object so, in the case of an object
Line 397: Line 403:
object, per se, but simply a reference to another object.
object, per se, but simply a reference to another object.


It is possible for two different classes to each contain references
It is possible for two different classes to each contain references to each other.
to each other.
But for an object variable to be defined, the object class must already have
But for an object variable to be defined, the object class must already have
been declared.
been declared.
Line 404: Line 409:
be declared without the references before the other.
be declared without the references before the other.
The simplest way to do this is with an empty Class block:
The simplest way to do this is with an empty Class block:
<pre>
 
class human
<p class="code">class human
end class
end class
   
   
Line 425: Line 430:
  ...
  ...
end class
end class
</pre>
</p>
 
It is also possible for a class to contain object variables that
It is also possible for a class to contain object variables that
refer to the containing class:
refer to the containing class:
<pre>
<p class="code">class pet
class pet
   public
   public
     ...
     ...
Line 437: Line 442:
  ...
  ...
end class
end class
</pre>
</p>
In such a case, no empty Class block is necessary to declare the class
 
because the Class block containing the object variable is sufficient
In such a case, no empty <var>Class</var> block is necessary to declare the class
because the <var>Class</var> block containing the object variable is sufficient
to declare the existence of the class.
to declare the existence of the class.
==Discarding objects==
==Discarding objects==


Line 450: Line 457:
An underlying object can be discarded explicitly by invoking the <var>Discard</var>
An underlying object can be discarded explicitly by invoking the <var>Discard</var>
method (system subroutine) against it:
method (system subroutine) against it:
<pre>
 
%mick  is object dog
<p class="code">%mick  is object dog
  ...
  ...
%mick = new('Terrier')
%mick = new('Terrier')
Line 457: Line 464:
* Done with object pointed to by %mick
* Done with object pointed to by %mick
%mick:discard
%mick:discard
</pre>
</p>
 
The Discard method never takes any input parameters and returns no value,
The Discard method never takes any input parameters and returns no value,
so it is a Subroutine.
so it is a Subroutine.
The Discard method is an AllowNullObject method because it can be invoked
The Discard method is an AllowNullObject method because it can be invoked
with a null object, such as one that was never set:
with a null object, such as one that was never set:
<pre>
 
%mick  is object dog
<p class="code">%mick  is object dog
   
   
for %i from 1 to 10
for %i from 1 to 10
Line 469: Line 477:
   ...
   ...
end for
end for
</pre>
</p>
 
In the first loop iteration, above, <code>%mick</code> would not be set, so the
In the first loop iteration, above, <code>%mick</code> would not be set, so the
<code>%mick:discard</code> call would not have anything to discard,
<code>%mick:discard</code> call would not have anything to discard,
but it would not indicate a request-cancelling null-pointer error.
but it would not indicate a request-cancelling null-pointer error.


'''Note:''' Not all objects may be discarded explicitly:  
<blockquote class="note">
<p>'''Note:''' Not all objects may be discarded explicitly: </p>
<ul>
<ul>
<li>Some objects are integral parts of other objects, and discarding one cannot be done without compromising the other. For example, you may not explicitly <var>Discard</var> an XmlNode object, though as discussed [[#xmlnode|below]], you may discard it by using the <var>DeepDiscard</var> method.
<li>Some objects are integral parts of other objects, and discarding one cannot be done without compromising the other. For example, you may not explicitly <var>Discard</var> an XmlNode object, though as discussed [[#xmlnode|below]], you may discard it by using the <var>DeepDiscard</var> method.
<li>Some objects may be explicitly defined with a <var>[[Classes and Objects#Disallow clause|Disallow Discard]]</var> clause, which protects them from being discarded directly.
<li>Some objects may be explicitly defined with a <var>[[Classes and Objects#Disallow clause|Disallow Discard]]</var> clause, which protects them from being discarded directly.
</ul>
</ul>
</blockquote>
===Discarding implicitly===
===Discarding implicitly===
Objects may be discarded implicitly, when there are no
Objects may be discarded implicitly, when there are no
more references to the underlying object.
more references to the underlying object.
Line 489: Line 500:
<var class="product">Janus SOAP User Language Interface</var> automatically discards the object.
<var class="product">Janus SOAP User Language Interface</var> automatically discards the object.
The following code demonstrates this principle:
The following code demonstrates this principle:
<pre>
<p class="code">%bunny  is object dog
%bunny  is object dog
   ...
   ...
%bunny = new('Ibizan Hound')
%bunny = new('Ibizan Hound')
Line 496: Line 506:
%bunny:feed
%bunny:feed
%bunny = new('Yorkshire Terrier')
%bunny = new('Yorkshire Terrier')
</pre>
</p>


When the statement <code>%bunny = new('Yorkshire terrier')</code> is executed,
When the statement <code>%bunny = new('Yorkshire terrier')</code> is executed,
Line 506: Line 516:
If a second reference to that object had been set, it would not have been
If a second reference to that object had been set, it would not have been
discarded:
discarded:
<pre>
 
%bunny  is object dog
<p class="code">%bunny  is object dog
%dallas  is object dog
%dallas  is object dog
   ...
   ...
Line 515: Line 525:
%bunny:feed
%bunny:feed
%bunny = new('Yorkshire terrier')
%bunny = new('Yorkshire terrier')
</pre>
</p>


A reference to an object can be inside another object:
A reference to an object can be inside another object:
<pre>
 
class dog
<p class="code">class dog
   public
   public
       variable name  is string len 32
       variable name  is string len 32
Line 532: Line 542:
%first = new('Josh', 'Newfoundland')
%first = new('Josh', 'Newfoundland')
%first:nextCompetitor = new('Mick', 'Kerry Blue Terrier')
%first:nextCompetitor = new('Mick', 'Kerry Blue Terrier')
</pre>
</p>


In the above example, the object created by
In the above example, the object created by
Line 539: Line 549:
discarded.
discarded.
In such a way, it is possible to build a chain of objects:
In such a way, it is possible to build a chain of objects:
<pre>
 
%first  is object dog
<p class="code">%first  is object dog
%last    is object dog
%last    is object dog
%new    is object dog
%new    is object dog
Line 556: Line 566:
%last:nextCompetitor = %new
%last:nextCompetitor = %new
%last  = %new
%last  = %new
</pre>
</p>
 
In the above example, the object created by
In the above example, the object created by
<code>new('Les', 'Pekingese')</code> can be accessed by
<code>new('Les', 'Pekingese')</code> can be accessed by
Line 566: Line 577:
A '''cycle''' is a collection of objects where the objects are linked
A '''cycle''' is a collection of objects where the objects are linked
in such a way as to form a ring:
in such a way as to form a ring:
<pre>
 
%first  is object dog
<p class="code">%first  is object dog
%last    is object dog
%last    is object dog
%new    is object dog
%new    is object dog
Line 579: Line 590:
%new  = new('Les', 'Pekingese')
%new  = new('Les', 'Pekingese')
%last:nextCompetitor = %first
%last:nextCompetitor = %first
</pre>
</p>
 
A cycle can even be created with a single object:
A cycle can even be created with a single object:
<pre>
 
%new    is object dog
<p class="code">%new    is object dog
  ...
  ...
%new  = new('Josh', 'Newfoundland')
%new  = new('Josh', 'Newfoundland')
%new:nextCompetitor = %new
%new:nextCompetitor = %new
</pre>
</p>


A web of objects can contain many cycles of objects.
A web of objects can contain many cycles of objects.
Line 599: Line 611:
The following illustrates a case where two objects cannot be reached via
The following illustrates a case where two objects cannot be reached via
any %variable, but they won't be discarded because they reference each other:
any %variable, but they won't be discarded because they reference each other:
<pre>
 
%first  is object dog
<p class="code">%first  is object dog
%last    is object dog
%last    is object dog
%new    is object dog
%new    is object dog
Line 610: Line 622:
%new  = new('Les', 'Pekingese')
%new  = new('Les', 'Pekingese')
%first = %new
%first = %new
</pre>
</p>
Such objects will not be discarded by the <var class="product">Janus SOAP User Language Interface</var> until the user logs off.
 
Most object-oriented languages solve this problem with [[Managing object storage|garbage collection]] &mdash; a process in which all objects are scanned to determine if they are "reachable" from some base variables (in the <var class="product">Janus SOAP User Language Interface</var> these would be local and common %variables).
Such objects will not be discarded by <var class="product">SOUL</var> until the user logs off.
Most object-oriented languages solve this problem with [[Global and session objects#Managing object storage|garbage collection]] &mdash; a process in which all objects are scanned to determine if they are "reachable" from some base variables (in <var class="product">SOUL</var> these would be local and common %variables).


<var class="product">Janus SOAP User Language Interface</var> has a DeepDiscard method, which provides an alternative approach to
<var class="product">SOUL</var> has a <var>DeepDiscard</var> method, which provides an alternative approach to
some of these cases that is less expensive than [[Managing object storage|garbage collection]]
some of these cases that is less expensive than garbage collection and simpler than <var>Discard</var>.
and simpler than Discard.
<var>DeepDiscard</var> is discussed in the next section.
DeepDiscard is discussed in the next section.


==Deep discard of objects==
==Deep discard of objects==
The Discard method (Object class subroutine) is usually available to explicitly
The Discard method ([[Global and session objects#Using system class methods to access global and session objects|Object class]] subroutine) is usually available to explicitly
discard the object referenced by an object variable.
discard the object referenced by an object variable.
If an object contains a reference to another object (of the same or a
If an object contains a reference to another object (of the same or a
Line 633: Line 645:
Since this is the only reference to that object, the object is then implicitly
Since this is the only reference to that object, the object is then implicitly
discarded.
discarded.
<pre>
 
class linkedList
<p class="code">class linkedList
   public
   public
       variable  name is string len 32
       variable  name is string len 32
Line 649: Line 661:
   
   
%chain:discard
%chain:discard
</pre>
</p>
 
Now suppose the class definition remains the same, but the code is changed to
Now suppose the class definition remains the same, but the code is changed to
the following:
the following:
<pre>
 
%chain    is object linkedList
<p class="code">%chain    is object linkedList
%link      is object linkedList
%link      is object linkedList
   
   
Line 663: Line 676:
   
   
%chain:discard
%chain:discard
</pre>
</p>
 
In this case, even when the object referenced by <code>%chain</code> is discarded,
In this case, even when the object referenced by <code>%chain</code> is discarded,
and its reference to the <code>Frack</code> object goes away, there is still a reference to
and its reference to the <code>Frack</code> object goes away, there is still a reference to
the <code>Frack</code> object, namely, <code>%link</code>, so that object is not discarded.
the <code>Frack</code> object, namely, <code>%link</code>, so that object is not discarded.


<var class="product">Janus SOAP User Language Interface</var> also has a generic '''DeepDiscard''' method:
<var class="product">SOUL</var> also has a generic '''DeepDiscard''' method:
<pre>
 
%obj:DeepDiscard
<p class="code">%obj:DeepDiscard
</pre>
</p>
Like the Discard method, DeepDiscard explicitly discards the method object. But, unlike Discard, it also explicitly discards all objects that are referenced directly or indirectly (a reference to an object that contains a reference to another object, and so on) by the object being discarded. This makes DeepDiscard useful for discarding an entire chain of objects, an object tree, an object cycle, or even an object forest, even if there are still references to some of the objects in the request.


Since DeepDiscard cleans up an object cycle or forest, it is an
Like the <var>Discard</var> method, <var>DeepDiscard</var> explicitly discards the method object. But, unlike Discard, it also explicitly discards all objects that are referenced directly or indirectly (a reference to an object that contains a reference to another object, and so on) by the object being discarded. This makes DeepDiscard useful for discarding an entire chain of objects, an object tree, an object cycle, or even an object forest, even if there are still references to some of the objects in the request.
 
Since <var>DeepDiscard</var> cleans up an object cycle or forest, it is an
efficient alternative to having garbage collection clean these up, if there is
efficient alternative to having garbage collection clean these up, if there is
an obvious point in code where the object cycle or forest is no longer used.
an obvious point in code where the object cycle or forest is no longer used.


Just as with the Discard method, there is a danger with DeepDiscard that
Just as with the <var>Discard</var> method, there is a danger with <var>DeepDiscard</var> that
some reference to an explicitly discarded object might still be required.
some reference to an explicitly discarded object might still be required.
But because it has a potential to
But because it has a potential to
discard more objects, the risk is somewhat greater with DeepDiscard,
discard more objects, the risk is somewhat greater with <var>DeepDiscard</var>,
so it should be used with caution.
so it should be used with caution.


The DeepDiscard method cannot be used on any object in a class that
The <var>DeepDiscard</var> method cannot be used on any object in a class that
<ul>
<ul>
<li>is declared with a <var>[[Classes and Objects#Disallow clause|Disallow Discard]]</var> clause
<li>is declared with a <var>[[Classes and Objects#Disallow clause|Disallow Discard]]</var> clause
Line 696: Line 711:
For most system classes, <var>DeepDiscard</var> works identically to <var>Discard</var>.
For most system classes, <var>DeepDiscard</var> works identically to <var>Discard</var>.
The exceptions to this are:
The exceptions to this are:
<ul>
<ul>
<li><var>Screenfield</var> objects, which you may <var>DeepDiscard</var> but not <var>Discard</var>.
<li><var>Screenfield</var> objects, which you may <var>DeepDiscard</var> but not <var>Discard</var>.
If you <var>DeepDiscard</var> a <var>Screenfield</var>, the underlying <var>Screen</var> object is also discarded.
If you <var>DeepDiscard</var> a <var>Screenfield</var>, the underlying <var>Screen</var> object is also discarded.
<li><var>XmlNode</var> objects, which you may <var>DeepDiscard</var> but not <var>Discard</var>.
<li><var>XmlNode</var> objects, which you may <var>DeepDiscard</var> but not <var>Discard</var>.
If you <var>DeepDiscard</var> an <var>XmlNode</var>, the underlying <var>XmlDoc</var> object is also discarded.
If you <var>DeepDiscard</var> an <var>XmlNode</var>, the underlying <var>XmlDoc</var> object is also discarded.
<li><var>XmlNodelist</var> objects, which you may <var>Discard</var> or <var>DeepDiscard</var>.
<li><var>XmlNodelist</var> objects, which you may <var>Discard</var> or <var>DeepDiscard</var>.
If you <var>Discard</var> an <var>XmlNodelist</var>, the <var>XmlNodelist</var> object (only) is discarded.
If you <var>Discard</var> an <var>XmlNodelist</var>, the <var>XmlNodelist</var> object (only) is discarded.
Line 708: Line 726:


==Working with null valued object variables==
==Working with null valued object variables==
If an object variable does not refer to an object, either because
If an object variable does not refer to an object, either because
it was never set, or because the object to which it referred was
it was never set, or because the object to which it referred was
Line 718: Line 735:
The most common comparison done with objects, in fact, is to test
The most common comparison done with objects, in fact, is to test
whether the object is <var>Null</var>:
whether the object is <var>Null</var>:
<pre>
 
%first  is object dog
<p class="code">%first  is object dog
%new    is object dog
%new    is object dog
  ...
  ...
Line 729: Line 746:
end of
end of
%last  = new
%last  = new
</pre>
</p>
 
If a null object variable is compared with another object variable,
If a null object variable is compared with another object variable,
it is considered equal if, and only if, the other object variable is
it is considered equal if, and only if, the other object variable is
Line 735: Line 753:


A null object variable can be assigned to another object variable:
A null object variable can be assigned to another object variable:
<pre>
<p class="code">%first  is object dog
%first  is object dog
%new    is object dog
%new    is object dog
   
   
%new  = %first
%new  = %first
</pre>
</p>
 
And a variable can be explicitly set to Null:
And a variable can be explicitly set to Null:
<pre>
<p class="code">%winner  is object dog
%winner  is object dog
  ...
  ...
%winner = null
%winner = null
</pre>
</p>


In both comparisons and assignments, <var>Null</var> is actually a shorthand for a [[Shared class members|shared]] null property on the class, and it can be indicated as such:
In both comparisons and assignments, <var>Null</var> is actually a shorthand for a [[Shared class members|shared]] null property on the class, and it can be indicated as such:
<pre>
<p class="code">%winner  is object dog
%winner  is object dog
  ...
  ...
%winner = %(dog):null
%winner = %(dog):null
Line 756: Line 772:
if %winner eq %(dog):null
if %winner eq %(dog):null
  ...
  ...
</pre>
</p>
The value <var>Null</var> can also be passed as an input parameter to
The value <var>Null</var> can also be passed as an input parameter to
a method:
a method:
<pre>
<p class="code">class show
class show
   public
   public
       ...
       ...
Line 775: Line 790:
%minScore = %akc:score(null)
%minScore = %akc:score(null)
  ...
  ...
</pre>
</p>


'''Note:''' Assigning a value to an object property, that is to a Property that
<p class="note">'''Note:''' Assigning a value to an object property, that is to a Property that
returns an object,
returns an object, is a special case of passing an input parameter to a method.
is a special case of passing an input parameter to a method.
The value assigned is
The value assigned is
an implicit parameter of the Set method of the property.
an implicit parameter of the <var>Set</var> method of the property.
In such cases, you may validly assign a Null value,
In such cases, you may validly assign a Null value,
as if the implicit parameter included an implicit AllowNull keyword.
as if the implicit parameter included an implicit AllowNull keyword.
 
</p>
<p>
An object that is explicitly discarded causes all references to that
An object that is explicitly discarded causes all references to that
object to become null:
object to become null: </p>
<pre>
<p class="code">%first  is object dog
%first  is object dog
%new    is object dog
%new    is object dog
   
   
Line 794: Line 808:
%first = %new
%first = %new
%first:discard
%first:discard
</pre>
</p>
In the above example, both <code>%first</code> and <code>%new</code> are
In the above example, both <code>%first</code> and <code>%new</code> are
set to <var>Null</var> after the <code>%first:discard</code>.
set to <var>Null</var> after the <code>%first:discard</code>.


==Passing object variables as parameters==
==Passing object variables as parameters==
Object variables can be passed as method or complex subroutine parameters:
Object variables can be passed as method or complex subroutine parameters:
<pre>
<p class="code">class clown
class clown
   public
   public
       subroutine honk(%nose is object nose)
       subroutine honk(%nose is object nose)
Line 814: Line 826:
  ...
  ...
%bozo:honk(%schnoz)
%bozo:honk(%schnoz)
</pre>
</p>


By default, passing a null object variable as a method or complex subroutine
By default, passing a null object variable as a method or complex subroutine
Line 821: Line 833:
qualifier in the method or complex subroutine declaration to indicate that
qualifier in the method or complex subroutine declaration to indicate that
the method or complex subroutine will accept null objects:
the method or complex subroutine will accept null objects:
<pre>
<p class="code">class clown
class clown
   public
   public
       subroutine honk(%nose is object nose allowNull)
       subroutine honk(%nose is object nose allowNull)
Line 829: Line 840:
   ...
   ...
end class
end class
</pre>
</p>


An Output object variable is always allowed to be null and can be set
An Output object variable is always allowed to be null and can be set
by a method:
by a method:
<pre>
 
class clown
<p class="code">class clown
   public
   public
       subroutine honk(%nose is object nose output)
       subroutine honk(%nose is object nose output)
Line 850: Line 861:
%bozo = new
%bozo = new
%bozo:honk(%schnoz)
%bozo:honk(%schnoz)
</pre>
</p>
 
In this example, <code>%schnoz</code> would be set to reference a new instance of
In this example, <code>%schnoz</code> would be set to reference a new instance of
a <code>nose</code> object that was instantiated by the <code>honk</code> method.
a <code>nose</code> object that was instantiated by the <code>honk</code> method.
Line 865: Line 877:
In the example below, the subroutine modifies the <code>%schnoz</code> object color,
In the example below, the subroutine modifies the <code>%schnoz</code> object color,
but the reassignment to <code>%schnozola</code> does not affect <code>%schnoz</code>:
but the reassignment to <code>%schnozola</code> does not affect <code>%schnoz</code>:
<pre>
<p class="code">class clown
class clown
public
public
subroutine honk(%nose is object nose output)
subroutine honk(%nose is object nose output)
Line 893: Line 904:
%bozo = new
%bozo = new
%bozo:honk(%schnoz)
%bozo:honk(%schnoz)
</pre>
</p>


'''Note:''' A case where a method significantly affects the object referenced by
<blockquote class="note">'''Note:''' A case where a method significantly affects the object referenced by an Input object variable is the Discard method.
an Input object variable is the Discard method.
A Discard method invoked against an Input parameter sets
A Discard method invoked against an Input parameter sets
the Input parameter and call argument to Null.
the Input parameter and call argument to Null.


This can happen directly:
This can happen directly:
<pre>
 
subroutine honk  (%nose is object nose input)
<p class="code">subroutine honk  (%nose is object nose input)
   
   
   %nose:discard
   %nose:discard
   
   
end subroutine
end subroutine
</pre>
</p>


Or, it can happen indirectly:
Or, it can happen indirectly:
<pre>
 
subroutine honk  (%nose is object nose input)
<p class="code">subroutine honk  (%nose is object nose input)
   
   
   %beak is object nose
   %beak is object nose
Line 919: Line 929:
   
   
end subroutine
end subroutine
</pre>
</p>
</blockquote>


==See also==
==See also==

Latest revision as of 19:05, 15 August 2018

An object variable is a proxy or substitute for an object. You do not access or perform actions against an object directly but instead via operations on an object variable that references the object. This page discusses how you create, work with, and discard object variables.

Why use an object reference instead of an object

Object variables are used to declare variables that refer to instances of a class. Despite their name, they are not really objects, as such, but references or pointers to objects. The underlying objects themselves are never directly accessible and can only be accessed via an object reference. This concept of reference variables being used to access underlying objects is common to all object-oriented languages. There are two, primary reasons for this:

  1. Objects can get quite large, and moving them around an application rather than moving references around would be extremely expensive.
  2. Objects usually represent some "real world" entity. To have multiple copies of such an entity in an application creates the possibility that these copies would get out of synch, causing application complexity and even bugs.

Assignment and comparison operations are probably the two most significant places to note the distinction between object variables being references to the objects or the objects themselves. The following is an example of assignment of an object reference, rather than an object:

class pet public variable type is string len 16 end public end class ... %rover is object pet %fluffy is object pet ... %rover:type = 'Dog' %fluffy = %rover %fluffy:type = 'Cat' print %rover:type

Because the statement %fluffy = %rover assigns to %fluffy a reference to the same object as %rover, both variables end up referring to the same object. The statement %fluffy:type = 'Cat' therefore changes the underlying object pointed to by %rover (since it's the same object as the one pointed to by %fluffy). As a result, the Print statement prints Cat.

As assignment assigns references, comparison compares references. That is, a comparison between two object references does not compare the objects being referred to, but it instead compares whether two object references point to the same object.

Consider the following example::

class pet public variable type is string len 16 end public end class ... %rover is object pet %fluffy is object pet ... %rover = new %fluffy = new %rover:type = 'Dog' %fluffy:type = 'Dog' if %fluffy eq %rover then print 'They''re equal!' end if

This will not print They're equal. Even though the objects pointed to by %fluffy and %rover have the same variable values, they are different objects, so %fluffy is not equal to %rover. However, if the code were changed:

class pet public variable type is string len 16 end public end class ... %rover is object pet %fluffy is object pet ... %rover:type = 'Dog' %rover = %fluffy if %fluffy eq %rover then print 'They''re equal!' end if

They're equal will be printed, because %rover = %fluffy sets %rover to point to the same object as %fluffy, making them equal.

Note: Since order comparisons (GE, LE, GT, and LT) are meaningless for references — when is a reference to one object greater than a reference to another? — only equality and inequality (EQ and NE) comparisons are allowed for objects.

Despite the foregoing remarks, for most purposes, one can still think of object variables as being the objects themselves, rather than references to the object. For example, in the statement:

%rover:type = 'Ferret'

it is quite natural to think of the statement as setting %rover's Type to "ferret," rather than as setting the type of the object referenced by %rover to "Ferret."

Creating object instances

Since object variables are references to objects, two questions naturally arise: what object does an object variable refer to initially, and where does the referenced object come from? The answer to the first question is that an object variable initially points to no object. So, the following program would cause a request cancellation error:

class pet public variable type is string len 16 end public end class ... %rover is object pet %rover:type = 'Dog'

The statement %rover:type = 'Dog' attempts to set the object's type to "Dog," but there is no instance of an object for which to set the type. This kind of error is sometimes referred to as a null pointer exception.

So how, then, is an object created? The answer is via a Constructor, usually the default one named New.

Using New or other Constructors

When you invoke a Constructor method, SOUL creates an object instance which is available to the Constructor code. The Constructor:

  • Operates on the new instance (which is the value of %this within the Constructor)

    Unlike a shared method, a Constructor operates on an object instance.

  • Returns the value of %this as the result.

    Like a Subroutine, the Constructor's Return statement may not specify a value, but like a Function, the Constructor does produce a result.

In any non-Abstract class, you can invoke a default Constructor, named New, which operates no further on %this and simply returns a new instance for explicit or implicit assignment. As described below, you can explicitly define New to operate on the new instance, you can define other constructors in addition to New, and you can also "disallow" New from use outside the class definition.

Syntax for Constructors

The syntax for invoking a Constructor is the same as the syntax for invoking a Shared method which returns an instance of the class.

To invoke the New constructor and assign its result:

%rover = new

You can explicitly indicate the class of the object as follows:

%rover = %(pet):new

While specifying the class in this way is unnecessary and might be viewed as detrimental because it results in the class name being sprinkled around inside application code, it might also be viewed as beneficial — making the object class clear in the part of code where the object is created.

Customizing a Constructor

Sometimes it is useful to run code when creating an instance of a class. In such cases, you can explicitly define the New Constructor:

class pet public variable initTime is float constructor new end public constructor new %initTime = $sir_datens end constructor end class

In the above example, the class variable initTime is set to the time the instance of the object is created. That code runs when the New Constructor is invoked in a program to create a pet instance:

%josh is object pet ... %josh = new

Sometimes it is useful to have a constructor take parameters. For example, if it doesn't make sense to have a Pet object without a Type, make the New constructor require an input parameter that sets the class Type variable:

class pet public variable type is string len 16 constructor new(%type is string len 16) end public constructor new(%type is string len 16) %this:type = %type end constructor end class

The parameters must be specified on the New constructor:

%snoopy is object pet ... %snoopy = new('Beagle')

As of Sirius Mods Version 7.2, constructors are allowed to change the object being constructed. For example, variable ExistingObj assigns an existing Dachsie object when constructor Newbie is called:

class dachsie public ... constructor newbie ... end public public shared variable ExistingObj is object dachsie end public shared constructor newbie %this = %(this):existingObj end constructor ... end class

However, this feature was actually provided for a different purpose, and using it in the context shown above requires caution. While %this is an input parameter to the Constructor, changing it changes the object returned to the Constructor invoker, so it acts almost like an output parameter. Modifying %this within the Constructor can also produce unexpected behavior if the Constructor is itself called from an extension class Construct statement.

Instead of using a Constructor to return a modified object as in the example above, you should consider using a "factory method".

Other ways to use a Constructor

A Constructor can also be used in these ways:

  • To specify a new instance of a class as an input parameter to a method:

    class pet public ... subroutine compare(%pet is object pet) ... end public ... end class ... %lassie is object pet ... %lassie:compare( new('Collie') )

  • Without being explicitly specified, to automatically create an instance of an object when an object variable is first referenced. For such instantiation, you must specify Auto New in the object's declaration.

Using multiple Constructors

Most object-oriented languages support only a single constructor name for a class. If multiple constructors are needed, this is achieved with overloading — the use of different methods with the same name that are distinguished by their parameter lists. Overloading, however, can be confusing, and it is limited: you can't have multiple methods with the same name and the same datatypes in the parameter list.

SOUL supports multiple constructors:

class resource public constructor newFromUrl(%url is string len 255) constructor newFromProc(%proc is string len 255) ... end public ... end class ... %res is object resource ... %res = newFromUrl('http://nfl.com/score') ... %res = newFromProc('LOCAL.RESOURCE.PROC') ... %res = new

This example illustrates:

  • Constructors not called New are invoked in exactly the same way as the New constructor.

    A function that invokes a constructor can be used in any other context in which the New Constructor can be used.

  • It is recommended that you always begin Constructor names with the word "New" to distinguish them from other methods.

Private Constructors

Although this section has discussed only public constructors, that is, constructors defined for use outside the class definition, you may also define private constructors, which may only be invoked from inside the class. You declare such a Constructor in the Private block of a class definition, and you define it with your other methods after the declaration blocks.

If you want to define a private constructor named New, however, you must make sure to specify Disallow New in the Public block of the class definition (see "Declaration block syntax"). No other private constructors require an additional Disallow New in the Public block.

Virtual constructors

It is possible to have a non-constructor shared function return an instance of a class:

class resource public shared function newFromUrl(%url is string len 255) - is object resource ... end public shared function newFromUrl(%url is string len 255) - is object resource %return is object resource print 'In the factory' %return = new end function ... end class ... %res is object resource ... %res = %res:newFromUrl('http://nfl.com/score')

Such functions are often called factory methods or virtual constructors. As the example illustrates, two things distinguish factory methods from constructors:

  • They can run code before the object is instantiated.
  • They might not actually instantiate an object but return a reference to an existing instance. Such a method may not truly be a factory method.

The support for multiple constructors means that SOUL users need factory methods less than those using most other object-oriented programming languages.

Virtual constructors can be invoked in much the same way that regular constructors are invoked, that is, without specifying the class name if the class name can be determined from context. For example, the above example of the NewFromUrl virtual constructor can be changed to the following:

%res is object resource ... %res = newFromUrl('http://nfl.com/score')

Similarly, if a method called Send in class Coworker took a resource object as an input parameter, the NewFromUrl virtual constructor could also be used as follows:

%sufjan is object coworker ... %sufjan:send(newFromUrl('http://asthmatickitty.com'))

Because the naming rules for virtual constructors are now identical to that for regular constructors, the two can be used interchangeably, and one can be changed to the other as requirements change, without breaking existing applications.

Object variables within class definitions

Classes can, themselves, contain object variables:

class pet public ... variable owner is object human ... end public ... end class

Remember that an object variable is not really the object itself but a reference to an underlying object so, in the case of an object variable inside a class block, the class does not contain another object, per se, but simply a reference to another object.

It is possible for two different classes to each contain references to each other. But for an object variable to be defined, the object class must already have been declared. So if two classes contain references to each other, at least one must be declared without the references before the other. The simplest way to do this is with an empty Class block:

class human end class class pet public ... variable owner is object human ... end public ... end class ... class human public ... variable dog is object pet ... end public ... end class

It is also possible for a class to contain object variables that refer to the containing class:

class pet public ... variable sibling is object pet ... end public ... end class

In such a case, no empty Class block is necessary to declare the class because the Class block containing the object variable is sufficient to declare the existence of the class.

Discarding objects

The New constructor creates an instance of a class. This instance is maintained until it is either implicitly or explicitly discarded (or destroyed in the terminology of some object-oriented languages).

Discarding explicitly

An underlying object can be discarded explicitly by invoking the Discard method (system subroutine) against it:

%mick is object dog ... %mick = new('Terrier') ...

  • Done with object pointed to by %mick

%mick:discard

The Discard method never takes any input parameters and returns no value, so it is a Subroutine. The Discard method is an AllowNullObject method because it can be invoked with a null object, such as one that was never set:

%mick is object dog for %i from 1 to 10 %mick:discard ... end for

In the first loop iteration, above, %mick would not be set, so the %mick:discard call would not have anything to discard, but it would not indicate a request-cancelling null-pointer error.

Note: Not all objects may be discarded explicitly:

  • Some objects are integral parts of other objects, and discarding one cannot be done without compromising the other. For example, you may not explicitly Discard an XmlNode object, though as discussed below, you may discard it by using the DeepDiscard method.
  • Some objects may be explicitly defined with a Disallow Discard clause, which protects them from being discarded directly.

Discarding implicitly

Objects may be discarded implicitly, when there are no more references to the underlying object. If there are no references to an underlying object, there is no way to retrieve or set values in the object or to invoke methods against the object. Since there is no reason to maintain the object any more, the Janus SOAP User Language Interface automatically discards the object. The following code demonstrates this principle:

%bunny is object dog ... %bunny = new('Ibizan Hound') %bunny:show %bunny:feed %bunny = new('Yorkshire Terrier')

When the statement %bunny = new('Yorkshire terrier') is executed, a new object is created, but it is no longer possible to access the object instantiated by %bunny = new('Ibizan hound') — there are no longer any references to that object. Because of that, the first Dog object is automatically discarded when the second Dog object is created and referenced by %bunny. If a second reference to that object had been set, it would not have been discarded:

%bunny is object dog %dallas is object dog ... %bunny = new('German Shepherd') %dallas = %bunny %bunny:show %bunny:feed %bunny = new('Yorkshire terrier')

A reference to an object can be inside another object:

class dog public variable name is string len 32 variable breed is string len 32 variable nextCompetitor is object ... end public end class ... %first is object dog ... %first = new('Josh', 'Newfoundland') %first:nextCompetitor = new('Mick', 'Kerry Blue Terrier')

In the above example, the object created by new('Mick', 'Kerry Blue Terrier') can be accessed via %first:nextCompetitor, so it will not be implicitly discarded. In such a way, it is possible to build a chain of objects:

%first is object dog %last is object dog %new is object dog ... %new = new('Josh', 'Newfoundland') %first = %new %last = %new %new = new('Mick', 'Kerry Blue Terrier') %last:nextCompetitor = %new %last = %new %new = new('Les', 'Pekingese') %last:nextCompetitor = %new %last = %new %new = new('Bunny', 'Ibizan Hound') %last:nextCompetitor = %new %last = %new

In the above example, the object created by new('Les', 'Pekingese') can be accessed by %first:nextCompetitor:nextCompetitor, so it is not implicitly discarded.

By linking objects in such a way, it is possible to create a wide variety of object super-structures, including chains, trees, webs, and cycles. A cycle is a collection of objects where the objects are linked in such a way as to form a ring:

%first is object dog %last is object dog %new is object dog ... %new = new('Josh', 'Newfoundland') %first = %new %last = %new %new = new('Mick', 'Kerry Blue Terrier') %last:nextCompetitor = %new %last = %new %new = new('Les', 'Pekingese') %last:nextCompetitor = %first

A cycle can even be created with a single object:

%new is object dog ... %new = new('Josh', 'Newfoundland') %new:nextCompetitor = %new

A web of objects can contain many cycles of objects.

If a cycle of objects is created, each object in the cycle will always have at least one reference to it — the previous item in the cycle. This means that even if all other references to the objects in a cycle were eliminated, the objects would still not be discarded because they would each still have a reference to them, even though those references, themselves, aren't reachable from any variables in the request. The following illustrates a case where two objects cannot be reached via any %variable, but they won't be discarded because they reference each other:

%first is object dog %last is object dog %new is object dog ... %first = new('Josh', 'Newfoundland') %new = new('Mick', 'Kerry Blue Terrier') %first:nextCompetitor = %new %new:nextCompetitor = %first %new = new('Les', 'Pekingese') %first = %new

Such objects will not be discarded by SOUL until the user logs off. Most object-oriented languages solve this problem with garbage collection — a process in which all objects are scanned to determine if they are "reachable" from some base variables (in SOUL these would be local and common %variables).

SOUL has a DeepDiscard method, which provides an alternative approach to some of these cases that is less expensive than garbage collection and simpler than Discard. DeepDiscard is discussed in the next section.

Deep discard of objects

The Discard method (Object class subroutine) is usually available to explicitly discard the object referenced by an object variable. If an object contains a reference to another object (of the same or a different class), an explicit Discard results in the elimination of the reference. This removal of the reference can result in an implicit discard of the reference object, as shown in the following example.

The object referenced by %chain contains a reference to another object. When %chain is discarded, the reference to the object with the name Frack is lost. Since this is the only reference to that object, the object is then implicitly discarded.

class linkedList public variable name is string len 32 variable next is object linkedList end public end class ... %chain is object linkedList %chain = new %chain:name = 'Frick' %chain:next = new %chain:next:name = 'Frack' %chain:discard

Now suppose the class definition remains the same, but the code is changed to the following:

%chain is object linkedList %link is object linkedList %chain = new %chain:name = 'Frick' %chain:next = new %chain:next:name = 'Frack' %link = %chain:next %chain:discard

In this case, even when the object referenced by %chain is discarded, and its reference to the Frack object goes away, there is still a reference to the Frack object, namely, %link, so that object is not discarded.

SOUL also has a generic DeepDiscard method:

%obj:DeepDiscard

Like the Discard method, DeepDiscard explicitly discards the method object. But, unlike Discard, it also explicitly discards all objects that are referenced directly or indirectly (a reference to an object that contains a reference to another object, and so on) by the object being discarded. This makes DeepDiscard useful for discarding an entire chain of objects, an object tree, an object cycle, or even an object forest, even if there are still references to some of the objects in the request.

Since DeepDiscard cleans up an object cycle or forest, it is an efficient alternative to having garbage collection clean these up, if there is an obvious point in code where the object cycle or forest is no longer used.

Just as with the Discard method, there is a danger with DeepDiscard that some reference to an explicitly discarded object might still be required. But because it has a potential to discard more objects, the risk is somewhat greater with DeepDiscard, so it should be used with caution.

The DeepDiscard method cannot be used on any object in a class that

  • is declared with a Disallow Discard clause
  • contains a reference to a class defined with Disallow Discard
  • contains an indirect reference to a class that is defined with Disallow Discard

Without these rules, an explicit DeepDiscard of an object could result in the explicit discard of an object of a class that expressly disallows explicit discards.

For most system classes, DeepDiscard works identically to Discard. The exceptions to this are:

  • Screenfield objects, which you may DeepDiscard but not Discard. If you DeepDiscard a Screenfield, the underlying Screen object is also discarded.
  • XmlNode objects, which you may DeepDiscard but not Discard. If you DeepDiscard an XmlNode, the underlying XmlDoc object is also discarded.
  • XmlNodelist objects, which you may Discard or DeepDiscard. If you Discard an XmlNodelist, the XmlNodelist object (only) is discarded. If you DeepDiscard an XmlNodelist, both the XmlNodelist object and the underlying XmlDoc object are discarded.

Working with null valued object variables

If an object variable does not refer to an object, either because it was never set, or because the object to which it referred was discarded, it is considered to have a Null value. While, an object variable with a Null value cannot be used as the object for most methods (except those declared with AllowNullObject), they can be used in comparisons.

The most common comparison done with objects, in fact, is to test whether the object is Null:

%first is object dog %new is object dog ... %new = new('Josh', 'Newfoundland') if %first eq null then %first = new else %last:nextCompetitor = %new end of %last = new

If a null object variable is compared with another object variable, it is considered equal if, and only if, the other object variable is null.

A null object variable can be assigned to another object variable:

%first is object dog %new is object dog %new = %first

And a variable can be explicitly set to Null:

%winner is object dog ... %winner = null

In both comparisons and assignments, Null is actually a shorthand for a shared null property on the class, and it can be indicated as such:

%winner is object dog ... %winner = %(dog):null ... if %winner eq %(dog):null ...

The value Null can also be passed as an input parameter to a method:

class show public ... function score(%entrant is object dog allowNull) - is float ... end public ... end class ... %winner is object dog %akc is object show ... %minScore = %akc:score(null) ...

Note: Assigning a value to an object property, that is to a Property that returns an object, is a special case of passing an input parameter to a method. The value assigned is an implicit parameter of the Set method of the property. In such cases, you may validly assign a Null value, as if the implicit parameter included an implicit AllowNull keyword.

An object that is explicitly discarded causes all references to that object to become null:

%first is object dog %new is object dog %new = new('Dallas', 'German Shepherd') %first = %new %first:discard

In the above example, both %first and %new are set to Null after the %first:discard.

Passing object variables as parameters

Object variables can be passed as method or complex subroutine parameters:

class clown public subroutine honk(%nose is object nose) ... end public ... end class ... %bozo is object clown %schnoz is object nose ... %bozo:honk(%schnoz)

By default, passing a null object variable as a method or complex subroutine parameter causes request cancellation. However, the AllowNull keyword can be specified as an Input parameter qualifier in the method or complex subroutine declaration to indicate that the method or complex subroutine will accept null objects:

class clown public subroutine honk(%nose is object nose allowNull) ... end public ... end class

An Output object variable is always allowed to be null and can be set by a method:

class clown public subroutine honk(%nose is object nose output) ... end public subroutine honk(%nose is object nose output) %nose = new('red') end subroutine ... end class ... %bozo is object clown %schnoz is object nose ... %bozo = new %bozo:honk(%schnoz)

In this example, %schnoz would be set to reference a new instance of a nose object that was instantiated by the honk method.

An Input object variable is passed by value to a method and may be modified within the method. The method actually receives a copy of a pointer to the object. The copied pointer may be used to modify the referenced object, and the modifications are propagated to the object outside the subroutine. Changes to the pointer like assignment or new instantiation, are allowed, but they are not propagated to the outer object.

In the example below, the subroutine modifies the %schnoz object color, but the reassignment to %schnozola does not affect %schnoz:

class clown public subroutine honk(%nose is object nose output) ... property color is string ... end public subroutine honk(%nose is object nose output) %schnozola is object nose If %clown eq %bozo 'red' = %nose:color ... %nose = %schnozola ... end subroutine ... property color is string ... end property color end class ... %bozo is object clown %schnoz is object nose ... %bozo = new %bozo:honk(%schnoz)

Note: A case where a method significantly affects the object referenced by an Input object variable is the Discard method.

A Discard method invoked against an Input parameter sets the Input parameter and call argument to Null.

This can happen directly:

subroutine honk (%nose is object nose input) %nose:discard end subroutine

Or, it can happen indirectly:

subroutine honk (%nose is object nose input) %beak is object nose %beak = %nose %beak:discard end subroutine

See also