Go to the first, previous, next, last section, table of contents.


Method declarations

A method declaration declares the existence of a method for the current object being defined. Declarations are only possible in an interface. The implementation contains only method definitions (see section Method definitions).

method_declaration:
          shared_method_part `;'
        ;

shared_method_part:
          method_decl [pre_condition] [post_condition]
        ;

method_decl:
          return_type method_qualifier* method_name_part
        | return_type method_qualifier* method_decl_part+
        ;

In the first rule of a method_decl, a method without any arguments is declared. In the second case, the method does have arguments.

method_name_part:
          [identifier | ...] [:]
        ;

A method_name_part can be an identifier or any of the TOM keywords, except post and pre. It is optionally suffixed by a colon. A colon itself also is a valid method_name_part. (Usually, by convention, any method_name_part containing a colon indicates an optional method part for which' arguments a default value is supplied in the declaration.)

method_qualifier:
          protection_qualifier
        | redo_qualifier
        | `deferred'
        ;

If deferred, the method is not implemented by the current object. The protection qualifiers (see section Encapsulation) define the availability of this method to the current class, its subclasses and the other classes.

redo_qualifier:
          `redeclare'
        | `redefine'
        ;

If a class redefines a method implemented by a super class, it must declare the method as being redefined.

[Note: redeclare is meant to allow a subclass to indicate different object kinds for the arguments to a method implemented by a superclass. This is not yet implemented, its precise semantics have not yet been defined and its usefulness is being questioned. End note.]

method_decl_part:
          method_name_part argument_type argument_name
          [`=' expression]
        ;

If the expression is provided it denotes a default value for the arguments mentioned in the argument_name. Provision of such a default implies that this part of the method name is optional in the invocation of this method. Note that this is fully handled by the compiler: an invocation of a method specifying not all the arguments can not be discerned from an invocation specifying all default values for the arguments.

The expression must be evaluable in every context where it is used. It is, however, not enforced by the compiler that the expression is evaluable in every context where it can be used. [Note: This is a bug. End note.]

argument_name:
          identifier
        | `(' identifier_list `)'
        ;

If the argument_type is not a tuple, the argument_name should be an identifier. For a tuple type, the argument_name should be a parenthesized identifier list, with the same number of elements as the tuple type.

[Note: This syntax rule does not allow an element of a tuple-typed argument to be a tuple. That is wrong, but currently how it is implemented. End note.]

Example

Given the following method declaration

int
   foo int a
  bar: (int, int) (b, c) = (0, 1);

which has one mandatory argument, a, and one optional argument, (b, c). Given a receiver rcv of the proper type, this method can be invoked in different ways:

[rcv foo 1];

[rcv foo 2 bar: (3, 4)]

It is considered good practice to use a colon suffix for those nameparts of a method that are optional.

Since optional method parts are a purely compile time affair, if the object defining this foo bar: method is also to respond to a foo message, the object must explicitly define that method:

<doc> Respond to `foo' in addition to `foo bar:'.  </doc>
int
  foo int a
{
  = [self foo a bar: (0, 1)];
}

Obviously, since with one optional argument there are only two possibilities, the foo bar: method could just as well not have optional arguments, their omission being handled by the foo method. However, in the context of multiple optional arguments, the selectors to which an object responds do become an issue.

Similarly, if a library was previously distributed with the following method declared for some class handling streams on files

instance (id)
            with String name
          input: boolean input_p = FALSE
         output: boolean output_p = FALSE
  if-not-exists: int ne_action = 0;

and the new version of the library changes this method to be

instance (id)
            with String name
          input: boolean input_p = FALSE
         output: boolean output_p = FALSE
      if-exists: int e_action = 0
  if-not-exists: int ne_action = 0;

then it would be wise to incorporate a compatibility method in the new library, just to avoid having to recompile all code depending on the library, which is an issue especially in the case of shared libraries. The method below would then exist in the new library for the sole purpose of responding to the original selector.

instance (id)
            with String name
          input: boolean input_p = FALSE
         output: boolean output_p = FALSE
  if-not-exists: int ne_action = 0
{
  = [self with name input: input_p output: output_p
          if-exists: 0 if-not-exists: ne_action];
}

In a method invocation, if multiple methods match, methods with a longer name (i.e. with more (unused) optional name parts) are preferred over methods with a shorter name. This implies that the specification of if-exists: 0 in the invocation in the example is unnecessary.


Go to the first, previous, next, last section, table of contents.