Professional Documents
Culture Documents
314–321, 3rd Floor, Plot 3, Splendor Forum, Jasola District Centre, New Delhi – 110025, India
103 Penang Road, #05–06/07, Visioncrest Commercial, Singapore 238467
www.cambridge.org
Information on this title: www.cambridge.org/9781009181341
DOI: 10.1017/9781009181358
Foreword xv
Preface xvii
Part 1 An Overview 1
1 Introduction 3
1.1 Standard development 3
1.2 Software engineering 4
1.3 Evolution and abstraction 6
1.4 Structure and objectives of this book 8
1.5 References 10
2 Simple Concepts 11
2.1 Key goals 11
2.2 Overall structure 12
2.3 The scalar type model 17
2.4 Arrays and records 19
2.5 Access types 22
2.6 Errors and exceptions 23
2.7 Terminology 26
3 Abstraction 27
3.1 Packages and private types 27
3.2 Objects and inheritance 30
3.3 Classes and polymorphism 34
3.4 Genericity 40
3.5 Object oriented terminology 41
3.6 Tasking 43
4 Programs and Libraries 47
4.1 The hierarchical library 47
4.2 Input–output 49
vii
19 Generics 469
19.1 Declarations and instantiations 469
19.2 Type parameters 475
19.3 Subprogram parameters 485
19.4 Package parameters 492
19.5 Generic library units 498
20 Tasking 501
20.1 Parallelism 501
20.2 The rendezvous 503
20.3 Timing and scheduling 508
20.4 Protected objects 513
20.5 Simple select statements 521
20.6 Timed and conditional calls 524
20.7 Concurrent types and activation 527
20.8 Termination, exceptions, and ATC 534
20.9 Signalling and scheduling 540
20.10 Summary of structure 546
21 Object Oriented Techniques 551
21.1 Extension and composition 551
21.2 Using interfaces 554
21.3 Mixin inheritance 560
21.4 Linked structures 562
21.5 Iterators 565
21.6 Generalized iteration 570
21.7 Object factories 577
21.8 Controlling abstraction 581
22 Tasking Techniques 587
22.1 Dynamic tasks 587
22.2 Multiprocessors 590
22.3 Synchronized interfaces 598
22.4 Discriminants 609
22.5 Task termination 614
22.6 Clocks and timers 617
22.7 The Ravenscar profile 626
Program 4 Super Sieve 627
Appendices 851
A1 Reserved Words, etc. 851
A1.1 Reserved words 851
A1.2 Predefined attributes 852
A1.3 Predefined aspects 859
A1.4 Predefined pragmas 862
A1.5 Predefined restrictions 864
A2 Glossary 867
A3 Syntax 873
A3.1 Syntax rules 873
A3.2 Syntax index 891
A4 Introducing Ada 2022 901
A5.6a Generalized literals 902
A7.3a Iteration filters 902
A8.8 General aggregates 903
A9.5 Declare expressions 904
A9.6 Reduction expressions 905
A13.7a Renaming objects and values 906
A15.5a Aspect No_Return 907
A16.2a Default initial conditions 907
A16.2b Contracts and access types 908
A16.6 Global state 908
A19.2a Default generic parameters 912
A20.2a Entries, aspects, and synchronization 913
A21.6a Iterator interfaces 914
A21.6b Procedural iterators 915
A22.7a Profiles 917
A22.8 Parallel blocks and loops 917
A22.9 Conflict checking 919
A23.4a Big numbers 920
A23.4b Random numbers 927
A23.6a Images 927
A23.6b Text buffers 928
A24a Containers 931
A24.2a Doubly linked lists 931
A24.3a Vectors 939
A24.4a Maps 941
A24.5a Sets 942
A24.6a Trees 943
T his is being written shortly after the successful launch of the James Webb Space
Telescope, a demonstration of what can be achieved if enough care is taken with
the software engineering.
It is also on the cusp between 2021 and 2022, a time to both look backwards and
to look forward. It is a similar matter with Ada 2022. On one hand, it looks back,
filling in gaps in what should, with the benefit of hindsight, have already been in
earlier editions of Ada. On the other hand, it looks forward to a world where many-
core processors are ubiquitous and need to be made use of efficiently.
The Ada programming language continues to evolve in order to better support
the development of software applications with high requirements for reliability and
system integrity. The 4th major revision of the language, Ada 2022, includes
improvements in many different areas, but with particular focus on a few topics:
• allowing software developers to easily and safely take advantage of the parallel
execution capabilities of multi-core and multi-threaded architectures;
• allowing developers to more precisely express their intent regarding a
program’s structure and logic via improved contracts and other forms of
assertions;
• providing improved support for containers;
• providing “creature comforts” to ease the use of common programming idioms.
The introduction of parallel loops and parallel block statements allows users to
express the possibility of parallel execution of constructs that also have well-
defined sequential semantics. The Global and Nonblocking aspects can be used to
enable static detection of unsafe concurrent access to variables.
Contracts are improved along two different axes: contracts are supported in
more contexts (e.g., the Default_Initial_Condition aspect and support for
precondition/postcondition specifications for access-to-subprogram types and for
generic formal subprograms), and more expressive forms of expressions are defined
in order to make it possible to write more precise contracts (e.g., declare
expressions, reduction expressions, delta aggregates, and calls to static functions).
There is a sometimes-unappreciated point about some of these expression forms that
may seem like just syntactic sugar (another example is Ada 2012’s quantified
expressions). It is true that the same value could be computed in a function body
xv
without too much trouble, but then what would the postcondition be for this
function? How would the declaration of the function describe its result? So these
new forms do enable more expressive contracts.
Support is added for iterating over containers, and for constructing container
values using aggregates. The mechanisms used to accomplish this can also be used
in user-defined container implementations; the implementation-defined containers
have no special “magic” that is unavailable to users who want to “roll their own”.
Support is also provided for literals of private types, for indexing operations on a
private type, for implicit dereferencing of certain non-access types; all of these are
intended to make it easier to hide the implementation of a private type without
taking useful functionality away from clients. And the private type in question may,
of course, be a container type.
“Creature comforts” include the introduction of some features that have long
been available in other programming languages. A name ("@") is defined for the
target of an assignment statement, as in:
Function_Call.Some_Long_Name(Some_Index_Expression) : = @ + 1;
The Image attribute is now available for almost all types and objects, not just
for scalars; support for (in effect) user-specified Image functions is provided.
Restrictions on aggregates are relaxed (index values can now be used in array
aggregate component expressions); a discriminant value in an aggregate can be non-
static in more cases. Predefined support for big numbers (integer and real) is added.
Internationalization support is improved via the various new Wide_File_Names and
Wide_Wide_File_Names packages.
And there are many, many other improvements to the language as well. The
Jorvik profile, the System.Atomic_Operations package, the Object_Size attribute,
iterator filters, and lots of other stuff.
And who better to guide a user through all of this material than John Barnes?
John has been involved in Ada programming language design efforts since shortly
after the birth of Ada Lovelace (or so it seems). He combines his detailed
knowledge of the subject with a special talent for exposition. He has an unusual
ability to anticipate, and correct for, the ways that a reader might be confused by
whatever corner of the language he is describing. His choices of examples are
invariably both enlightening and entertaining. His writing combines technical
correctness with accessibility and humor.
For folks who want to write software that works correctly (admittedly, a small
audience), there is value in learning about Ada and, in particular, about Ada 2022.
And for anyone who wants to learn about Ada, there is both value and fun in
learning about it from John’s fine book.
Enjoy!
Steve Baird & Jeff Cousins,
Current and Past Chairs of the
ISO/IEC JTC1/SC22/WG9
Ada Rapporteur Group (ARG)
xvii
In order to avoid the book becoming unwieldy, the full details of the syntax for
Ada 2022 and an updated table summarising the containers in Ada 2022 are
provided on the website. The answers to all exercises are also on the website but
those for the introductory Part 1 are also included in the book for the convenience
of readers encountering Ada for the first time. More details of the website will be
found below.
Whenever a new standard appears and is put into use, it is almost inevitable that
various imperfections are soon discovered. Ada 2012 was no exception and a
number of corrections and improvements were deemed to be necessary. These
alterations were processed in the usual manner by the Ada Rapporteur Group and
resulted in a Corrigendum which was approved and published by ISO in February
2016. The body of this version of Programming in Ada 2012 accordingly covers this
updated 2016 standard. I have also taken the opportunity to convert the uses of
pragmas such as Pure and Preelaborate to aspect clauses in order to smooth the
transition to Ada 2022.
The revisions are described by Ada Issues (AIs) and a number of these are
mentioned in the Index. The early ones relate to the 2016 corrigendum but most
concern the evolution of Ada 2022.
And now I must thank all those who have helped with this new book both by
pointing out errors in the first edition and by reviewing the text of this new edition
and especially the Ada 2022 material. Many thanks therefore (in alphabetical order)
to Steve Baird, Janet Barnes, Ben Brosgol, Randy Brukardt, Jeff Cousins, Bob Duff,
Tama McGlinn, Pascal Pignard, and Tucker Taft. Their much valued comments
enabled me to improve the presentation and to eliminate a number of errors. I must
also give extra thanks to Randy Brukardt without whose eternal energy as editor of
the Ada standard, I would find writing about Ada a very difficult task indeed.
Finally, many thanks to my wife Barbara for help in typesetting and proof-
reading and to friends at Cambridge University Press for their continued guidance
and help.
John Barnes
Caversham, England
January 2022
The first program, Magic Moments, illustrates type extension and dispatching.
It shows how the existence of common components and common operations enable
dispatching to compute various geometrical properties almost by magic.
The Sylvan Sorter is an exercise in access types and basic algorithmic
techniques including recursion.
The Rational Reckoner provides two examples of abstract data types – the
rational numbers themselves and the stack which is the basis of the calculator part
of the program.
The Super Sieve illustrates multitasking and communication between tasks both
directly through entry calls and indirectly through protected objects. For added
interest it is made generic so that more general primes than those from the familiar
domain of integers may be found. This provides the opportunity to use a
discriminated record type and a modular type to represent binary polynomials.
The program Wild Words is probably the hardest to follow because it is not
based on any particular example described in the preceding chapters. It illustrates
many of the facilities of the character and string handling packages as well as the
generation of random numbers.
The final program from the book, Playing Pools, shows how users might write
their own storage allocation package for the control of storage pools. The example
shown enables the user to monitor the state of the pool and it is exercised by running
the familiar Tower of Hanoi program which moves a tower of discs between three
poles. Variety is provided by implementing the stack structures representing the
three poles (and defined by an interface) in two different ways and dispatching to
the particular implementation. The website includes an extended version which uses
three different ways.
The website also includes a number of sample programs illustrating new
features in Ada 2022. One program addresses encryption and uses the RSA
algorithm mentioned in Section A23.4a.
Information on many aspects of Ada such as vendors, standards, books and so
on can be obtained from the websites listed in the Bibliography.
An Overview
Chapter 1 Introduction 3
Chapter 2 Simple Concepts 11
Chapter 3 Abstraction 27
Chapter 4 Programs and Libraries 47
Program 1 Magic Moments 59
T
his first part covers the background to the Ada language and an
overview of most of its features. Enough material is presented
here to enable a programmer to write complete simple
programs.
Chapter 1 contains a short historical account of the origins and
development of various versions of Ada from Ada 83 through Ada 95
and Ada 2005 and leading to Ada 2012 and Ada 2022 which are the
topics of this book. There is also a general discussion of how the
evolution of abstraction has been an important key to the development
of programming languages in general.
Broadly speaking, the other three chapters in this part provide an
overview of the material in the corresponding other parts of the book.
Thus Chapter 2 describes the simple concepts familiar from languages
such as C and Pascal and which form the subject of the seven chapters
which comprise Part 2. Similarly Chapter 3 covers the important topic
of abstraction which is the main theme of Part 3. And then Chapter 4
rounds off the overview by showing how a complete program is put
together and corresponds to Part 4 which covers material such as the
predefined library.
A da 2012 (and the nascent Ada 2022) are direct descendants of Ada 83 which
was originally sponsored by the US Department of Defense for use in the
embedded system application area. (An embedded system is one in which the
computer is an integral part of a larger system such as a chemical plant, missile, or
dishwasher.)
The story of Ada goes back to about 1974 when the United States Department
of Defense realized that it was spending far too much on software, especially in the
embedded systems area. To cut a long story short the DoD sponsored the new
language through a number of phases of definition of requirements, competitive and
parallel development and evaluation which culminated in the issue of the ANSI
standard for Ada in 19831. The team that developed Ada was based at CII
Honeywell Bull in France under the leadership of Jean D Ichbiah.
The language was named after Augusta Ada Byron, Countess of Lovelace
(1815–52). Ada, the daughter of the poet Lord Byron, was the assistant and patron
of Charles Babbage and worked on his mechanical analytical engine. In a very real
sense she was therefore the world’s first programmer. Note that the 1983 standard
was published on Ada’s birthday (December 12) and the standard number 1815
happens to be the year of her birth!
Ada 83 became ISO standard 8652 in 1987 and, following normal ISO practice,
work leading to a revised standard commenced in 1988. The DoD, as the agent of
ANSI, the original proposers of the standard to ISO, established the Ada project in
1988 under the management of Christine M Anderson. The revised language design
was contracted to Intermetrics Inc. under the technical leadership of S Tucker Taft.
The revised ISO standard was published in February 1995 and so became Ada 952.
The maintenance of the language is performed by the Ada Rapporteur Group
(ARG) of ISO/IEC committee SC22/WG9. The ARG under the leadership of Erhard
Plödereder identified the need for some corrections and these were published as a
Corrigendum on 1 June 20013.
Experience with Ada 95 and other modern languages such as Java indicated that
further improvements would be very useful. The changes needed were not so large
as the step from Ada 83 to Ada 95 and so an Amendment was deemed appropriate
rather than a Revised standard. The ARG then developed the Amended language
known as Ada 2005 under the leadership of Pascal Leroy4.
Further experience with Ada 2005 showed that additions especially in the area
of contracts and multiprocessor support would be appropriate. It was decided that
this time a consolidated Edition should be produced. This was accordingly done
under the leadership of Ed Schonberg with the editor being Randy Brukardt and
resulted in the version known as Ada 2012 which became an ISO standard towards
the end of 20125. Maintenance then continued under the leadership of Jeff Cousins.
A number of corrections were made and resulted in the Corrigendum 1 version of
Ada 2012 published in 20166 and which is the subject of the main body of this book.
It was clear that further development was required in order to take full
advantage of the contract features and multiprocessor support. This progressed
under the leadership of Steve Baird and resulted in the draft ISO standard for Ada
2022 which is currently being processed. The main features of Ada 2022 are
described in Appendix 4.
I t should not be thought that Ada is just another programming language. Ada is
about Software Engineering, and by analogy with other branches of engineering
it can be seen that there are two main problems with the development of software:
the need to reuse software components as much as possible and the need to establish
disciplined ways of working.
As a language, Ada largely solves the problem of writing reusable software
components – or at least through its excellent ability to prescribe interfaces, it
provides an enabling technology in which reusable software can be written.
The establishment of a disciplined way of working seems to be a Holy Grail
which continues to be sought. One of the problems is that development
environments change so rapidly that the stability necessary to establish discipline
can be elusive.
But Ada is stable and encourages a style of programming which is conducive to
disciplined thought. Experience with Ada shows that a well designed language can
reduce the cost of both the initial development of software and its later
maintenance.
The main reason for this is simply reliability. The strong typing and related
features ensure that programs contain few surprises; most errors are detected at
compile time and of those that remain many are detected by run-time constraints.
Moreover, the compile-time checking extends across compilation unit boundaries.
This aspect of Ada considerably reduces the costs and risks of program
development compared for example with C and its derivatives such as C++.
Moreover, an Ada compilation system includes the facilities found in separate tools
such as ‘lint’ and ‘make’ for C. Even if Ada is seen as just another programming
language, it reaches parts of the software development process that other languages
do not reach.
Ada 95 added extra flexibility to the inherent reliability of Ada 83. That is, it
kept the Software Engineering but allowed more flexibility. The features of Ada 95
which contributed to this more flexible feel are the extended or tagged types, the
hierarchical library facility and the greater ability to manipulate pointers or
references. Another innovation in Ada 95 was the introduction of protected types to
the tasking model.
As a consequence, Ada 95 incorporated the benefits of object oriented
languages without incurring the pervasive overheads of languages such as Smalltalk
or the insecurity brought by the weak C foundation in the case of C++. Ada 95
remained a very strongly typed language but provided the benefits of the object
oriented paradigm.
Ada 2005 added yet further improvements to the object model by adding
interfaces in the style of Java and providing constructor functions and also
extending the object model to incorporate tasking. Experience has shown that a
standard library is important and accordingly Ada 2005 had a much larger library
including predefined facilities for containers.
Ada has long been renowned as the flagship language for multitasking
applications. (Multitasking is often known as multithreading.) This position was
strengthened by the addition of further standard paradigms for scheduling and
timing and the incorporation of the Ravenscar profile into Ada 2005. The Ravenscar
profile enables the development of real-time programs with predictable behaviour.
Further improvements which resulted in Ada 2012 were in three main areas.
First there was the introduction of material for ‘programming by contract’ such as
pre- and postconditions somewhat on the lines of those found in Eiffel. There were
also additions to the tasking model including facilities for mapping tasks onto
multiprocessors. Other important extensions were additional facilities in the
container library enabling further structures (such as trees and queues) to be
addressed; other improvements also simplified many operations on the existing
container structures.
Ada 2022 builds on the experience with Ada 2012 in a number of areas. The use
of the contract model based on pre- and postconditions showed that their use would
be simplified and encouraged by the addition of more expression features. However,
although Ada 2022 has features enabling objects to be declared within expressions,
Ada is not moving towards being an expression language of the style historically
introduced by LISP with the attendant difficulties of legibility. Other proof related
features such as the ability to describe the effect of a subprogram on the overall
global state are also added. Major improvements are made to the container library
enabling greater efficiency of operation whilst retaining security. And lightweight
tasking is added to aid the simpler use of multiple processors. The key features of
Ada 2022 are described in Appendix 4.
Two kinds of application stand out where Ada is particularly relevant. The very
large and the very critical.
Very large applications, which inevitably have a long lifetime, require the
cooperative effort of large teams. The information hiding properties of Ada and
especially the way in which integrity is maintained across compilation unit
boundaries are invaluable in enabling such developments to progress smoothly.
Furthermore, if and when the requirements change and the program has to be
modified, the structure and especially the readability of Ada enable rapid
understanding of the original program even if it is modified by a different team.
Very critical applications are those that just have to be correct otherwise people
or the environment get damaged. Obvious examples occur in avionics, railway
signalling, process control, and medical applications. Such programs may not be
large but have to be very well understood and often mathematically proven to be
correct. The full flexibility of Ada is not appropriate in this case but the intrinsic
reliability of the strongly typed kernel of the language is exactly what is required.
Indeed many certification agencies dictate the properties of acceptable languages
and whereas they do not always explicitly demand a subset of Ada, nevertheless the
properties are not provided by any other practically available language. The SPARK
language which is based around a kernel subset of Ada illustrates how special tools
can provide extra support for developing high integrity systems. A SPARK program
includes additional information regarding data flow, state, and proof. In the original
versions of SPARK this was done in the form of Ada comments. However, in later
versions of SPARK, information is presented using features of Ada including pre-
and postconditions and additional assertions. This information is processed by the
SPARK tools and can be used to show that a program meets certain criteria such as
not raising any predefined exceptions. Much progress has been made in the area of
proof in recent years. A brief introduction to SPARK will be found in Chapter 27.
X = A + B(I)
so that the use of the machine registers to evaluate the expression was completely
hidden from the programmer. In these early languages the expression abstraction
was not perfect since there were somewhat arbitrary constraints on the complexity
of expressions; subscripts had to take a particularly simple form for instance. Later
languages such as Algol 60 removed such constraints and completed the
abstraction.
The second advance concerned ‘control abstraction’. The prime example was
Algol 60 which took a remarkable step forward; no language since then has made
such an impact on later developments. The point about control abstraction is that the
flow of control is structured and individual control points do not have to be named
or numbered. Thus we write
if X = Y then P := Q else A := B
and the compiler generates the gotos and labels which would have to be explicitly
used in early versions of languages such as Fortran. The imperfection of early
expression abstraction was repeated with control abstraction. In this case the
obvious flaw was the horrid Algol 60 switch which has now been replaced by the
case statement of later languages.
The third advance was ‘data abstraction’. This means separating the details of
the representation of data from the abstract operations defined upon the data.
Older languages take a very simple view of data types. In all cases the data is
directly described in numerical terms. Thus if the data to be manipulated is not
really numerical (it could be traffic light colours) then some mapping of the abstract
type must be made by the programmer into a numerical type (usually integer). This
mapping is purely in the mind of the programmer and does not appear in the written
program except perhaps as a comment.
Pascal introduced a certain amount of data abstraction as instanced by the
enumeration type. Enumeration types allow us to talk about the traffic light colours
in their own terms without our having to know how they are represented in the
computer. Moreover, they prevent us from making an important class of
programming errors – accidentally mixing traffic lights with other abstract types
such as the names of fish. When all such types are described in the program as
numerical types, such errors can occur.
Another form of data abstraction concerns visibility. It has long been
recognized that the traditional block structure of Algol and Pascal is not adequate.
For example, it is not possible in Pascal to write two procedures to operate on some
common data and make the procedures accessible without also making the data
directly accessible. Many languages have provided control of visibility through
separate compilation; this technique is adequate for medium-sized systems, but
since the separate compilation facility usually depends upon some external system,
total control of visibility is not gained. The module of Modula is an example of an
appropriate construction.
Ada was probably the first practical language to bring together these various
forms of data abstraction.
Another language which made an important contribution to the development of
data abstraction is Simula 67 with its concept of class. This leads us into the
paradigm now known as object oriented programming. There seems to be no precise
definition of OOP, but its essence is a flexible form of data abstraction providing
the ability to define new data abstractions in terms of old ones and allowing
dynamic selection of types.
All types in Ada 83 were static and thus Ada 83 was not classed as a truly object
oriented language but as an object based language. However, all later versions of
Ada include the essential functionality associated with OOP such as type extension
and dynamic polymorphism.
We are, as ever, probably too close to the current scene to achieve a proper
perspective. Data abstraction in Ada 83 seems to have been not quite perfect, just
as Fortran expression abstraction and Algol 60 control abstraction were imperfect
in their day. It remains to be seen just how well Ada now provides what we might
call ‘object abstraction’. Indeed it might well be that inheritance and other aspects
of OOP turn out to be unsatisfactory by obscuring the details of types although not
hiding them completely; this could be argued to be an abstraction leak making the
problems of program maintenance even harder.
A brief survey of how Ada relates to other languages would not be complete
without mention of C and C++. These have a completely different evolutionary trail
to the classic Algol–Pascal–Ada route.
The origin of C can be traced back to the CPL language devised by Strachey,
Barron and others in the early 1960s. This was intended to be used on major new
hardware at Cambridge and London universities but proved hard to implement.
From it emerged the simple system programming language BCPL and from that B
and then C. The essence of BCPL was the array and pointer model which abandoned
any hope of strong typing and (with hindsight) a proper mathematical model of the
mapping of the program onto a computing engine. Even the use of := for assignment
was lost in this evolution which reverted to the confusing use of = as in Fortran.
Having hijacked = for assignment, C uses == for equality thereby conflicting with
several hundred years of mathematical usage. About the only feature of the elegant
CPL remaining in C is the unfortunate braces {} and the associated compound
statement structure which was abandoned by many other languages in favour of the
more reliable bracketed form originally proposed by Algol 68. It is again tragic to
observe that Java has used the familiar but awful C style. The very practical
problems with the C notation are briefly discussed in Chapter 2.
Of course there is a need for a low level systems language with functionality
like C. It is, however, unfortunate that the interesting structural ideas in C++ have
been grafted onto the fragile C foundation. As a consequence although C++ has
many important capabilities for data abstraction, including inheritance and
polymorphism, it is all too easy to break these abstractions and create programs that
violently misbehave or are exceedingly hard to understand and maintain. Java is
free from most of these flaws but persists with anarchic syntax.
The designers of Ada 95 incorporated the positive dynamic facilities of the kind
found in C++ onto the firm foundation provided by Ada 83. The designers of Ada
2005 and Ada 2012 have added further appropriate good ideas from Java. But the
most important step taken by Ada 2012 was to include facilities for ‘programming
by contract’ which in a sense is the ultimate form of abstraction. Ada 2022 adds
further features of this nature.
Ada thus continues to advance along the evolution of abstraction. It
incorporates full object abstraction in a way that is highly reliable without incurring
excessive run-time costs.
L earning a programming language is a bit like learning to drive a car. Certain key
things have to be learnt before any real progress is possible. Although we need
not know how to use the cruise control, nevertheless we must at least be able to start
the engine, steer, and brake. So it is with programming languages. We do not need
to know all about Ada before we can write useful programs but quite a lot must be
learnt. Moreover, many virtues of Ada become apparent only when writing large
programs just as many virtues of a Rolls-Royce are not apparent if we only use it to
drive to the local store.
This book is not an introduction to programming but an overall description of
programming in Ada. It is assumed that the reader will have significant experience
of programming in some other language such as Pascal, C or Java (or earlier
versions of Ada). But a specific knowledge of any particular language is not
assumed.
This book is in four main parts. The first part, Chapters 1 to 4, is an extensive
overview of most of the language and covers enough material to enable a wide
variety of programs to be written; it also lays the foundation for understanding the
rest of the material.
The second part, Chapters 5 to 11, covers the traditional algorithmic parts of the
language and roughly corresponds to the domain addressed by Pascal or C although
the detail is much richer. The third part, Chapters 12 to 22, covers modern and
exciting material associated with data abstraction, programming in the large, OOP,
contracts, and parallel processing.
Finally, the fourth part, Chapters 23 to 27, completes the story by discussing the
predefined environment, interfacing to the outside world and the specialized
annexes; the concluding chapter also pulls together a number of threads that are
slightly dispersed in the earlier chapters and finishes with an introduction to SPARK.
There are also six complete program examples which are interspersed at various
points. The first follows Chapter 4 and illustrates various aspects of OOP. Others
follow Chapters 11, 13, 22, 23 and 25 and illustrate access types, data abstraction,
generics and tasking, string handling, and storage pools respectively. These
examples illustrate how the various components provided by Ada can be fitted
together to make a complete program. The full text of these programs including
additional comments and other explanatory material will be found on the associated
website.
Most sections contain exercises. They are an integral part of the discussion and
later sections often use the results of earlier exercises. Solutions to all exercises will
be found on the website.
Most chapters end with a short checklist of key points and a brief summary of
what was new in Ada 2012 and what is new in Ada 2022 and in most cases provides
a cross reference to Appendix 4 for further details.
Other appendices are provided in order to make this book reasonably self-
contained. They cover matters such as reserved words, attributes, aspects, pragmas,
and restrictions. There is also a glossary of terms and the complete syntax organized
to correspond to the order in which the topics are introduced. The book concludes
with a Bibliography and Index.
This book includes references to Ada Issues. These are the reports of the Ada
Rapporteur Group (ARG) which analyses technical queries and drafts the new Ada
standards from time to time. Since Ada 2012 became an ISO standard, a small
number of improvements to the language were made resulting in the 2016
Corrigendum. The evolution towards Ada 2022 is similarly described by Ada
Issues. The relevant Issues are listed in the Index.
This book covers all aspects of Ada but does not explore every pathological
situation. Its purpose is to describe the effect of and intended use of the features of
Ada. In a few areas the discussion is incomplete; these are areas such as system
dependent programming, input–output, and the specialized annexes. System
dependent programming (as its name implies) is so dependent upon the particular
implementation that only a brief overview seems appropriate. Input–output,
although important, does not introduce new concepts but is rather a mass of detail;
again a simple overview is presented. And, as their name implies, the specialized
annexes address the very specific needs of certain communities; to cover them in
detail would make this book excessively long and so only an overview is provided.
Further details of these areas can be found in the Ada Reference Manual (the
ARM) which is referred to from time to time. The appendices are mostly based upon
material drawn from the ARM. There is also an extended form of the reference
manual known as the Annotated Ada Reference Manual (the AARM) – this includes
much embedded commentary and is aimed at the language lawyer and compiler
writer. These documents will all be found on the Ada website as described in the
Bibliography.
1.5 References
T his is the first of three chapters covering in outline the main goals, concepts and
features of Ada. Enough material is given in these chapters to enable the reader
to write significant programs. It also allows the reader to create a framework in
which the exercises and other fragments of program can be executed, if desired,
before all the required topics are discussed in depth.
The material covered in this chapter corresponds approximately to that in
simple languages such as Pascal and C.
• Readability – professional programs are read much more often than they are
written. So it is important to avoid a cryptic notation such as in APL which,
although allowing a program to be written down quickly, makes it almost
impossible to be read except perhaps by the original author soon after it was
written.
• Strong typing – this ensures that each object has a clearly defined set of values
and prevents confusion between logically distinct concepts. As a consequence
many errors are detected by the compiler which in other languages (such as C)
can lead to an executable but incorrect program.
11
An overall theme in the design of Ada was concern for the programming
process as a human activity. An important aspect of this is enabling errors to be
detected early in the overall process. For example a single typographical error in
Ada usually results in a program that does not compile rather than a program that
still compiles but does the wrong thing. We shall see some examples of this in
Section 2.6.
Suppose we wish to write a program to print out the square root of some
number. We can expect various library units to be available to provide us with a
means of computing square roots and performing input and output. Our job is
merely to write a main subprogram to use these services as we wish.
We will suppose that the square root can be obtained by calling a function in
our library whose name is Sqrt. We will also suppose that our library includes a
package called Simple_IO containing various simple input–output facilities. These
facilities might include procedures for reading numbers, printing numbers, printing
strings of characters and so on.
Our program might look like
reserved words in lower case bold and use leading capitals for all others. This is a
matter of style; the language rules do not distinguish the two cases except when we
consider the manipulation of characters themselves. Note also how the underline
character is used to break up long identifiers to increase readability.
Finally, observe that the name of the procedure, Print_Root, is repeated between
the final end and the terminating semicolon. This is optional but is recommended
so as to clarify the overall structure although this is obvious in a small example such
as this.
Our program is very simple; it might be more useful to enable it to cater for a
whole series of numbers and print out each answer on a separate line. We could stop
the program somewhat arbitrarily by giving it a value of zero.
The output has been enhanced by calling further procedures New_Line and Put
in the package Simple_IO. A call of New_Line outputs the number of new lines
specified by the parameter (of the predefined type Integer); the procedure New_Line
has been written in such a way that if no parameter is supplied then a default value
of 1 is assumed. There are also calls of Put with a string as argument. This is a
different procedure from the one that prints the number X. The compiler
distinguishes them by the different types of parameters. Having more than one
subprogram with the same name is known as overloading. Note also the form of
strings; this is a situation where the case of the letters does matter.
Various new control structures are also introduced. The statements between
loop and end loop are repeated until the condition X = 0.0 in the exit statement is
found to be true; when this is so the loop is finished and we immediately carry on
after end loop. We also check that X is not negative; if it is we output the message
‘not calculable’ rather than attempting to call Sqrt. This is done by the if statement;
if the condition between if and then is true, then the statements between then and
else are executed, otherwise those between else and end if are executed.
The general bracketing structure should be observed; loop is matched by end
loop and if by end if. All the control structures of Ada have this closed form rather
than the open form of Pascal and C which can lead to poorly structured and
incorrect programs.
We will now consider in outline the possible general form of the function Sqrt
and the package Simple_IO that we have been using.
The function Sqrt will have a structure similar to that of our main subprogram;
the major difference will be the existence of parameters.
We see here the description of the formal parameters (in this case only one) and
the type of the result. The details of the calculation are represented by the comment
which starts with a double hyphen. The return statement is the means by which the
result of the function is indicated. Note the distinction between a function which
returns a result and is called as part of an expression, and a procedure which does
not have a result and is called as a single statement.
The package Simple_IO will be in two parts: the specification which describes
its interface to the outside world, and the body which contains the details of how it
is implemented. If it just contained the procedures that we have used, its
specification might be
package Simple_IO is
procedure Get(F: out Float);
procedure Put(F: in Float);
procedure Put(S: in String);
procedure New_Line(N: in Integer := 1);
end Simple_IO;
The parameter of Get is an out parameter because the effect of a call such as Get(X);
is to transmit a value out from the procedure to the actual parameter X. The other
parameters are all in parameters because the value goes in to the procedures. The
parameter mode can be omitted and is then taken as in by default. There is a third
mode in out which enables the value to go both ways. Both functions and
procedures can have parameters of all modes. We usually give the mode in for
procedures explicitly but omit it for functions.
Only a part of the procedures occurs in the package specification; this part is
known as the procedure specification and just gives enough information to enable
the procedures to be called.
We see also the two overloaded specifications of Put, one with a parameter of
type Float and the other with a parameter of type String. Finally, note how the
default value of 1 for the parameter of New_Line is indicated.
The package body for Simple_IO will contain the full procedure bodies plus any
other supporting material needed for their implementation and is naturally hidden
from the outside user. In vague outline it might look like
with Ada.Text_IO;
package body Simple_IO is
procedure Get(F: out Float) is
...
end Get;
... -- other procedures similarly
end Simple_IO;
The with clause shows that the implementation of the procedures in Simple_IO
uses the more general package Ada.Text_IO. The notation indicates that Text_IO is
a child package of the package Ada. It should be noted how the full body of Get
repeats the procedure specification which was given in the corresponding package
specification. (The procedure specification is the bit up to but not including is.)
Note that the package Ada.Text_IO really exists whereas Simple_IO is a figment of
our imagination made up for the purpose of this example. We will say more about
Ada.Text_IO in Chapter 4.
The example in this section has briefly revealed some of the overall structure
and control statements of Ada. One purpose of this section has been to stress that
the idea of packages is one of the most important concepts in Ada. A program
should be conceived as a number of components which provide services to and
receive services from each other.
Finally, note that there is a special package Standard which exists in every
implementation and contains the declarations of all the predefined identifiers such
as Float and Integer. Access to Standard is automatic and it does not have to be
mentioned in a with clause. It is discussed in detail in Chapter 23.
Exercise 2.2
1 Suppose that the function Sqrt is not on its own but in a package Simple_Maths
along with other mathematical functions Log, Ln, Exp, Sin and Cos. By analogy
with the specification of Simple_IO, write the specification of such a package.
How would the program Print_Roots need to be changed?
W e have said that one of the key benefits of Ada is its strong typing. This is well
illustrated by the enumeration type. Consider
declare
type Colour is (Red, Amber, Green);
type Fish is (Cod, Hake, Salmon);
X, Y: Colour;
A, B: Fish;
begin
X := Red; -- ok
A := Hake; -- ok
B := X; -- illegal
...
end;
which plays a key role in control flow. Thus the predefined relational operators such
as < produce a result of this type and such a value follows if as in
if X < 0.0 then
The other predefined enumeration types are Character, Wide_Character and Wide_
Wide_Character whose values are the 8-bit ISO Latin-1, the 16-bit ISO Basic
Multilingual Plane and the full 32-bit ISO 10646 characters; these types naturally
play an important role in input–output. Their literal values include the printable
characters and these are represented by placing them in single quotes thus 'X' or 'a'
or indeed '''.
The other fundamental types are the numeric types. One way or another, all
other data types are built out of enumeration types and numeric types. The two
major classes of numeric types are the integer types and floating point types (there
are also fixed point types which are rather obscure and deserve no further mention
in this overview). The integer types are further subdivided into signed integer types
(such as Integer) and unsigned or modular types. All implementations have the
types Integer and Float. An implementation may also have other predefined numeric
types, Long_Integer, Long_Float, Short_Float and so on. There will also be specific
integer types for an implementation depending upon the supported word lengths
such as Integer_16 and unsigned types such as Unsigned_16.
One of the problems of numeric types is how to obtain both portability and
efficiency in the face of variation in machine architecture. In order to explain how
this is done in Ada it is convenient to introduce the concept of a derived type. (We
will deal with derived types in more detail in the next chapter when we come to
object oriented programming.)
The simplest form of derived type introduces a new type which is almost
identical to an existing type except that it is logically distinct. If we write
type Light is new Colour;
then Light will, like Colour, be an enumeration type with literals Red, Amber and
Green. However, values of the two types cannot be arbitrarily mixed since they are
declare
type Light is new Colour;
C: Colour;
L: Light;
begin
L := Amber; -- the light amber, not the colour
C := Colour(L); -- explicit conversion
...
end;
would violate the strong typing rule and this violation would be detected during
compilation.
Returning now to the numeric types, if we write
then My_Float will have all the operations (+, - etc.) of Float and in general can be
considered as equivalent. Now suppose we transfer the program to a different
computer on which the predefined type Float is not so accurate and that Long_Float
is necessary. Assuming that the program has been written using My_Float rather
than Float then replacing the declaration of My_Float by
is the only change necessary. We can actually do better than this by directly stating
the precision that we require, thus
will cause My_Float to be based on the smallest predefined type with at least 7
decimal digits of accuracy.
A similar approach is possible with integer types so that rather than using the
predefined types we can give the range of values required thus
The point of all this is that it is not good practice to use the predefined numeric
types directly when writing professional programs which may need to be portable.
However, for simplicity, we will generally use the types Integer and Float in
examples in most of this book. We will say no more about numeric types for the
moment except that all the expected operations apply to all integer and floating
types.
A da naturally enables the creation of composite array and record types. Arrays
may actually be declared without giving a name to the underlying type (the
type is then said to be anonymous) but records always have a type name.
As an example of the use of arrays suppose we wish to compute the successive
rows of Pascal’s triangle. This is usually represented as shown in Figure 2.1. The
reader will recall that the rows are the coefficients in the expansion of (1 + x)n and
that a neat way of computing the values is to note that each one is the sum of the
two diagonal neighbours in the row above.
Suppose that we are interested in the first ten rows. We can declare an array
Pascal to hold such a row and a variable N to hold the row number by
If the current values of the array Pascal correspond to row n–1, with the component
Pascal(0) being 1, then the next row can be computed in a similar array Next by
Next(0) := 1;
for I in 1 .. N-1 loop
Next(I) := Pascal(I-1) + Pascal(I);
end loop;
Next(N) := 1;
and then the array Next could be copied into the array Pascal.
This illustrates another form of loop statement where a controlled variable I
takes successive values from a range; the variable is automatically declared to be of
the type of the range which in this case is Integer. Note that the intermediate array
Next could be avoided by iterating backwards over the array; we indicate this by
writing reverse in front of the range thus
Pascal(N) := 1;
for I in reverse 1 .. N-1 loop
Pascal(I) := Pascal(I-1) + Pascal(I);
end loop;
Pascal2(N, 0) := 1;
for I in 1 .. N-1 loop
Pascal2(N, I) := Pascal2(N-1, I-1) + Pascal2(N-1, I);
end loop;
Pascal2(N, N) := 1;
We have declared the arrays without giving a name to their type. We could
alternatively have written
where we have given the name Row to the type and then declared the two arrays
Pascal and Next. There are advantages to this approach as we shall see later.
Incidentally, the bounds of an array do not have to be constant, they could be any
computed values such as the value of some variable Size.
We conclude this brief discussion of arrays by noting that the type String which
we encountered in Section 2.2 is in fact an array whose components are of the
enumeration type Character. Its declaration (in the package Standard) is
and this illustrates a form of type declaration which is said to be indefinite because
it does not give the bounds of the array; these have to be supplied when an object is
declared
The identifier Positive in the declaration of the type String denotes what is
known as a subtype of Integer; values of the subtype Positive are the positive
integers and so the bounds of all arrays of type String must also be positive – the
lower bound is of course typically 1 but need not be.
A record is an object comprising a number of named components typically of
different types. We always have to give a name to a record type. If we were
manipulating a number of buffers then it would be convenient to declare a record
type containing the buffer and an indication of the start and finish of that part of the
buffer actually containing useful data.
type Buffer is
record
Data: String(1 .. 80);
Start, Finish: Integer;
end record;
and the components of the buffer can then be manipulated using a dotted notation
to select the individual components
My_Buffer.Start := 1;
My_Buffer.Finish := 3;
My_Buffer.Data(1 .. 3) := "XYZ";
Note that the last statement assigns values to the first three components of the array
My_Buffer.Data using a so-called slice.
Whole array and record values can be created using aggregates which are
simply a set of values in parentheses separated by commas.
Thus we could assign appropriate values to Pascal and to My_Buffer by
where in the latter case we have in fact assigned all 80 values to the array
My_Buffer.Data and used others so that after the three useful characters the
remainder of the array is padded with spaces. Note the nesting of parentheses and
the optional use of named notation for the record components.
This concludes our brief discussion on simple arrays and records. In the next
chapter we will show how record types can be extended.
Exercise 2.4
1 Write statements to copy the array Next into the array Pascal.
2 Write a nested loop to compute all the rows of Pascal’s triangle in the two-
dimensional array Pascal2.
3 Declare a type Month_Name and then declare a type Date with components
giving the day, month, and year. Then declare a variable Today and assign
Queen Victoria’s date of birth to it (or your own).
T he previous section showed how the scalar types (numeric and enumeration
types) may be composed into arrays and records. The other vital means for
creating structures is through the use of access types (the Ada name for pointer
types); access types allow list processing and are typically used with record types.
The explicit manipulation of pointers or references has been an important
feature of most languages since Algol 68. References rather dominated Algol 68
and caused problems and the corresponding pointer facility in Pascal is rather
austere. The pointer facility in C on the other hand provides raw flexibility which is
open to abuse and quite insecure and thus the cause of many wrong programs.
Ada provides both a high degree of reliability and considerable flexibility
through access types. A full description will be found in Chapter 11 but the
following brief description will be useful for discussing polymorphism in the next
chapter.
Ada access types must explicitly indicate the type of data to which they refer.
The most general form of access types can refer to any data of the type concerned
but we will restrict ourselves in this overview to applications which just refer to
data declared in a storage pool (the Ada term for a heap).
For example suppose we wanted to declare various buffers of the type Buffer in
the previous section. We might write
Handle: access Buffer;
...
Handle := new Buffer;
This allocates a buffer in the storage pool and sets a reference to it into the variable
Handle. We can then refer to the various components of the buffer indirectly using
the variable Handle
Handle.Start := 1;
Handle.Finish := 3;
and we can refer to the complete record as Handle.all. Note that Handle.Start is
strictly an abbreviation for Handle.all.Start.
Access types are of particular value for list processing where one record
structure contains an access value to another record structure. The classic example
which we will encounter in many forms is typified by
type Cell is
record
Next: access Cell;
Value: Data;
end record;
The type Cell is a record containing a component Next which can refer to
another similar record plus a component of some type Data. An example of the use
of this sort of construction will be found in the next chapter.
Sometimes it is important to give a name to an access type. We can rewrite the
above example so that the component Next is of a named type by first using an
incomplete type thus
Using this two stage approach and naming the access type is necessary if we are
doing our own control of storage as described in Section 25.4.
Access types often refer to record types as in these examples but can refer to
any type. Access types may also be used to refer to subprograms and this is
particularly important for certain repetitive operations and when communicating
with programs in other languages.
by the block
begin
Put(Sqrt(X));
exception
when Constraint_Error =>
Put("not calculable");
end;
• Many errors are detected by the compiler – these include simple punctuation
mistakes such as leaving out a semicolon or attempting to violate the type rules
such as mixing up colours and fishes. In these cases the program is said to be
illegal and will not be executed.
• Other errors are detected when the program is executed. An attempt to find the
square root of a negative number or divide by zero are examples of such errors.
In these cases an exception is raised as we have just seen.
• There are also certain situations where the program breaks the language rules
but there is no simple way in which this violation can be detected. For example
a program should not use a variable before a value is assigned to it. In cases like
this the behaviour is not predictable but will nevertheless lie within certain
bounds. Such errors are called bounded errors.
• In more extreme situations there are some kinds of errors which can lead to
quite unpredictable behaviour. In these (quite rare) cases we say that the
behaviour is erroneous.
Finally, there are situations where, for implementation reasons, the language
does not prescribe the order in which things are to be done. For example, the order
in which the parameters of a procedure call are evaluated is not specified. If the
behaviour of a program does depend on such an order then it is not considered to be
incorrect but just not portable.
We mentioned earlier that an overall theme in the design of Ada was concern
for correctness and that errors should be detected early in the programming process.
As a simple example consider a fragment of program controlling the crossing gates
on a railroad. First we have an enumeration type describing the state of a signal
type Signal is (Danger, Caution, Clear);
Mulai Hashem, a native of Tafilelt, tells me that the Jews are very
numerous in his country. He says there are two races of Jews
among them, one race has been in Tafilelt since eight years previous
to the Hegira of Mohammed, the other having been brought in by a
chief named Mulai Ali, the son of Mulai Hassan.
Mulai Ali, says my informant, had purchased these Jews from
some distant country of the East—where he found them in great
distress—and he gave fifty pieces of money for each: what money
he does not know.
Mulai Hashem says that these two races are thus distinguished.
The older race have the whole head shaved. The colony brought by
Mulai Ali leave a small segment of a circle unshaved on the top of
the forehead. These latter also wear a black cap, somewhat pointed
at the top, where it is made to curl down on one side of the face.
The Jewesses are not dressed like those that live in Tangier, but
in the costume of the Moorish woman, and wear rich dresses with
jewels. They are however to be distinguished from the Moorish
woman by the arrangement of their hair, which the latter draw
backwards from either side of the forehead over the temples to the
back of the head; whereas the Jewesses (unmarried) twist their hair
in circles on the top of the head. The married Jewesses are not
allowed by the law to show their hair. This law, by the way, is not
from the Bible, but is an invention of the Rabbis.
The Jews, said Mulai Hashem, are well treated in Tafilelt, whilst
they behave well and according to the rules laid down for them;
which, by the specimen of one that he gave, appear sufficiently
humiliating—viz. that should a Jew pass or be passed by a Sheríf,
he, the Jew, must take off his shoes; or, if mounted, must dismount,
unless specially absolved by the Sheríf.
He tells me that they exercise all the crafts which are practised in
the country, except tilling the soil. It appears that the Jews
themselves seldom, if ever, accompany the ‘kafilas’ (caravans), but,
he says, they have commercial dealings with the Sudan country.
It would appear that the Tafilelt Jews are much at their ease, if
one may judge from the joking adage—according to Mulai Hashem
common in Tafilelt—that ‘forty Mohammedans work for one Jew.’
Mulai Hashem said that the Filali Jews, or Jews of Tafilelt, speak the
Shloh tongue as well as the Arabic, and whenever they wish to say
what they would not have known to Moors or others they speak in
Hebrew.
A learned Jew of this country tells me that all Arabs and Moors
whose names are composed with Ben are of an Israelitish origin.
Mulai Hashem tells me that the following oath is administered in
his country to the Jews, and that they will rather give back anything
they may have come by unjustly than take so grave an oath:—
‘By God, there is no other God but He, the Eternal and Just—who
uttered His word upon the mighty hill—and by the truth of the
existence of the two palm-trees which meet together over the river
Sebts, and by the Book of Moses—peace be upon him—and by the
Ten Commandments delivered unto Moses, and by all that is
contained in his Book, the Gadi, God forbid that I should add or
diminish in this affair, else may God destroy my memory, and may
the name of my family be never mentioned in the world.’
Sebts is the Arabic for Sabbath, and is here applied to the fabled
river called by the Jews Sabbatyon.
It is not clear what is meant by Gadi.
A Jewish Rabbi, named Benshiten, tells me that two and a half
tribes of Israel are the portion which make up the number of Jews
that are found in Europe and Africa—and the remaining nine and a
half are found to exist on the East of a river which is named
Sabbatyon, and is said to be to the East of Mecca. This river, said
he, has the peculiarity of the stones in its bed fighting with each
other all the week excepting the Sabbath, on which day Hebrews
cannot travel; so that the nine and a half tribes cannot communicate
with their separated brethren.
Mr. Hay, it may be added, was the first to break through some of
the despotic rules imposed by the Moors on the Jews. On his arrival
at Tangier in 1844 the Hebrew interpreters attached to the different
Consulates were obliged to remove—as did their brethren—their
slippers on passing a mosque or other sanctuary. When he paid his
visit of ceremony to the Basha, on succeeding his father as Consul-
General and Political Agent, Mr. Hay went, according to the custom
of those days, in full uniform. He was accompanied by his staff, of
which one member—the Interpreter, Mr. David Sicsu—was a Jew, a
shrewd and able man, who had been attached for some years to the
British Consulate. On their way to the Basha’s residence they
passed the great mosque. Mr. Hay noticed that Sicsu stopped and
took off his shoes; so turning, he called out to him in a loud voice,
that all might hear, ‘What are you doing? Put on your shoes.
Remember you are an English employé and, as such, have all the
privileges of British subjects. If ever you do that again, I shall dismiss
you.’
Also, on his first visit to the Sultan’s Court, in 1846, Mr. Hay
insisted on his Jewish interpreters being allowed to ride about the
capital on mule-back, and to enjoy the same rights and privileges as
granted to other members of his staff.
It is only within the last thirty years that Jews in Morocco—not
foreign employés or protected subjects—have been allowed to
assume the European dress, or to wear yellow slippers or red caps
when in native costume. Formerly they were compelled to confine
themselves to black slippers and caps and the Jewish gaberdine.
CHAPTER X.
The Moors have returned, delighted with their visit to the land of the
Nazarenes. Around my house, groups of respectable men may be seen listening
to the wondrous tales of Kaid Abd-el-Kerim or of my groom. The old chief hunter,
Hadj Abdallah, sits in his village—amidst a motley crowd of Arabs and Rifians—
telling them of the magnificence and wonders of London, and the kindness the
poor Moors received, from the Queen down to the servants that assisted them. He
proclaims loudly to the astonished fanatics that power, wealth, honesty, and charity
are to be found in the land of the Infidel and not in the land of the Moslem.
The Hadj tells me that at one time he had almost lost his reason in thinking
over what he had seen. His stories have amused me as much as they do the
Moors, and I have been almost inclined to publish the ‘Travels of the Hadj,’ or get
my brother to do so, as I am rather lazy about writing when it is not a duty.
All the Moors talk much of the Queen and Prince Albert, who they declare sent
for them more than once. So England and the English are in the mouth of every
Moor since the return of the travellers.
When relations between France and Morocco were in a critical condition and a
declaration of war seemed imminent, the Sultan sent for Abd-el-Hadi, the Kadi of
his Capital, said to be the wisest man in Morocco, and asked him what he was to
reply to the demands of the French.
‘Refuse the infidel,’ said Abd-el-Hadi. ‘Order the destruction of all your ports;
blow up the fortifications; let every man arm and become, as were his ancestors, a
wandering Arab, and then tell the French to do their worst!’
When Abd-el-Hadi had retired, the Sultan turned to his Uzir and said, ‘The Kadi
ought to have added—Abdicate, encourage anarchy and revolution, and destroy at
once the Empire.’
It may be surmised, however, that Abd-el-Hadi was a wiser man than he
appears. Desirous of humouring his lord and master by recommending war, he yet
put his advice in a light which would show the Sultan the folly of resisting the
French.
Not only was the residence of the Minister for Foreign Affairs at El
Araish most inconvenient at all times to the Representatives—all of
whom lived at Tangier—but it necessitated, as has been seen,
frequent hurried journeys on their part to that port.
On one such occasion, Mr. Hay had proceeded to El Araish by
land to interview Sid Buselham, and had succeeded in getting from
him a reply, which he desired to forward at once to head-quarters by
one of the rare steamers to England due to leave Tangier next
morning. In expectation of this he had, on his way to El Araish,
arranged that four relays of horses were to await his return at
different points of the road between that town and Tangier, a
distance of sixty miles—and, as soon as he had obtained the
Minister’s signature, he mounted and dashed off homewards.
The Governor of El Araish, anxious for the British Agent’s safety
in those troubled times, had given orders that a mounted escort
should also await him with every fresh horse and follow him on the
road. These, however, were unable to keep pace with him. On arrival
at the little town of Azaila, situated about halfway between Tangier
and El Araish, he found no horse prepared for him. Riding at once to
the British Consular Agent’s house, Mr. Hay demanded his horse.
The Agent, a Jew, explained that it was locked up in the stable of the
Basha, who was away, and that the groom was not to be found.
‘Take me to the stable,’ said Mr. Hay, and, calling to four men of the
little crowd of idlers that had gathered, he ordered them to lift a large
log of wood which lay near and direct it as a ram against the door.
‘Now, all together,’ said Mr. Hay. Down came the door with a crash,
and quickly putting his saddle on the fresh horse, and throwing
money to the Agent to repay the damage to the door, he mounted
and rode on.
Before reaching the river Mishra-el-Hashef, some miles to the
west of Tangier, he found his own sturdy pony awaiting him, and
riding this, his favourite mount, he galloped to the river bank where
the ferry, rowed by two men, awaited him. Shouting to them to stand
clear, he jumped his pony into the boat, and out again on reaching
the further side. He arrived at Tangier having ridden the whole
distance in five hours.
The escorts appointed to accompany him returned to their
quarters, having failed to keep Mr. Hay in sight. ‘It was useless,’ said
they. ‘We galloped along behind him but he ran away from us, and
as soon as he had gone a little way ahead he spread large wings
and flew away with his horse!’
As Mr. Hay wore a loose Inverness cape, to protect him from sun
and weather, the fluttering of this may have suggested the idea of
wings.
An account of a curious and unpleasant adventure which befell
Mr. Hay, and which points to the unsettled and fanatical state of the
inhabitants of Tangier at that time is given in the following letter to his
wife’s sister, Mme. Marcussen.
I am glad to find that the straightforward course I have always pursued with this
Government—though often not very flattering to their vanity and fanaticism—
begins to be understood and appreciated, rather than the cajolery they are
accustomed to meet with from others.
The French bombarded Salli on the 25th ult., without giving any notice to us
here or to the Sultan or his Government. Not much harm is done to the town: some
thirteen persons killed in all, and the French have five killed and thirty wounded.
One of their steam frigates was compelled to retire from the combat. After the
bombardment they came here, and all the petty affairs they had to settle were
settled at once—as they would have been before the bombardment if they would
only have been inclined to arrange matters amicably. They saluted the town and
peace was concluded. A reference was then made to the Sultan. His Majesty
accepts the peace, but asks for explanations about bombardment; so B.[22] has
taken umbrage and embarks with all the French subjects, or most of them, leaving
the French flag flying and the Sardinian Consul-General in charge. It has been
mere bullying; the strong trampling on the weak.
I have been very busy, and have been compelled to suspend all relations with
the Moorish Court—though I do not strike my flag. I have given them ten days in
which to give way, and have no doubt they will. My demands have reference to our
rights in trade in this country, which we are anxious to place on a better footing, not
only for Great Britain but for Morocco itself and all countries.
The Moorish Government have announced that they send an Envoy to
England; and his object, it is reported, is to complain of the insistance and audacity
which I have shown in this negotiation. I am delighted at this manœuvre because it
will only tend finally to show these people I am acting up to my instructions and the
views of Government. So much for Moorish politics.
LIFE AT TANGIER.
Mr. Hay had married, in 1845, a daughter of Mr. Carstensen, a
former Danish Consul-General to Morocco. Except when the
exigencies of a climate which proved very trying in summer for
children of northern race compelled him to send them home, he, with
his wife and young family, resided either at the old Government
House in Tangier or in a villa called by him ‘The Wilderness,’ outside
the walls, which had belonged to his father-in-law. This existence
was only varied by missions to the Court or occasional visits to
England. Beyond the very small European society, composed chiefly
of the various Representatives and their families, residence in
Tangier offered no occupation for the leisure hours of a young and
active man. Thrown therefore on the resources of sport, he mingled
constantly with the wilder natives of the hills as well as with the less
uncivilised farmers and agricultural peasantry of the plains. His
interest in these folk grew, and he gained their respect and even
affection.
Justice amongst these people, when regarded from a purely
personal point of view, as Mr. Hay found, often took rather a romantic
than a strictly logical form. But his hope was to gain the hearts of the
natives, and he knew that such an aim was best attained by bending
in some cases to such national prejudices and customs as those
which are illustrated in the following letter to his mother.
The promise made by the robber was faithfully kept, and Mr. Hay
reaped the reward of his leniency in after years, as, by this clan at
least, his property was always respected.
An indefatigable sportsman, Mr. Hay delighted in expeditions into
remote districts of the country in pursuit of game. It was thus in part
that he acquired his intimate knowledge of the character of the
people. Brought into personal contact with the wild tribesmen, in
circumstances which strongly appealed to their natural chivalry, he
gained an influence among them which he was often able to turn to
useful account. A good illustration of his power of dealing with the
native races is afforded by his suppression of piracy among the
Rifians. The story is told in his own words.
Before the year 1856, vessels becalmed on the Rif coast between
the Algerian frontier and the Spanish fortress Peñon, which is
situated about sixty miles to the eastward of the Moorish port of
Tetuan, were frequently captured by Rifian ‘karebs,’ large galleys
manned by thirty or forty men, armed with long guns, pistols, and
daggers.
When a vessel becalmed, drawn by the current, approached the
Rif coast, especially in the vicinity of the village of Benibugaffer, near
Cape ‘Tres Forcas,’ about fifteen miles to the westward of the
Spanish fortress of Melilla, the natives launched their ‘karebs,’
hidden in nooks on the rocky coast, or buried under sand, and set
out in pursuit, firing volleys as they neared the vessel. The crew, if
they had not escaped in the ship’s boats when the piratical craft
hove in sight, were made prisoners, but were not in general ill-
treated unless they attempted to offer resistance.
On landing, they were compelled to labour in the fields, receiving
a daily allowance of very coarse food. The captured vessel was rifled
of cargo and rigging, and then burnt, so as to leave no vestige.
In the year 1851 a British vessel was taken by the ‘karebs’ of
Benibugaffer.
In pursuance of instructions from H.M.’s Government, a strong
representation was made by me to the Sultan of Morocco, then Mulai
Abderahman, demanding that the pirates should be chastised, that
compensation should be given to the owner of the vessel, and that
energetic steps should be taken by His Sherifian Majesty to put a
stop to these piratical acts of his lawless subjects of the Rif.
The Sultan, on the receipt of this demand, dispatched officers
from his Court to the Rif country with a Sherifian edict to the
chieftains, directing that the sums demanded for the destruction of