Difference between revisions of "Language Reference/Generic Interfaces and Classes"
m (Consistency (TypeParameter => TypeVariable)) |
(→Syntax: lines) |
||
Line 72: | Line 72: | ||
<vipbnf><InterfaceDeclaration> : | <vipbnf><InterfaceDeclaration> : | ||
interface <InterfaceName> { <ScopeTypeVariable>-comma-sep-list-opt } <ScopeQualifications> <Sections> end interface <InterfaceName>-opt | interface <InterfaceName> { <ScopeTypeVariable>-comma-sep-list-opt } | ||
<ScopeQualifications> | |||
<Sections> | |||
end interface <InterfaceName>-opt | |||
<ScopeTypeVariable> : | <ScopeTypeVariable> : |
Revision as of 11:42, 24 October 2012
Interfaces and classes can be parametrized with type parameters so that they can be used in different instantiations in different contexts.
This section must be considered as an extension to the individual sections about:
The pragmatic reason to use generic classes and interfaces is to declare parametrized object facts and implement operations on these facts. As illustrated in the Queue example below.
Example: Queue
Consider this interface
interface queue_integer predicates insert : (integer Value). tryGet : () -> integer Value. end interface queue_integer
An object of this type is a queue of integers, if you replace "integer" with "string" you would have a type describing queues of strings.
A generic interface can be used to describe all such interfaces in a single interface definition:
interface queue{@Elem} predicates insert : (@Elem Value). tryGet : () -> @Elem Value determ. end interface queue
@Elem is a scope type variable (distinguished from local type variables by the @).
queue{integer} represents integer-queues; queue{string} represents string-queues; and so forth.
We can declare a generic queue class like this:
class queueClass{@Elem} : queue{@Elem} end class queueClass
queueClass{@Elem} constructs objects type queue{@Elem} for any instantiation of @Elem.
The implementation can look like this:
implement queueClass{@Elem} facts queue_fact : (@Elem Value). clauses insert(Value) :- assert(queue_fact(Value)). clauses tryGet() = Value :- retract(queue_fact(Value)), !. end implement queueClass
This piece of code illustrates how to create an integer queue and insert an element in it:
..., Q = queueClass{integer}::new(), Q:insert(17), ...
It is not necessary to apply the type explicitly, instead the compiler can infer it from the context:
..., Q = queueClass::new(), Q:insert(17), ...
The compiler sees that Q must be an integer queue, because we insert 17 into it.
Generic Interfaces
Syntax
Generic interfaces have a list of type parameters:
InterfaceDeclaration : interface InterfaceName { ScopeTypeVariable-comma-sep-list-opt } ScopeQualifications Sections end interface InterfaceName-opt ScopeTypeVariable : @ UppercaseName
The scope type parameters can be used in any declaration/definition in the interface.
Semantics
A generic interface defines all the interfaces that can be obtained by instantiating the type parameters with actual types. The scope type parameters from the opening are bound in the entire interface.
Restrictions
Then closing name should not have parameters:
interface xxx{@A} ... end interface xxx % no parameters here
It is illegal to use same interface name for interfaces with different arity (in the same namespace):
interface xxx % xxx/0 ... end interface xxx interface xxx{@A, @B} % error: Several classes, interfaces and/or namespaces have the same name 'xxx' ... end interface xxx
Parameters can be used in supported interfaces:
interface xxx{@P} supports yyy{@P} % legal: @P is bound ... end interface xxx interface xxx supports yyy{@P} % illegal: @P must be bound ... end interface xxx
Supported interfaces can be instantiated with any type expressions (as long as parameters are bound):
interface xxx{@A} supports yyy{integer, @A*} ...
Generic Classes
Syntax
Generic classes have a list of type parameters, and constructs objects of an interface type uses the these parameters.
ClassDeclaration : class ClassName { ScopeTypeVariable-comma-sep-list-opt } ConstructionType ScopeQualifications Sections end class ClassName-opt ... ScopeTypeVariable : @ UppercaseName ConstructionType : : TypeExpression
The construction type must be generic (i.e. a generic interface).
Semantics
A generic class declares a class with a generic constructor. The type of the constructed object will be inferred from the usage of the constructor.
Restrictions
Then closing name should not have parameters:
class xxx{@A} : xxx{@AAA} ... end class xxx % no parameters here
It is illegal to use same class name for class with different arity (in the same namespace):
class xxx % xxx/0 ... end class xxx class xxx{@A} : yyy{@A} % error: Several classes, interfaces and/or namespaces have the same name 'xxx' ... end class xxx
If a class and interface can have the same name, the class must construct objects of that interface.
interface xxx{@A} ... end interface xxx class xxx{@Q, @P} : object % error: Several classes, interfaces and/or namespaces have the same name 'xxx' ... end class xxx
Parameters in the construction type, etc must be bound:
class bbb : xxx{@Q} % error: Free parameter '@Q' is used in type expression ...
All the parameters from the class must be used in the construction type:
class xxx{@P} : object % error: Unused type parameter '@P' ...
In class declarations scope parameter can only be used in constructors, domains and constants.
class xxx{@P} : xxx{@P} domains list = @P*. % legal constants empty : @P* = []. % legal constructors new : (@P Init). % legal predicates p : (@P X). % error: Scope parameter '@P' used in a class entity end class xxx
Generic Implmentations
Syntax
Generic implementations have a list of type parameters.
ClassImplementation : implement ClassName { ScopeTypeVariable-comma-sep-list-opt } ScopeQualifications Sections end implement ClassName-opt ... ScopeTypeVariable : @ UppercaseName
Semantics
A generic class declares a class with a generic constructor. The type of the constructed object will be inferred from the usage of the constructor.
Restrictions
Then closing name should not have parameters:
implement xxx{@A} ... end implement xxx % no parameters here
The parameters must be the same as in the corresponding class declaration and have same order.
class xxx{@A} : aaa{@A} ... end class xxx implement xxx{@B} % error: The parameter '@B' is not the same as in the declaration '@A' ... end implement xxx
In class implementations scope parameter can be used in constructors, domains, constants and in object entities (i.e. object facts, object predicates and object properties).
implement xxx{@P} domains list = @P*. % legal constants empty : @P* = []. % legal constructors new : (@P Init). % legal predicates op : (@P X). % legal class predicates cp : (@P X). % error: Scope parameter '@P' used in a class entity facts ofct : (@P). % legal class facts cfct : (@P). % error: Scope parameter '@P' used in a class entity ... end implement xxx