Polymorphism: Difference between revisions

Content added Content deleted
(→‎{{header|Kotlin}}: Added a Logtalk example.)
Line 2,423: Line 2,423:
Circle at center (5, 6), radius 8
Circle at center (5, 6), radius 8
</pre>
</pre>

=={{header|Logtalk}}==

Logtalk is a declarative form of OOP, not imperative, so many of the requirements of the task, while hypothetically being possible in Logtalk, are not going to be native idioms in it and will lead to code that is hard to read, reason about, and maintain (as they, indeed, do in imperative OOP). As such the notion of "copy constructor" and other stateful issues will not be addressed.

Logtalk supports both prototypal OOP as well as classical OOP. This example illustrates the prototypal solution as it is the most straightforward. It also uses the notion of parametric objects as a more natural way of expressing the relationship. The advantages of such will be explained in a later example.

=== shapes.lgt ===

<syntaxhighlight lang="logtalk">:- object(point(_X_, _Y_)).

:- public([x/1, y/1, print/0]).
x(_X_).
y(_Y_).

print :- logtalk::print_message(information, shapes, @point(_X_,_Y_)).

:- end_object.

:- object(circle(_X_, _Y_, _R_),
extends(point(_X_, _Y_))).

:- public([r/1]).

r(_R_).

print :- logtalk::print_message(information, shapes, @circle(_X_,_Y_,_R_)).

:- end_object.</syntaxhighlight>

In the following output, any text after `%%` is a pedagogical comment and does not show up in the actual output. Running from the Logtalk toplevel:

{{out}}
<pre>
%% First we bring in the shapes code.
?- logtalk_load(shapes). %% or `{shapes}.` in most back-ends.
% [ c:/users/michael t. richter/documents/shapes.lgt loaded ]
% (0 warnings)
true.

%% The following is a single query at the toplevel, broken out into multiple lines for clarity.
?- P = point(1, 2), %% `P` is unified with the term `point(1, 2)` (assignment...ish)
| P::print, %% send the `print` message to the object `point(1, 2)`
| P::x(X), %% get the X value of the object `point(1, 2)` by sending the `x` message
| P::y(Y). %% get the Y value of the object `point(1, 2)` by sending the `y` message
% point(1,2) %% output of P::print
P = point(1, 2), %% value of P after executing this query
X = 1, %% value of X after executing this query
Y = 2. %% value of Y after executing this query

%% The following is, again, a single query at the toplevel broken out into multiple lines.
%% Only important differences will be noted.
?- C = circle(3, 2, 1), %% `C` is unified with the term `circle(3, 2, 1)`
| C::print,
| C::x(X),
| C::y(Y),
| C::r(R).
% circle(3,2,1) %% circle/3's print method was be called on this message
C = circle(3, 2, 1),
X = 3, %% x/1 and y/1 are called from point/2's implementation to set X and Y
Y = 2,
R = 1. %% R, however, is set from circle/3's implementation

%% A shorthand for the first example:
?- P = point(1,2),
| P::(print, x(X), y(Y)).
% point(1,2)
P = point(1, 2),
X = 1,
Y = 2.

%% A shorthand for the second example:
?- C = circle(3, 2, 1),
| C::(print, x(X), y(Y), r(R)).
% circle(3,2,1)
C = circle(3, 2, 1),
X = 3,
Y = 2,
R = 1.
</pre>

Now consider this source code to illustrate some of the features of this implementation of shapes.

=== shapes_demo.lgt ===

<syntaxhighlight lang="logtalk">point(1, 2).
point(3, 4).
point(5, 6).

circle(30, 20, 10).
circle(40, 30, 20).
circle(50, 40, 30).</syntaxhighlight>

Here we have merely supplied a set of "facts": simple term assertions. These are not objects. These are not constructor calls. They are simply declarative statements in Logtalk (which in this case operate as in native Prolog).

Continuing from the toplevel:

{{out}}
<pre>
%% Showing that these are just Prolog facts.
?- point(X, Y).
X = 1,
Y = 2 ;
X = 3,
Y = 4 ;
X = 5,
Y = 6.

?- circle(X, Y, R).
X = 30,
Y = 20,
R = 10 ;
X = 40,
Y = 30,
R = 20 ;
X = 50,
Y = 40,
R = 30.
</pre>

Why does this matter? Because in Logtalk terms can be proxies for parametric objects using the `{...}` operator. Combining with the shortcut `(...)` syntax demonstrated earlier:

<pre>
%% For each point, bind consecutively with X and Y.
?- {point(_, _)}::(x(X), y(Y)).
X = 1,
Y = 2 ;
X = 3,
Y = 4 ;
X = 5,
Y = 6.

%% For each circle, print the circle contents and bind the radius.
?- {circle(_, _, _)}::(print, r(R)).
% circle(30,20,10)
R = 10 ;
% circle(40,30,20)
R = 20 ;
% circle(50,40,30)
R = 30.
</pre>

Here we can see that although the contents of `shapes_demo.lgt` is only a database of simple (Prolog) facts, those facts can, in fact, be iterated over using backtracking and be treated as Logtalk objects. When queried as proxies, the facts __did not have parameter bindings__. (`_` is the "don't care; don't bind" parameter in Prolog and Logtalk.) Yet we were still able to treat them as the objects in question, sending the messages and binding to their parameterized values through the object code.


=={{header|Lua}}==
=={{header|Lua}}==