Abstractions

Abstractions in Paml define contracts and object/value data composition, and provide ability for "is a" relation and subtyping polymorphism.

Abstractions in Paml are similar to abstract classes in C#, but instead of inheritance they actually provide object compositions.

An abstraction can have data (for values and objects) and/or messages (for objects). Abstraction data are aggregated in objects and values into compositions. Abstraction messages are similar to interfaces in C# and define contract behavior for composing objects.

Abstractions cannot be instantiated; they can only be used as parts for object/value compositions. Abstractions can have messages with implementation and they (messages) become the behavior of composing objects as well.

Unlike from virtual base classes in C++, multiple abstractions in an object are not combined or joined into single definition. If an object belongs to multiple abstractions and they have data or messages with the same names/signatures, each of them can be accessed with explicit specifying which abstraction is in mind.

Messages from abstractions are implemented in objects with the syntax similar to explicit interface implementation in C#.

In Paml there is no feature like virtual methods; behavior from abstractions is a contract like interfaces in C#. The reason of such decision is that virtual methods in languages such C# is dangerous in the sense that they can corrupt behavior of base class contract. This is resolving by "Template Method" design pattern. But in Paml, routines with transformations have actually the same semantics and behavior, but more powerful and generalized.

Also in Paml there is no explicit "as" operator that casts a base type to derived one (that's to some abstraction). One reason is that in Paml there is no null term. The second is that for this semantics the syntax of constructor call is used, because conceptually we receive an object of some type like we create it with the existing variable as an argument.

abstraction Shape
{
data X, Y : integer;
message MoveTo ( val x : integer, val y : integer )
{
this.X = x;
this.Y = y;
}
message Draw ( obj canvas : Canvas );
}
object Circle is Shape
{
data Radius : integer;
message Shape.Draw ( obj canvas : Canvas )
{
TODO:
}
}
object Square is Shape
{
data Length : integer;
message Shape.Draw ( obj canvas : Canvas )
{
TODO:
}
}
subject Painter
{
collaborator Canvas;
col Shapes of Shape;
message Render
{
this . Canvas -> Clear ( ) ;
this.Shapes (shape)
forEach {
shape->Draw (this.Canvas) };
}
message RenderCircles
{
this . Canvas -> Clear ( ) ;
this.Shapes (shape)
where {
shape is Circle }
select {
Circle(shape) } (circle) Cast shape to circle, the syntax is similar to "constructor" call
forEach {
circle->Draw (this.Canvas) };
}
message RenderCircle (circle)
{
Casting to abstraction if an object has multiple abstractions to resolve possible name conflicts
obj shape = Shape(circle);
shape->Draw ( this.Canvas );
}
Parameter type is inferred by convention as "Circle"
message AddCircle (circle)
{
add (this.Shapes, circle); "add" is an operator in N-arity syntax
or
this.Shapes add circle; "add" is an operator in binary syntax
}
message AddSquare (square)
{
this.Shapes add square;
}
}

Write a comment

Comments: 0

Pallada project, Copyright © 2015 - 2021.

For any mentions and citations of the site materials, a link to the Pallada project site is obligatory.