Talk About Network



Register and Login
Nick
Password
Register create new account Sign up is FREE and you can post replies, new topics, bookmark posts and more!
Recover lost password


Programming > Languages Misc > Re: Preview cha...
Latest [ Topics | Posts ] Archive Post A New Topic Post a Reply
<< Topic < Post Post 1 of 3 Topic 1107 of 1154
Post > Topic >>

Re: Preview chapter about object orientation

by thomas.mertes@[EMAIL PROTECTED] Feb 15, 2008 at 03:58 AM

On 10 Feb., 15:56, thomas.mer...@[EMAIL PROTECTED]
 wrote:
Hello,
I have improved my chapter about object orientation.
Many thanks to all who gave suggestions.
It would be nice to get some feedback about the
new version before the final release. Here is it:

7. OBJECT ORIENTATION
=====================

    Many people will be familiar with object-orientation from
  languages like C++, Smalltalk, and Java. Seed7 follows the
  route of declaring "interfaces". An interface is a common
  set of operations supported by an object. For instance
  cars, motorcycles, lorries and vans can all accelerate or
  brake, if they are legal to drive on the road they can all
  indicate right and left.

  This view isn't new. C provides a primitive form of
  interfacing. When you write to a 'file' in C you use the same
  interface ('fprintf') for harddisk files, console output and
  printer output. The implementation does totally different
  things for this files. UNIX has used the "everything is a
  file" philosopy for ages (even network communication uses
  the file' interface (see sockets)).

  For short: An interface defines which methods are supported
  while the implementation describes how this is done.
  Several types with different method implementations can
  share the same interface.


7.1 Interface and implementation

  Seed7 uses interface types and implementation types.
  Objects declared with an interface type refer to a value
  which has an implementation type. The interface type of
  an object can always be determined at compile-time. Several
  implementation types can belong to one interface type (they
  implement the interface type). E.g.: The types 'null_file',
  'external_file' and 'socket' implement the 'file' interface.
  An interface object can only refer to a value with an
  implementation type that implements the interface. E.g.:
  A 'shape' variable cannot refer to a 'socket'.

  A new interface type is declared with:

    const type: shape is new interface;

  Interface (DYNAMIC) functions describe what can be done
  with objects of an interface type. An interface function
  for a 'shape' could be:

    const proc: draw (in shape param, inout window param) is DYNAMIC;

  Now we know that it is possible to 'draw' a 'shape' to a
  'window'. How this drawing is done is described in the
  implementation type. An implementation type for 'shape' is:

    const type: circle is new struct
        var integer: radius is 0;
      end struct;

  The fact that the type 'circle' is an implementation type of
  'shape' is described with:

    type_implements_interface(circle, shape);

  The function which implements 'draw' for 'circle's is:

    const proc: draw (in circle: aCircle, inout window: aWindow) is
func
      begin
        circle(aWindow.win, aWindow.currX, aWindow.currY,
            aCircle.radius, aWindow.foreground);
      end func;

  In the classic OOP philosopy a message is sent to an object.
  In the method the receiving object is referred with 'self' or
  'this'. The other parameters use the same mechanisms as in
  procedural programming languages (value or reference parameter).
  Seed7 uses a different approach: All parameters get a user
  defined name. In the above example the name 'aCircle' was used
  for the 'self'/'this' parameter.

  A function to create new circle objects can also be helpful:

    const func circle: circle (in integer: radius) is func
      result
        var circle: result is circle.value;
      begin
        result.radius := radius;
      end func;

  Now we can draw a 'circle' object with:

    draw(circle(50), aWindow);

  Although the statement above does exactly what it should
  do and the separation between interface and implementation
  is obvious, most OO enthusiasts would not be thrilled. All
  decisions which implementation function should be called
  can be made at compile time. To please the OO fans such
  decisions must be made at runtime. This decision process
  is called dynamic dispatch.


7.2 Dynamic dispatch

    When the implementation types have different implementations
  of the same function (method) a dynamic dispatch is necessary.
  The type of the value, refered by an interface object, is not
  known at compile-time. In this case the program must decide at
  runtime which implementation of the function should be invoked.
  This decision is based on the type of the value of an object.
  A dynamic dispatch only takes place when a DYNAMIC (or
  interface) function is called. When the program is analyzed
  (in the interpreter or compiler) the interface functions take
  precedence over normal functions when both are to be considered.

  To demonstrate the dynamic dispatch we define the type 'line'
  which also implements a 'shape':

    const type: line is new struct
        var integer: xLen is 0.0;
        var integer: yLen is 0.0;
      end func;

    type_implements_interface(line, shape);

    const proc: draw (in line: aLine, in window: aWindow) is func
      begin
        line(aWindow.win, aWindow.currX, aWindow.currY,
            aLine.xLen, aLine.yLen, aWindow.foreground);
      end func;

    const func line: line (in integer: xLen, in integer: yLen) is func
      result
        var line: result is line.value;
      begin
        result.xLen := xLen;
        result.yLen := yLen;
      end func;

  In addition we define a normal (not DYNAMIC) function
  which draws 'shape's to the 'currWindow':

    const proc: draw (in shape: aShape) is func
      begin
        draw(aShape, currWindow);
      end func;

  In the example above the call of the (DYNAMIC) interface
  function is 'draw(aShape, currWindow)'. The
  interface function declared with

    const proc: draw (in shape param, inout window param) is DYNAMIC;

  decides which implementation function has to be called.
  The dynamic dispatch works as follows:

  - For all parameters which have an interface type the
    parameter is replaced with its value. In this case the
    parameter 'aShape' is replaced by a value of type
    'circle' or 'line'.

  - The same logic as in the analyze part of the compiler
    is used to find the matching function. In this search
    normal functions take precedence over interface functions.

  - When a matching function is found it is called.

  This process describes the principal logic of the dynamic
  dispatch. In practice it is not necessary to execute the
  analyze part of the compiler during the runtime. It is
  possible to simplify this process with tables and function
  pointers.


7.3 Inheritance

    When a new 'struct' type is defined it is possible to
  inherit from an existing 'struct' type. E.g.:

    const type: external_file is sub null_file struct
        var PRIMITIVE_FILE: ext_file is PRIMITIVE_NULL_FILE;
        var string: name is "";
      end struct;

  That way the type 'external_file' inherits the fields and
  methods of 'null_file', which is declared as:

    const type: null_file is new struct
      var char: bufferChar is '\n';
      var boolean: io_empty is FALSE;
      var boolean: io_ok is TRUE;
    end struct;

  In most situations it makes sense when the implementation
  types inherit from a basic implementation type such as
  'null_file'. That way it is possible to define functions
  which are inherited by all derived implementation types.
  In the standard library the function 'getln' is such a
  function:

    const func string: getln (inout null_file: aFile) is func
      result
        var string: stri is "";
      local
        var string: buffer is "";
      begin
        buffer := gets(aFile, 1);
        while buffer <> "\n" and buffer <> "" do
          stri &:= buffer;
          buffer := gets(aFile, 1);
        end while;
        aFile.bufferChar := buffer[1];
      end func;

  All inherited types of 'null_file' inherit the function
  'getln', but they are also free to redeclare it. In the
  'getln' function above the function call 'gets(aFile, 1)'
  uses the (DYNAMIC) interface function:

    const func string: gets (inout file param, in integer param) is
DYNAMIC;

  In other OO languages the distinction between interface type
  and basic implementation type is not done. Such languages
  either use a dynamic dispatch for every method call (as Java
  does) or need a keyword to request a dynamic dispatch (as C++
  does with the 'virtual' keyword).

  When assignments take place between inherited implementation
  types it is important to note that structure assignments are
  done with (deep) copies. Naturally such assignments can only
  copy the elements that are present in both structures.
  In the following example just the 'null_file' elements
  are copied from 'anExternalFile' to 'aNullFile':

    const proc: example is func
      local
        var null_file: aNullFile is null_file.value;
        var external_file: anExternalFile is external_file.value;
      begin
        aNullFile := anExternalFile;
        write(aNullFile, "hello");
      end func;

  Although the variable 'anExternalFile' is assigned to
  'aNullFile', the statement 'write(aNullFile, "hello")'
  calls the 'write' function (method) of the type 'null_file'.

  A new interface type can also inherit from an existing
  interface type:

    const type: shape is sub object interface;

  Although inheritance is a very powerful feature it should
  be used with care. In many situations it makes more sense
  that a new type has an element of another type (so called
  has-a relation) instead of inheriting from that type (so
  called is-a relation).


7.4 Multiple dispatch

    The Seed7 object system allows multiple dispatch (not to
  be confused with multiple inheritance). The methods are
  not assigned to one type (class). The decision which
  function (method) is called at runtime is done based upon
  the types of several arguments. The classic object
  orientation is a special case where a method is connected
  to one class and the dispatch decision is done based on
  the type of the 'self' or 'this' parameter.
  The classic object orientation is a single dispatch system.

  In the following example the type 'Number' is introduced
  which is capable to unify numerical types. The type
  'Number' is an interface type which defines
  the inferface function for the '+' operation:

    const type: Number is sub object interface;

    const func Number: (in Number param) + (in Number param) is
DYNAMIC;

  The interface type 'Number' can represent an 'Integer' or a 'Float':

    const type: Integer is new struct
        var integer: val is 0;
      end struct;

    type_implements_interface(Integer, Number);

    const type: Float is new struct
        var float: val is 0.0;
      end struct;

    type_implements_interface(Float, Number);

  The declarations of the converting '+' operators are:

    const func Float: (in Integer: a) + (in Float: b) is func
      result
        var Float: result is Float.value;
      begin
        result.val := flt(a.val) + b.val;
      end func;

    const func Float: (in Float: a) + (in Integer: b) is func
      result
        var Float: result is Float.value;
      begin
        result.val := a.val + flt(b.val);
      end func;

  The declarations of the normal '+' operators (which do not convert)
are:

    const func Integer: (in Integer: a) + (in Integer: b) is func
      result
        var Integer: result is Integer.value;
      begin
        result.val := a.val + b.val;
      end func;

    const func Float: (in Float: a) + (in Float: b) is func
      result
        var Float: result is Float.value;
      begin
        result.val := a.val + b.val;
      end func;

  The type 'Number' can be extended to support other
  operators and there can be also implementations using
  'complex', 'bigInteger', 'bigRational', etc. . That way
  'Number' can be used as universal type for math
  calculation. Further extending can lead to an universal
  type. Such an universal type is loved by proponents of
  dynamic typed languages, but there are also good reasons
  to have destinct types for different purposes.

================================

Thanks in advance for your effort.

Greetings Thomas Mertes

Seed7 Homepage:  http://seed7.sourceforge.net
Seed7 - The extensible programming language: User defined statements
and operators, abstract data types, templates without special
syntax, OO with interfaces and multiple dispatch.




 3 Posts in Topic:
Re: Preview chapter about object orientation
thomas.mertes@[EMAIL PROT  2008-02-15 03:58:39 
Re: Preview chapter about object orientation
"Malcolm McLean"  2008-02-15 21:53:01 
Re: Preview chapter about object orientation
Reinder Verlinde <rein  2008-02-16 00:57:27 

Post A Reply:
  Go here to Signup

AddThis Feed Button


About - Advertising - Contact - Frequently Asked Questions - Privacy Policy - Terms of Use - Signup

Contact
tan12V112 Tue May 13 18:44:12 CDT 2008.