The <TT CLASS="LITERAL" >typecase</TT > statement

Sather - A Language Tutorial
Prev | Chapter 5. Abstract Classes and Subtyping | Next

# 5.6. The `typecase` statement

It is sometimes necessary to bypass the abstraction and make use of information about the actual type of the object to perform a particular action. Given a variable of an abstract type, we might like to make use of the actual type of the object it refers to, in order to determine whether it either has a particular implementation or supports other abstractions.

The `typecase` statement provides us with the ability to make use of the actual type of an object held by a variable of an abstract type.

    a:$OB := 5;
    ... some other code...
    res:STR;

    typecase a
    when INT then                -- 'a' is of type INT in this branch
       #OUT + "Integer result: " + a;
    when FLT then                -- 'a' is of type FLT in this branch
       #OUT + "Real result: " + a;
    when $STR then               -- 'a' is $STR and supports '.str'
       #OUT + "Other printable result: " + a.str;
    else
       #OUT + "Non printable result";
    end;

The typecase must act on a local variable or an argument of a method.On execution, each successive type specifier is tested for being a supertype of the type of the object held by the variable. The statement list following the first matching type specifier is executed and control passes to the statement following the `typecase`.

## Points to note

- It is not legal to assign to the `typecase` variable within the statement lists.

- If the object's type is not a subtype of any of the type specifiers and an `else` clause is present, then the statement list following it is executed.

- It is a fatal error for no branch to match in the absence of an `else` clause.

- If the value of the variable is `void` when the `typecase` is executed, then its type is taken to be the declared type of the variable. In the above example, the declared type of `a` is `$OB` , which does not match any of the branches, so the `else` clause is taken

- The variable of the typecase must be a local variable or a method argument.

- If the `typecase` appears in an iterator, then the mode of the argument must be `once`; otherwise, the type of object that such an argument holds could change.

- The typecase does not search for the branch with the tightest match - it goes down the first branch that matches.

- After a branch has been selected, the typecase tries to cast the variable to as narrow a type as possible - if the declared type of the variable is actually stronger than (a subtype of) the chosen branch, then the variable will keep the stronger, declared type. For instance

      a:$SET{INT};
      typecase a
      when INT then ... -- a will never get here, INT is not < $SET{INT}
      when $OB then ...
         -- a has the type of $SET{INT} which is stronger than $OB

## Typecase Example

For instance, suppose we want to know the total number of subordinates in an array of general employees.

    peter ::= #EMPLOYEE("Peter",1);      -- Name = "Peter", id = 1
    paul  ::= #MANAGER("Paul",12,10);    -- id = 12,10 subordinates
    mary  ::= #MANAGER("Mary",15,11);    -- id = 15,11 subordinates
    employees: ARRAY{$EMPLOYEE} := |peter,paul,mary|;
    totalsubs: INT := 0;
    loop employee:$EMPLOYEE := employees.elt!; -- yields array elements
       typecase employee
       when MANAGER then
          totalsubs := totalsubs + employee.numsubordinates;
       else
       end;
    end;
    #OUT + "Number of subordinates: " + totalsubs + "\n";

Within each branch of the typecase, the variable has the type of that branch (or a more restrictive type, if the declared type of the variable is a subtype of the type of that branch).

Prev | Home | Next
Type Conformance | Up | The Overloading Rule