Home

Interfaces

 

An Object's Interface

 

Introduction

An interface is a non-functioning layout for a structure or a class. The interface itself is not a structure or a class; it only provides a list of actions that a structure or a class would need.

Like a class or a structure, an interface has members but those members are not defined. Each member simply indicates its name but also provides such information as its type of arguments, if any, and its return type.

Creating an Interface

The primary formula to create an interface is:

type InterfaceName
  [ interface ]
  	abstract Member 1 : [ Data Type 1 -> ] Return Type 1
  	abstract Member 2 : [ Data Type 2 -> ] Return Type 2
  	abstract Member_n : [ Data Type_n -> ] Return Type_n
  [ end ]

You start with the required type keyword followed by a name. By tradition, the name of an interface starts with I (i uppercase i). After the name of the interface, create a body for it on the next line. You can start the body with the interface keyword. If you do, then you must end the body with the end keyword. Normally, both keywords are a combinational option. This means that either you omit both or you use both.

In the body of the interface, create an abstraction for each member. Every member of an interface must start with the abstract keyword but doesn't include a body. Here is an example:

type ICircular =
    interface
        abstract member Area : double
    end

Implementing an Interface

Once an interface exists, any class that needs its functionality must imprement it. The formula to follow to implement an interface is:

type Class-Name[(Parametere(s))] =
    Member(s)
    interface InterfaceName with
  	Interface-Member(s)

To implement an interface, in the body of the class, after the local members of the class, type interface, followed by the name of the interface, and followed by with. After this and on the next line, implement the member(s) of the interface. This would be done as follows:

type ICircular =
    interface
        abstract member Circumference : unit -> double
        abstract Area : unit -> double
    end

type Circle(radius : double) =
    member this.Radius : double = radius;
    interface ICircular with
        member this.Circumference() = radius * 2.00 * 3.14156
        member this.Area() : double = radius * radius * 3.14156

Using an Interface

To actually use the functionaity of an interface, you must cast an object created from a class implementer to interface. There are various techniques you can use.

After implementing an interface in a class, you can create an object of the class by declaring a variable from that class. To access a method from the interface, declare another variable that same class but you must up-cast it to the interface. Here is an example:

type ICircular =
    abstract Circumference : unit -> double
    abstract Area : unit -> double

type Circle(radius : double) =
    member this.Radius : double = radius;
    interface ICircular with
        member this.Circumference() = radius * 2.00 * 3.14156;
        member this.Area() : double = radius * radius * 3.14156;

let circ = new Circle(28.14);
let disc = circ :> ICircular;

printfn "Circle Characteristics";
printfn "----------------------";
printfn "Radius:        %f" circ.Radius;
printfn "Circumference: %f" (disc.Circumference());
printfn "Area:          %f" (disc.Area());

Instead of first declaring a variable, you can also use a local cast. Here are examples:

type ICircular =
    abstract Circumference : unit -> double
    abstract Area : unit -> double

type Circle(radius : double) =
    member this.Radius : double = radius;
    interface ICircular with
        member this.Circumference() = radius * 2.00 * 3.14156;
        member this.Area() : double = radius * radius * 3.14156;

let circ = new Circle(28.14);
let around = (circ :> ICircular).Circumference();

printfn "Circle Characteristics";
printfn "-------------------------";
printfn "Radius:        %f" circ.Radius;
printfn "Circumference: %f" around;
printfn "Area:          %f\n" ((circ :> ICircular).Area());

This would produce:

Circle Characteristics
-------------------------
Radius:        28.140000
Circumference: 176.806997
Area:          2487.674445

Press any key to continue . . .

As another technique, when implementing an interface in a class, after defining a method of the interface, create another member function that holds the same name as the method. To define that other method, create an upcast and call the method of the interface. The formula to follow is:

member [this | Self | InterfaceName].Interface-Method() = ([this | Self | InterfaceName] :> InterfaceName).Interface-Method()

Start with the member keyword. It is followed by either the this keyword, a self identifier of your choice (which can be a letter or a word of your choice), or the name of the interface. This is followed by a period and the name of the method from the interface with its parentheses and the = sign. To case the interface, add some parentheses. In the parentheses, use the same option you chose for this, the Self identifier, or the name of the interface. This means that if you decide to use this, you must use this on both sides. If you decide to use a self-identifier, you must use the same on both sides. If you decide to use the name of the interface, you must use it on both sides. After the up-cast, access the name of the method using a period and end it with parentheses. Once this has been done, you can access the interface method from an object created from the class. Here are examples:

type ICircular =
    abstract Circumference : unit -> double
    abstract Area : unit -> double

type Circle(radius : double) =
    member this.Radius : double = radius
    member me.Circumference() = (me :> ICircular).Circumference()
    member ICircular.Area()        = (ICircular :> ICircular).Area()
    interface ICircular with
        member this.Circumference() = radius * 2.00 * 3.14156
        member this.Area() : double = radius * radius * 3.14156

let circ = new Circle(46.8506);

printfn "Circle Characteristics";
printfn "-------------------------";
printfn "Radius:        %f" circ.Radius;
printfn "Circumference: %f" (circ.Circumference());
printfn "Area:          %f\n" (circ.Area());

This would produce:

Circle Characteristics
-------------------------
Radius:        46.850600
Circumference: 294.367942
Area:          6895.657349

Press any key to continue . . .
 
   
 

Implementing Many Interfaces

F# doesn't support multiple inheritance, which is the ability to create a class that is directly based on many classes. As an alternative, you can create a class that implements more than one interface.

The formula to implement many interfaces is:

type Class-Name[(Parametere(s))] =
    Member(s)
    interface InterfaceName 1 with
  	Interface-Member(s) 1
    interface InterfaceName 2 with
  	Interface-Member(s) 2
    . . .
    interface InterfaceName n with
  	Interface-Member(s) n

In the body of the class, each interface has its implementation section. The individual implementations follow the techniques we have used so far. To access the member of an interface from the object created using the class, you can declare a variable that is up-cast from the interface. This can be done as follows:

type ICircular =
    abstract Circumference : unit -> double
    abstract Area : unit -> double

type IQuadrilateralArea =
    abstract Area : double * double -> double
    
type Circle(radius : double) =
    member this.Radius : double = radius;
    member me.Circumference() = (me :> ICircular).Circumference();
    member ICircular.Area()   = (ICircular :> ICircular).Area();
    interface ICircular with
        member this.Circumference() = radius * 2.00 * 3.14156;
        member this.Area() : double = radius * radius * 3.14156;
    
type Cylinder(radius : double, height : double) =
    member this.Radius : double = radius
    member this.Height : double = height
    member me.Circumference() = (me :> ICircular).Circumference()
    member ICircular.BottomArea()   = (ICircular :> ICircular).Area()
    interface ICircular with
        member this.Circumference() = radius * 2.00 * 3.14156
        member this.Area() : double = radius * radius * 3.14156
    interface IQuadrilateralArea with
        member this.Area(length : double, width : double) : double = length * width

let cup = new Cylinder(35.74, 22.82);
let around = cup :> ICircular;
let lateral = cup :> IQuadrilateralArea;

printfn "Ice Cream Cup Characteristics";
printfn "-------------------------";
printfn "Radius:        %0.2f" cup.Radius;
printfn "Circumference: %0.2f" (around.Circumference());
printfn "Bottom Area:   %0.2f" (cup.BottomArea());
printfn "Lateral Area:  %0.2f\n" (lateral.Area(around.Circumference(), cup.Height));

This would produce:

Ice Cream Cup Characteristics
-------------------------
Radius:        35.74
Circumference: 224.56
Bottom Area:   4012.86
Lateral Area:  5124.43

Press any key to continue . . .

Properties in an Interface

A property is called abstract if it is not defined. Any class that wants to use that property must implement it.

 
 
   
 

Previous Copyright © 2014-2015 FunctionX Next