module Interfaces { 
 
  // DEFINING INTERFACES 
 
  // use interface to define code abstractions 
  // an interface is a set of functions which may be implemented 
  // for different types and then used polymorphically  
 
  // define Point structure used in examples below 
  struct Point { 
    x : double; 
    y : double; 
  } 
 
  // the following defines a Graphics interface, used below 
  interface Graphics { 
    move_to(point : Point); 
    line_to(point : Point); 
    circle(point : Point, radius: double); 
  } 
 
  // the Drawable interface is invoked to allow a type to draw to a Graphics  
  interface Drawable { 
    draw(graphics: Graphics); 
  } 
 
  // interfaces can include other interfaces using ... 
  // interfaces can have property set/get and index set/get 
  interface Shape { 
    ...Drawable;              // Shape interface includes methods from Drawable interface 
    origin.get() : Point;     // get method for property origin of type Point 
  } 
 
  // IMPLEMENTING INTERFACES 
 
  // define Circle structure which will implement Shape interface 
  struct Circle { 
    origin: Point; 
    radius: double; 
  } 
 
  // define Line structure which will implement Shape interface 
  struct Line { 
    p1: Point; 
    p2: Point; 
  } 
 
  // use impl to provide implementions of one or more methods 
  // of an interface for one or more types. 
  // 
  // the first parameter is the type the implementation is for. 
  // 
  // this parameter is omitted from the interface definition 
  // but provided in the impl definition. 
  // 
  // using this for the name of the first parameter is  
  // just a convention - there is nothing special about the name. 
  // 
  // specify the interface name with impl, followed by implementations 
  // for methods of specific types. 
 
  // implement methods of Shape interface 
  impl Shape { 
 
    // implement Shape origin get for Line 
    origin.get(this : Line) : Point => { 
      // compute origin based on line points 
      return Point( 
        (this.p1.x + this.p2.x) / 2, 
        (this.p1.y + this.p2.y) / 2 
      ); 
    } 
 
    // implement Shape draw for Line 
    draw(this: Line, graphics: Graphics) { 
      graphics.move_to(this.p1); 
      graphics.line_to(this.p2); 
    } 
 
    // implement Shape origin get for Circle 
    origin.get(this : Circle) : Point => { 
      return this.origin; 
    } 
 
    // implement Shape draw for Circle 
    draw(this: Circle, graphics: Graphics) { 
      graphics.circle(this.origin, this.radius); 
    } 
  } 
 
  // impl can also be used to define a single method by omitting the {} 
 
  // implement Shape origin get for Point 
  impl Shape origin.get(this : Point) : Point => { 
    return this; 
  } 
 
  // USING INTERFACES 
 
  // to use an interface, cast the defining type to the interface type using ::. 
  // 
  // it is not possible to cast from an interface back to the defining type, e.g. 
  // the implementing type is "hidden" from the user of the interface 
  fn test() { 
    let graphics = getGraphics(); 
    let line = Line(Point(1, 2), Point(3, 4)); 
    let shape = line::Shape;      // get Shape interface for Line 
    shape.draw(graphics);         // invoke draw method on Shape interface 
    let line2 = shape::Line;      // not allowed: can't cast interface back to Line 
  } 
 
  // MUTABLE INTERFACES  
 
  // interfaces are immutable by default, meaning the types that can implement 
  // the interface must be immutable.  use mut to allow mutable types 
  // to implement the interface. 
 
  // define interface for accessing array of data 
  mut interface DataArray { 
    get(offset : uint) : u8; 
    set(offset : uint, data : u8);  
  } 
 
  // type that will implement DataArray in memory 
  mut struct MemoryArray { 
    bytes : mut u8[];             // mutable array of bytes 
  } 
 
  // implement DataArray interface for MemoryArray type 
  impl DataArray { 
    set(this : MemoryArray, offset: uint, data : u8) { 
      this.bytes[offset] = data; 
    } 
 
    get(this : MemoryArray, offset: uint) : u8 => { 
      return this.bytes[offset]; 
    } 
  } 
 
  fn test2() { 
    // initialize mutable array with 1024 zero bytes 
    let mem = MemoryArray([0::u8 ## 1024]);  
    let data = mem::DataArray;  
    let b = data.get(0);        // b is 0 
    data.set(0, 123); 
    let c = data.get(0);        // c is 123  
  } 
 
  // IMPLEMENTING METHODS ON A TYPE AND AN INTERFACE 
 
  // It may be desireable to have methods on a type and have those same methods 
  // available as an interface.  First implement the methods on the type 
  // and then use impl to signify that the type implements the interface. 
 
  // generic Stack interface with push and pop methods 
  mut interface Stack{T} { 
    push(value : T); 
    pop() : T; 
  } 
 
  // type that will implement Stack{int} 
  mut struct IntStack { 
    values : mut int[]; // mutable array of int 
  } 
 
  // implement push method for IntStack 
  push(this : IntStack, value : int) => { 
    this.values.insert_at(0, value); 
  } 
 
  // implement pop method for IntStack 
  pop(this : IntStack) : int => { 
    let value = this.values[0]; 
    this.values.delete_at(0); 
    return value; 
  } 
 
  // specify that IntStack type implements Stack{int} 
  impl Stack{int} { 
    ...IntStack; 
  } 
 
  fn test3() => { 
 
    // use IntStack directly 
    let int_stack = IntStack();           // construct IntStack 
    int_stack.push(1);                    // direct call on type 
 
    // use IntStack via Stack{int} interface 
    let stack = int_stack::Stack{int};    // cast to Stack{int} interface 
    stack.push(1);                        // call through interface 
  } 
}