Abstract type: Difference between revisions

From Rosetta Code
Content added Content deleted
m (? English)
No edit summary
Line 5: Line 5:
'''Abstract type''' is a type without instances or without definition.
'''Abstract type''' is a type without instances or without definition.


For example in [[object-oriented programming]] abstract types can be in some languages a partial implementation of other types, which are later derived from it. Abstract type may provide implementation of some operations and/or components. Abstract types without any implementation are called '''interfaces'''. In the languages that do not support multiple [[inheritance]] ([[Ada]], [[Java]]), interfaces are usually allowed to be multiply inherited from. The languages with multiple inheritance (like [[C++]]) usually make no distinction between partially implementable abstract types and interfaces. Because the abstract type's implementation is incomplete, if any, it makes no sense to have any instances (objects) of it. Therefore an [[object-oriented programming | OO]] language would prevent creation of such objects.
For example in [[object-oriented programming]] using some languages, abstract types can be partial implementations of other types, which are to be derived therefrom. An abstract type may provide implementation of some operations and/or components. Abstract types without any implementation are called '''interfaces'''. In the languages that do not support multiple [[inheritance]] ([[Ada]], [[Java]]), classes can, nonetheless, inherit from multiple interfaces. The languages with multiple inheritance (like [[C++]]) usually make no distinction between partially implementable abstract types and interfaces. Because the abstract type's implementation is incomplete, [[object-oriented programming | OO]] languages normally prevent instantiation from them (instantiation must derived from one of their descendent classes).


In strongly statically typed languages, abstract types can be used for example to hide the implementation of a type in the interface of a module. So both the complexity is hidden for the user of the module, and also the implementation can change without repercutions on the source code that use it. Abstract types that even have no definition in the implementation can also be used for the type algebra.
In strongly statically typed languages, abstract types can be used to separate implementation from interface declarations. This hides complexity while allowing the implementation to change without repercussions on the usage.


'''Task''': show how an abstract type can be declared in the language. If the language makes a distinction between interfaces and partially implemented types illustrate both.
'''Task''': show how an abstract type can be declared in the language. If the language makes a distinction between interfaces and partially implemented types illustrate both.
Line 111: Line 111:
def Dequeue(self):
def Dequeue(self):
raise NotImplementedError
raise NotImplementedError
def Print_Contents(self):
for i in self.contents:
print i,
</python>
</python>


Python allows multiple inheritance and it's more common to implement "mix-in" classes rather than abstract interfaces. (Mix-in classes can implement functionality as well define interaces).
Python allows multiple inheritance and it's more common to implement "mix-in" classes rather than abstract interfaces. (Mix-in classes can implement functionality as well define interfaces).


In this example we're simply following the Python convention of raising the built-in "NotImplementedError" for each function which must be implemented by our subclasses. This is a "purely virtual" class because all of its methods raise the exception. (It is sufficient for __init__ to do so for any partial virtual abstractions since that still ensures that the exception will be raised if anyone attempts to instantiate the base/abstract class directly rather than one of it's concrete descendents).
In this example we're simply following the Python convention of raising the built-in "NotImplementedError" for each function which must be implemented by our subclasses. This is a "purely virtual" class because all of its methods raise the exception. (It is sufficient for __init__ to do so for any partial virtual abstractions since that still ensures that the exception will be raised if anyone attempts to instantiate the base/abstract class directly rather than one of its concrete (fully implemented) descendents).


The method signatures and the instantiation of a "contents" list shown here can be viewed as documentary hints to anyone inheriting from this class. They won't actually do anything in the derived classes (since these methods must be over-ridden therein).
The method signatures and the instantiation of a "contents" list shown here can be viewed as documentary hints to anyone inheriting from this class. They won't actually do anything in the derived classes (since these methods must be over-ridden therein).

In this case we've implemented one method (''Print_Contents''). This would be inherited by any derived classes. It could be over-ridden, of course. If it's not over-ridden it establishes a requirement that all derived classes provide some "contents" attribute which must allow for iteration and printing as shown. Without this method the class would be "purely virtual" or "purely abstract." With its inclusion the class becomes "partially implemented."


:'''Note:''' This "BaseQueue" example should not be confused with Python's standard library Queue class. That is used as the principle "producer/consumer" communications mechanism among threads (and newer ''multiprocessing'' processes).
:'''Note:''' This "BaseQueue" example should not be confused with Python's standard library Queue class. That is used as the principle "producer/consumer" communications mechanism among threads (and newer ''multiprocessing'' processes).

Revision as of 22:43, 20 November 2008

Task
Abstract type
You are encouraged to solve this task according to the task description, using any language you may know.

Abstract type is a type without instances or without definition.

For example in object-oriented programming using some languages, abstract types can be partial implementations of other types, which are to be derived therefrom. An abstract type may provide implementation of some operations and/or components. Abstract types without any implementation are called interfaces. In the languages that do not support multiple inheritance (Ada, Java), classes can, nonetheless, inherit from multiple interfaces. The languages with multiple inheritance (like C++) usually make no distinction between partially implementable abstract types and interfaces. Because the abstract type's implementation is incomplete, OO languages normally prevent instantiation from them (instantiation must derived from one of their descendent classes).

In strongly statically typed languages, abstract types can be used to separate implementation from interface declarations. This hides complexity while allowing the implementation to change without repercussions on the usage.

Task: show how an abstract type can be declared in the language. If the language makes a distinction between interfaces and partially implemented types illustrate both.

Ada

Interface

Interfaces in Ada may have no components or implemented operation except for ones implemented as null operations. Interfaces can be multiply inherited. <ada> type Queue is limited interface; procedure Enqueue (Lounge : in out Queue; Item : in out Element) is abstract; procedure Dequeue (Lounge : in out Queue; Item : in out Element) is abstract; </ada> Interfaces can be declared synchronized or task when intended implementations are to be provided by protected objects or tasks. For example: <ada> type Scheduler is task interface; procedure Plan (Manager : in out Scheduler; Activity : in out Job) is abstract; </ada>

Abstract type

Abstract types may provide components and implementation of their operations. Abstract types are singly inherited. <ada> with Ada.Finalization; ... type Node is abstract new Ada.Finalization.Limited_Controlled and Queue with record

  Previous : not null access Node'Class := Node'Unchecked_Access;
  Next     : not null access Node'Class := Node'Unchecked_Access;

end record; overriding procedure Finalize (X : in out Node); -- Removes the node from its list if any overriding procedure Dequeue (Lounge : in out Node; Item : in out Element); overriding procedure Enqueue (Lounge : in out Node; Item : in out Element); procedure Process (X : in out Node) is abstract; -- To be implemented </ada> Here Node is an abstract type that is inherited from Limited_Controlled and implements a node of a doubly linked list. It also implements the interface of a queue described above, because any node can be considered a head of the queue of linked elements. For the operation Finalize an implementation is provided to ensure that the element of a list is removed from there upon its finalization. The operation itself is inherited from the parent type Limited_Controlled and then overridden. The operations Dequeue and Enqueue of the Queue interface are also implemented.

C++

You can declare a virtual function to not have an implementation (called "pure virtual function") by the following "= 0" syntax after the method declaration. A class containing at least one pure virtual function (or inheriting one and not overriding it) cannot be instantiated. <java>class Abs { public: virtual int method1(double value) = 0; virtual int add(int a, int b){ return a+b; } };</java> Because C++ allows multiple inheritance of classes, no distinction is made between interfaces and abstract classes.

Java

Methods that don't have an implementation are called abstract methods in Java. A class that contains an abstract method or inherits one but did not override it must be an abstract class; but an abstract class does not need to contain any abstract methods. An abstract class cannot be instantiated. If a method is abstract, it must be public or protected <java>public abstract class Abs { abstract public int method1(double value); abstract protected int method2(String name); int add(int a, int b){ return a+b; } }</java> Interfaces in Java may not implement any methods and all methods are implicitly public and abstract. <java>public interface Inter { int method1(double value); int method2(String name); int add(int a, int b); }</java>

OCaml

Virtual

The equivalent of what is called abstract type in the other OO examples of this page is just called virtual in Objective Caml to define virtual methods and virtual classes:

<ocaml>class virtual foo =

 object
   method virtual bar : int
 end</ocaml>

Abstract Type

In OCaml what we call an abstract type is not OO related, it is only a type defined without definition, for example: <ocaml>type t</ocaml> it is used for example to hide an implementation from the interface of a module or for type algebra.

Example of abstracting a type in an interface: <ocaml>module Foo : sig

 type t

end = struct

 type t = int * int

end</ocaml>

Pure abstract types in the implementation: <ocaml>type u type v type 'a t type ut = u t type vt = v t</ocaml>

Python

<python>

  class BaseQueue(object):
      """Abstract/Virtual Class 
      """
      def __init__(self):
          self.contents = list()
          raise NotImplementedError
      def Enqueue(self, item):
          raise NotImplementedError
      def Dequeue(self):
          raise NotImplementedError
      def Print_Contents(self):
          for i in self.contents:
              print i,

</python>

Python allows multiple inheritance and it's more common to implement "mix-in" classes rather than abstract interfaces. (Mix-in classes can implement functionality as well define interfaces).

In this example we're simply following the Python convention of raising the built-in "NotImplementedError" for each function which must be implemented by our subclasses. This is a "purely virtual" class because all of its methods raise the exception. (It is sufficient for __init__ to do so for any partial virtual abstractions since that still ensures that the exception will be raised if anyone attempts to instantiate the base/abstract class directly rather than one of its concrete (fully implemented) descendents).

The method signatures and the instantiation of a "contents" list shown here can be viewed as documentary hints to anyone inheriting from this class. They won't actually do anything in the derived classes (since these methods must be over-ridden therein).

In this case we've implemented one method (Print_Contents). This would be inherited by any derived classes. It could be over-ridden, of course. If it's not over-ridden it establishes a requirement that all derived classes provide some "contents" attribute which must allow for iteration and printing as shown. Without this method the class would be "purely virtual" or "purely abstract." With its inclusion the class becomes "partially implemented."

Note: This "BaseQueue" example should not be confused with Python's standard library Queue class. That is used as the principle "producer/consumer" communications mechanism among threads (and newer multiprocessing processes).