A method is a unit of executable code that is associated with a specific class defined in the DOM. A method is like a function, but it is in a script associated with a class on a node. Methods are contained in class method scripts, each script of which is associated with one of the classes on the node.
In other words:
- A class has fields which represents what the data objects of the class know.
- A class can also have methods which represent what objects of the class can do.
Class Methods enable a traditional object oriented programming style, where objects (classes) have code that is tightly coupled to the class data. For any class, the methods for that class are in a script named after that class. So for class FooBar, the associated script would be FooBarClassMethods
Class fields can be designated as private. A private field can only be referenced by methods of a class which contains that same private field. This allows a scripter to create a class that hides its data from other scripts, and the class's methods are responsible for any manipulation of that data. (Of course methods can be written to access these private fields, but in doing so you are creating an explicit interface to the data which conforms more closely to the Object Oriented ideal).
<ClassName> + ClassMethods
The HeroMachine (script interpreter) expects the method script for a class to be named in a very specific fashion. It expects the script to be named as a munge of ClassName + ClassMethods.
For example, the Class Foo would have a class Methods script named FooClassMethods.
method DoFoo() as noderef of class Foo
Method signatures are located in a shared namespace, which means that for any given method name, there is one and only one signature for that method name no matter how many scripts in which it might be used.
For example, DoFoo() as noderef of class Foo is the ONLY signature you will ever see for a method named DoFoo.
Methods (like functions) have a signature which is made up of parameters and their types.
method <name>(<arg> <argdef> <type>, <arg> <argdef> <type>, ...) [as <type>] .
- One of the arguments to the method. Also called a parameter.
- This is a linking word in the parameter list which must be one of the following:
- the parameter is just passed in, but its value cannot be changed
- passes the variable as a pointer, so the value can be changed. This means that, within the method, you will be operating the data that is passed in directly, not a copy of that data. This is particularly useful when you have a method that needs to operate on (or return) large lists or classes.
- a copy is made of the variable that the function can change, but it doesn't change the value that was originally passed in.
- One of the possible Data Types, such as
string, noderef, list of noderef, integer, enum <enum_list>, etc.
- (optional) The return value of the method. If not specified, then the method does not return a value.
method attack( target as noderef, maneuv as enum maneuver )
- Main page: Function/method modifiers
Methods may have a prepended keyword which indicates more information about where the method exists and how it can be accessed. As a quick overview:
- (no modifier)
- The default, which is similar to the shared modifier for functions. Without any additional modifier, methods of the same name in different scripts are expected to have the same signature (argument list).
- Tells the compiler that the method exists in one and only one classMethods script. This allows a class to determine that certain functionality should not be able to be overridden by the ClassMethods scripts of children Classes of that method.
- Indicates that a method may be called via Remote Calls. This call could go from one server to another, or from a server to the client.
- Indicates that a method may be remote called from a client script. Because clients may be "hacked", the Untrusted keyword reminds us that input must be carefully verified and may not be trusted.
ProxyLocal and ProxyForward
These modifiers, new in version 1.22, are for designating how to handle things when a method is called on a copy of a node (aka a proxied node) made via replication. If neither of these modifiers are present, attempts to call the method on a proxy node produce a Script Error. However, when calling a method on the original node, these modifiers have no effect.
- Flags a method as one that should be run locally, in the local GOM, if called on a proxied node.
- Flags a method as one that should be run on the GOM of the source node, rather than the GOM of the proxied node.
method Simple() MsgArea("Hello area!") . unique remote method NotSoSimple( best as String, worst copies String) as Boolean // the compiler automatically knows that me is kindof the class me.aSampleField = "isn't it cool" . unique method DestroyFoo( foo as noderef of class Foo ) proxyForward method attack( target as noderef, maneuv as enum maneuver ) // statements to be executed on the original node .
Like shared function names, method names/signatures live in the shared namespace. That means care should be taken to avoid using generic/short names for methods to minimize the potential for confusion.
While the good names are more verbose, it facilitates ease of understanding when reading code with which you are unfamiliar.
Calling a method
Calling by Node Ref
aFooNode as noderef of class Foo = CreateNodeFromClass("Foo")
now the method call
Because the concept of methods is an object oriented one, and objects ( data ) are noderefs in our development environment, methods may only be called via noderef. That is to say, you can not call the method
DoFoo using the syntax
FooClassMethods:DoFoo(). Rather you would call DoFoo, assuming you have a noderef of class Foo named SomeFooNode, using the syntax
function demo() var n = createNodeFromClass("item") n.Simple() var result = n.NotSoSimple( "test", "ing" ) .
Note that the syntax uses a period ( . ) not a colon.
Calling a parent class
Sometimes a child class needs to implement a method to implement additional functionality to some base method but it is still desirable to run the method code for the parent class. As long as your hierarchy tree of classes does not produce method conflicts, there is a mechanic that supports this functionality.
method Foo() // Do minor child foo stuff // call parent foo to do its normal processing parentClass::Foo() .
Note that the syntax is double-colon ( :: ) not a single-colon.
Calling a parent class explicitly
If you have created a method conflict it may be necessary for you to explicitly define which parent class is to be called ( as parentClass::methodName() will script error due to the conflict ).
Assume two classes ( BaseFoo and SpiffyFoo ), both of which implement the method Foo. This isn't a problem until we create a conflict by creating the new class ConflictFoo that has both BaseFoo and SpiffyFoo as parent classes. Now when we call foo() the Hero Machine can't tell which one we meant to call.
We could resolve the conflict by copying all of the code we needed from a particular parent's ClassMethods script, but code duplication is almost always a bad idea. Since we know in our hypothetical conflict that we want the foo found in BaseFoo.
method Foo() BaseFoo::Foo() .
Note that calling methods the syntax is double-colon ( :: )
Class inheritance and methods
When a method call is made, it first attempts to call the method in the base class and any Glommed classes. If the method is not found, it attempts to call the method in the parent classes of the base class and all of the Glommed classes and so on until it reaches the penultimate parent of each of those classes. Consequently, inheritance is a big part of Methods. HSL supports class inheritence like most languages do, but we also have the concept of objects that can have new classes glommed on to them. This means a method can appear twice for a noderef for two reasons:
- It is overridden in a Method class through inheritence of the class
- A node is of one class and another class is GLOMmed on to it
In the case of A, a child's Method can override it's parent's class' implementation. This cool and useful. However in the case of B, if more than one class specifies the same Method then the results would be unpredictable... which one should you call? Since there is no clear answer to that, it is considered an error and a script error results when you try to call the method (and eventually during run-time during the GLOMming ).
The upshot of this is you want to be careful how you name your methods. Be more "wordy" in method names than usual to ensure you don't have conflicts like this between classes that might end up on the same node. Generally speaking, since all methods use a shared signature namespace... they are hard to reuse inappropriately anyway. But, never the less, use care.