Water 5-Type and Object System-Object SystemContract| Return type | wob | | No input parameters. | | Parameter kind | Default value | Type | | Other unkeyed arguments | opt with ekind of expression | | Other keyed arguments | opt with ekind of code | | Water Contract<class class
_name_argument=req=wob=ekind.expression
_body =opt=vector
_return_type =wob
_other_keyed =opt=wob="_add_to_environment"
_other_unkeyed=opt=wob=ekind.expression=wob="_body"
/> | |
In Water, every piece of data (including code) is represented by an object.
Objects can take on roles depending on how they are used.
'Class' is such a role. An object can be considered to be a class
if it is used to make 'instances' of the class. 'Instance' is, you guessed it,
just another role. Whether an object is considered to be a class, an instance,
or both is up to how it is used and how you're thinking of it.
With few exceptions, any object can be used as a class or an instance.
You can, for example, make an object that you think of as an instance of
a class, then turn around and use that instance as the 'class' for another object.
Think of class_instance as a relationship between two objects.
The essential aspect of the relationship is that the instance inherits from
the class. The easiest way to understand objects and their inheritance is to know something about their implementation.
An object is just a collection of fields.
A field has a key and a value.
Any object can be a value; any object can be a key.
Usually field keys are strings, but they can be integers (as in the
case of vector objects and string objects) or any other kind of
objects as when you're making an object-to-object map commonly implemented
with hash tables in other languages.
You can get field values, set field values, add and remove fields,
get all the keys of an object and find out which key has a particular
object as its value.
Each object has a field whose key is "_parent". When you 'lookup' the
value of a field, if the object you lookup in doesn't have the supplied
key, the object from the _parent field is looked in for the supplied key.
This lookup process goes up the _parent chain until it finds a field
with that key or reaches the root object without finding that key and thereby
errors. This process is called inheritance.
'thing' is the name of on object that can hold anything and is globally available.
thing.<set smell="good"/>
thing.smell
 | "good" |
Below we make an instance of thing that will contain two fields,
a field with key 'smell' that has the value "bad" and a field
with key '_parent' that has the value thing.
<thing smell="bad"/>.smell
"bad" <thing smell="bad"/>._parent
thing
is_a just means that the parent or grandparent or some ancestor
of the subject is the first arg to is_a.
<thing smell="bad"/>.<is_a thing/>
 | true |
Below we make an instance of thing and use THAT as the
parent of another instance.
<<thing smell="bad"/>/>._parent._parent.<is thing/>
 | true |
Example: smell is looked up and found in the parent of our instance.
<<thing smell="bad"/>/>.smell
"bad" Example: smell is looked up and found in the parent of our instance.
<<thing smell="bad"/>/>._parent.smell
 | "bad" |
Example: bypass the low field of smell and get it out of thing itself.
<<thing smell="bad"/>/>._parent._parent.smell
 | "good" |
Just as we can 'get' the parent of an object using the same mechanism for
getting the value of any field, we can also 'set' the parent of any
object using the same mechanism for setting the value of any field.
You should know that it is unusual to change the parent of an object
after it has been created, but at times it comes in extremely handy.
This is a powerful feature of Water that few languages have.
If you're having
a hard time imagining when this could be useful, suppose you are modeling
family relationships and a kid is adopted. Here's an example:
<set dad=<thing is_rich=true/>/>
<set kid=<thing/>/> <!-- kid created with 'thing' as its parent. But as
everyone knows, 'thing' is a lousy parent -->
kid.<set _parent=dad/>
kid.is_rich | true |
Now with an understanding of the relationship of objects through
inheritance, we introduce the method named 'class'.
class makes a new object.
a wob
| Parameter key | Default value | Type |
| _name | "class" | string |
The first parameter to class is the name of the class.
Example: name a _name field in the new object.
<class vehicle/>._name
"vehicle" a wob
| Parameter key | Default value | Type |
| "_parent" | false |
Each class has a 'superclass' or '_parent'. If you don't specify the parent
(such as what we've done above), the _parent is wob, the root Water OBject.
<class vehicle/>._parent
wob
We can specify the parent by extending the name with a "prefix" path.
In this case, the parent of our new class is the non-last parts of
the name of the call.
<class vehicle.boat/>._parent
vehicle
The actual _name of the new class is the last part of the first argument of the call.
<class vehicle.boat/>._name
"boat"
There's another way to specify the parent of a class, by passing in
a _parent argument.
<class bike _parent=thing/>
thing.bike._parent
 | thing |
In the parent of a class, a field is created whose key is the name of the new object
and whose value is the new object. The default for the parent is wob,
the root Water object. A call to class returns the new object.
Example: set a field in the parent, wob
<class vehicle/>
wob.vehicle
 | vehicle |
a wob
| Parameter key | Default value | Type |
| _save_expression_call | false |
Rarely will you need this functionality but it comes in handy if you
are writing code that needs to write code or need a flexible syntax.
When you call a class with some keyword args to make an instance,
you cannot normally
find out the order that those args were passed to the method.
In fact you can't find out a variety of things like whether they were passed as
keywords or by position.
By defining the class with a "param" of _save_expression_call=true,
it will not be a real param, but will instead bind the expression
of the call to the local variable of _expression_call when the
body of the make method is being executed.
<class boat x=2 _save_expression_call=true>
<method make>
._expression_call
</method>
</class>
<boat x=5/>.<is_a expression.call/> | true |
What good is this? You can inspect the result of <boat x=5/> above,
but here's some ideas:
_expression_call.<length/> will give you the number of args passed._expression_call.0.name will give you the name of the first arg if it was passed by keyword._expression_call.0.arg_source will give you the source for the first arg._expression_call.file gives you the source file that the call is in.
Subclasses
If you call class in the content area of another call to class,
the outer new object becomes the parent of the inner new one.
All three of the following do the same thing.
<class vehicle>
<class boat/>
</class> <class vehicle/>
<class vehicle.boat/>
<class vehicle/>
vehicle.<set boat=<vehicle/>/>
vehicle.boat.<set _name="boat"/>
We can refer to the outer class as wob.vehicle or just vehicle for short.
we can refer to the inner class as wob.vehicle.boat or vehicle.boat for short.
You can also give a class fields.
These fields are passed in exactly like you make parameters in a call to method.
But instead of making method parameters, they just become fields of the
new class.
<class vehicle wheels=true speed=true/>.wheels
 | true |
Naturally, instances of our class inherit these fields.
<vehicle/>.wheels
true
or they can "shadow" the class variables like so:
<vehicle wheels=false/>.wheels
 | false |
Subclasses can shadow the class fields as well:
<class vehicle.boat wheels=false/>.wheels
 | false |
vehicle.<boat/>.wheels
false
Class fields take the same characteristics as method parameters,
a name, a default value, a type, and an execution kind.
Think of creating an instance just like calling a method only instead of
executing the body of the method, just make an instance that has all the
passed-in fields.
vehicle.<boat wheels="usually not"/>.wheels
 | "usually not" |
Make
Actually when you make an instance, a method IS called. It is the 'make' method
of the class if any. The default just returns the new object.
When the init method is called, the _subject local variable is
bound to the new object. You can then do further initialization of the
new object in the make method.
<class vehicle wheels=true>
<method make>
<if> .wheels.<is true/>
.<set wheels="usually"/>
</if>
_subject
</method>
</class>
<vehicle/>.wheels | "usually" |
Notice that the last expression in the body of 'make' is _subject.
That is because whatever is returned by the make method is retuned by the
call to vehicle.
<class vehicle wheels=true>
<method make>
<if> .wheels.<is true/> _subject
else "wheelless"
</if>
</method>
</class>
<vehicle wheels="no"/> | "wheelless" |
Think of the 'make' method as the constructor for the new object.
It is just a method called with a _subject that is
bound to a new object containing
all the fields passed, with its parent being the 'container' of the
'make' method itself. Thus the default 'make' method is simply:
<method make> _subject</>
Since 'make' returns the value of the last expression in its body
that is executed (just like all methods), and that value is returned
by a call to the container of make, you can have a call to
a class return something other than an instance to the class.
This is unusual, but certainly possible.
While the body of make is being executed, the local variable
_subject_of_call is bound to the subject of the original
call to making the instance.
Example: _subject_of_call
<class boat>
<method make> _subject_of_call </>
</class>
13.<boat/>
 | 13 |
Here's what's going on above:
Our call 13.<boat/> looks up 'boat' in 13, doesn't find it, looks on up
to wob before it finally finds the key "boat" with our class as its value.
Then the method boat.make is called with a subject of the new instance of
boat, and _subject_of_call bound to 13.
Our make method just returns the value of _subject_of_call which is 13.
_subject_of_call isn't used often, but can come in handy when the make
method is trying to do something different based on the original subject
to the call.
By placing a call to method in the content of a call to class,
we not only make a method object, but we also create a field in the
new class that has the name of the new method and the value of the new method.
<class vehicle>
<method launch> "go"</>
</class>
vehicle.<launch/>
 | "go" |
a wob
| Parameter key | Default value | Type |
| content | false |
The content of a call to class normally contains just calls to methods of that class.
See the documetation om 'method' for how to define methods on a class outside
of the body of their class.
If you want to make a subclass, you can stick a call to class in the content of a class call
along with the methods for the class.
<class vehicle>
<class boat>
<method launch> "go" </method>
</class>
<method launch> "onward, James"</method>
</class> | vehicle |
Above we've defined 2 classes each with a launch method.
vehicle.boat
vehicle.boat Example: use the class itself
vehicle.<launch/>
"onward, James"Example: make an instance and use that.
<vehicle/>.<launch/>
"onward, James"Example: use our subclass
vehicle.boat.<launch/>
"go"Example: make an instance of our subclass
vehicle.<boat/>.<launch/>
"go"
Methods are objects and are stored in regular fields of their "containing"
object which is usually an object created by class, but can be any
object.
thing.<set drive=<method null> "on the road"</method> />
thing.<drive/>
 | "on the road" |
Calling method with null gives it no name. But we don't care since it will usually be accessed from thing.
Below we grab the method above via thing.drive, and make a synonym for it inside of
the vehicle class named "cruise".
vehicle.<set cruise=thing.drive/>
<vehicle/>.<cruise/>
 | "on the road" |
You can create methods for only certain instances of a class using 'set' or
even set up the methods while making the instance.
<thing get_lost=<method null> "go jump in a lake"</method>/>.<get_lost/>
 | "go jump in a lake" |
Above we create a new method via <method null> "go jump in a lake"</method>.
that is used as the value of the "get_lost" field of the new instance of thing
that we're creating with:
<thing get_lost=<method null> "go jump in a lake"</method>/>
Finally we're using that new instance of thing as the subject of a call to
the "get_lost" method that we just created. this isn't the kind of code
you'd write in practice but it is instructive to see how it all works.
Methods are objects, classes are objects, instances are objects
and they all follow the same consistent rules.
_subject
When a call to 'class' is executed, its content is also executed.
That's how the methods and subclasses get defined.
You can also stick random code in the content of a class, though
we don't recommend truely random code. It should be code that helps in the creation of the class.
During the execution of a class call's content,
the local variable _subject is bound to the
new class being made.
This lets you do extra initialization on the class or report about the creation.
<class foo>
<echo "making new class: " _subject/>
</class>
© Copyright 2007 Clear Methods, Inc.