    [NAME]
    ALL.dao.tutorial.interface

    [TITLE]
    Abstract Interface

    [DESCRIPTION]

    Abstract interface is a type that describes how an object can be used, by specifying
    what methods and overloaded operators should be supported the object. An object is
    compatible (matching) to an interface type, if only if the object supports all the
    methods and operators that are specified by the interface. Interface is an abstract type,
    since no instance can be created from an interface, also all the methods of an interface
    are abstract without implementation.

    Here is a simple interface that contains a size checking method,

       1  interface HasSize
       2  {
       3      routine size()=>int
       4  }

    Now we can define a function that can take a parameter of any object that is compatible
    to this interface,

       1  routine PrintSize( object: HasSize )
       2  {
       3      io.writeln( object.size() )
       4  }

    Then this function can be called upon types such as string, list or map etc.

       1  PrintSize( 'hello world' )
       2  PrintSize( { 1, 2, 3 } );

    Interface supports inheritance in the same way as class does,

       1  interface Resizable : HasSize
       2  {
       3      routine resize( size :int )
       4  }

    Similarly,

       1  routine Resize( object: Resizable, size: int )
       2  {
       3      io.writeln( 'old size:', object.size() )
       4      io.writeln( 'new size:', size )
       5      object.resize( size )
       6  }
       7
       8  ls = {}
       9  Resize( ls, 5 )
      10  io.writeln( ls )

    Interface also supports operator overloading, however, built-in operators for built-in
    types cannot be checked against an interface, because they are not implemented as
    methods. So interfaces are normally more useful with class instances and wrapped C/C++
    types.

    Interfaces with the same set of abstract methods are interchangeable,

       1  interface HasSize2
       2  {
       3      routine size()=>int
       4  }
       5  routine PrintSize2( object: HasSize2 )
       6  {
       7      o :HasSize = object; # assign an object of "HasSize2" to a variable of "HasSize";
       8      io.writeln( object.size() )
       9  }
      10  PrintSize2( {} );

    Just for testing,

       1  interface HasSize
       2  {
       3      routine size()=>int
       4  }
       5  routine PrintSize( object: HasSize )
       6  {
       7      io.writeln( object.size() )
       8  }
       9  PrintSize( 'hello world' )
      10  PrintSize( { 1, 2, 3 } );
      11
      12  interface Resizable : HasSize
      13  {
      14      routine resize( size :int )
      15  }
      16  routine Resize( object: Resizable, size: int )
      17  {
      18      io.writeln( 'old size:', object.size() )
      19      io.writeln( 'new size:', size )
      20      object.resize( size )
      21  }
      22
      23  ls = {}
      24  Resize( ls, 5 )
      25  io.writeln( ls )
      26
      27
      28
      29  interface HasSize2
      30  {
      31      routine size()=>int
      32  }
      33  routine PrintSize2( object: HasSize2 )
      34  {
      35      o :HasSize = object;
      36      io.writeln( object.size() )
      37  }
      38  PrintSize2( {} );