SlideShare a Scribd company logo
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
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
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
Effective Kotlin Best Practices Marcin Moskala
Effective Kotlin Best Practices Marcin Moskala
Effective Kotlin
Best practices
Marcin Moskala
This book is for sale at http://leanpub.com/effectivekotlin
This version was published on 2020-06-20
This is a Leanpub book. Leanpub empowers authors and
publishers with the Lean Publishing process. Lean Publishing is
the act of publishing an in-progress ebook using lightweight tools
and many iterations to get reader feedback, pivot until you have
the right book and build traction once you do.
© 2018 - 2020 Marcin Moskala
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
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
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
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
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
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:
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.
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.
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:
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
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:
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).
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
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
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.
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.
Part 1: Good code
13
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
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
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
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.
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
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:
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
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:
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,
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.
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 }
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
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.
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:
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.
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:
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
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:
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:
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.
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.
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:
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
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:
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:
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
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).
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.
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
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.
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.
Other documents randomly have
different content
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
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
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
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
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.
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
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
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.
"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.
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
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
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
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
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."
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."
"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."
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
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."
"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."
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
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,
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
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
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
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
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
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
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.
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,
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
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
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
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

More Related Content

PDF
Top 10 Tips for Developing Android Apps Using Kotlin
PDF
Kotlin Programming Concise Expressive And Powerful Theophilus Edet
PDF
Introduction to Kotlin - Android KTX
PDF
A Review Paper on Kotlin Programming Language
PDF
ApiDesign
PDF
API design
PDF
Kotlin vs Java: Which is Better for Android App Development?
PPTX
Kotlin With JetPack Compose Presentation
Top 10 Tips for Developing Android Apps Using Kotlin
Kotlin Programming Concise Expressive And Powerful Theophilus Edet
Introduction to Kotlin - Android KTX
A Review Paper on Kotlin Programming Language
ApiDesign
API design
Kotlin vs Java: Which is Better for Android App Development?
Kotlin With JetPack Compose Presentation

Similar to Effective Kotlin Best Practices Marcin Moskala (20)

PDF
Gen Apps on Google Cloud PaLM2 and Codey APIs in Action
PDF
Tech leaders guide to effective building of machine learning products
PDF
Learn Kotlin and Build Robust Android Apps with Bcoder.pdf
PPTX
moocs_ppt.pptx
PPTX
MOOC_PRESENTATION_KOTLIN[1].pptx
PDF
MOUG17: Oracle APEX - Tame IT Backlog Low Code Micro Apps in APEX
PDF
Kotlin App Development Tips.pdf
PDF
Kotlin for Android
PDF
Java and AI with LangChain4j: Jakarta EE gets AI
PDF
What is Kotlin.pdf
PDF
Kotlin in Action, Second Edition (MEAP V09) Svetlana Isakova
PDF
JavaCro'14 - Is there Kotlin after Java 8 – Ivan Turčinović and Igor Buzatović
PDF
CLR_via_CSharp_(Jeffrey_Richter_4th_Edition).pdf
DOCX
Patterns (contd)Software Development ProcessDesign patte.docx
PDF
Web components and friends
PPTX
Say Goodbye To Java: Getting Started With Kotlin For Android Development
PPTX
Refactoring, 2nd Edition
PPTX
QlikView Macro's Are Bad
PDF
Wondershare Filmora 14.3.2 Crack + License Key Free Download
PDF
2025-03-20 - How to use AI to your advantage - AI-Driven Development.pdf
Gen Apps on Google Cloud PaLM2 and Codey APIs in Action
Tech leaders guide to effective building of machine learning products
Learn Kotlin and Build Robust Android Apps with Bcoder.pdf
moocs_ppt.pptx
MOOC_PRESENTATION_KOTLIN[1].pptx
MOUG17: Oracle APEX - Tame IT Backlog Low Code Micro Apps in APEX
Kotlin App Development Tips.pdf
Kotlin for Android
Java and AI with LangChain4j: Jakarta EE gets AI
What is Kotlin.pdf
Kotlin in Action, Second Edition (MEAP V09) Svetlana Isakova
JavaCro'14 - Is there Kotlin after Java 8 – Ivan Turčinović and Igor Buzatović
CLR_via_CSharp_(Jeffrey_Richter_4th_Edition).pdf
Patterns (contd)Software Development ProcessDesign patte.docx
Web components and friends
Say Goodbye To Java: Getting Started With Kotlin For Android Development
Refactoring, 2nd Edition
QlikView Macro's Are Bad
Wondershare Filmora 14.3.2 Crack + License Key Free Download
2025-03-20 - How to use AI to your advantage - AI-Driven Development.pdf
Ad

Recently uploaded (20)

PDF
TR - Agricultural Crops Production NC III.pdf
PDF
FourierSeries-QuestionsWithAnswers(Part-A).pdf
PPTX
Lesson notes of climatology university.
PDF
BÀI TẬP BỔ TRỢ 4 KỸ NĂNG TIẾNG ANH 9 GLOBAL SUCCESS - CẢ NĂM - BÁM SÁT FORM Đ...
PDF
01-Introduction-to-Information-Management.pdf
PDF
2.FourierTransform-ShortQuestionswithAnswers.pdf
PDF
Saundersa Comprehensive Review for the NCLEX-RN Examination.pdf
PPTX
Introduction_to_Human_Anatomy_and_Physiology_for_B.Pharm.pptx
PDF
O7-L3 Supply Chain Operations - ICLT Program
PDF
O5-L3 Freight Transport Ops (International) V1.pdf
PDF
Sports Quiz easy sports quiz sports quiz
PDF
Pre independence Education in Inndia.pdf
PPTX
IMMUNITY IMMUNITY refers to protection against infection, and the immune syst...
PPTX
GDM (1) (1).pptx small presentation for students
PPTX
Final Presentation General Medicine 03-08-2024.pptx
PDF
3rd Neelam Sanjeevareddy Memorial Lecture.pdf
PPTX
Pharma ospi slides which help in ospi learning
PDF
RMMM.pdf make it easy to upload and study
PDF
The Lost Whites of Pakistan by Jahanzaib Mughal.pdf
PDF
Complications of Minimal Access Surgery at WLH
TR - Agricultural Crops Production NC III.pdf
FourierSeries-QuestionsWithAnswers(Part-A).pdf
Lesson notes of climatology university.
BÀI TẬP BỔ TRỢ 4 KỸ NĂNG TIẾNG ANH 9 GLOBAL SUCCESS - CẢ NĂM - BÁM SÁT FORM Đ...
01-Introduction-to-Information-Management.pdf
2.FourierTransform-ShortQuestionswithAnswers.pdf
Saundersa Comprehensive Review for the NCLEX-RN Examination.pdf
Introduction_to_Human_Anatomy_and_Physiology_for_B.Pharm.pptx
O7-L3 Supply Chain Operations - ICLT Program
O5-L3 Freight Transport Ops (International) V1.pdf
Sports Quiz easy sports quiz sports quiz
Pre independence Education in Inndia.pdf
IMMUNITY IMMUNITY refers to protection against infection, and the immune syst...
GDM (1) (1).pptx small presentation for students
Final Presentation General Medicine 03-08-2024.pptx
3rd Neelam Sanjeevareddy Memorial Lecture.pdf
Pharma ospi slides which help in ospi learning
RMMM.pdf make it easy to upload and study
The Lost Whites of Pakistan by Jahanzaib Mughal.pdf
Complications of Minimal Access Surgery at WLH
Ad

Effective Kotlin Best Practices Marcin Moskala

  • 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
  • 6. Effective Kotlin Best practices Marcin Moskala This book is for sale at http://leanpub.com/effectivekotlin This version was published on 2020-06-20 This is a Leanpub book. Leanpub empowers authors and publishers with the Lean Publishing process. Lean Publishing is the act of publishing an in-progress ebook using lightweight tools and many iterations to get reader feedback, pivot until you have the right book and build traction once you do. © 2018 - 2020 Marcin Moskala
  • 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.
  • 23. Part 1: Good code 13
  • 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.
  • 55. Other documents randomly have different content
  • 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