1. Effective Kotlin Best Practices Marcin Moskala
download
https://ebookbell.com/product/effective-kotlin-best-practices-
marcin-moskala-11756822
Explore and download more ebooks at ebookbell.com
2. Here are some recommended products that we believe you will be
interested in. You can click the link to download.
Effective Kotlin Best Practices 2nd Edition 2nd Edition Marcin Moskala
https://ebookbell.com/product/effective-kotlin-best-practices-2nd-
edition-2nd-edition-marcin-moskala-97474930
Effective Kotlin Best Practices Marcin Moskala
https://ebookbell.com/product/effective-kotlin-best-practices-marcin-
moskala-26518668
Effective Kotlin Best Practices Marcin Moskala
https://ebookbell.com/product/effective-kotlin-best-practices-marcin-
moskala-26518680
Handson Serverless Applications With Kotlin Develop Scalable And
Costeffective Web Applications Using Aws Lambda And Kotlin Hardik
Trivedi Ameya Kulkarni
https://ebookbell.com/product/handson-serverless-applications-with-
kotlin-develop-scalable-and-costeffective-web-applications-using-aws-
lambda-and-kotlin-hardik-trivedi-ameya-kulkarni-48958776
3. Effective Universal Instruction An Actionoriented Approach To
Improving Tier 1 Illustrated Kimberly Gibbons
https://ebookbell.com/product/effective-universal-instruction-an-
actionoriented-approach-to-improving-tier-1-illustrated-kimberly-
gibbons-46074078
Effective Science Communication A Practical Guide To Surviving As A
Scientist 2nd Edition Sam Illingworth
https://ebookbell.com/product/effective-science-communication-a-
practical-guide-to-surviving-as-a-scientist-2nd-edition-sam-
illingworth-46110938
Effective Implementation Of Transformation Strategies How To Navigate
The Strategy And Change Interface Successfully Angelina Zubac
https://ebookbell.com/product/effective-implementation-of-
transformation-strategies-how-to-navigate-the-strategy-and-change-
interface-successfully-angelina-zubac-46323700
Effective Technology Tools For School Leadership Understanding Digital
And Datadriven Strategies Leslie Jones
https://ebookbell.com/product/effective-technology-tools-for-school-
leadership-understanding-digital-and-datadriven-strategies-leslie-
jones-46496250
Effective Results And Methods For Diophantine Equations Over Finitely
Generated Domains Janhendrik Evertse
https://ebookbell.com/product/effective-results-and-methods-for-
diophantine-equations-over-finitely-generated-domains-janhendrik-
evertse-46507382
7. Tweet This Book!
Please help Marcin Moskala by spreading the word about this
book on Twitter!
The suggested tweet for this book is:
I just bought @EffectiveKotlin!
The suggested hashtag for this book is #effectivekotlin.
Find out what other people are saying about the book by clicking
on this link to search for this hashtag on Twitter:
#effectivekotlin
8. Contents
Introduction: Be pragmatic 1
Part 1: Good code 13
Chapter 1: Safety 14
Item 1: Limit mutability 15
Item 2: Minimize the scope of variables 35
Item 3: Eliminate platform types as soon as possible 42
Item 4: Do not expose inferred types 50
Item 5: Specify your expectations on arguments and state 53
Item 6: Prefer standard errors to custom ones 64
Item 7: Prefer null or Failure result when the lack of
result is possible 66
Item 8: Handle nulls properly 70
Item 9: Close resources with use 81
Item 10: Write unit tests 84
Chapter 2: Readability 88
Item 11: Design for readability 90
Item 12: Operator meaning should be consistent with its
function name 96
Item 13: Avoid returning or operating on Unit? 101
Item 14: Specify the variable type when it is not clear 103
Item 15: Consider referencing receivers explicitly 105
Item 16: Properties should represent state, not behavior 113
Item 17: Consider naming arguments 119
9. CONTENTS
Item 18: Respect coding conventions 126
Part 2: Code design 129
Chapter 3: Reusability 130
Item 19: Do not repeat knowledge 132
Item 20: Do not repeat common algorithms 141
Item 21: Use property delegation to extract common
property patterns 146
Item 22: Use generics when implementing common al-
gorithms 153
Item 23: Avoid shadowing type parameters 157
Item 24: Consider variance for generic types 159
Item 25: Reuse between different platforms by extracting
common modules 172
Chapter 4: Abstraction design 177
Item 26: Each function should be written in terms of a
single level of abstraction 182
Item 27: Use abstraction to protect code against changes 189
Item 28: Specify API stability 205
Item 29: Consider wrapping external API 209
Item 30: Minimize elements visibility 211
Item 31: Define contract with documentation 216
Item 32: Respect abstraction contracts 230
Chapter 5: Object creation 233
Item 33: Consider factory functions instead of constructors 234
Item 34: Consider a primary constructor with named
optional arguments 250
Item 35: Consider defining a DSL for complex object
creation 261
Chapter 6: Class design 273
Item 36: Prefer composition over inheritance 274
10. CONTENTS
Item 37: Use the data modifier to represent a bundle of
data 288
Item 38: Use function types instead of interfaces to pass
operations and actions 296
Item 39: Prefer class hierarchies to tagged classes 301
Item 40: Respect the contract of equals 308
Item 41: Respect the contract of hashCode 322
Item 42: Respect the contract of compareTo 332
Item 43: Consider extracting non-essential parts of your
API into extensions 336
Item 44: Avoid member extensions 341
Part 3: Efficiency 345
Chapter 7: Make it cheap 346
Item 45: Avoid unnecessary object creation 348
Item 46: Use inline modifier for functions with parame-
ters of functional types 363
Item 47: Consider using inline classes 379
Item 48: Eliminate obsolete object references 388
Chapter 8: Efficient collection processing 397
Item 49: Prefer Sequence for big collections with more
than one processing step 401
Item 50: Limit the number of operations 419
Item 51: Consider Arrays with primitives for performance-
critical processing 422
Item 52: Consider using mutable collections 425
Dictionary 427
11. Introduction: Be
pragmatic
Stories of how popular programming languages originate are often
fascinating.
The prototype of JavaScript (named Mocha back then) was created
in just 10 days. Its creators first considered using Java, but they
wanted to make a simpler language for Web designers¹.
Scala was created at a university by a scientist, Martin Odersky. He
wanted to move some concepts from functional programming into
the Java Object Oriented Programming world. It turned out that
these worlds are connectable².
Java was originally designed in the early ‘90s for interactive televi-
sion and set-top boxes by a team called “The Green Team” working
at Sun. Eventually, this language was too advanced for the digital
cable television industry at the time. It ended up revolutionising
general programming instead³.
Many languages were designed for a totally different purpose than
for what they are used for today. Many originated as experiments.
This can be seen in them still today. The differences in the Kotlin
story are that:
1. Since the beginning, it was created and designed to be a
general-purpose programming language, suitable for large
applications.
¹Read about it here: www.en.wikipedia.org/wiki/JavaScript and
www.2ality.com/2011/03/javascript-how-it-all-began.html
²Read about it here: https://www.artima.com/scalazine/articles/origins_-
of_scala.html
³Read about it here: https://bit.ly/36LMw2z
1
12. Introduction: Be pragmatic 2
2. The creators of Kotlin are taking their time. Development of
Kotlin started in 2010, and the first officially stable version
was released in February of 2016. During this period, a lot
has changed. If you find some code from the first proposals,
it looks almost nothing like Kotlin today.
Kotlin was created as a pragmatic language for practical ap-
plications, and this is reflected in its design. For instance, as
opposed to academic or hobbyist languages, it never had ambitions
to experiment with new concepts. Kotlin introduced a few new
concepts (like property delegation) but the Kotlin team is very
conscientious and they prefer to analyze how existing concepts
have cooperated and worked for other languages. They are always
trying to understand the strengths and weaknesses of other lan-
guages and build on them. It is a good strategy for JetBrains since
it is the biggest creator of integrated programming environments
(IDE). They have a lot of data and knowledge about how various
languages are used. They also have specialists that understand each
of those languages.
For that same reason, Kotlin is also different because it has reached
a new level of cooperation between the IDE and the language. Code
analysis in IntelliJ or Eclipse is done using the same compiler that is
used to compile the code. Thanks to that, Kotlin can freely introduce
more and more advanced smart casting and type inference without
the necessity of IDE adjustments. The Kotlin team also supports
developers by constantly improving IntelliJ warnings and lints.
Because of this mechanism, most of the classic optimization hints
don’t need to be collected in books or articles because they can just
be provided via discrete warnings exactly where they are needed.
The philosophy of Kotlin
Every language has its philosophy that determines design decisions.
The central point of Kotlin’s philosophy is pragmatism. This means
that in the end, all choices need to serve business needs, like:
13. Introduction: Be pragmatic 3
• Productivity - application production is fast.
• Scalability - with application growth, its development does
not become more expensive. It may even get cheaper.
• Maintainability - maintenance is easy.
• Reliability - applications behave as expected, and there are
fewer errors.
• Efficiency - the application runs fast and needs fewer re-
sources (memory, processor, etc.).
We, as a programming community, have tried to satisfy those needs
for quite some time. Based on our experiences, we have developed
different tools and techniques. For instance, we have learned that
automatic testing is very important to prevent errors that are
accidentally added to one feature when someone modifies another.
There are also rules to follow. For instance, the Single Responsibility
Principle from SOLID⁴ helps us with the same problem. Throughout
this book, we will mention many such rules.
The programming community also found out that there are some
less abstract values (from the programmers’ point of view) that
support higher level business needs. The Kotlin team collected those
values that are important in terms of language design and used
them as a point of reference for all design decisions. Those values
are:
• Safety
• Readability
• Powerful code reusability
• Tool friendliness
• Interoperability with other languages
I would add another point that is normally not included, but that
can be seen in many decisions:
⁴SOLID is a popular set of principles for OOP, introduced and popular-
ized by Robert C. Martin.
14. Introduction: Be pragmatic 4
• Efficiency
Those requirements were not something present only at the begin-
ning. They have been with Kotlin until today and each change is
considered with them in mind. I will also show that they are all
very strongly reflected in Kotlin’s design. This was possible thanks
to the fact that Kotlin was intentionally kept in beta for nearly 6
years. During this time it was changing at all levels. It takes a lot
of time to shape the design of a programming language to reflect
high-level values. The Kotlin creators did a good job on that.
The purpose of this book
To really unleash the advantages of Kotlin, we need to use it
properly. Knowing features and the standard library (stdlib) is
not enough. The main goal of this book is to explain how to use
different Kotlin features to achieve safe, readable, scalable, and
efficient code. Since this book is written to help developers get
better at writing code, it also touches on many general rules for
programmers. You can find the influence of programming classics
like Clean Code, Effective Java, Structure and Implementation of
Computer Programs, Code Complete, and many more. You can also
find influence from presentations and Kotlin forums. This book
tries to compose as much knowledge about best practices in Kotlin
as possible, no matter where it originated.
You can call it a collection of best practices; though it differs
from classic “Effective X” books because of Kotlin characteristics.
The Effective Java book contains many warnings about internal
Java problems. In Kotlin such problems are mostly eliminated by
the Kotlin team. In contrast to Java, Kotlin is not worried about
deprecating something and fixing it in the future⁵. In the worst
case, the Kotlin team controls a powerful IDE that can do nearly
any migration to a better alternative. Most “Effective X” books also
⁵KotlinConf 2018 keynote by Andrey Breslav.
15. Introduction: Be pragmatic 5
give hints about using some functions or constructs over others.
These kinds of suggestions are rarely useful in Kotlin as most of
them already have a warning or hint in IntelliJ. I left only a few
such items. This book is different: it concentrates on higher-level
good practices that come from authorities, the Kotlin creators, and
from my experience as a developer, consultant, and trainer for
international companies worldwide.
For whom is this book written?
This book is not teaching basics. It assumes that you have enough
knowledge and skills to do Kotlin development. If you don’t, I
recommend starting first with some resources designed for be-
ginners. I recommend Kotlin in Action by Dmitry Jemerov and
Svetlana Isakova or the Coursera course Kotlin for Java Developers
by Andrey Breslav and Svetlana Isakova. Effective Kotlin is for
experienced Kotlin developers.
I will assume that even experienced developers might not know
some features. This is why I explain some concepts like:
• Property
• Platform type
• Named arguments
• Property delegation
• DSL creation
• Inline classes and functions
I want this book to be a complete guide for Kotlin developers on
how to become an amazing Kotlin developer.
Book design
Concepts in the book are grouped into three parts:
16. Introduction: Be pragmatic 6
• Good code - more general rules about making good quality
code. This part is for every Kotlin developer, no matter how
big their project is. It starts from items about safety and
later talks about readability. It is not a coincidence that the
first chapter is dedicated to safety. I believe that program
correctness generally is of the highest priority. Readability is
another chapter because the code is not only for a compiler
but also for programmers. Even when we work alone, we
want code that is readable and self-explanatory.
• Code design - this section is for developers creating a project
together with other developers, or creating libraries. It is
about conventions and setting contracts. It will, in the end,
reflect on readability and safety, but all in terms of correct
code design. This part is a bit more abstract at the beginning,
but thanks to that it can explore topics that are often omitted
in books about code quality. This section is also about prepar-
ing our code for growth. A lot of items are about being ready
for changes in the future. Therefore especially important for
developers creating large projects.
• Efficiency - this section is for developers that care about code
efficiency. Most of the rules presented here do not come at
the cost of development time or readability, so they are suit-
able for everyone. However, they are particularly important
for developers implementing high-performance applications,
libraries, or applications for millions.
Each part is divided into chapters, which are subdivided into items.
Here are the chapters in each part:
Part 1: Good code
• Chapter 1: Safety
• Chapter 2: Readability
Part 2: Code design
17. Introduction: Be pragmatic 7
• Chapter 3: Reusability
• Chapter 4: Design abstractions
• Chapter 5: Objects creation
• Chapter 6: Class design
Part 3: Efficiency
• Chapter 7: Make it cheap
• Chapter 8: Efficient collection processing
Each chapter contains items, which are like rules. The concept is
that items are rules that in most cases need an explanation, but once
the idea is clear, it can be triggered just by this title. For instance,
the first rule, “Limit mutability”, might be enigmatic for someone
who meets it for the first time, but is clear enough to just write
in a comment on a code review for someone who is familiar with
this book. In the end, suggestions designed this way, with their
explanations, should give a clear guideline on how to write good
and idiomatic Kotlin code.
Chapters organization
Chapters often start with the most important concept that is used in
other items. A very visible example is Chapter 2: Readability which
starts with Item 11: Design for readability, but it is also true for:
• Chapter 7: Make it cheap’s first item Item 45: Avoid unneces-
sary object creation
• Chapter 3: Reusability’s first item Item 19: Do not repeat
knowledge
• Chapter 1: Safety’s first item Item 1: Limit mutability
Chapters can also end with an item that is generally less connected
with the rest, but present an important concept that needs to be
included, for instance:
18. Introduction: Be pragmatic 8
• Chapter 1: Safety’s last item is Item 10: Write unit tests
• Chapter 2: Readability’s last item is Item 18: Respect coding
conventions
• Chapter 3: Reusability’s last item is Item 25: Reuse between
different platforms by extracting common modules
How should this book be read?
How should this book be read? The way you like it. Don’t bother
jumping between chapters. To some degree, one builds on an-
other, but knowledge is presented in such a way that chapters
should be understandable independently of others. Having said
that, you should read chapters from the beginning as chapters are
constructed to make one flow.
Choose whatever chapter you want to start with and you can get
back to others later. If you feel bored with some item or chapter,
skip it. This book was written with pleasure, and it should be
read in the same way.
Labels
It is impossible to write a book for everyone. This book is written
primarily for experienced Kotlin developers. Many of them are
already familiar with general best practices for programming and
they look for Kotlin specific suggestions. Nevertheless, there are
some items I decided to include even though they are not Kotlin-
specific or they might seem basic for experienced developers. To
make it clear which one are those, I added the following labels at
the beginning of such items:
• Not Kotlin-specific - item does not have Kotlin-specific sug-
gestions, and similar arguments might be applied to other
OOP languages like Java, C# or Swift. If you are looking for
Kotlin-specific content, skip such items (those are items 10,
19, 26, 27, 36).
19. Introduction: Be pragmatic 9
• Basics - presented suggestions might sound basic for experi-
enced Kotlin developers, as they are already covered in other
best-practices books and they seem to be understood by the
community. If the title seems clear to you, skip such item
(those are items 10, 18, 19, 20, 25, 26, 27).
• Edu - item is less about best practices and it is dedicated
to teaching advanced Kotlin features that are useful for
experienced Kotlin developers. If you know those features,
skip such items (those are items 21, 22, 24, 32)
Suggestions
If you have any suggestions or corrections regarding this book, send
them to contact@marcinmoskala.com
20. Introduction: Be pragmatic 10
Acknowledgments
This book would not be so good without great reviewers who highly
influenced it by suggestions and comments. I would like to thank
all of them. Here is the whole list of reviewers, starting from the
most active ones.
Márton Braun - A Kotlin enthusiast since
version 1.0 of the language, and an aspiring
writer, speaker, educator. Android developer
and self-proclaimed Kotlin evangelist at Aut-
Soft. Android/Kotlin tech editor for RayWen-
derlich.com. University student and instruc-
tor at BME-VIK, studying computer engineering while teaching
Kotlin and Android. Creator of the MaterialDrawerKt and Krate
libraries. Occasionally gets addicted to StackOverflow.
Márton highly influenced especially chapters 1 to 6 with useful
comments, suggestions and corrections. He suggested changes in
names of chapters, supported book reorganization, and contributed
many important ideas.
David Blanc - After graduating in Computer
Science from the INSA (a French Engineer-
ing school), David started working as a Java
engineer for 8 years in various French IT
companies, and moved to mobile application
development on iOS and Android in 2012.
In 2015, he decided to focus on Android and joined i-BP, an IT
department of the banking group BPCE, as Android expert. He is
now passionate about Android, clean code, and, of course, Kotlin
programming since version 1.0.
David gave many on-point corrections and corrected wording for
nearly all chapters. He suggested some good examples and useful
21. Introduction: Be pragmatic 11
ideas.
Jordan Hansen - Jordan has been develop-
ing on and off since he was 10. He started
developing full time since he graduated from
the University of Utah. He started evaluating
Kotlin as a viable language since version 0.6
and has been using it as his primary language
since version 0.8. He was part of an influential team that brought
Kotlin to his entire organisation. Jordan loves playing tabletop
games with his family.
Jordan highly influenced most of the book, left many corrections
and suggestions also to snippets and titles. He suggested deeper
explanation for DSL, and how item dedicated to unit testing can
be shortened. He protected correct technical wording.
Juan Ignacio Vimberg - The most active reviewer in the toughest
part of this book - in the Part 3: Efficiency. Also highly influenced
chapters 1 to 4. He suggested to show correct benchmarks, and to
describe Semantic Versioning.
Kirill Bubochkin - Left perfectly on-point and well thought com-
ments all around the book.
Fabio Collini - Great review, especially for the Chapter 4 and 5.
Inspired point that factory method can be inline in opposition to
constructors, and how configuration can be stored in data classes.
Bill Best - Important reviewer who influenced chapters 6 to 8,
where he left important corrections.
Geoff Falk - Helped improving language, grammar, and some code
snippets, especially in chapters 2 and 5.
Danilo Herrera - Influenced chapter 3, and highly influenced
Chapter 4: Abstractions design.
Allan Caine - Highly influenced Chapter 5: Objects creation.
22. Introduction: Be pragmatic 12
Edward Smith - Highly influenced Chapter 6: Class design.
Juan Manuel Rivero - Reviewed Chapter 6, 7 and 8.
I would also like to thank:
• Marta Raźniewska, who made drawings starting each section.
• Most active alpha testers: Pablo Guardiola, Hubert Kosacki,
Carmelo Iriti and Maria Antonietta Osso.
• Everyone who helped this book by sharing news about it or
sharing feedback and feelings with me.
24. Chapter 1: Safety
Why do we decide to use Kotlin in our projects instead of Java,
JavaScript or C++? Developers are often bought by conciseness or
amazing Kotlin features. For business, as I found out, the truly
convincing argument is Kotlin safety - how its design eliminates
potential application errors. You don’t need to have any experience
with development to get upset when the application you use
crashes, or when there is an error on a website that does not let you
check out after you spent an hour collecting products into a basket.
Having fewer crashes makes the lives of both users and developers
better, and it provides significant business value.
Safety is important for us, and Kotlin is a really safe language, but it
still needs developer support to be truly safe. In this chapter, we’ll
talk about the most important best practices for safety in Kotlin.
We’ll see how Kotlin features promote safety, and how we can use
them properly. The general purpose of every item in this chapter is
to produce code that is less prone to errors.
14
25. Chapter 1: Safety 15
Item 1: Limit mutability
In Kotlin, we design programs in modules and each of them is
composed of different kinds of elements such as classes, objects,
functions, type aliases and top-level properties. Some of those
elements can hold state, for instance by having read-write property
var or by composing a mutable object:
1 var a = 10
2 val list: MutableList<Int> = mutableListOf()
When an element holds state, the way it behaves depends not only
on how you use it, but also on its history. A typical example of a
class with a state is a bank account that has some money balance:
1 class BankAccount {
2 var balance = 0.0
3 private set
4
5 fun deposit(depositAmount: Double) {
6 balance += depositAmount
7 }
8
9 @Throws(InsufficientFunds::class)
10 fun withdraw(withdrawAmount: Double) {
11 if (balance < withdrawAmount) {
12 throw InsufficientFunds()
13 }
14 balance -= withdrawAmount
15 }
16 }
17
18 class InsufficientFunds : Exception()
19
26. Chapter 1: Safety 16
20 val account = BankAccount()
21 println(account.balance) // 0.0
22 account.deposit(100.0)
23 println(account.balance) // 100.0
24 account.withdraw(50.0)
25 println(account.balance) // 50.0
Here BankAccount has a state that represents how much money is
present on that account. Holding state is a double-edged sword.
On one hand it is very useful because it makes it possible to
represent elements changing over time, but on the other hand state
management is hard, because:
1. It is harder to understand and debug a program with many
mutating points. The relationship between these mutations
needs to be understood, and it is harder to track how they
changed when there are more of them. A class with many
mutating points that depend on each other is often really hard
to understand and to modify. It is especially problematic in
case of unexpected situations or errors.
2. Mutability makes it harder to reason about the code. State
of immutable element is clear. Mutable state is much harder
to comprehend. It is harder to reason what is its value as it
might change at any point and just because we checked in
some moment it doesn’t mean it is still the same.
3. It requires proper synchronization in multithreaded programs.
Every mutation is a potential conflict.
4. Mutable elements are harder to test. We need to test every
possible state, and the more mutability, the more states there
are to test. What is more, the number of states we need to test
generally grows exponentially with the number of mutation
points in the same object or file, as we need to test all different
combinations of possible states.
5. When state mutates, often some other classes need to be
notified about this change. For instance, when we add a
27. Chapter 1: Safety 17
mutable element to a sorted list, once the element is changed,
we need to sort this list again.
Problems with state consistency and the growing complexity of
the project with more mutation points are familiar for developers
working in bigger teams. Let’s see an example of how hard it is to
manage shared state. Take a look at the below snippet⁶. It shows
multiple threads trying to modify the same property, however
because of conflicts some of those operations will be lost.
1 var num = 0
2 for (i in 1..1000) {
3 thread {
4 Thread.sleep(10)
5 num += 1
6 }
7 }
8 Thread.sleep(5000)
9 print(num) // Very unlikely to be 1000
10 // Every time a different number
When we use Kotlin coroutines, there are less conflicts because less
threads are involved, but they still occur:
⁶To test it, just place it in an entry point (main function) and run.
Similarly with other snippets not having an entry point.
28. Chapter 1: Safety 18
1 suspend fun main() {
2 var num = 0
3 coroutineScope {
4 for (i in 1..1000) {
5 launch {
6 delay(10)
7 num += 1
8 }
9 }
10 }
11 print(num) // Every time a different number
12 }
In real-life projects, we generally cannot just lose some operations,
and so we need to implement proper synchronization like the one
presented below. Although implementing proper synchronization
is hard, and the more mutation points we have, the harder it is.
Limiting mutability does help.
1 val lock = Any()
2 var num = 0
3 for (i in 1..1000) {
4 thread {
5 Thread.sleep(10)
6 synchronized(lock) {
7 num += 1
8 }
9 }
10 }
11 Thread.sleep(1000)
12 print(num) // 1000
The drawbacks of mutability are so numerous that there are lan-
guages that do not allow state mutation at all. These are purely
functional languages. One well-known example is Haskell. Such
29. Chapter 1: Safety 19
languages are rarely used for mainstream development though,
since it’s very hard to do programming with so limited mutability.
Mutating state is a very useful way to represent the state of real-
world systems. I recommend using mutability, but do it sparingly
and wisely decide where our mutating points should be. The good
news is that Kotlin supports limiting mutability well.
Limiting mutability in Kotlin
Kotlin is designed to support limiting mutability. It is easy to make
immutable objects or to keep properties immutable. It is a result
of many features and characteristics of this language, but the most
important ones are:
• Read-only properties val
• Separation between mutable and read-only collections
• copy in data classes
Let’s discuss them one by one.
Read-only properties val
In Kotlin we can make each property read-only val (like value)
or read-write var (like variable). Read-only properties val do not
allow setting:
1 val a = 10
2 a = 20 // ERROR
Notice though that read-only properties are not necessarily im-
mutable nor final. A read-only property can hold a mutable object:
30. Chapter 1: Safety 20
1 val list = mutableListOf(1,2,3)
2 list.add(4)
3
4 print(list) // [1, 2, 3, 4]
A read-only property can also be defined using a custom getter that
might depend on another property:
1 var name: String = "Marcin"
2 var surname: String = "Moskała"
3 val fullName
4 get() = "$name $surname"
5
6 fun main() {
7 println(fullName) // Marcin Moskała
8 name = "Maja"
9 println(fullName) // Maja Moskała
10 }
Notice that it is possible because when we define a custom getter,
it will be called every time we ask for the value.
1 fun calculate(): Int {
2 print("Calculating... ")
3 return 42
4 }
5
6 val fizz = calculate() // Calculating...
7 val buzz
8 get() = calculate()
9
10 fun main() {
11 print(fizz) // 42
12 print(fizz) // 42
13 print(buzz) // Calculating... 42
31. Chapter 1: Safety 21
14 print(buzz) // Calculating... 42
15 }
This trait, that properties in Kotlin are encapsulated by default
and they can have custom accessors (getters and setters) is very
important in Kotlin because it gives us flexibility when we change
or define our API. It will be described in detail in Item 16: Properties
should represent state, not behavior. The core idea though is that
val do not offer mutation points because it is only a getter under
the hood when var is both getter and setter. That’s why we can
override val with var:
1 interface Element {
2 val active: Boolean
3 }
4
5 class ActualElement: Element {
6 override var active: Boolean = false
7 }
Values of read-only properties val can change, but such properties
do not offer a mutation point which is the main source of problems
when we need to synchronize or reason about a program. This is
why we generally prefer val over var.
Although remember that val doesn’t mean immutable. It can be
defined by getter or delegate. This fact gives us more freedom to
change. Though when we don’t need that, final properties should
be preferred. It is easier to reason about them as they have the state
stated next to their definition. They are also better supported in
Kotlin. For instance, they can be smart-casted:
32. Chapter 1: Safety 22
1 val name: String? = "Márton"
2 val surname: String = "Braun"
3
4 val fullName: String?
5 get() = name?.let { "$it $surname" }
6
7 val fullName2: String? = name?.let { "$it $surname" }
8
9 fun main() {
10 if (fullName != null) {
11 println(fullName.length) // ERROR
12 }
13
14 if (fullName2 != null) {
15 println(fullName2.length) // Márton Braun
16 }
17 }
Smart cast is impossible for fullName because it is defined using
getter, so it might give a different value during check and different
later during use (for instance, if some other thread would set name).
Non-local properties can be smart-casted only when they are final
and do not have custom getter.
Separation between mutable and read-only
collections
Similarly, as Kotlin separates read-write and read-only proper-
ties, Kotlin separates read-write and read-only collections. This is
achieved thanks to the way the hierarchy of collections was de-
signed. Take a look at the diagram presenting collections hierarchy
in Kotlin. On the left side, you can see the Iterable, Collection,
Set, and List interfaces that are read-only. This means that they do
not have any methods that would allow modification. On the right
side, you can see the MutableIterable, MutableCollection,
33. Chapter 1: Safety 23
MutableSet, and MutableList interfaces that represent muta-
ble collections. Notice that each mutable interface extends the
corresponding read-only interface, and adds methods that allow
mutation. This is similar to how properties work. A read-only
property means just a getter, while a read-write property means
both a getter and a setter.
The hierarchy of collection interfaces in Kotlin and actual objects that can be
used on Kotlin/JVM. On the left side interfaces are read-only. On the right side
collections and interfaces are mutable.
Read-only collections are not necessarily immutable. Very often
they are mutable, but they cannot be mutated because they are hid-
den behind read-only interfaces. For instance, the Iterable<T>.map
and Iterable<T>.filter functions return ArrayList, which is a
mutable list, as a List, which is a read-only interface. In the below
snippet you can see a simplified implementation of Iterable<T>.map
from stdlib.
34. Chapter 1: Safety 24
1 inline fun <T, R> Iterable<T>.map(
2 transformation: (T) -> R
3 ): List<R> {
4 val list = ArrayList<R>()
5 for (elem in this) {
6 list.add(transformation(elem))
7 }
8 return list
9 }
The design choice to make these collection interfaces read-only
instead of truly immutable is very important. It gives us much more
freedom. Under the hood, any actual collection can be returned as
long as it satisfies the interface. Therefore, we can use platform-
specific collections.
The safety of this approach is close to the one achieved from having
immutable collections. The only risk is when a developer tries to
“hack the system” and performs down-casting. This is something
that should never be allowed in Kotlin projects. We should be able
to trust that when we return a list as read-only, it will be used only
to read it. This is part of the contract. More about it on Part 2 of
this book.
Down-casting collections is not only breaking their contract and
depending on implementation instead of abstraction as we should,
but it is also insecure and can lead to surprising consequences. Take
a look at this code:
1 val list = listOf(1,2,3)
2
3 // DON’T DO THIS!
4 if (list is MutableList) {
5 list.add(4)
6 }
35. Chapter 1: Safety 25
The result of this operation is platform-specific. On the JVM listOf
returns an instance of Arrays.ArrayList that implements Java
List interface. This Java List interface has methods like add
or set, and so it translates to the Kotlin MutableList interface.
However, Arrays.ArrayList does not implement some of those
operations. This is why the result of the above code is the following:
Exception in thread “main”
java.lang.UnsupportedOperationException
at java.util.AbstractList.add(AbstractList.java:148)
at java.util.AbstractList.add(AbstractList.java:108)
Though there is no guarantee how this will behave in a year from
now. Underlying collections might change. They might be replaced
with truly immutable collections implemented in Kotlin and not
implementing MutableList at all. Nothing is guaranteed. This
is why down-casting read-only collections to mutable should
never take place in Kotlin. If you need to change from read-only
to mutable, you should use List.toMutableList function, which
creates a copy that you can then modify:
1 val list = listOf(1, 2, 3)
2
3 val mutableList = list.toMutableList()
4 mutableList.add(4)
This way does not breaking any contract, and it is also safer for us
as we can feel safe that when we expose something as List it won’t
be modified from outside.
Copy in data classes
There are many reasons to prefer immutable objects - objects that
do not change their internal state, like String or Int. In addition to
36. Chapter 1: Safety 26
the already named reasons why we generally prefer less mutability,
immutable objects have their own advantages:
1. They are easier to reason about since their state stays the same
once they are created.
2. Immutability makes it easier to parallelize the program as
there are no conflicts among shared objects.
3. References to immutable objects can be cached as they are
not going to change.
4. We do not need to make defensive copies on immutable
objects. When we do copy immutable objects, we do not need
to make it a deep copy.
5. Immutable objects are the perfect material to construct other
objects. Both mutable and immutable. We can still decide
where mutability takes place, and it is easier to operate on
immutable objects.
6. We can add them to set or use them as keys in maps, in
opposition to mutable objects that shouldn’t be used this way.
This is because both those collections use hash table under the
hood in Kotlin/JVM, and when we modify elements already
classified to a hash table, its classification might not be correct
anymore and we won’t be able to find it. This problem will
be described in detail in Item 41: Respect the contract of
hashCode. We have a similar issue when a collection is sorted.
37. Chapter 1: Safety 27
1 val names: SortedSet<FullName> = TreeSet()
2 val person = FullName("AAA", "AAA")
3 names.add(person)
4 names.add(FullName("Jordan", "Hansen"))
5 names.add(FullName("David", "Blanc"))
6
7 print(s) // [AAA AAA, David Blanc, Jordan Hansen]
8 print(person in names) // true
9
10 person.name = "ZZZ"
11 print(names) // [ZZZ AAA, David Blanc, Jordan Hansen]
12 print(person in names) // false
At the last check, collection returned false even though that person
is in this set. It couldn’t be found because it is in an incorrect
position.
As you can see, mutable objects are more dangerous and less
predictable. On the other hand, the biggest problem of immutable
objects is that data sometimes needs to change. The solution is
that the immutable objects should have methods that produce an
object after some change. For instance, Int is immutable, and it has
many methods like plus or minus that do not modify it but instead
return a new Int after this operation. Iterable is read-only, and
collection processing functions like map or filter do not modify
it, but instead return a new collection. The same can be applied
to our immutable objects. For instance, let’s say that we have an
immutable class User and we need to allow its surname to change.
We can support it with a withSurname method that produces a copy
with a particular property changed:
38. Chapter 1: Safety 28
1 class User(
2 val name: String,
3 val surname: String
4 ) {
5 fun withSurname(surname: String) = User(name, surname)
6 }
7
8 var user = User("Maja", "Markiewicz")
9 user = user.withSurname("Moskała")
10 print(user) // User(name=Maja, surname=Moskała)
Writing such functions is possible, but also tedious if we need one
for every property. Here comes the data modifier to the rescue. One
of the methods it generates is copy. It creates a new instance where
all primary constructor properties are the same as in the previous
one by default. New values can be specified as well. copy together
with other methods generated by data modifier are described in
detail in Item 37: Use data modifier to represent a bundle of data.
Here is a simple example showing how it works:
1 data class User(
2 val name: String,
3 val surname: String
4 )
5
6 var user = User("Maja", "Markiewicz")
7 user = user.copy(surname = "Moskała")
8 print(user) // User(name=Maja, surname=Moskała)
This is an elegant and universal solution that supports making data
model classes immutable. Surely, this way is less efficient than just
using a mutable object instead, but it has all described advantages
of immutable objects and should be preferred by default.
39. Chapter 1: Safety 29
Different kinds of mutation points
Let’s say that we need to represent a mutating list. There are two
ways we can achieve that. Either by using a mutable collection or
by using read-write property var:
1 val list1: MutableList<Int> = mutableListOf()
2 var list2: List<Int> = listOf()
Both properties can be modified, but in different ways:
1 list1.add(1)
2 list2 = list2 + 1
Both of these ways can be replaced with the plus-assign operator
as well, but each of them is translated into a different behavior:
1 list1 += 1 // Translates to list1.plusAssign(1)
2 list2 += 1 // Translates to list2 = list2.plus(1)
Both those ways are correct and they both have their pros and
cons. They both have a single mutating point, but it is located in a
different place. In the first one mutation takes place on the concrete
list implementation. We might depend on the fact that it has proper
synchronization in case of multithreading, but such an assumption
is also dangerous since it is not really guaranteed. In the second
one, we need to implement the synchronization ourselves, but the
overall safety is better because the mutating point is only a single
property. Though, in case of a lack of synchronization, remember
that we can still lose some elements:
40. Chapter 1: Safety 30
1 var list = listOf<Int>()
2 for (i in 1..1000) {
3 thread {
4 list = list + i
5 }
6 }
7 Thread.sleep(1000)
8 print(list.size) // Very unlikely to be 1000,
9 // every time a different number, like for instance 911
Using a mutable property instead of a mutable list allows us to track
how this property changes when we define a custom setter or using
a delegate (which is using a custom setter). For instance, when we
use an observable delegate, we can log every change of a list:
1 var names by Delegates.observable(listOf<String>()) {
2 _, old, new ->
3 println("Names changed from $old to $new")
4 }
5
6 names += "Fabio"
7 // Names changed from [] to [Fabio]
8 names += "Bill"
9 // Names changed from [Fabio] to [Fabio, Bill]
To make this possible for a mutable collection, we would need a
special observable implementation of the collection. For read-only
collections on mutable properties, it is also easier to control how
they change - there is only a setter instead of multiple methods
mutating this object, and we can make it private:
1 var announcements = listOf<Announcement>()
2 private set
41. Chapter 1: Safety 31
In short, using mutable collections is a slightly faster option, but
using a mutable property instead gives us more control over how
the object is changing.
Notice that the worst solution is to have both a mutating property
and a mutable collection:
1 // Don’t do that
2 var list3 = mutableListOf<Int>()
We would need to synchronize both ways it can mutate (by
property change and by internal state change). Also, changing it
using plus-assign is impossible because of ambiguity:
The general rule is that one should not create unnecessary ways
to mutate state. Every way to mutate state is a cost. It needs to be
understood and maintained. We prefer to limit mutability.
Do not leak mutation points
It is an especially dangerous situation when we expose a mutable
object that makes up state. Take a look at this example:
42. Chapter 1: Safety 32
1 data class User(val name: String)
2
3 class UserRepository {
4 private val storedUsers: MutableMap<Int, String> =
5 mutableMapOf()
6
7 fun loadAll(): MutableMap<Int, String> {
8 return storedUsers
9 }
10
11 //...
12 }
One could use loadAll to modify UserRepository private state:
1 val userRepository = UserRepository()
2
3 val storedUsers = userRepository.loadAll()
4 storedUsers[4] = "Kirill"
5 //...
6
7 print(userRepository.loadAll()) // {4=Kirill}
It is especially dangerous when such modifications are accidental.
There are two ways how we can deal with that. The first one is
copying returned mutable objects. We call that defensive copying.
This can be a useful technique when we deal with a standard objects
and here copy generated by data modifier can be really helpful:
43. Chapter 1: Safety 33
1 class UserHolder {
2 private val user: MutableUser()
3
4 fun get(): MutableUser {
5 return user.copy()
6 }
7
8 //...
9 }
Though whenever possible we prefer limiting mutability, and for
collections we can do that by upcasting those objects to their read-
only supertype:
1 data class User(val name: String)
2
3 class UserRepository {
4 private val storedUsers: MutableMap<Int, String> =
5 mutableMapOf()
6
7 fun loadAll(): Map<Int, String> {
8 return storedUsers
9 }
10
11 //...
12 }
Summary
In this chapter we’ve learned why it is important to limit mutability
and to prefer immutable objects. We’ve seen that Kotlin gives us a
lot of tools that support limiting mutability. We should use them to
limit mutation points. Simple rules are:
• Prefer val over var.
44. Chapter 1: Safety 34
• Prefer an immutable property over a mutable one.
• Prefer objects and classes that are immutable over mutable.
• If you need them to change, consider making them immutable
data classes, and using copy.
• When you hold state, prefer read-only over mutable collec-
tions.
• Design your mutation points wisely and do not produce
unnecessary ones.
• Do not expose mutable objects.
There are some exceptions to these rules. Sometimes we prefer a
mutable object because they are more efficient. Such optimizations
should be preferred only in the performance critical parts of our
code (Part 3: Efficiency) and when we use them, we need to remem-
ber that mutability requires more attention when we prepare it for
multithreading. The baseline is that we should limit mutability.
45. Chapter 1: Safety 35
Item 2: Minimize the scope of
variables
When we define a state, we prefer to tighten the scope of variables
and properties by:
• Using local variables instead of properties
• Using variables in the narrowest scope possible, so for in-
stance, if a variable is used only inside a loop, defining it
inside this loop
The scope of an element is the region of a computer program where
the element is visible. In Kotlin, the scope is nearly always created
by curly braces, and we can generally access elements from the
outer scope. Take a look at this example:
1 val a = 1
2 fun fizz() {
3 val b = 2
4 print(a + b)
5 }
6 val buzz = {
7 val c = 3
8 print(a + c)
9 }
10 // Here we can see a, but not b nor c
In the above example, in the scope of the functions fizz and buzz,
we can access variables from the outer scope. However, in the outer
scope, we cannot access variables defined in those functions. Here
is an example of how limiting variable scope might look like:
46. Chapter 1: Safety 36
1 // Bad
2 var user: User
3 for (i in users.indices) {
4 user = users[i]
5 print("User at $i is $user")
6 }
7
8 // Better
9 for (i in users.indices) {
10 val user = users[i]
11 print("User at $i is $user")
12 }
13
14 // Same variables scope, nicer syntax
15 for ((i, user) in users.withIndex()) {
16 print("User at $i is $user")
17 }
In the first example, the user variable is accessible not only in the
scope of the for-loop, but also outside of it. In the second and third
examples, we limit the scope of the user variable concretely to the
scope of the for-loop.
Similarly, we might have many scopes inside scopes (most likely
created by lambda expressions inside lambda expressions), and it is
better to define variables in as narrow scope as possible.
There are many reasons why we prefer it this way, but the most
important one is: When we tighten a variable’s scope, it is easier
to keep our programs simple to track and manage. When we
analyze code, we need to think about what elements are there at
this point. The more elements there are to deal with, the harder
it is to do programming. The simpler your application is, the less
likely it will be to break. This is a similar reason to why we prefer
immutable properties or objects over their mutable counterparts.
Thinking about mutable properties, it is easier to track how
47. Chapter 1: Safety 37
they change when they can only be modified in a smaller scope.
It is easier to reason about them and change their behavior.
Another problem is that variables with a wider scope might be
overused by another developer. For instance, one could reason
that if a variable is used to assign the next elements in an iteration,
the last element in the list should remain in that variable once the
loop is complete. Such reasoning could lead to terrible abuse, like
using this variable after the iteration to do something with the last
element. It would be really bad because another developer trying
to understand what value is there would need to understand the
whole reasoning. This would be a needless complication.
Whether a variable is read-only or read-write, we always
prefer a variable to be initialized when it is defined. Do not force
a developer to look where it was defined. This can be supported
with control structures such as if, when, try-catch or the Elvis
operator used as expressions:
1 // Bad
2 val user: User
3 if (hasValue) {
4 user = getValue()
5 } else {
6 user = User()
7 }
8
9 // Better
10 val user: User = if(hasValue) {
11 getValue()
12 } else {
13 User()
14 }
If we need to set-up multiple properties, destructuring declarations
can help us:
48. Chapter 1: Safety 38
1 // Bad
2 fun updateWeather(degrees: Int) {
3 val description: String
4 val color: Int
5 if (degrees < 5) {
6 description = "cold"
7 color = Color.BLUE
8 } else if (degrees < 23) {
9 description = "mild"
10 color = Color.YELLOW
11 } else {
12 description = "hot"
13 color = Color.RED
14 }
15 // ...
16 }
17
18 // Better
19 fun updateWeather(degrees: Int) {
20 val (description, color) = when {
21 degrees < 5 -> "cold" to Color.BLUE
22 degrees < 23 -> "mild" to Color.YELLOW
23 else -> "hot" to Color.RED
24 }
25 // ...
26 }
Finally, too wide variable scope can be dangerous. Let’s describe
one common danger.
Capturing
When I teach about Kotlin coroutines, one of my exercises is to
implement the Sieve of Eratosthenes to find prime numbers using
a sequence builder. The algorithm is conceptually simple:
49. Chapter 1: Safety 39
1. We take a list of numbers starting from 2.
2. We take the first one. It is a prime number.
3. From the rest of the numbers, we remove the first one and
we filter out all the numbers that are divisible by this prime
number.
A very simple implementation of this algorithm looks like this:
1 var numbers = (2..100).toList()
2 val primes = mutableListOf<Int>()
3 while (numbers.isNotEmpty()) {
4 val prime = numbers.first()
5 primes.add(prime)
6 numbers = numbers.filter { it % prime != 0 }
7 }
8 print(primes) // [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31,
9 // 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]
The challenge is to let it produce a potentially infinite sequence of
prime numbers. If you want to challenge yourself, stop now and try
to implement it.
This is what the solution could look like:
1 val primes: Sequence<Int> = sequence {
2 var numbers = generateSequence(2) { it + 1 }
3
4 while (true) {
5 val prime = numbers.first()
6 yield(prime)
7 numbers = numbers.drop(1)
8 .filter { it % prime != 0 }
9 }
10 }
11
50. Chapter 1: Safety 40
12 print(primes.take(10).toList())
13 // [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
Although in nearly every group there is a person who tries to
“optimize” it, and to not create the variable in every loop he or
she extracts prime as a mutable variable:
1 val primes: Sequence<Int> = sequence {
2 var numbers = generateSequence(2) { it + 1 }
3
4 var prime: Int
5 while (true) {
6 prime = numbers.first()
7 yield(prime)
8 numbers = numbers.drop(1)
9 .filter { it % prime != 0 }
10 }
11 }
The problem is that this implementation does not work correctly
anymore. These are the first 10 yielded numbers:
1 print(primes.take(10).toList())
2 // [2, 3, 5, 6, 7, 8, 9, 10, 11, 12]
Stop now and try to explain this result.
The reason why we have such a result is that we captured the vari-
able prime. Filtering is done lazily because we’re using a sequence.
In every step, we add more and more filters. In the “optimized”
one we always add the filter which references the mutable property
prime. Therefore we always filter the last value of prime. This is
why this filtering does not work properly. Only dropping works
and so we end up with consecutive numbers (except for 4 which
was filtered out when prime was still set to 2).
51. Chapter 1: Safety 41
We should be aware of problems with unintentional capturing
because such situations happen. To prevent them we should avoid
mutability and prefer narrower scope for variables.
Summary
For many reasons, we should prefer to define variables for the
closest possible scope. Also, we prefer val over var also for local
variables. We should always be aware of the fact that variables are
captured in lambdas. These simple rules can save us a lot of trouble.
52. Chapter 1: Safety 42
Item 3: Eliminate platform types as
soon as possible
The null-safety introduced by Kotlin is amazing. Java was known in
the community from Null-Pointer Exceptions (NPE), and Kotlin’s
safety mechanisms make them rare or eliminate them entirely. Al-
though one thing that cannot be secured completely is a connection
between a language that does not have solid null-safety - like Java
or C - and Kotlin. Imagine that we use a Java method that declares
String as a return type. What type should it be in Kotlin?
If it is annotated with the @Nullable annotation then we assume
that it is nullable and we interpret it as a String?. If it is annotated
with @NotNull then we trust this annotation and we type it as
String. Though, what if this return type is not annotated with
either of those annotations?
1 // Java
2 public class JavaTest {
3
4 public String giveName() {
5 // ...
6 }
7 }
We might say that then we should treat such a type as nullable.
This would be a safe approach since in Java everything is nullable.
However, we often know that something is not null so we would
end up using the not-null assertion !! in many places all around
our code.
The real problem would be when we would need to take generic
types from Java. Imagine that a Java API returns a List<User>
that is not annotated at all. If Kotlin would assume nullable types
by default, and we would know that this list and those users are not
53. Chapter 1: Safety 43
null, we would need to not only assert the whole list but also filter
nulls:
1 // Java
2 public class UserRepo {
3
4 public List<User> getUsers() {
5 //***
6 }
7 }
8
9 // Kotlin
10 val users: List<User> = UserRepo().users!!.filterNotNull()
What if a function would return a List<List<User>> instead?
Gets complicated:
1 val users: List<List<User>> = UserRepo().groupedUsers!!
2 .map { it!!.filterNotNull() }
Lists at least have functions like map and filterNotNull. In other
generic types, nullability would be an even bigger problem. This
is why instead of being treated as nullable by default, a type that
comes from Java and has unknown nullability is a special type in
Kotlin. It is called a platform type.
Platform type - a type that comes from another language and has
unknown nullability.
Platform types are notated with a single exclamation mark ! after
the type name, such as String!. Though this notation cannot be
used in a code. Platform types are non-denotable, meaning that
one cannot write them down explicitly in the language. When a
platform value is assigned to a Kotlin variable or property, it can
be inferred but it cannot be explicitly set. Instead, we can choose
the type that we expect: Either a nullable or a non-null type.
54. Chapter 1: Safety 44
1 // Java
2 public class UserRepo {
3 public User getUser() {
4 //...
5 }
6 }
7
8 // Kotlin
9 val repo = UserRepo()
10 val user1 = repo.user // Type of user1 is User!
11 val user2: User = repo.user // Type of user2 is User
12 val user3: User? = repo.user // Type of user3 is User?
Thanks to this fact, getting generic types from Java is not problem-
atic:
1 val users: List<User> = UserRepo().users
2 val users: List<List<User>> = UserRepo().groupedUsers
The problem is that is still dangerous because something we as-
sumed to be not-null might be null. This is why for safety reasons
I always suggest to be very conscientious of when we get platform
types from Java. Remember that even if a function does not return
null now, that doesn’t mean that it won’t change in the future. If
its designer hasn’t specified it by an annotation or by describing it
in a comment, they can introduce this behavior without changing
any contract.
If you have some control over Java code that needs to interoper-
ate with Kotlin, introduce @Nullable and @NotNull annotations
wherever possible.
56. The defenders reeled back, and Santa Anna, thinking the time
had come to deliver the final blow, sent the Mexican infantry in
thousands down the sides of the gorge, where they attacked with
the bayonet the few hundreds that yet fought. Phil was quite sure
that no hope was left. Before, at every critical moment there had
always been a slender chance of some kind or other, but now he
could see absolutely none. A million red motes danced before him,
and he struck almost blindly with his clubbed rifle at a Mexican who
was trying to bayonet him.
But from a point above, not yet taken by the Mexicans, the
brave O'Brien and Thomas, as brave, were still firing their cannon
and sending the shot and shell into the Mexican masses, where they
were not mingled with the Americans. But they themselves were
exposed to a deadly fire. One by one their gunners fell. They were
compelled to fall back step by step. Not enough men were left to
load and fire the pieces. Soon all the gunners were killed or
wounded except O'Brien himself. Presently he, too, was wounded,
and the guns were silent. Now, truly, it seemed that the last moment
had come!
Phil, when he struck with his clubbed rifle, knew that he hit
something, because the Mexican with the eager bayonet was no
longer there. He saw Breakstone and Arenberg yet beside him, both
wounded, but both erect and defiant. He saw Grayson a little
distance away, still alive, and farther on a little group of Kentuckians
and Illinoisans, fighting to the last. He had an instant's vision of the
whole awful gorge, filled with men driven on by the rage of battle,
the dead and wounded strewed all about, the smoke hovering above
57. like a roof, and the masses of Mexicans who completely encircled
them now closing in for the final blow.
It was all a real panorama, passing in an instant, and then from
above, and at a new point, came the crash of great guns, the shot
and shell striking among the Mexicans, not among the Americans.
Not even at this, the last crisis, when the battle seemed lost beyond
redemption, had fortune, or rather courage and energy, failed.
Bragg, coming on a run with his battery, suddenly opened at short
range, and with awful effect, into the Mexican masses. In another
minute Sherman arrived with his guns, and close behind, coming as
fast as breath would allow, were infantry with the rifle, and, to make
the surprise complete, Washington's guns suddenly appeared on the
right and began to sweep away the lancers who held the mouth of
the gorge.
Never had fortune made a quicker and more complete change.
The Mexicans who had suddenly trapped the Kentuckians and
Illinoisans had been entrapped themselves with equal suddenness.
The fire now rose to the greatest height of the day. They had
been fighting on the plateau, in the ravines, on the slopes, and
through the pass for hours. Vast quantities of smoke still hung about
and lay like a blanket against the side of the mountain. The sun was
far down the western slope.
The Kentucky and Illinois men drew themselves into a close
body near the upper end of the gorge. There they fired as fast as
exhaustion would allow, but salvation was coming from above, and
now they knew it. Closer and closer crept the American artillery.
Heavier and heavier grew its fire. The riflemen, also, sent in the
bullets like hail. Taylor himself, a half dozen bullets through his
58. clothing, stood on the brink directing the attack. The gorge where
the Mexicans stood was swept by a storm of death. Santa Anna,
from the other side, watched in dismay. Lancers and infantry alike,
unable to stand such a sleet, rushed for the mouth of the gorge.
Few of the lancers, who made the larger target, escaped, and the
infantry suffered almost as much.
The gorge was cleared, and the Americans held the plateau.
Everywhere the Mexicans fell back, leaving the whole field in
possession of the little force that had fought so long and so fiercely
to hold it. The Mexican bugle sounded again, but now it was the
command to retire. The sun dipped down behind the mountains, and
the shadows began to gather in the Pass of Angostura. The
impossible had happened. Mexico's finest army, five to one, led by
her greatest general, had broken in vain against the farmer lads of
the South and West, and the little band of regulars. The victory was
won over the greatest odds ever faced by Americans in a pitched
battle.
CHAPTER XV
THE WOMAN AT THE WELL
Phil was still in a daze. He and those around him, exhausted by such
long and desperate efforts, such a continuous roar in their ears, and
such a variation of intense emotions from the highest to the lowest,
were scarcely conscious that the battle was over. They knew, indeed,
that night was falling on the mountains and the pass, that the
59. Mexicans had withdrawn from the field, that their flags and lances
were fading in the twilight, but it was all, for a little while, dim and
vague to them. The night and the silence coming together contained
a great awe. Phil felt the blood pounding in his ears, and he looked
around with wonder. It was Breakstone who first came to himself.
"We've won! We've won!" he cried. "As sure as there is a sun
behind those mountains, we've beat all Mexico!"
Then Phil, too, saw, and he had to believe.
"The victory is ours!" he cried.
"It is ours, but harm has been done," said Arenberg in a low
voice. Then he sank forward softly on his face. Phil and Breakstone
quickly raised him up. He had fainted from loss of blood, but as his
wounds were only of the flesh he was soon revived. Breakstone had
three slight wounds of his own, and these were bound up, also. Phil,
meanwhile, was hunting in the gorge for other friends. Grayson was
alive and well, but some that he had known were gone. He was
weak, mind and body alike, with the relaxation from the long battle
and all those terrible emotions, but he helped with the wounded.
Below them lay the army of Santa Anna, its lights shining again in
the darkness, and, for all Phil knew, it might attack again on the
morrow, but he gave little attention to it now. His whole concern was
for his comrades. The victory had been won, but they had been
compelled to purchase it at a great price. The losses were heavy.
Twenty-eight officers of rank were among the killed, regiments were
decimated, and even the unhurt were so exhausted that they could
scarcely stand.
Phil sat down at the edge of the gorge. He was yet faint and
dizzy. It seemed to him that he would never be able to exert himself
60. again. Everything swam before him in a sort of confused glare. He
was conscious that his clothing was stained red in two or three
places, but when he looked, in a mechanical way, at the wounds, he
saw they were scratches, closed already by the processes of nature.
Then his attention wandered again to the field. He was full of the joy
of victory, but it was a vague, uncertain feeling, not attaching itself
to any particular thing.
The twilight had already sunk into the night, and the black
wind, heavy with chill, moaned in the Pass of Angostura. It was a
veritable dirge for the dead. Phil felt it all through his relaxed frame,
and shivered both with cold and with awe. Smoke and vapor from so
much firing still floated about the plateau, the pass, and the slopes,
but there was a burning touch on his face which he knew did not
come from any of them. It was the dust of the desert again stinging
him after the battle as it had done before it. He obeyed its call,
summoned anew all his strength, both of body and mind, and
climbed out of the gorge, where friend and foe still lay in hundreds,
mingled and peaceful in death.
He found more light and cheer on the plateau and in the pass.
Here the unhurt and those hurt slightly were building fires, and they
had begun to cook food and boil coffee. Phil suddenly perceived that
he was hungry. He had not tasted food since morning. He joined one
of the groups, ate and drank, and more vigor returned. Then he
thought of the horse which he had left tethered in an alcove, and
which he had not used at all that day. The horse was there
unharmed, although a large cannon-ball lay near his feet. It was
evidently a spent ball which had rolled down the side of the
mountain, as it was not buried at all.
61. The horse recognized Phil and neighed. Phil put his hand upon
his mane and stroked it. He was very glad that this comrade of his
had escaped unhurt. He wondered in a dim way what his terror must
have been tied in one place, while the battle raged all day about
him. "Poor old horse," he said, stroking his mane again. Then he led
him away, gave him food and water, and returned to his comrades
and the field. He knew that his duty lay there, as the Mexican army
was still at hand. Many thought that it would attack again in the
morning, and disposition for defense must be made. He did not see
either Breakstone or Arenberg, but he met Middleton, to whom he
reported.
"Scout down at the mouth of the pass and along the mountain
slopes, Phil," he said, and the boy, replenishing his ammunition,
obeyed. It was not quite dark, and the wind was exceedingly cold.
The mercury that night went below the freezing point, and the
sufferings of the wounded were intense. Phil kept well among the
ravines and crags. He believed that the Mexican lancers would be
prowling in front of their camp, and he would not have much chance
if he were attacked by a group of them. Moreover, he was tired of
fighting. He did not wish to hurt anybody. Never had his soul inclined
more fervently to peace.
He passed again into the gorge which had witnessed the climax
and deadliest part of the battle. Here he saw dark-robed figures
passing back and forth among the wounded. He looked more closely
and saw that they were Mexican nuns from a convent near Buena
Vista, helping the wounded, Americans and Mexicans alike.
Something rose in his throat, but he went on, crossing the pass and
climbing the slopes of the Sierra Madre. Here there was yet smoke
62. lingering in the nooks and crannies, but all the riflemen seemed to
have gone.
He climbed higher. The wind there was very cold, but the
moonlight was brighter. He saw the peaks and ridges of the Sierra
Madre, like a confused sea, and he looked down upon the two
camps, the small American one on the plateau and in the pass and
the larger, still far larger, Mexican one below. He could trace it by the
lights in the Mexican camp, forming a great half circle, and he would
have given much to know what was going on there. If Santa Anna
and his men possessed the courage and tenacity of the defenders,
they would attack again on the morrow.
He moved forward a little to get a better view, and then sank
down behind an outcropping of rock. A Mexican, a tall man, rifle on
shoulder, was passing. He, too, was looking down at the two camps,
and Phil believed that he was a scout like himself. The Mexican, not
suspecting the presence of an enemy, was only a dozen feet away,
and Phil could easily have shot him without danger to himself, but
every impulse was against the deed. He could not fire from ambush,
and he had seen enough of death. The Mexican was going toward
his own camp, and presently, he went on, disappearing behind a
curve of the mountain, and leaving Phil without a shadow of
remorse. But he soon followed, creeping on down the mountainside
toward the camp of Santa Anna.
The rocks and gullies enabled him to come so near that he
could see within the range of light. He beheld figures as they passed
now and then, dark shadows before the blaze, but the camp of
Santa Anna did not show the life and animation that he had
witnessed in it when he spied upon it once before. No bugles were
63. blowing, no bodies of lancers, with the firelight shining on glittering
steel, rode forth to prepare for the morrow and victory. Everything
was slack and relaxed. He even saw men lying in hundreds upon the
ground, fast asleep from exhaustion. As far as he could determine,
no scouting parties of large size were abroad, and he inferred from
what he saw that the Mexican army was worn out.
He could not go among those men, but the general effect
produced upon him at the distance was of gloom and despair among
them. An army preparing for battle in the morning would be awake
and active. The longer he looked, the greater became his own hope
and confidence, and then he slowly made his way back to his own
camp with his report. Lights still burned there, but it was very silent.
After he passed the ring of sentinels he saw nothing but men
stretched out, almost as still as the dead around them. They slept
deeply, heavily, a sleep so intense that a blow would not arouse.
Many had lain down where they were standing when the battle
ceased, and would lie there in dreamless slumber until the next
morning. Phil stepped over them, and near one of the fires he saw
Breakstone and Arenberg, each with his head on his arm, deep in
slumber.
He made his report to Middleton, describing with vivid detail
everything that he had seen.
"It agrees with the reports of the other scouts," said Middleton.
"I think the enemy is so shattered that he cannot move upon us
again, and now, Phil, you must rest. It will be midnight in an hour,
and you have passed through much."
"It was a great battle!" said Phil, with a look of pride.
64. "And a great victory!" said Middleton, he, too, although older,
feeling that flash of pride.
Phil was glad enough now to seek sleep. The nervous
excitement that kept him awake and alert was all gone. He
remembered the fire beside which Bill Breakstone and Arenberg
slept, and made his way back there. Neither had moved a particle.
They still lay with their heads on their elbows, and they drew long,
deep breaths with such steadiness and regularity that apparently
they had made up their minds to sleep for years to come. Four other
men lay near them in the same happy condition.
"Six," said Phil. "Well, the fable tells of the Seven Sleepers, so I
might as well complete the number."
He chose the best place that was left, secured his blanket from
his saddlebow, wrapped himself thoroughly in it, and lay down with
his feet to the fire. How glorious it felt! It was certainly very cold in
the Pass of Angostura. Ice was forming, and the wind cut, but there
was the fire at his feet and the thick blanket around him. His body
felt warm through and through, and the hard earth was like down
after such a day. Now victory came, too, with its pleasantest aroma.
Lying there under the stars, he could realize, in its great sense, all
that they had done. And he had borne his manly part in it. He was a
boy, and he had reason for pride.
Phil stared up for a little while at the cold stars which danced in
the sky, myriads of miles away, but after awhile his glance turned
again toward the earth. The other six of the seven sleepers slept on,
not stirring at all, save for the rising and falling of their chests, and
Phil decided that he was neglecting his duty by failing to join them
at once in that vague and delightful land to which they had gone.
65. He shut his eyes, opened them once a minute or two later, but
found the task of holding up the lids too heavy. They shut down
again, stayed down, and in two minutes the six sleepers had become
the seven.
Phil slept the remainder of the night as heavily as if he had
been steeped in some eastern drug. He, too, neither moved hand
nor foot after he had once gone to oblivion. The fire burned out, but
he did not awake. He was warm in his blanket, and sleep was
bringing back the strength that body and mind had wasted in the
day. It was quiet, too, on the battlefield. The surgeons still worked
with the wounded, but they had been taken back in the shelter of
the pass, and the sounds did not come to those on the plateau. Only
the wind moaned incessantly, and the cold was raw and bitter.
About half way between midnight and morning Bill Breakstone
awoke. He merely opened his eyes, not moving his body, but he
stared about him in a dim wonder. His awakening had interrupted a
most extraordinary dream. He had been dreaming that he was in a
battle that had lasted at least a month, and was not yet finished.
Red strife and its fierce emotions were still before him when he
awoke. Now he gazed all around, and saw only blackness, with a
few points of light here and there.
His eyes, growing used to the darkness, came back, and he saw
six stiff figures stretched on the ground in a row, three on each side
of him. He looked at them fixedly and saw that they were the figures
of human beings. Moreover, he recognized two of them, and they
were his best friends. Then he remembered all about the battle, the
great struggle, how the terrible crisis came again and again, how the
victory finally was won, and he was glad that these two friends of
66. his were alive, though they seemed to be sleeping as men never
slept before.
Breakstone sat up and looked at the six sleepers. The blankets
of two of them had shifted a little, and he pulled them back around
their necks. Then he glanced down the valley where the lights of
Santa Anna's army flickered, and it all seemed wonderful,
unbelievable to him. Yet it was true. They had beaten off an army of
more than twenty thousand men, and had inflicted upon Santa Anna
a loss far greater than their own. He murmured very softly:
"Dreadful was the fight,
Welcome is the night;
Fiercely came the foe,
Many we laid low;
Backward he is sent,
But we, too, are spent.
I believe that's about as true a poem as I ever composed," he said,
"whatever others may think about the rhyme and meter, and to be
true is to be right. That work well done, I'll go back to sleep again."
He lay down once more and, within a minute, he kept his word.
Phil and his comrades were awakened just at the break of day by
Middleton. Only a narrow streak of light was to be seen over the
eastern ridges, but the Captain explained that he wanted them to go
on a little scout toward the Mexican army. They joined him with
willingness and went down the southern edge of the plateau. A few
lights could be seen at the points that Phil had marked during the
night, and they approached very cautiously. But they saw no signs of
67. life. There were no patrols, no cavalry, none of the stir of a great
army, nothing to indicate any human presence, until they came upon
wounded men, abandoned upon the rugged ground where they lay.
When Phil and his comrades, belief turned into certainty, rushed
forward, Santa Anna and his whole army were gone, leaving behind
them their dead and desperately wounded. Tents, supplies, and
some arms were abandoned in the swift retreat, but the army itself
had already disappeared under the southern horizon, leaving the
field of Buena Vista to the victors.
They hurried back with the news. It spread like fire through the
army. Every man who could stand was on his feet. A mighty cheer
rolled through the Pass of Angostura, and the dark gorges and
ravines of the Sierra Madre gave it back in many echoes.
The victory, purchased at so great a price, was complete.
Mounted scouts, sent out, returned in the course of the day with the
information that Santa Anna had not stopped at Agua Neva. He was
marching southward as fast as he could, and there was no doubt
that he would not stop until he reached the City of Mexico, where he
would prepare to meet the army of Scott, which was to come by the
way of Vera Cruz. The greatness of their victory did not dawn upon
the Americans until then. Not only had they beaten back a force that
outnumbered them manifold, but all Northern Mexico lay at the feet
of Taylor. The war there was ended, and it was for Scott to finish it
in the Valley of Mexico.
The following night the fires were built high on the plateau and
in the Pass of Angostura. Nearly everybody rested except the
surgeons, who still worked. Hundreds of the Mexican wounded had
been left on the field, and they received the same attention that was
68. bestowed upon the Americans. Nevertheless, the boy soldiers were
cheerful. They knew that the news of their wonderful victory was
speeding north, and they felt that they had served their country
well.
Phil did not know until long afterward that at home the army of
Taylor had been given up as lost. News that Santa Anna was in front
of him with an overwhelming force had filtered through, and then
had come the long blank. Nothing was heard. It was supposed that
Taylor had been destroyed or captured. It was known that his force
was composed almost wholly of young volunteers, boys, and no
chance of escape seemed possible.
In the West and South, in Kentucky, Illinois, Indiana, Arkansas,
and Mississippi, the anxiety was most tense and painful. There,
nearly every district had sent some one to Buena Vista, and they
sought in vain for news. There were dark memories of the Alamo
and Goliad, especially in the Southwest, and these people thought of
the disaster as in early days they thought of a defeat by the Indians,
when there were no wounded or prisoners, only slain.
But even the nearest states were separated from Mexico by a
vast wilderness, and, as time passed and nothing came, belief
settled into certainty. The force of Taylor had been destroyed. Then
the messenger arrived literally from the black depths with the news
of the unbelievable victory. Taylor was not destroyed. He had beaten
an army that outnumbered him five to one. The little American force
held the Pass of Angostura, and Santa Anna, with his shattered
army, was flying southward. At first it was not believed. It was
incredible, but other messengers came with the same news, and
then one could doubt no longer. The victory struck so powerfully
69. upon the imagination of the American people that it carried Taylor
into the White House.
Meanwhile, Phil, in the Pass of Angostura, sitting by a great fire
on the second night after the battle, was thinking little of his native
land. After the tremendous interruption of Buena Vista, his mind
turned again to the object of his search. He read and reread his
letter. He thought often of the lava that had cut his brother's feet
and his own. John was sure that they had gone through a pass, and
he knew that a woman at a well had given him water. The belief that
they were on the trail of those forlorn prisoners was strong within
him. And Bill Breakstone and Arenberg believed it, too.
"Our army, I understand, will go into quarters in this region," he
said, "and will make no further advance by land into Mexico. We
enlisted only for this campaign, and I am free to depart. I mean to
go at once, boys."
"We go with you, of course," said Bill Breakstone. "Good old
Hans and I here have already talked it over. There will be no more
campaigning in Northern Mexico, and we've done our duty. Besides,
we've got quests of our own that do not lead toward the valley of
Mexico."
Phil grasped a hand of each and gave it a strong squeeze.
"I knew that you would go with me, as I'll go with you when the
time comes," he said.
They received their discharge the next morning, and were
thanked by General Taylor himself for bravery in battle. Old Rough
and Ready put his hand affectionately on Phil's shoulder.
"May good fortune follow you wherever you may be going," he
said. "It was such boys as you who won this battle."
70. He also caused them to be furnished with large supplies of
ammunition. Middleton could go no farther. He and some other
officers were to hurry to Tampico and join Scott for the invasion of
Mexico by the way of Vera Cruz.
"But boys," he said, "we may meet again. We've been good
comrades, I think, and circumstances may bring us together a
second time when this war is over."
"It rests upon the knees of the gods," said Arenberg.
"I know it will come true," said the more sanguine Breakstone.
"So do I," said Phil.
Middleton rode away with his brother officers and a small body
of regulars, and Phil, Arenberg, and Breakstone rode southward to
Agua Neva. When they had gone some distance they stopped and
looked back at the plateau and the pass.
"How did we ever do it?" said Phil.
"By refusing to stay whipped," replied Arenberg.
"By making up our minds to die rather than give up," replied Bill
Breakstone.
They rode on to the little Mexican town, where Phil had an
errand to do. He had talked it over with the other two, and the three
had agreed that it was of the utmost importance. All the time a
sentence from the letter was running in Phil's head. Some one
murmuring words of pity in Mexican had given him water to drink,
and the voice was that of a woman.
"It must have been from a well," said Phil, "this is a dry country
with water mostly from wells, and around these wells villages usually
grow. Bill, we must be on the right track. I can't believe that we're
going wrong."
71. "The signs certainly point the way we're thinking," said Bill
Breakstone. "The lava, the dust, and the water. We've passed the
lava and the dust, and we know that the water is before us."
They came presently to Agua Neva, a somber little town, now
reoccupied by a detachment from Taylor's army. The people were
singularly quiet and subdued. The defeat of Santa Anna by so small
a force and his precipitate flight made an immense impression upon
them, and, as they suffered no ill treatment from the conquerors,
they did not seek to make trouble. There was no sharpshooting in
the dark, no waylaying of a few horsemen by guerillas, and the three
could pursue without hesitation the inquiry upon which they were
bent.
Wells! Wells! Of course there were wells in Agua Neva. Several
of them, and the water was very fine. Would the señors taste it?
They would, and they passed from one well to another until they
drank from them all. Breakstone could speak Spanish, and its
Mexican variations, and he began to ask questions--chance ones at
first, something about the town and its age, and the things that he
had seen. Doubtless in the long guerilla war between Texas and
Mexico, captives, the fierce Texans, had passed through there on
their way to strong prisons in the south. Such men had passed more
than once, but the people of Agua Neva did not remember any
particular one among them. They spent a day thus in vain, and Phil,
gloomy and discouraged, rode back to the quarters of the American
detachment.
"Don't be downhearted, Phil," said Breakstone. "In a little place
like this one must soon pick up the trail. It will not be hard to get at
the gossip. We'll try again to-morrow."
72. They did not go horseback the next morning, not wishing to
attract too much attention, but strolled about the wells again,
Breakstone talking to the women in the most ingratiating manner. He
was a handsome fellow, this Breakstone, and he had a smile that
women liked. They did not frown upon him at Agua Neva because
he belonged to the enemy, but exchanged a gay word or two with
him, Spanish or Mexican banter as he passed on.
They came to a well at which three women were drawing water
for the large jars that they carried on their heads, and these were
somewhat unlike the others. They were undoubtedly of Indian
blood, Aztec perhaps, or more likely Toltec. They were tall for
Mexican women, and it seemed to Phil that they bore themselves
with a certain erectness and pride. Their faces were noble and good.
Phil and his comrades drew near. He saw the women glance at
them, and he saw the youngest of them look at him several times.
She stared with a vague sort of wonder in her eyes, and Phil's heart
suddenly began to pound so hard that he grew dizzy. Since the
letter, coming out of the unknown and traveling such a vast distance,
had found him in the little town of Paris, Kentucky, he had felt at
times the power of intuition. Truths burst suddenly upon him, and
for the moment he had the conviction that this was the woman.
Moreover, she was still looking at him.
"Speak to her, Bill! Speak to her!" he exclaimed. "Don't let her
go until you ask her."
But Breakstone had already noticed the curious glances the
woman was casting at Phil, and in the Spanish patois of the region
he bade them a light and courteous good morning. Here all the
charm of Breakstone's manner showed at its very best. No one could
73. take offense at it, and the three women, smiling, replied in a similar
vein. Breakstone understood Phil's agitation. The boy might be right,
but he did not intend to be too headlong. He must fence and
approach the subject gradually. So he spoke of the little things that
make conversation, but presently he said to the youngest of the
women:
"I see that you notice my comrade, the one who is not yet a
man in years, though a man in size. Does it chance that you have
seen some one like him?"
"I do not know," replied the woman. "I am looking into my
memory that I may see."
"Perhaps," said Breakstone smoothly, "it was one of the Texan
prisoners whom they brought through here two or three years ago.
A boy, tall and fair like this boy, but dusty with the march, bent with
weariness, his feet cut and bleeding by the lava over which he had
been forced to march, stood here at this well. He was blindfolded
that he might not see which way he had come, but you, the Holy
Virgin filling your heart with pity, took the cup of cool water and
gave it to him to drink."
Comprehension filled the eyes of the woman, and she gazed at
Breakstone with growing wonder.
"It is so!" she exclaimed. "I remember now. It was three years
ago. There was a band of prisoners, twelve or fifteen, maybe, but he
was the youngest of them all, and so worn, so weak! I could not see
his eyes, but he had the figure and manner of the youth who stands
there! It was why I looked, and then looked again, the resemblance
that I could not remember."
74. "It is his brother who is with me," said Breakstone. "Can you tell
where these prisoners were taken?"
"I do not know, but I have heard that they were carried into the
mountains to the south and west, where they were to be held until
Texas was brought back to Mexico, or to be put to death as
outlaws."
"What prisons lie in these mountains to the south and west?"
"I do not know how many, but we have heard most of the
Castle of Montevideo. Some of our own people have gone there,
never to come back."
She and her companions shuddered at the name of the Castle
of Montevideo. It seemed to have some vague, mysterious terror for
them. It was now Bill Breakstone who had the intuition. The Castle
of Montevideo was the place. It was there that they had taken John
Bedford. He translated clearly for Phil, who became very pale.
"It is the place, Phil," he said. "We must go to the Castle of
Montevideo to find him."
He drew from his pocket a large octagonal gold piece, worth
fifty dollars, then coined by the United States.
"Give this to her, Bill," he said, "and tell her it is for the drink of
water that she gave to the blindfolded boy three years ago."
Bill Breakstone translated literally, and he added:
"You must take it. It comes from his heart. It is not only worth
much money, but it will be a bringer of luck to you."
She took it, hesitated a moment, then hid it under her red
reboso, and, the jars being filled, she and her two companions
walked away, balancing the great weights beautifully on their heads.
"To-night," said Phil, "we ride for the Castle of Montevideo."
75. CHAPTER XVI
THE CASTLE OF MONTEVIDEO
The Castle of Montevideo, as its name indicates, commanded a
magnificent view. Set in a niche of a mountain which towered far
above, it looked down upon and commanded one of the great roads
that led to the heart of Mexico, the city that stood in the vale of
Tenochtitlan, the capital, in turn, of the Toltecs, the Aztecs, the
Spaniards, and the Mexicans, and, for all that men yet knew, of
races older than the Toltecs. But the Spaniards had built it,
completing it nearly a hundred and fifty years ago, when their hold
upon the greater part of the New World seemed secure, and the
name of Spain was filled with the suggestion of power.
It was a gloomy and tremendous fortress, standing seven
thousand feet above the level of the sea, and having about it,
despite its latitude, no indication of the tropics.
Spain had lavished here enormous sums of money dug for her
by the slaves of Mexico and Peru. It was built of volcanic pumice
stone, very hard, and of the color of dark honey. Its main walls
formed an equilateral triangle, eight hundred feet square on the
inside, and sixty feet from the top of the wall to the bottom of the
enclosing moat. There was a bastion at each corner of the main
rampart, and the moat that enveloped the main walls and bastions
was two hundred feet wide and twenty feet deep. Fifty feet beyond
the outside wall of the moat rose a chevaux de frise built of squared
cedar logs twelve feet long, set in the ground and fastened together
76. by longitudinal timbers. Beyond the chevaux de frise was another
ditch, fourteen feet wide, of which the outer bank was a high
earthwork. The whole square enclosed by the outermost work was
twenty-six acres, and on the principal rampart were mounted eighty
cannon, commanding the road to the Valley of Tenochtitlan.
Few fortresses, even in the Old World, were more powerful or
complete. It enclosed armories, magazines, workshops, and cells;
cells in rows, all of which were duly numbered when Montevideo was
completed in the eighteenth century. And, to give it the last and
happiest touch, the picture of Ferdinand VII., King of Spain, Lord of
the Indies and the New World, was painted over the doorway of
every cell, and they were many.
Nor is this the full tale of Montevideo. On the inner side of each
angle, broad wooden stairways ascended to the top, the stairways
themselves being enclosed at intervals by wooden gates twelve feet
high. The real fortifications enclosed a square of nearly five hundred
feet, and inside this square were the buildings of the officers and the
barracks of the soldiers. The floor of the square was paved with
thick cement, and deep down under the cement were immense
water tanks, holding millions of gallons, fed by subterranean springs
of pure cold water. By means of underground tunnels the moats
could be flooded with water from the tanks or springs.
It has been said that the Spaniards are massive builders, the
most massive since the Romans, and they have left their mark with
many a huge stone structure in the southern part of the New World.
What Montevideo cost the kings of Spain no one has ever known,
and, although they probably paid twice for every stick and stone in
it, Peru and Mexico were still pouring forth their floods of treasure,
77. and there was the fortress, honey colored, lofty, undeniably majestic
and powerful.
When Mexico displaced Spain, she added to the defenses of
Montevideo, and now, on this spring day in 1847, it lowered, dark
and sinister, over the road. It was occupied by a strong garrison
under that alert and valiant soldier, Captain Pedro de Armijo, raised
recently to that rank, but still stinging with the memories of Buena
Vista, he was anxious that the Americans should come and attack
him in Montevideo. He stood on the rampart at a point where it was
seventy feet wide, and he looked with pride and satisfaction at the
row of eighty guns. Pedro de Armijo, swelling with pride, felt that he
could hold the castle of Montevideo against twenty thousand men.
Time had made no impression upon those massive walls, and the
moat was filled with water. The castle, mediæval, but grim and
formidable, sat in its narrow mountain valley with the Cofre de
Montevideo (Trunk of Montevideo) behind it on the north. This peak
was frequently covered with snow and at all times was gloomy and
forbidding. Even on bright days the sun reached it for only a few
hours.
While Pedro de Armijo walked on the parapet, looking out at the
range of mountain and valley and enjoying the sunlight, which would
soon be gone, a young man stood at the window of cell No. 87, also
looking out at the mountain, although no sunlight reached him
there. He gazed through a slit four inches wide and twelve inches
high, and the solid wall of masonry through which this slit was cut
was twelve feet thick. The young man's ankles were tied together
with a chain which, although long enough to allow him to walk,
weighed twenty-five pounds. Once he had been chained with
78. another man. Formerly the prisoners who had been brought with
him to the Castle of Montevideo had been chained in pairs, the chain
in no case weighing less than twenty pounds, but, since only John
Bedford was left, Pedro de Armijo concluded that it was his duty to
carry the chain alone.
John Bedford was white with prison pallor. Although as tall, he
weighed many pounds less than his younger brother, Philip. His
cheeks were sunken, and his eyes were set in deep hollows. The
careless observer would have taken him for ten years more than his
real age. He had shuffled painfully to the slit in the wall, where he
wished to see the last rays of the daylight falling on the
mountainside. The depth of the slit made the section of the
mountain that he could see very narrow, and he knew every inch of
it. There was the big projection of volcanic rock, the tall, malformed
cactus that put out a white flower, the little bunch of stunted cedars
or pines--he could never tell which--in the shelter of the rock, and
the yard or two of gully down which he had seen the water roaring
after the big rains or at the melting of the snows on the Cofre de
Montevideo.
How often he had looked upon these things! What a little slice
of the world it was! Only a few yards long and fewer yards broad,
but what a mighty thing it was to him! Even with the slit closed, he
could have drawn all of it upon a map to the last twig and pebble.
He would have suffered intensely had that little view been
withdrawn, but it tantalized him, too, with the sight of the freedom
that was denied him. Three years, they told him, he had been gazing
out at that narrow slit at the mountainside, and he only at the
beginning of life, strong of mind and body--or at least he was. Never
79. in that time had he been outside the inner walls or even in the court
yard. He knew nothing of what had happened in the world.
Sometimes they told him that Texas had been overrun and retaken
by the Mexicans, and he feared that it was true.
They did not always put the chains upon him, but lately he had
been refractory. He was easily caught in an attempt to escape, and a
new governor of the castle, lately come, a young man extremely
arrogant, had demanded his promise that he make no other such
attempt. He had refused, and so the chains were ordered. He had
worn them many times before, and now they oppressed him far less
than his loneliness. He alone of that expedition was left a prisoner in
the castle. How all the others had gone he did not know, but he
knew that some had escaped. Both he and his comrade of the
chains were too ill to walk when the escape was made, and there
was nothing to do but leave them behind. His comrade died, and he
recovered after weeks, mainly through the efforts of old Catarina,
the Indian woman who sometimes brought him his food.
John Bedford's spirits were at the bottom of the depths that
afternoon. How could human beings be so cruel as to shut up one of
their kind in such a manner, one who was no criminal? It seemed to
him that lately the watch in the castle had become more vigilant
than ever. More soldiers were about, and he heard vaguely of
comings and goings. His mind ran back for the thousandth time over
the capture of himself and his comrades.
When taken by an overwhelming force they were one hundred
and seventy in number, and there were great rejoicings in Mexico
when they were brought southward. They had been blindfolded at
some points, once when he walked for a long time on sharp volcanic
80. rock, and once, when, as he was fainting from heat and thirst, a
woman with a kind voice had given him a cup of water at a well. He
remembered these things very vividly, and he remembered with
equal vividness how, when they were not blindfolded, they were led
in triumph through the Mexican towns, exactly as prisoners were led
to celebrate the glory of a general through the streets of old Rome.
They, the "Terrible Texans," as they were called, had passed through
triumphal arches decorated with the bright garments of women.
Boys and girls, brilliant handkerchiefs bound around their heads, and
shaking decorated gourds with pebbles in them, had danced before
the captives to the great delight of the spectators. Sometimes
women themselves in these triumphal processions had done the
zopilote or buzzard dance. At night the prisoners had been forced to
sleep in foul cattle sheds.
Then had come the Day of the Beans. One hundred and fifty-
three white beans and seventeen black beans were placed in a bowl,
and every prisoner, blindfolded, was forced to draw one. The
seventeen who drew the black beans were promptly shot, and the
others were compelled to march on. He remembered how lightly
they had taken it, even when it was known who had drawn the black
beans. These men, mostly young like himself, had jested about their
bad luck, and had gone to their death smiling. He did not know how
they could do it, but it was so, because he had seen it with his own
eyes.
Then they had marched on until they came to the Castle of
Montevideo. There the world ended. There was nothing but time,
divided into alternations of night and day. He had seen nobody but
soldiers, except the old woman Catarina, who seemed to be a sort of
81. scullion. After he recovered from the prison fever of which his
comrade of the chains died, the old woman had shown a sort of pity
for him; perhaps she liked him as one often likes those upon whom
one has conferred benefits. She yielded to his entreaties for a pencil
for an hour or so, and some paper, just a sheet or two. She
smuggled them to him, and she smuggled away the letter that he
wrote. She did not know what would happen, but she would give it
to her son Porfirio, who was a vaquero. Porfirio would give it to his
friend Antonio Vaquez, who was leading a burro train north to
Monterey. After that was the unknown, but who could tell? Antonio
Vaquez was a kind man, and the Holy Virgin sometimes worked
miracles for the good. As for the poor lad, the prisoner, he must rest
now. He had been muy malo (very sick), and it was not good to
worry.
John tried not to worry. It was such easy advice to give and so
very hard for one to take who had been buried alive through a time
that seemed eternity, and who had been forgotten by all the world,
except his jailers. That letter had gone more than a year ago, and,
of course, it had not reached its destination. He ought never to have
thought such a thing possible. Very likely it had been destroyed by
Porfirio, the vaquero, old Catarina's son. He had not seen old
Catarina herself in a long time. Doubtless they had sent her away
because she had been kind to him, or they may have found out
about the letter. He was very sorry. She was far from young, and she
was far from beautiful, but her brief presence at intervals had been
cheering.
He watched the last rays of the sun fade on the volcanic slope.
A single beam, livid and splendid, lingered for a moment, and then
82. was gone. After it came the dark, with all the chilling power of great
elevation. The cold even penetrated the deep slit that led through
twelve feet of solid masonry, and John Bedford shivered. It was
partly the dark that made him shiver. He rose from the stool and
made his way slowly and painfully to his cot against the wall, his
chains rattling heavily over the floor.
He heard a key turning in the lock and the door opening, but he
did not look around. They usually came with his food at this hour,
and the food was always the same. There was no cause for curiosity.
But when he heard the steps of two men instead of one he did look
around. There was the same soldier bringing his supper of frijoles
and tortillas on a tin plate, and a cup of very bad coffee, but he was
accompanied by the new governor of the castle, Captain Pedro de
Armijo, whom John did not like at all. The soldier drew up the stool,
put the food on it, and also a candle that he carried.
John began to eat and drink, taking not the slightest notice of
de Armijo. The man from the first had given him the impression of
cold, malignant cruelty. John Bedford had often thought that his own
spirit was crushed, but it was far from being so. Pride was strong
within him, and he resolved that de Armijo should speak first.
De Armijo stood in silence for some time, looking down at the
prisoner. He was not in a good humor, he had seldom been so since
that fatal day when the whole army of Santa Anna was hurled back
by the little force from the North. He knew many things of which the
prisoner did not dream, and he had no thought of giving him even
the slightest hint of them. In him was the venomous disposition of
the cat that likes to play with the rat it has caught. A curious piece
83. of mockery, or perhaps it was not wholly mockery, had occurred to
him.
"Bedford," he said, speaking good English, "you have been a
prisoner here a long time, and no one loves captivity."
"I have not heard that any one does," replied John, taking
another drink of the bad coffee.
"You cannot escape. You see the impossibility of any such
attempt."
"It does not look probable, I admit. Still, few things are
impossible."
De Armijo smiled, showing even white teeth. He rather liked this
game of playing with the rat in the trap. So much was in favor of the
cat.
"It is not a possibility with which one can reckon," he said, "and
I should think that the desire to be free would be overpowering in
one so young as you."
"Have you come here to make sport of me?" said John, with
ominous inflection. "Because if you have I shall not answer another
question."
"Not at all," said de Armijo. "I come on business. You have been
here, as I said, a long time, and in that time many changes have
occurred in the world."
"What changes?" asked John sharply.
"The most important of them is the growth in power of Mexico,"
said de Armijo smoothly. "We triumph over all our enemies."
"Do you mean that you have really retaken Texas?" asked John,
with a sudden falling of the heart.
84. De Armijo smiled again, then lighted a cigarette and took a puff
or two before he gave an answer which was really no answer at all,
so far as the words themselves were concerned.
"I said that Mexico had triumphed over her enemies
everywhere," he replied, "and so she has, but I give you no details.
It has been the order that you know nothing. You have been
contumacious and obstinate, and, free, you would be dangerous. So
the world was to be closed to you, and it has been done. You know
nothing of it except these four walls and the little strip of a mountain
that you can see from the window there. You are as one dead."
John Bedford winced. What the Mexican said was true, and he
had long known it to be true, but he did not like for de Armijo to say
it to him now. His lonesomeness in his long imprisonment had been
awful, but not more so than his absolute ignorance of everything
beyond his four walls. This policy with him had been pursued
persistently. Old Catarina, before her departure, had not dared to tell
him anything, and now the soldier who served him would not
answer any question at all. He had felt at times that this would
reduce him to mental incompetency, to childishness, but he had
fought against it, and he had felt at other times that the isolation,
instead of weakening his faculties, had sharpened them. But he
replied without any show of emotion in his voice:
"What you say is true in the main, but why do you say it."
"In order to lay before you both sides of a proposition. You are
practically forgotten here. You can spend the rest of your life in this
cell, perish, perhaps, on the very bed where you are now sitting, but
you can also release yourself. Take the oath of fealty to Mexico,
85. become a Mexican citizen, join her army and fight her enemies. You
might have a career there, you might rise."
It was a fiendish suggestion to one who knew nothing of what
was passing, and de Armijo prided himself upon his finesse. To
compel brother to fight against brother would indeed be a master
stroke. He did not notice the rising blood in the face before him, that
had so long borne the prison pallor.
"Have you reconquered Texas?" asked John sharply.
"What has that to do with it?"
"Do you think I would join you and fight against the Texans? Do
you think I would join you anyhow, after I've been fighting against
you? I'd rather rot here than do such a thing, and it seems strange
that you, an officer and the governor of this castle, should make
such an offer. It's dishonest!"
Blood flashed through de Armijo's dark face, and he raised his
hand in menace. John Bedford instantly struck at him with all his
might, which was not great, wasted as he was by prison
confinement. De Armijo stepped back a little, drew his sword, and,
with the flat of it, struck the prisoner a severe blow across the
forehead. John had attempted to spring forward, but twenty-five
pounds of iron chain confining his ankles held him. He could not
ward off the blow, and he dropped back against the cot, bleeding
and unconscious.
When John Bedford recovered his senses he was lying on the
cot, and it was pitch dark, save for a slender shaft of moonlight that
entered at the slit, and that lay like a sword-blade across the floor.
His head throbbed, and when he put his hand to it he found that it
was swathed in bandages. He remembered the blow perfectly, and
86. he moved his feet, but the chains had been taken off. They had had
the grace to do that much. He strove to rise, but he was very weak,
and the throbbing in his head increased. Then he lay still for a long
time, watching the moonbeam that fell across the floor. He was in a
state of mind far from pleasant. To be shut up so long is inevitably
to grow bitter, and to be struck down thus by de Armijo, while he
was chained and helpless, was an injury to both body and mind that
he could never forgive. He had nothing to do in his cell to distract his
mind from grievous wrongs, and there was no chance for them to
fade from his memory. His very soul rose in wrath against de Armijo.
He judged that it was far in the night, and, after lying perfectly
still for about an hour, he rose from the bed. His strength had
increased, and the throbbing in his head was not so painful. He
staggered across the floor and put his face to the slit in the wall. The
cold air, as it rushed against his eyes and cheeks, felt very good. It
was spring in the lowlands, but there was snow yet on the peak
behind the Castle of Montevideo, and winter had not yet wholly left
the valley in which the castle itself stood. But the air was not too
cold for John, whose brain at this moment was hotter than his blood.
The night was uncommonly clear. One could see almost as well
as by day, and he began to look over, one by one, the little objects
that his view commanded on the mountainside. He looked at every
intimate friend, the various rocks, the cactus, the gully, and the
dwarfed shrubs--he still wished to know whether they were pines or
cedars, the problem had long annoyed him greatly. He surveyed his
little landscape with great care. It seemed to him that he saw
touches of spring there, and then he was quite sure that he saw the
figure of a man, dark and shadowy, but, nevertheless, a human
87. figure, pass across the little space. It was followed in a moment by a
second, and then by a third. It caused him surprise and interest. His
tiny landscape was steep, and he had never before seen men cross
it. Hunters, or perhaps goat herders, but it was strange that they
should be traveling along such a steep mountainside at such an
hour.
A person under ordinary conditions would have forgotten the
incident in five minutes, but this was an event in the life of the
lonely captive. Save his encounter with de Armijo, he could not recall
another of so much importance in many months. He stayed at the
loophole a long time, but he did not see the figures again nor
anything else living. Once, about a month before, he had caught a
glimpse of a deer there, and it had filled him with excitement,
because to see even a deer was a great thing, but this was a
greater. He remained at the loophole until the rocks began to redden
with the morning sun, but his little landscape remained as it had
ever been, the same rocks, the same pines or cedars--which, in
Heaven's name, were they?--and the same cactus.
Then he walked slowly back to his cot. The chains were lying on
the floor beside it, and he knew that, in time, they would be put on
him again, but he was resolved not to abate his independence a
particle. Nor would he defer in any way to de Armijo. If he came
again he would speak his opinion of him to his face, let him do what
he would.
There was proud and stubborn blood in every vein of the
Bedfords. John Bedford's grandfather had been one of the most
noted of Kentucky's pioneers and Indian fighters, and on his
mother's side, too, there was a strain of tenacious New England. By
88. Welcome to our website – the perfect destination for book lovers and
knowledge seekers. We believe that every book holds a new world,
offering opportunities for learning, discovery, and personal growth.
That’s why we are dedicated to bringing you a diverse collection of
books, ranging from classic literature and specialized publications to
self-development guides and children's books.
More than just a book-buying platform, we strive to be a bridge
connecting you with timeless cultural and intellectual values. With an
elegant, user-friendly interface and a smart search system, you can
quickly find the books that best suit your interests. Additionally,
our special promotions and home delivery services help you save time
and fully enjoy the joy of reading.
Join us on a journey of knowledge exploration, passion nurturing, and
personal growth every day!
ebookbell.com