1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530
|
\newcounter{theexercise}
\setcounter{theexercise}{1}
\newenvironment{exercises}{%
\section{Exercises}
\begin{enumerate}}{%
\end{enumerate}}
\newcommand{\exercise}[1]{%
\item[Exercise \arabic{theexercise}]\hfil%
\addtocounter{theexercise}{1} \\ #1}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\chapter{Getting the Dialogue}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Creating and Manipulating Objects}
XPCE is an object-oriented system and defines four predicates that
allows you to create, manipulate, query and destroy objects from
Prolog: new/2, send/[2-12], get/[3-13] and free/1:
\begin{code}
?- new(X, point(5, 6)).
X = @791307/point
\end{code}
Created an instance of class `point' at location (5,6). In general,
The first argument of new/2 provides or is unified to the {\em object
reference}, which is a Prolog term of the functor @/1. The second
argument is a ground Prolog term. The function describes the class
from which an instance is to be created, while the arguments provide
initialisation arguments.
New/2 may also be used to create objects with a predefined object
reference:
\begin{code}
?- new(@s, size(100, 5)).
Yes
\end{code}
Created an instance of class size with width 100 and height 5. We call
@s a `named' or `global' object reference.
\begin{code}
?- send(@791307, x, 7).
Yes
\end{code}
Send {\em Manipulates} objects. In the example above, the X-coordinate
of the point is changed to 7. The first argument of send is the
object-reference. The second is the {\em selector} and the remaining
arguments (up to 10) provide arguments to the operation.
\begin{code}
?- get(@791307, distance, point(0,0), D).
D = 9
\end{code}
Get {\em requests} the object to return (compute) a value. In this case
this is the (rounded) distance to the origin of the coordinate system.
The arguments to get/[3-13] are the same as for send/[2-12], but
get/[3-13] requires one additional argument for the return value.
Finally, the following call destroys the created object.
\begin{code}
?- free(@791307).
Yes
\end{code}
\section{Creating Windows is More Fun}
In the previous section we have seen the basic operations on objects.
In this section we will give some more examples to clarify object
manipulation. In this section we will use windows and graphics.
\begin{code}
?- new(P, picture('Hello World')),
send(P, display, text('Hello World'), point(20, 20)),
send(P, open).
P = @682375
\end{code}
First created a picture (=graphics) window labeled `Hello World',
displays a text (graphical object representing text) on the picture at
location (20,20) from the top-left corner of the window and finally
opens this window on the display:
\postscriptfig[width=3in]{hello}{Screendump for the `Hello World' window}
\section{Architecture}
XPCE is a C-library written in an object-oriented fashion.%
\footnote{It was developed before C++ was in focus. We are
considering C++ but due to the totally different viewpoints
taken by XPCE (symbolic, dynamically typed) and C++ (strong
static typing) it is unclear whether any significant
advantage is to be expected.}
This library is completely dynamically typed: each data element is
passed the same way and the actual type may be queried at runtime if
necessary. Also written in C is a meta-layer that describes the
functions implementing the methods and the C-structures realising the
storage. The meta-layer is written in the same formalism as the rest of
the system and describes itself. C-functions allow for invoking methods
(functions) in this library through the meta-layer. This sub-system is
known as the message passing system or PCE virtual machine. This
machine implements the 4 basic operations of XPCE: new(), send(), get()
and free().
The `host' language (Prolog in this document) drives the PCE virtual
machine instructions through the Prolog to C interface.
PCE predefines class `host' and the instance @prolog. Messages send
to this object will call predicates in the Prolog environment:
\begin{code}
?- send(@prolog, format, 'Hello World~n', []).
Hello World
\end{code}
makes Prolog call PCE send() through its foreign interface. In turn,
the message to the @prolog is mapped on the predicate format. Note
however that both systems have their own data representation. Try
\begin{code}
?- send(@prolog, member, A, [hello, world]).
\end{code}
PCE has nothing that resembles a logical variable and thus will complain
that `A' is an illegal argument. Neither the following will work as
Prolog lists have no counterpart in XPCE:%
\footnote{The empty list [] is an atom, and thus maybe passed!}
\begin{code}
?- send(@prolog, member, hello, [hello, world]).
\end{code}
And finally, Calls to PCE cannot be resatisfied:
\begin{code}
?- send(@prolog, repeat), fail.
No
\end{code}
Figure~\ref{fig:control} summarises the data and control flow
in the XPCE/Prolog system.
\postscriptfig[width=\textwidth]{control}{Data and Control flow in PCE/Prolog}
\section{The Manual Tools} \label{sec:manualtools}
The manual tools are started using the Prolog predicate manpce/[0,1]%
\footnote{Quintus: user_help/0. To use manpce/1, load the
library(pce_manual).}
Just typing manpce creates a small window on your screen with a menu
bar. The most useful options from this menu are:
\begin{description}
\item[File/Demo Programs] starts a demo-starter which also provides
access to the sources of the demo's.
\item[Browsers/Class Hierarchy] examines the inheritance hierarchy
of PCE classes. Most classes are right below class object. Useful
sub-trees are program_object (PCE's class en executable world),
recogniser (event handling) and visual (anything that can appear on
the screen.
\item[Browsers/Class Browser] is the most commonly used tool. It
displays attributes of a class. Various searching options allow for
finding candidate methods or classes. The {\bf Scope} option
needs explanation. By default it is set to `own', making the tool
search only for things (re)defined on this class. Using scope
`Super' will make the browser show inherited functionality too. Using
scope `sub' is for searching the entire class hierarchy below the
current class.%
\footnote{The current implementation does not show {\em delegated}
behaviour.}
\item[Browsers/Global Objects] visualises all predefined (named) objects:
@pce, @prolog, @display, @arg1, @event, etc.
\item[Browsers/Search]
Provides a {\sc wais} search facility for the entire hypercard system.
\item[Browsers/Group OverView] provides an overview of functionally related
methods. Typing in the window searches.
\item[Tools/Visual Hierarchy] provides an overview of the consists
of hierarchy of GUI components.
\item[Tools/Inspector] to analyse the structure of objects.
\item[History] allows you to go back to previously visited cards.
\end{description}
Manpce/1 accepts a classname, in which case it switches the ClassBrowser
to this class. It also accepts a term of the form `class <-selector' or
`class ->selector', in which case it will pop up the documentation card
of the indicated card. Try
\begin{code}
?- manpce((display ->inform)).
\end{code}
\begin{exercises}
\exercise{%
Start the PCE manual tools and find answers to the following questions:
\begin{enumerate}
\item What is the super-class of class `device'?
\item Find the description of class `tree'. Which different layouts
are provided by class tree?
\item Which attributes describe the appearance of a box?
\item Which classes (re)define the ->report method?
\end{enumerate}
}
\exercise{%
Examine the structure of the inheritance path visualisation as shown in
the top-right window of the ClassBrowser using the VisualHierachy tool.
}
\exercise{%
Class device defines compound (`nested') graphical objects. Define a
predicate make_text_box(?Ref, +Width, +Height, +String), which creates
a box with a centered text object. Test your predicate using:
{\tt\obeyspaces
?- send(new(P, picture), open), \\
make_text_box(B, 100, 50, 'Hi There'), \\
send(P, display, B, point(50, 20)).
}
}
\exercise{%
Class tree and class node define primitives for creating a hierarchy
of graphical objects. The method `directory <-directories' allow
you to query the Unix directory structure. Write a predicate
show_directory_hierarchy(+{\em DirName}) with displays the Unix
directory hierarchy from the given root.
Some methods and classes you might want to use are: class picture,
class tree, class node, class directory and the methods `node->son',
`directory <-directories' and `directory <-directory'.
}
\end{exercises}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\chapter{Programming Techniques}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Control Structure of Graphical Applications}
Interactive terminal operated applications often are implemented as
simple `Question-Answer' dialogues: the program provides a form, the
user answers the question(s) and the program continues its execution.
Graphical interfaces often allow the user to do much more than just
answering the latest question presented by the program. This
flexibility complicates the design and implementation of graphical
interfaces. Most interface libraries use an `event-driven'
control-structure.
\subsection{Event Driven Applications}
Using the event-driven control structure, the program creates the
UI objects and instructs the graphical library to start some operation
when the user operates the UI object. The following example illustrates
this:
\begin{code}
?- send(button(hello, message(@prolog, format, 'Hi There~n')), open).
Yes
\end{code}
This query creates a button object and opens the button on your screen.
The button is instructed to call the Prolog predicate format/1 with
the given argument when it is pressed. The query itself just returns
(to the Prolog toplevel).
Using this formalism, the overall structure of your application will be:
\begin{code}
initialise :-
initialise_database,
create_GUI_components.
call_back_when_GUI_xyz_is_operated(Context ...) :-
change_application_database(Context ...),
update_and_create_GUI_components.
\end{code}
This type of control structure is suitable for applications that define
operations on a database represented using the Prolog database or some
external persistent database (see also chapter~\ref{chap:data}.
Unfortunately `good' style Prolog programming often manipulates data
represented on the Prolog runtime stacks because destructive operations
on the Prolog database are dangerous and loose two important features of
Prolog: logical variables and backtracking.
The event-driven approach is commonly used by applications that present
and/or edit some external (persistent) database. As long as name
conflicts in the Prolog program and the global PCE name spaces (classes
and named object references (e.g.\ @prolog, @main_window)) are avoided,
multiple applications may run simultaneously in the same XPCE/Prolog
process. For example the PCE manual runs together with the various
PCE demo applications.
\subsection{Asking Questions: Modal windows}
Prolog applications that want to manipulate data represented on the Prolog
runtime stacks cannot use the event-driven approach presented above.
Unlike with event-driven applications, a single-threat Prolog system
can only run one task. The overall structure of such an application
is:
\begin{code}
application :-
initialise(Heap),
create_GUI_components(Heap),
process_events_until_computation_may_proceed,
proceed(Heap),
...
\end{code}
The `process_events_until_computation_may_proceed' is generally realised
using the methods `frame <-confirm' combined with `frame ->return'.
Suppose we have a diagnose system that presents a graphics
representation of the system to be diagnosed. The application wants to
the the user's hypothesis for the faulty component. The window has
implemented a selection mechanism, an ok button and a label to ask
the question. The relevant program fragment could read:%
\footnote{The variables are supposed to the instantiated to the
proper UI components. The construct ``Diagram?selection''
denotes a PCE `obtainer'. When the button is pressed,
PCE will send a message ->return to the frame. The
argument to this message the return value of
`get(Diagram, selection, Selection)'.}
\begin{code}
....
send(Label, format, 'Select hypothesis and press "OK"'),
send(OkButton, message,
message(Frame, return, Diagram?selection)),
get(Frame, confirm, Hypothesis),
....
\end{code}
\section{Executable Objects}
In the previous sections we have seen some simple examples of the
general notion of `PCE Executable Objects'. Executable objects in
PCE are used for three purposes:
\begin{itemize}
\tick{Define action associated with GUI component}
This is the oldest and most common usage. A simple example is below:
\begin{code}
?- new(D, dialog('Hello')),
send(D, append,
button(hello, message(@prolog, format, 'Hello~n', []))),
send(D, append,
button(quit, message(D, destroy))),
send(D, open).
\end{code}
\tick{Code fragment argument as method parameter}
The behaviour of various methods may be refined using a code object that
is passed as an (optional) parameter. For example, the method
`chain->sort' is defined to sort (by default) a chain of names
alphabetically. When the chain contains other objects than names or
sorting has to be done on another criterium, a code object may be
used to compare pairs of objects. Suppose `Chain' is a chain of
class objects which have to be sorted by name:
\begin{code}
...
send(Chain, sort, ?(@arg1?name, compare, @arg1?name)),
...
\end{code}
`?' is the class-name of a PCE `obtainer'. When executed, an obtainer
evaluates to the result of a PCE get-operation: @arg1?name%
\footnote{Equivalent to ?(@arg1, name): `?' is a Prolog infix
operator.}
evaluates to the return value of `get(@arg1, name, Name)'.
\tick{Implement a method}
A method represents the mapping of a `selector' to an `action'.
The action is normally represented using a PCE executable object.
Define methods is discussed further in section~\ref{sec:classes}.
\end{itemize}
\subsection{Procedures and Functions}
Like send- and get-operations, PCE defines both procedures and
functions. Procedures return success/failure after completion and
functions return a value (a PCE object or integer) or failure.
PCE defines the following procedures:
\begin{quote}
\begin{tabular}{ll}
\bf message & Invoke a send-operation \\
\bf assign & Variable assignment (see also `var') \\
\bf if & Conditional branch \\
\bf and & Sequence and logical connective \\
\bf or & logical connective \\
\bf not & logical connective \\
\bf while & loop \\
\verb$==$ & Equivalence test \\
\verb$\==$ & Non-Equivalence test \\
\verb$>, =, =<, >, >=$ & Arithmetic tests \\
\end{tabular}
\end{quote}
and defines the following functions
\begin{quote}
\begin{tabular}{ll}
\bf ? & Evaluates the result of get-operation \\
\bf progn & Sequence returning value \\
\bf when & Conditional function \\
\bf var & Variable (returning <-_value) \\
\bf *, +, -, / & Arithmetic operations \\
\end{tabular}
\end{quote}
A function is evaluated iff
\begin{enumerate}
\item It is the receiver of a get- or send-operation {\bf and}
the method is not defined on class function or a relevant
subclass. These classes define very few methods for general
object manipulation, which normally start with an '_'
(underscore).
\item It is passed as an argument to a method and the argument's
type-test does not allow for functions. This is true for
most arguments except for behaviour that requires a function.
\item It appears as part of another code object.
\end{enumerate}
\section{Creating PCE Classes} \label{sec:classes}
A PCE class defines common%
\footnote{Note that object can define individual methods and
variables.}
storage details and behaviour of its instances (objects). A PCE
class is an instance of class `class'. Behaviour, variables and
other important properties of classes are all represented using
normal PCE objects. These properties allow the Prolog programmer
to query and manipulate PCE's class world using the same primitives
as for normal object manipulation: send(), get(), new() and free().
\subsection{The Prolog Front End}
The XPCE/Prolog interface defines a dedicated syntax for defining
XPCE classes that have their method implemented in Prolog.%
\footnote{The XPCE/CommonLisp interface defines a dedicated
syntax for defining XPCE classes and methods where
the implementation is realised by PCE executable
objects. See \cite{PCE:lisp}}
The definition of an XPCE class from Prolog is bracketed by:
\begin{code}
:- pce_begin_class(ClassName, SuperClassName, [Comment]).
<variable and method definitions>
:- pce_end_class.
\end{code}
These two predicates manipulate Prolog's macro processing and Prolog's
operator table, which changes the basic syntax.
An (additional) instance variable for the class is defined using
\begin{code}
variable(Name, Type, Access, [Comment]).
\end{code}
Where `Name' is the name of the instance variable, `Type' defines the
type and `Access' the implicit side-effect-free methods:
{\tt\{none,get,send,both\}}.
The definition of a method is very similar to the definition of an
ordinary Prolog clause:
\begin{code}
name(Receiver, Arg1:Type1, ...) :->
"Comment"::
Normal Prolog Code.
\end{code}
Defines a send method for the current class. `Receiver', `Arg1', ...
are Prolog variables that are at runtime bound to the corresponding
XPCE objects. The body of the method is executed as any normal
Prolog clause body. The definition of a get method is very similar:
\begin{code}
name(Receiver, Arg1:Type1, ..., ReturnValue:ReturnType) :->
"Comment"::
Normal Prolog Code.
\end{code}
The body is supposed to bind `ReturnValue' to the return value of the
method or fail.
\subsection{Called methods}
Some methods are called by the infra-structure of XPCE. These methods
may be redefined to modify certain aspects of the class. The most
commonly redefined methods are:
\begin{table}
\begin{tabular}{lp{5in}}
initialise & Called when an instance of the class is created \\
unlink & Called when an instance is destroyed \\
event & Called when an event arrives on the (graphical) object \\
geometry & Called when the size/position of a (graphical) object
is changed \\
\end{tabular}
\end{table}
\subsection{Examples}
\subsubsection{Defining a two-dimensional matrix} \label{sec:2dvector}
The first example defines a class two-dimensional matrix of fixed size.
We want to be able to say:
\begin{code}
?- new(@matrix, matrix(3,3)).
?- send(@matrix, element, 2, 2, x).
?- send(@matrix, element, 1, 2, o).
\end{code}
We will implement the two-dimensional matrix as a subclass of the one
dimensional vector:
\begin{code}
:- pce_begin_class(matrix(width, height), vector, "Two-dimensional array").
variable(width, int, get, "Width of the matrix").
variable(height, int, get, "Height of the matrix").
initialise(M, Width:int, Height:int) :->
"Create matrix fom width and and height"::
send(M, send_super, initialise),
send(M, slot, width, Width),
send(M, slot, height, Height),
Size is Width * Height,
send(M, fill, @nil, 1, Size).
element(M, X:int, Y:int, Value:any) :->
"Set element at X-Y to Value"::
get(M, width, W),
get(M, height, H),
between(1, W, X),
between(1, H, Y),
Location is X + (Y * (W-1)),
send(M, send_super, element, Location, Value).
:- pce_end_class.
\end{code}
\subsubsection{Defining a graphical matrix (table)}
In the second example, we will define a graphical matrix of textual
values and similar access functions to set/get the (string) values
for the cells. We will use class device as a starting point. Class
device defines a compound graphical object.
\begin{code}
:- pce_begin_class(text_table(width, height), device,
"Two-dimensional table").
initialise(T, W:int, H:int, CellWidth:[int], CellHeight:[int]) :->
"Create from Width, Height and cell-size"::
send(T, send_super, initialise),
default(CellWidth, 80, CW),
default(CellHeight, 20, CH),
Pen = 1,
between(1, W, X),
between(1, H, Y),
GX is (X-1) * (CW-Pen),
GY is (Y-1) * (CH-Pen),
send(T, display, new(B, box(CW, CH)), point(GX, GY)),
send(B, pen, Pen),
new(Txt, text('', center)),
xy_name(X, Y, XYName),
send(Txt, name, XYName),
send(Txt, center, point(GX + CW/2, GY + CH/2)),
send(T, display, Txt),
fail ; true.
element(T, X:int, Y:int, Value:char_array) :->
"Set text of cell at X-Y"::
xy_name(X, Y, XYName),
get(T, member, XYName, Text),
send(Text, string, Value).
xy_name(X, Y, Name) :-
get(string('%d,%d', X, Y), value, Name).
:- pce_end_class.
\end{code}
\begin{exercises}
\exercise{%
Extend class matrix with a get-method <-element. See what happens if
you define the return-type incorrect (for example as `int').
}
\exercise{%
We would like to {\em visualise} a matrix using a text_table object,
such that changes to the matrix are reflected on the text_table and
modifications of the text_table are reflected in the matrix.
XPCE does not provide a built-in model/controller architecture such as
SmallTalk. There are various ways to relate objects to each other:
object-level attributes (see `object <->attribute'), instance-variables
and finally `hyper-links'. See class hyper.
Try to realise the mapping using hyper objects. See class hyper and
`object ->send_hyper'. What are the (dis)advantages of all these
techniques?
}
\exercise{%
Advanced usage! Suppose the matrix is used in heavy computations and
modified often. This would imply passing through the mechanism
described above many times. The display is not updated for each
intermediate state (unless you explicitly request this using `graphical
->flush').
To avoid part of the computation as well, you can use the mechanism
described by `graphical ->request_compute' and `graphical ->compute'.
Try to implement this interface.
}
\end{exercises}
\section{Types}
XPCE is an untyped language like Prolog. This allows the system
to define container classes such as class chain, vector, hash_table
etc.\ in a comfortable fashion. Unlike Prolog however, XPCE {\bf
allows} you to declare types. Types are used for four purposes:
\begin{itemize}
\tick{Documentation}
Given the name, argument-names and argument-types for each method
generally suffices to get a strong clue on what it does.
\tick{Run-time trapping of errors}
The earlier errors are trapped, the easier it is to locate the
errornous statement in your source!
\tick{Run-time conversion}
Each type defines a validation method and a conversion method.
If the first fails, the second is tried to convert the input value
to the requested type. For example if the expected argument is
of type `int' and you provide the string ``554'' it will gracefully
convert ``554'' to the integer 554 and pass this value to the
implementation of the method.
\tick{Ensuring some level of consistency in the data}
The predicate checkpce/0 collects all instances and verifies that
each instance-variable is consistent with the type-declaration.
\end{itemize}
\subsection{Types are not (only) classes}
Types are first-class objects that defined {\em validation} and {\em
conversion}. Type objects are seldomly defined using
\mbox{new(X,~type(...))}, but normally by conversion of a
type-description to a type object. Here is a brief summary of the
syntax used by `type <-convert':
\begin{tabular}{lp{4in}}
\tt Name=Type &Argument named `Name' of type `Type' \\
\tt Type ... &Zero or more of these arguments.
Used in variable-arguments methods. \\
\verb$Type1|Type2$ &Disjunction (either of the types) \\
\tt Type* &The type or the constant @nil \\
\tt [Type] &The type or @default (optional argument) \\
\tt \{Name1,Name2\} &One of these names \\
\tt int &An integer (the only non-object datum) \\
\tt 3..5 &An integer 3 $\leq$ value $\leq$ 5 \\
\tt 3.2..5.6 &A real (float) in this range \\
\tt 3.. &An integer $\geq$ 3 \\
\tt ..3 &An integer $\leq$ 3 \\
\tt ClassName &Any instance of this class (or sub-class) \\
\tt alien:char * &Alien (C) data. In this case a char *
\end{tabular}
\subsection{Programming conversion}
The reserved get-method <-convert has the task to convert an incomming
object to an instance of the specified class.
\begin{exercises}
\exercise{%
If an argument is specified as type `bool', what values are acceptable
as input.
}
\exercise{%
Advanced usage: A very common usage for conversion is a class with
uniquely named reusable objects. Try to define such a class. You will
have to define the methods ->initialise, <-lookup and <-convert. }
\end{exercises}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\chapter{Tracing and Debugging}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
This chapter provides a brief overview of the tracer. Besides the
tracer, the VisualHierachy and Inspector tools are very useful
tools for locating problems with your application. See
section~\ref{sec:manualtools}.
\section{Tracing PCE Methods and Executable Objects}
XPCE offers tracing capabilities that are similar to those found in
many Prolog and Lisp environments. The XPCE tracer is defined at
the level of class program_object. Executable objects (messages,
etc.), and methods are the most important subclasses of class
program_object. Execution of program_objects can be monitored at
three `ports':
\begin{itemize}
\tick{The call port}
Entry point of executing the object.
\tick{The exit port}
The object executed successfully.
\tick{The fail port}
Execution of the object failed.
\end{itemize}
On each port, the user can specify a {\bf trace-} point or a {\bf
break-} point. A trace-point will cause a message printed when the
port is `passed'. A break-point will do the same and start the
interactive tracer (similar to a {\it spy-} point in Prolog.
The Prolog predicates ({\tt no})tracepce/1 and ({\tt no})breakpce/1%
\footnote{The XPCE debugging predicates are defined in the
library pce_debug. For Prolog systems lacking
autoload you need to do
{\tt ?- [library(pce_debug)].}}
provide a friendly interface for setting trace- and break-points on
methods. Example:
\begin{code}
?- tracepce((point->x)).
Trace variable: point <->x
?- new(P, point), send(P, x, 20).
PCE: 2 enter: V @892203/point <->x: 20
PCE: 2 exit: V @892203/point <->x: 20
P = @892203/point
\end{code}
Both tracepce/1 and breakpce/1 accept a specification of the form
$<$Class$>$ {\tt ->, <- or -}$<$Selector$>$.
\begin{code}
?- tracepce((box->device)).
?- send(new(@p, picture), open).
?- send(@p, display, new(@b, box(20,20))).
\end{code}
\subsection{Trapping situations: conditional breaks}
Suppose a graphical is at some point erased from the screen while you
do not expect this to happen. How do you find what is causing the
graphical to disappear and from where this action is called? If your
program is small, or at least you can easily narrow down the possible
area in your code where the undesired behaviour happens, just using
the Prolog tracer will generally suffice to find the offending call.
What if your program is big, you don't know the program to well and
you have no clue? You will have to work with conditional trace- and
breakpoints to get a clue. If you know the reference of the offending
object (lets assume @284737), you can spy all send-operations invoked
using:
\begin{code}
?- send(@vmi_send, trace, @on, full, @receiver == @284737).
\end{code}
If---for example---you finally discovered that the object is sent
the message ->device: @nil, you can trap the tracer using:
\begin{code}
?- send(@vmi_send, break, @on, call, and(@receiver == @284737,
@selector == device)).
\end{code}
\begin{exercises}
\exercise{%
Consider PceDraw. Use the XPCE tracer to find out what happens to
an object if the {\em Cut} operation is activated.
}
\end{exercises}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\chapter{Dialogue Windows in Depth}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Modal Dialogue Windows (Prompters)}
A common use is to query or inform the user during an ongoing task. The
task is blocked until the user presses some button. For example, the
user selected `Quit' and you want to give the user the opportunity to
save before doing so or cancel the quit all the way.
{\em Model} dialog windows are the answer to the problem. In XPCE,
Windows by themselves are not {\em modal}, but any window may be
operated in a {\em modal} fashion using the method `frame <-confirm'.
This method behaves as `frame->open' and next starts an
event-dispatching subloop until `frame ->return' is activated. So,
our quit operation will look like this:
\begin{code}
quit :-
new(D, dialog('Quit my lovely application?')),
( application_is_modified
-> send(D, append,
button(save_and_quit,
message(D, return, save_and_quit)))
; true
),
send(D, append, button(quit, message(D, return, quit))),
send(D, append, button(cancel, message(D, return, cancel))),
get(D, confirm, Action),
send(D, destroy),
( Action == save_and_quit
-> save_application
; Action == quit
-> true
),
send(@pce, die).
\end{code}
\section{Entering Values}
Operations often require multiple values and dialog windows are a
common way to specify the values of an operation. Actually executing
the operation is normally associated with a button. Below is an
example of a dialog for this type of operations.
\begin{code}
create_window :-
new(D, dialog('Create a new window')),
send(D, append, new(Label, text_item(label, 'Untitled'))),
send(D, append, new(Class, menu(class, choice))),
send_list(Class, append,
[ class(window),
class(picture),
class(dialog),
class(browser),
class(view)
]),
send(D, append,
new(Width, slider(width, 100, 1000, 400))),
send(D, append,
new(Height, slider(height, 100, 1000, 200))),
send(D, append,
button(create,
message(@prolog, create_window,
Class?selection,
Label?selection,
Width?selection,
Height?selection))),
send(D, append,
button(cancel, message(D, destroy))),
send(D, open).
create_window(Class, Label, Width, Height) :-
get(Class, instance, Label, Window),
send(Window?frame, set, @default, @default, Width, Height),
send(Window, open).
\end{code}
Note that a menu accepts the method ->append: menu_item. Class
menu_item defines a type-conversion converting any value to a
new menu_item using the value as `menu_item <->value'. The visible
labels of the menu_items are generated automatically (see `menu_item
<-default_label').
The action associated with the button is a message invoking the Prolog
predicate create_window/4. Four obtainers collect the values to be
passed.
\section{Editing Attributes of Existing Entities}
All dialog items that may be used to edit attributes (i.e.\ represent
some value) define a <->default value and the methods ->restore and
->apply. <->default specifies an XPCE {\em function} object or plain
value. On ->restore, the <-selection is restored to the <-default or
the result of evaluating the <-default function. ->apply will execute
<-message with the current <-selection if the <-selection has been
changed by the user.
Class dialog defines the methods ->restore and ->apply, which
will invoke these methods on all items in the dialog that understand
them. This schema is intended to define {\em attribute} editors
comfortably.
Below we define a dialog-window to edit some appearance values of a
box object.
\begin{code}
edit_box(Box) :-
new(D, dialog(string('Edit box %N', Box))),
send(D, append,
text_item(name, Box?name, message(Box, name, @arg1))),
send(D, append,
new(S, slider(pen, 0, 10, Box?pen, message(Box, pen, @arg1)))),
send(S, width, 50),
send(D, append, button(apply)),
send(D, append, button(restore)),
send(D, append, button(cancel, message(D, destroy))),
send(D, default_button, apply),
send(D, open).
\end{code}
\section{Status, Progress and Error Reporting}
XPCE defines a standard protocol for reporting progress, errors,
status, etc. This protocol is implemented by two methods: the
send-method ->report and the get-method <-report_to. The aim
is to provide the application programmer with a mechanism that
allows for reporting things to the user without having to know
the context of the objects involved.
\subsection{Generating reports}
For example, you define a predicate my_move that moves a graphical
to some location, but not all locations are valid. You can simply
define this using:
\begin{code}
my_move(Gr, Point) :-
( valid_position(Gr, Point)
-> send(Gr, move, Point)
; send(Gr, report, warning,
'Cannot move %N to %N', Gr, Point)
).
\end{code}
The first argument of ->report is the type of report. The reporting
mechanism uses this information to decide what to do with the report.
The types are: {\em status}, {\em warning}, {\em error}, {\em inform},
{\em progress} and {\em done}.
\subsection{Handling reports}
A default report handling mechanism is defined that will try to
report in a {\em label} object called {\em reporter} in a dialog
window in the frame from where the command was issued. If no such
label can be found important (error, inform) reports are reported
using a confirmer on the display. Less serious (warning) are reported
using the ->alert mechanism (->bell, ->flash) and others are ignored.
Most applications therefore can just handle all reports by ensuring the
frame has a dialog window with a label called {\em reporter} in it.
In specific cases, redefining ->report or <-report_to can improve
error reporting.
\begin{exercises}
\exercise{%
Define a dialog based application that allows you to inspect the
properties of Prolog predicates. Use predicate_property/2 and
source_file/2. The dialog should have appropriate fields for
the file the predicate is defined in, whether it is dynamic
or not, multiple, built-in, etc.
Use a browser to display all available predicates. Double-clicking
on an predicate in the browser should show the predicate in the
dialog.
}
\end{exercises}
\section{Custom Dialog-Items}
As from XPCE version 4.7 (ProWindow 1.1), graphics and dialog_items are
completely integrated. This implies that custom dialog-items can be
constructed using general graphics as well as other dialog-items.
Dialog-items should respond in a well-defined manner to a number of
messages and have standard initialisation arguments. These methods
are:
\begin{description}
\sendmethod{item}{initialise}{Name:name, Default:[any], Message:[code]*}
Items are normally created from their {\em Name}, which is processed
by `char_array <-label_name' to produce a capitalised visible label,
the {\em Default} value and a message to execute on ->apply or
operation of the item.
\sendmethod{item}{selection}{Value:any}
Sets the selection. After this, <-modified is supposed to return
@off.
\getmethod{item}{selection}{Value:any}
Return the current selection.
\sendmethod{item}{default}{Value:any}
Sets the {\em default} value and the ->selection. If ->restore
is called after the user modified the item and before it is
->apply'd, the <-selection should be restored to the <-default.
Normally called by ->initialise. Normally implemented by setting
the -default slot and calling ->restore.
\sendmethod{item}{restore}{}
Normally simply invokes ->selection with <-default.
\sendmethod{item}{apply}{Force:[bool]}
If <-modified returns @on or Force equals @on, forward the
<-selection over @arg1 of the <-message.
\end{description}
The XPCE library (`@pce <-home'/prolog/library) contain various examples
of custom dialog items. See for example pce_font_item.pl (consists of
three cycle-menus for specifying a PCE font), pce_style_item.pl (enter
a style (font, colour, underline, etc.) for an editor-fragment). The
dialog editor contains various examples as well.
\begin{exercises}
\exercise{%
Study the pce_font_item.pl file. Use the font_item to control the
font of a simple text object. Analyse the structure of the application
using the Visual Hierarchy tool.
}
\end{exercises}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\chapter{Graphics}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
In this chapter we will build a little direct-manipulation graphical
editor. The application consists of a graphical editor that allows the
use to define entities and their interrelations involved.
\section{Graphical Devices}
A graphical device (class device) defines a compound graphical object
with it's own local coordinate system. Graphical devices may be nested.
Graphical devices are usually subclassed to define application-specific
visual representations. As a first step towards our graphical
application, we will define a box with centered text and a possibly grey
background.
\begin{code}
:- pce_begin_class(text_box, device, "Box with centered text").
resource(size, size, 'size(100, 50)', "Default size").
resource(label_font, font, '@helvetica_bold_12', "Font for text").
initialise(TB, Label:[name]) :->
"Create a box with centered editable text"::
send(TB, send_super, initialise),
get(TB, resource_value, size, size(W, H)),
get(TB, resource_value, label_font, Font),
send(TB, display, box(W, H)),
send(TB, display, new(T, text(Label, center, Font))),
send(T, transparent, @off),
send(TB, recenter).
recenter(TB) :->
"Center text in box"::
get(TB, member, box, Box),
get(TB, member, text, Text),
send(Text, center, Box?center).
geometry(TB, X:[int], Y:[int], W:[int], H:[int]) :->
"Handle geometry-changes"::
get(TB, member, box, Box),
send(Box, set, 0, 0, W, H),
send(TB, recenter),
send(TB, send_super, geometry, X, Y).
fill_pattern(TB, Pattern:image*) :->
"Specify fill-pattern of the box"::
get(TB, member, box, Box),
send(Box, fill_pattern, Pattern).
fill_pattern(TB, Pattern:image*) :<-
"Read fill-pattern of the box"::
get(TB, member, box, Box),
get(Box, fill_pattern, Pattern).
string(TB, String:char_array) :->
"Specify string of the text"::
get(TB, member, text, Text),
send(Text, string, String).
string(TB, String:char_array) :<-
"Read string of the text"::
get(TB, member, text, Text),
get(Text, string, String).
:- pce_end_class.
\end{code}
\section{Making Graphicals Sensitive} \label{sec:sensitive}
\subsection{Adding popup menus to graphicals}
In this section we will use the text_box defined in the previous section
to define a graphical editor that allows you to create a graph of with
text-boxes as nodes. In the first step we will define window that
allows us to add new text-boxes to it using a background popup. We
will prompt for the text to be put in the box.
\begin{code}
:- use_module(library(pce_prompter)).
make_graph_editor(E) :-
new(E, picture('Graph Editor')),
send(E, popup, new(P, popup(options))),
send_list(P, append,
[ menu_item(add_new_box,
message(@prolog, add_new_box,
E, E?focus_event?position)),
menu_item(clear,
and(message(@display, confirm,
'Clear entire drawing?'),
message(E, clear)))
]),
send(E, open).
add_new_box(E, Pos) :-
prompter('Name of box',
[ name:name = Name
]),
send(E, display, text_box(Name), Pos).
\end{code}
\subsection{Using gestures}
A gesture is an object that is designed to parse mouse-button event
sequences into meaningful actions. XPCE predefines gestures for
clicking, moving, resizing, linking and drag-drop of graphical objects.
All gesture classes are designed to be subclassed for more application
specific handling of button-events.
There are two ways to connect a gesture to a graphical object. The
first is `graphical ->recogniser' which makes the gesture work for
a single graphical object. The alternative is to define an ->event
method for the graphical. Below we will use this to extend our
text-box class with the possibility to move and resize the boxes.%
\footnote{In this example we define the class text_box in small
parts that can be loaded on top of each other. We
use {\tt :- pce_extend_class(+Class).} to continue
the class-definition.}
\begin{code}
:- pce_extend_class(text_box).
:- pce_global(@text_box_recogniser,
make_text_box_recogniser).
make_text_box_recogniser(R) :-
new(R, handler_group(new(resize_gesture),
new(move_gesture),
popup_gesture(new(P, popup(options))))),
TB = @arg1,
send_list(P, append,
[ menu_item(rename,
message(TB, rename),
end_group := @on),
menu_item(delete,
message(TB, free))
]).
event(TB, Ev:event) :->
( send(TB, send_super, event, Ev)
-> true
; send(@text_box_recogniser, event, Ev)
).
rename(TB) :->
"Prompt for new name"::
prompter('Rename text box',
[ name:name = Name/TB?string
]),
send(TB, string, Name).
:- pce_end_class.
\end{code}
\section{Graphs: Using Connections} \label{sec:connect}
A connection is a line connecting two graphical objects. A connection
has typed end-points that can attach to a {\em handle} of the same
type. If multiple such handles exist, the system will attach to the
`best' one using some simple heuristics.
Below is the code fragment that allows you to link up graphicals by
dragging from the one to the other with the left-button held down.
\begin{code}
:- pce_extend_class(text_box).
handle(0, h/2, link, west).
handle(w, h/2, link, east).
handle(w/2, 0, link, north).
handle(w/2, h, link, south).
:- pce_global(@link_recogniser, new(connect_gesture)).
event(TB, Ev:event) :->
( send(TB, send_super, event, Ev)
; send(@text_box_recogniser, event, Ev)
; send(@link_recogniser, event, Ev)
).
:- pce_end_class.
\end{code}
\section{Reading the Diagram}
XPCE has been designed to be able to create drawings that can be
interpreted. This design is exemplified by the use of connections. If
the drawing had been built from just lines, boxes and text it would have
been difficult to convert the drawing into a Prolog representation of
a graph. Connections explicitly relate {\em graphical object} instead
of positions.
Below is a Prolog fragment that generates a Prolog fact-list from the
graph.
\begin{code}
assert_graph(E, Predicate) :-
functor(Term, Predicate, 2),
retractall(Term),
send(E?graphicals, for_all,
if(message(@arg1, instance_of, connection),
message(@prolog, assert_link,
Predicate,
@arg1?from?string?value,
@arg1?to?string?value))).
assert_link(Predicate, From, To) :-
Term =.. [Predicate, From, To],
assert(Term).
\end{code}
\begin{exercises}
\exercise{%
Extend the graph-editor's frame with a dialog window that allows for
saving the graph to the Prolog database.
}
\exercise{%
The example in section~\ref{sec:connect} uses a generic connect gesture
and a generic connection. Make a refinement of class connect_gesture
that creates instances of a class arc_connection. Define class
arc_connection as a subclass of class connection that has a popup
attached which allows the user to delete the connection.
}
\exercise{%
Write a predicate to create a graph from a list of Prolog facts defining
the graph. Add a possibility to load a graph to the dialog window.
}
\exercise{%
Experiment with the `graphical ->layout' method to create some layout
for the graph-elements created in the above exercise
}
\end{exercises}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%% Process interface
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\input process.tex
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%% Using XPCE as a database
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\chapter{Representation and Storing Application Data}
There are various alternatives for representing application data in
XPCE/Prolog. The most obvious choice is to use Prolog. There
are some cases where XPCE is an alternative worth considering:%
\footnote{
Using XPCE for storage of application-data has been used in three
Esprit-funded projects for the development of knowledge acquisition
tools: `Shelley' (storage only), The `Common Kads WorkBench' (using XPCE
for OO control structure) and `KEW' (Common Lips, Using XPCE for
storage only). In the `Games' project XPCE user-defined classes
are only used for specialising the UI library. CLOS is used for
storing application data.
Representing `knowledge' in XPCE to be used for reasoning in Prolog or
Lisp is difficult due to the lack of `natural' access to the knowledge
base. Representing text and drawings in XPCE works well.}
\begin{itemize}
\tick{Store data that is difficult to represent in Prolog}
The most typical example are hyper-text and graphics. XPCE has
natural data-types for representing this as well as a save and
load facilities to communicate with files.
\tick{Manipulations that are hard in Prolog}
XPCE has a completely different architecture than Prolog: its
basic control-structure is message passing and it's data-elements
are global and use destructive assignment. These properties can
make it a good alternative for storing data in the recorded or
clause database of Prolog.
\tick{You want to write a pure OO system}
Not only can you model your interface, but also the {\em application}
as a set of XPCE classes. This provides you with a purely object
oriented architecture where XPCE is responsible for storage and message
passing and Prolog is responsible for implementing the methods.
\end{itemize}
\section{Data Representation Building Blocks} \label{chap:data}
In this section we will discuss the building-blocks for
data-representation using XPCE. We start with the data {\em organising}
classes:
\begin{itemize}
\tick{chain}
A chain is a single-linked list. Class chain defines various
set-oriented operations and iteration primitives.
\tick{vector}
A vector is a dynamically expanding one-dimensional array.
Multi-dimensional arrays may be represented as vectors holding
vectors or using a large one-dimensional array and redefine
the access methods. See also section~\ref{sec:2dvector}.
\tick{hash_table}
A hash-table maps an arbitrary key on an arbitrary value. Class
hash_table defines various methods for finding and iteration over
the associations stored in the table. Class chain_table may be
considered to associate a single key with multiple values.
\end{itemize}
For the representation of frames and relations, XPCE offers the
following building-blocks:
\begin{itemize}
\tick{sheet}
A sheet is a dynamic attribute-value set. Cf. a property list in
Lisp.
\tick{Refining class object}
A common way to define storage primitives is by modeling them
as subclasses of class object. This way of modeling data allows
you to exploit the typing primitives of XPCE. Modeling as classes
rather than using dynamic sheets also minimises storage overhead.
\tick{hyper}
A hyper is a relation between two objects. The classes hyper and
objects provide methods to define the semantics of hypers and to
manipulate and exploit them in various ways.
A hyper is a simple and safe way to represent a relation between
two objects than cannot rely on their mutual existence.
\end{itemize}
\section{A Simple Database}
In this section we will define a simple family database.%
\footnote{Unfortunately we cannot use class data for representing
dates as the current implementation only ranges from
the Unix epoch (Jan 1 1970 to somewhere in the 22-nth
century).}
This example used hyper-objects to express marriage and child relations.
The advantage of hyper-objects is that they will automatically be
destroyed if one of the related objects is destroyed and they may
be created and queried from both sides.
\begin{code}
:- pce_begin_class(person, object, "Person super-class").
variable(name, name, both, "Name of the person").
variable(date_of_birth, name, both, "Textual description of date").
initialise(P, Name:name, BornAt:name) :->
send(P, send_super, initialise),
send(P, name, Name),
send(P, date_of_birth, BornAt).
father(P, M:male) :<-
"Get my father"::
get(P, hypered, father, M).
mother(P, M:female) :<-
"Get my mother"::
get(P, hypered, mother, M).
sons(P, Sons:chain) :<-
"Get my sons"::
get(P, all_hypers, Hypers),
new(Sons, chain),
send(Hypers, for_all,
if(@arg1?forward_name == son,
message(Sons, append, @arg1?to))).
daughters(P, Daughters:chain) :<-
"Get my daughters"::
get(P, all_hypers, Hypers),
new(Daughters, chain),
send(Hypers, for_all,
if(@arg1?forward_name == daughter,
message(Daughters, append, @arg1?to))).
:- pce_end_class.
:- pce_begin_class(female, person, "Female person").
mary(F, Man:male) :->
"Marry with me"::
( get(F, husband, Man)
-> send(F, report, error, '%N is already married to %N', F, Man),
fail
; new(_, hyper(F, Man, man, woman))
).
husband(F, Man:male) :<-
"To whom am I married?"::
get(F, hypered, man, Man).
deliver(F, M:male, Name:name, Date:name, Sex:{male,female}, Child:person) :<-
"Deliver a child"::
( Sex == male
-> new(Child, male(Name, Date)),
new(_, hyper(F, Child, son, mother)),
new(_, hyper(M, Child, son, father))
; new(Child, female(Name, Date)),
new(_, hyper(F, Child, daughter, mother)),
new(_, hyper(M, Child, daughter, father))
).
:- pce_end_class.
:- pce_begin_class(male, person, "Male person").
mary(M, F:female) :->
"Marry with me"::
send(F, mary, M).
wife(M, Female:female) :<-
"To whom am I married?"::
get(M, hypered, woman, Female).
:- pce_end_class.
\end{code}
\begin{exercises}
\exercise{%
Load the file family.pl containing the example above and enter a simple
database by hand. Inspect the data-representation using the inspector
and online manual tools.
}
\exercise{%
Design and implement a simple graphical editor for entering a database.
What visualisation will you choose? What UI technique will you use
for marriage and born children?
}
\exercise{%
The current implementation does not define an object that reflects the
entire database. Define and maintain a hash-table that maps names onto
person entries. You can redefine destruction of an object by redefining
the ->unlink method.
}
\end{exercises}
|