SlideShare a Scribd company logo
Visit https://ebookfinal.com to download the full version and
explore more ebooks
API Design for C 1st Edition Martin Reddy
_____ Click the link below to download _____
https://ebookfinal.com/download/api-design-for-c-1st-
edition-martin-reddy/
Explore and download more ebooks at ebookfinal.com
Here are some suggested products you might be interested in.
Click the link to download
RESTful Web API Design with Node js Second Edition Bojinov
https://ebookfinal.com/download/restful-web-api-design-with-node-js-
second-edition-bojinov/
Pipelined Processor Farms Structured Design for Embedded
Parallel Systems 1st Edition Martin Fleury
https://ebookfinal.com/download/pipelined-processor-farms-structured-
design-for-embedded-parallel-systems-1st-edition-martin-fleury/
Understanding and Applying Research Design 1st Edition
Martin Lee Abbott
https://ebookfinal.com/download/understanding-and-applying-research-
design-1st-edition-martin-lee-abbott/
Statistics and Experimental Design for Toxicologists and
Pharmacologists Fourth Edition Shayne C. Gad
https://ebookfinal.com/download/statistics-and-experimental-design-
for-toxicologists-and-pharmacologists-fourth-edition-shayne-c-gad/
Design of Aircraft 1st Edition Thomas C. Corke
https://ebookfinal.com/download/design-of-aircraft-1st-edition-thomas-
c-corke/
An Introduction to Continuum Mechanics 2ed. Edition Reddy
J.N.
https://ebookfinal.com/download/an-introduction-to-continuum-
mechanics-2ed-edition-reddy-j-n/
Machine Design 2010th Edition U. C. Jindal
https://ebookfinal.com/download/machine-design-2010th-edition-u-c-
jindal/
Design Theory 2nd Edition Charles C. Lindner
https://ebookfinal.com/download/design-theory-2nd-edition-charles-c-
lindner/
C 3 0 Design Patterns 1st Edition Judith Bishop
https://ebookfinal.com/download/c-3-0-design-patterns-1st-edition-
judith-bishop/
API Design for C 1st Edition Martin Reddy
API Design for C 1st Edition Martin Reddy Digital
Instant Download
Author(s): Martin Reddy
ISBN(s): 9780123850034, 0123850037
Edition: 1
File Details: PDF, 17.71 MB
Year: 2011
Language: english
API Design for C 1st Edition Martin Reddy
Acquiring Editor: Todd Green
Editorial Assistant: Robyn Day
Project Manager: André Cuello
Designer: Eric DeCicco
Morgan Kaufmann is an imprint of Elsevier
30 Corporate Drive, Suite 400, Burlington, MA 01803, USA
# 2011 Elsevier, Inc. All rights reserved.
No part of this publication may be reproduced or transmitted in any form or by any means, electronic
or mechanical, including photocopying, recording, or any information storage and retrieval system,
without permission in writing from the publisher. Details on how to seek permission, further
information about the Publisher’s permissions policies and our arrangements with organizations such
as the Copyright Clearance Center and the Copyright Licensing Agency, can be found at our
website: www.elsevier.com/permissions.
This book and the individual contributions contained in it are protected under copyright by the
Publisher (other than as may be noted herein).
Notices
Knowledge and best practice in this field are constantly changing. As new research and experience broaden
our understanding, changes in research methods or professional practices may become necessary. Practitioners
and researchers must always rely on their own experience and knowledge in evaluating and using any
information or methods described herein. In using such information or methods they should be mindful of their
own safety and the safety of others, including parties for whom they have a professional responsibility.
To the fullest extent of the law, neither the Publisher nor the authors, contributors, or editors, assume any liability for
any injury and/or damage to persons or property as a matter of products liability, negligence or otherwise, or from
any use or operation of any methods, products, instructions, or ideas contained in the material herein.
Library of Congress Cataloging-in-Publication Data
Application submitted
British Library Cataloguing-in-Publication Data
A catalogue record for this book is available from the British Library.
ISBN: 978 0 12 385003 4
Printed in the United States of America
11 12 13 14 10 9 8 7 6 5 4 3 2 1
For information on all MK publications visit our website at www.mkp.com
Foreword
I should begin by confessing that I do not consider myself a world-class API designer or software
engineer. I do, however, consider myself an expert researcher in the areas of computer graphics
and geometric modeling. It was in this line of work that I first met Martin at Pixar Animation
Studios.
As a graphics researcher I was accustomed to writing mathematically sophisticated papers. I was
also formally trained as a computer scientist at a major university and had written my share of code.
Armed with this background, when I was presented with the opportunity to lead a group of software
engineers working on a new generation of animation software for Pixar, I figured that it couldn’t be
any more difficult than research. After all, research is, by definition, the creation of the unknown,
whereas engineering is the implementation of well-understood subjects. I could not have been more
wrong.
I came to realize that software engineering was, without a doubt, the most difficult challenge
I had ever been presented with. After more years than I care to admit, I eventually gave up and went
back to graphics research.
I can’t tell you how much I would have benefitted from a book such as “API Design for C++.”
Many of the lessons we learned the hard way have been captured by Martin in this insightful,
easy-to-use book. Martin approaches the subject not from the perspective of an academic software
researcher (although he draws heavily from results and insights gained there), but from the perspec-
tive of an in-the-trenches software engineer and manager. He has experienced firsthand the importance
of good software design and has emerged as an articulate voice of what “good” means. In this book
he presents effective strategies for achieving that goal.
I particularly like that Martin is not focusing just on API design, but more broadly on software
life cycles, allowing him to cover topics such as versioning, strategies for backward compatibility,
and branching methodologies.
In short, this book should be of great value to those creating or managing software activities. It is
a comprehensive collection of best practices that have proven themselves time and time again.
Tony DeRose
Senior Scientist and Research Group Lead, Pixar Animation Studios
xv
Preface
Writing large applications in C++ is a complex and tricky business. However, designing reusable C++
interfaces that are robust, stable, easy to use, and durable is even more difficult. The best way to suc-
ceed in this endeavor is to adhere to the tenets of good Application Programming Interface (API)
design.
An API presents a logical interface to a software component and hides the internal details
required to implement that component. It offers a high-level abstraction for a module and promotes
code reuse by allowing multiple applications to share the same functionality.
Modern software development has become highly dependent on APIs, from low-level application
frameworks to data format APIs and graphical user interface (GUI) frameworks. In fact, common
software engineering terms such as modular development, code reuse, componentization, dynamic
link library or DLL, software frameworks, distributed computing, and service-oriented architecture
all imply the need for strong API design skills.
Some popular C and C++ APIs that you may already be aware of include the Standard Template
Library (STL), Boost, the Microsoft Windows API (Win32), Microsoft Foundation Classes (MFC),
libtiff, libpng, zlib, libxml++, OpenGL, MySQL++, Trolltech’s Qt, wxWidgets, GTK+, KDE, Sky-
peKit, POSIX pthreads, Intel’s Threading Building Blocks, the Netscape Plugin API, and the
Apache module API. In addition, many of Google’s open-source projects are C++, as is much of
the code on the sourceforge.net, bitbucket.org, and freshmeat.net Web sites.
APIs such as these are used in all facets of software development, from desktop applications, to
mobile computing and embedded systems, to Web development. For example, the Mozilla Firefox
Web browser is built on top of more than 80 dynamic libraries, each of which provides the imple-
mentation for one or more APIs.
Elegant and robust API design is therefore a critical aspect of contemporary software develop-
ment. One important way in which this differs from standard application development is the far
greater need for change management. As we all know, change is an inevitable factor in software
development; new requirements, feature requests, and bug fixes cause software to evolve in ways
that were never anticipated when it was first devised. However, changes to an API that is shared
by hundreds of end-user applications can cause major upheaval and ultimately may cause clients
to abandon an API. The primary goal of good API design is therefore to provide your clients with the
functionality they need while also causing minimal impact to their code ideally zero impact when
you release a new version.
WHY YOU SHOULD READ THIS BOOK
If you write C++ code that another engineer relies upon, you’re an API designer and this book has
been written for you.
Interfaces are the most important code that you write because a problem with your interface is far
more costly to fix than a bug in your implementation. For instance, an interface change may require
all of the applications based on your code to be updated, whereas an implementation-only change
can be integrated transparently and effortlessly into client applications when they adopt the new
xvii
API version. Put in more economic terms, a poorly designed interface can seriously reduce the long-
term survival of your code. Learning how to create high-quality interfaces is therefore an essential
engineering skill, and the central focus of this book.
As Michi Henning noted, API design is more important today than it was 20 years ago. This is
because many more APIs have been designed in recent years. These also provide richer and more
complex functionality and are shared by more end-user applications (Henning, 2009). Despite this
fact, no other books currently on the market concentrate on the topic of API design for C++.
It’s worth noting that this book is not meant to be a general C++ programming guide there are
already many good examples of these on the market. I will certainly cover lots of object-oriented
design material and present many handy C++ tips and tricks. However, I will focus on techniques
for representing clean modular interfaces in C++. By corollary, I will not dive as deeply into the
question of how to implement the code behind these interfaces, such as specific algorithm choices
or best practices limited to the code within the curly braces of your function bodies.
However, this book will cover the full breadth of API development, from initial design through
implementation, testing, documentation, release, versioning, maintenance, and deprecation. I will
even cover specialized API topics such as creating scripting and plugin APIs. While many of these
topics are also relevant to software development in general, the focus here will be on the particular
implications for API design. For example, when discussing testing strategies I will concentrate on
automated API testing techniques rather than attempting to include end-user application testing
techniques such as GUI testing, system testing, or manual testing.
In terms of my own credentials to write this book, I have led the development of APIs for research
code shared by several collaborating institutions, in-house animation system APIs that have been used
to make Academy Award-winning movies, and open-source client/server APIs that have been used by
millions of people worldwide. Throughout all of these disparate experiences, I have consistently wit-
nessed the need for high-quality API design. This book therefore presents a practical distillation of the
techniques and strategies of industrial-strength API design that have been drawn from a range of real-
world experiences.
WHO IS THE TARGET AUDIENCE
While this book is not a beginner’s guide to C++, I have made every effort to make the text easy to
read and to explain all terminology and jargon clearly. The book should therefore be valuable to new
programmers who have grasped the fundamentals of C++ and want to advance their design skills, as
well as senior engineers and software architects who are seeking to gain new expertise to comple-
ment their existing talents.
There are three specific groups of readers that I have borne in mind while writing this book.
1. Practicing software engineers and architects. Junior and senior developers who are working on
a specific API project and need pragmatic advice on how to produce the most elegant and
enduring design.
2. Technical managers. Program and product managers who are responsible for producing an API
product and who want to gain greater insight into the technical issues and development processes
of API design.
xviii Preface
3. Students and educators. Computer science and software engineering students who are learning
how to program and are seeking a thorough resource on software design that is informed by prac-
tical experience on large-scale projects.
FOCUSING ON C++
While there are many generic API design methodologies that can be taught skills that apply equally
well to any programming language or environment ultimately an API has to be expressed in a par-
ticular programming language. It is therefore important to understand the language-specific features
that contribute to exemplary API design. This book is therefore focused on the issues of designing
APIs for a single language (C++) rather than diluting the content to make it applicable for all
languages. While readers who wish to develop APIs for other languages, such as Java or C#, may
still gain much general insight from this text, the book is directly targeted at C++ engineers who must
write and maintain APIs for other engineers to consume.
C++ is still one of the most widely used programming languages for large software projects and
tends to be the most popular choice for performance-critical code. As a result, there are many diverse
C and C++ APIs available for you to use in your own applications (some of which I listed earlier).
I will therefore concentrate on aspects of producing good APIs in C++ and include copious source
code examples to illustrate these concepts better. This means that I will deal with C++-specific topics
such as templates, encapsulation, inheritance, namespaces, operators, const correctness, memory
management, use of STL, the pimpl idiom, and so on.
Additionally, this book will be published during an exciting time in the evolution of C++. A new
version of the C++ specification is currently working its way through the ISO/IEC standardization
process. Most C++ compilers currently aim to conform to the standard that was first published in
1998, known as C++98. A later revision of this standard was published in 2003 to correct several
defects. Since that time, the standards committee has been working on a major new version of the
specification. This version is referred to informally as C++0x, until such time that the standard is rati-
fied and the date of publication is known. By the time you read this book, the new standard will
likely have been published. However, at the time of writing, it is still referred to as C++0x.
Nonetheless, C++0x has reached an advanced stage of the standardization process, and many of
the new features can be predicted with relatively high confidence. In fact, some of the major C++
compilers have already started to implement many of the proposed new features. In terms of API
design, several of these new language features can be used to produce more elegant and sturdy inter-
faces. As such, I have endeavored to highlight and explain those areas of C++0x throughout the book.
This book should therefore remain a relevant resource for several years to come.
CONVENTIONS
While it is more traditional to employ the term “user” to mean a person who uses a software appli-
cation, such as a user of Microsoft Word or Mozilla Firefox, in the context of API design I will apply
the term to mean a software developer who is creating an application and is using an API to achieve
xix
Preface
this. In other words, I will generally be talking about API users and not application users. The term
“client” will be used synonymously in this regard. Note that the term “client,” in addition to referring
to a human user of your API, can also refer impersonally to other pieces of software that must call
functions in your API.
While there are many file format extensions used to identify C++ source and header files, such as
.cpp, .cc, .cxx, .h, .hh, and .hpp, I will standardize on the use of .cpp and .h throughout this book.
“I will also use the terms module and component” interchangeably to mean a single .cpp and .h file
pair. These are notably not equivalent to a class because a component or module may contain multi-
ple classes. I will use the term library to refer to a physical collection, or package, of components,
that is, library > module/component > class.
The term method, while generally understood in the object-oriented programming community, is
not strictly a C++ term; it originally evolved from the Smalltalk language. The equivalent C++ term is
member function, although some engineers prefer the more specific definition of virtual member
function. Because I am not particularly concerned with the subtleties of these terms in this book, I
will use method and member function interchangeably. Similarly, although the term data member
is the more correct C++ expression, I will treat the term member variable as a synonym.
In terms of typographical conventions, I will use a fixed-width font to typeset all source code
examples, as well as any filenames or language keywords that may appear in the text. Also, I will
prefer upper camel case for all class and function names in the examples that I present, that is,
CamelCase instead of camelCase or snake case, although obviously I will preserve the case for
any external code that I reference, such as std::for each(). I follow the convention of using an
“m” prefix in front of data members, for example, mMemberVar, and “s” in front of static variables,
for example, sStaticVar.
It should be pointed out that the source examples within the book are often only code snippets
and are not meant to show fully functional samples. I will also often strip comments from the exam-
ple code in the book. This is done for reasons of brevity and clarity. In particular, I will often omit
any preprocessor guard statements around a header file. I will assume that the reader is aware that
every C/C++ header should enclose all of its content within guard statements and that it’s good prac-
tice to contain all of your API declarations within a consistent namespace (as covered in Chapters 3
and 6). In other words, it should be assumed that each header file that I present is implicitly sur-
rounded by code, such as the following.
#ifndef MY MODULE H
#define MY MODULE H
// required #include files. . .
namespace apibook {
// API declarations . . .
}
#endif
xx Preface
TIP
I will also highlight various API design tips and key concepts throughout the book. These callouts are provided to
let you search quickly for a concept you wish to reread. If you are particularly pressed for time, you could simply
scan the book for these tips and then read the surrounding text to gain greater insight for those topics that interest
you the most.
BOOK WEB SITE
This book also has a supporting Web site, http://APIBook.com/. On this site you can find general
information about the book, as well as supporting material, such as the complete set of source code
examples contained within the text. Feel free to download and play with these samples yourself
they were designed to be as simple as possible, while still being useful and illustrative. I have used
the cross-platform CMake build system to facilitate compiling and linking the examples so they
should work on Windows, Mac OS X, and UNIX operating systems.
I will also publish any information about new revisions of this book and any errata on this Web
site, as well as useful links to other related API resources on the Internet, such as interesting toolkits,
articles, and utilities.
The book Web site also provides access to a utility that I wrote called API Diff. This program
lets you compare two versions of an API and review differences to code or comments in a visual
side-by-side format. You can also generate a report of everything that changed in a particular release
so that your clients know exactly what to look out for. This utility is available for Windows, Mac
OS X, and Linux.
xxi
Preface
Acknowledgments
This book has benefited greatly from the technical review and feedback of several of my esteemed
colleagues. I am indebted to them for taking the time to read early versions of the manuscript and
provide thoughtful suggestions for improvement. In particular, I thank Paul Strauss, Eric Gregory,
Rycharde Hawkes, Nick Long, James Chalfant, Brett Levin, Marcus Marr, Jim Humelsine, and Geoff
Levner.
My passion for good API design has been forged through my relationship with many great soft-
ware engineers and managers. As a result of working at several different companies and institutions,
I’ve been exposed to a range of design perspectives, software development philosophies, and
problem-solving approaches. Throughout these varied experiences, I’ve had the privilege to meet
and learn from some uniquely talented individuals. Some of these giants whose shoulders I have
stood upon include:
• SRI International: Bob Bolles, Adam Cheyer, Elizabeth Churchill, David Colleen, Brian Davis,
Michael Eriksen, Jay Feuquay, Marty A. Fischler, Aaron Heller, Lee Iverson, Jason Jenkins, Luc
Julia, Yvan G. Leclerc, Pat Lincoln, Chris Marrin, Ray C. Perrault, and Brian Tierney.
• Pixar Animation Studios: Brad Andalman, David Baraff, Ian Buono, Gordon Cameron, Ed
Catmull, Chris Colby, Bena Currin, Gareth Davis, Tony DeRose, Mike Ferris, Kurt Fleischer,
Sebastian Grassia, Eric Gregory, Tara Hernandez, Paul Isaacs, Oren Jacob, Michael Kass, Chris
King, Brett Levin, Tim Milliron, Alex Mohr, Cory Omand, Eben Osbty, Allan Poore, Chris
Shoeneman, Patrick Schork, Paul Strauss, Kiril Vidimče, Adam Woodbury, David Yu, Dirk
van Gelder, Brad West, and Andy Witkin.
• The Bakery Animation Studio: Sam Assadian, Sebastien Guichou, Arnauld Lamorlette, Thierry
Lauthelier, Benoit Lepage, Geoff Levner, Nick Long, Erwan Maigret, and Bariş Metin.
• Linden Lab: Nat Goodspeed, Andrew de Laix, Howard Look, Brad Kittenbrink, Brian McGroarty,
Adam Moss, Mark Palange, Jim Purbrick, and Kent Quirk.
In particular, I acknowledge the great impact that Yvan G. Leclerc made on my life during my
early years at SRI International. Yvan was my first manager and also a true friend. He taught me
how to be a good manager of people, how to be a rigorous scientist and engineer, and, at the same
time, how to enjoy life to its fullest. It is a great sorrow that incredible individuals such as Yvan
are taken from us too soon.
Many thanks must also go to Morgan Kaufmann Publishers for all of their work reviewing, copy
editing, typesetting, and publishing this book. This work would quite literally not exist without their
backing and energy. In particular, I acknowledge the contribution of Todd Green, Robyn Day, André
Cuello, and Melissa Revell.
Most importantly, I thank my wife, Genevieve M. Vidanes, for encouraging me to write this book
and for putting up with me while I spent many late nights hunched over the keyboard. As this is my
second book, she knew full well how much it would impact our personal life. Nonetheless, she sup-
ported me throughout the whole process, while also knowing exactly when to make me pause and
take a break. Thank you Genevieve for your constant love and support.
xxiii
Author Biography
Dr. Martin Reddy is CEO of Code Reddy Inc. He holds a Ph.D. in computer science and has over
15 years of experience in the software industry. During this time, Dr. Reddy has produced more than
40 professional publications, three software patents, and coauthored the book Level of Detail for 3D
Graphics. He is a member of the Association of Computing Machinery (ACM) and the Institute of
Electrical and Electronic Engineers (IEEE).
Dr. Reddy worked for 6 years at Pixar Animation Studios, where he was lead engineer for the
studio’s in-house animation system. This work involved the design and implementation of various
high-performance APIs to support Academy Award-winning and nominated films, such as Finding
Nemo, The Incredibles, Cars, Ratatouille, and Wall-E.
He then took on the role of engineering manager at The Bakery Animation Studio, where he led
the development of the startup studio’s animation software. This included the design and implemen-
tation of many key APIs as well as devising the overall animator workflow and user interface.
Earlier in his career, Dr. Reddy worked for 5 years at SRI International on distributed 3D terrain
visualization technologies, which involved the development of several open source geospatial APIs.
He cofounded a successful effort to create an ISO standard to represent 3D geospatial models on the
Web and was elected as a director of the Web3D Consortium for 2 consecutive years.
Through his consulting company, Dr. Reddy has provided his technical expertise to various soft-
ware companies, including Linden Lab and Planet 9 Studios. The former involved API design and
infrastructure improvements for the open source product Second Life, an online 3D virtual world that
has been used by over 16 million people around the world.
xxv
CHAPTER
Introduction
1
1.1 WHAT ARE APPLICATION PROGRAMMING INTERFACES?
An Application Programming Interface (API) provides an abstraction for a problem and specifies
how clients should interact with software components that implement a solution to that problem.
The components themselves are typically distributed as a software library, allowing them to be used
in multiple applications. In essence, APIs define reusable building blocks that allow modular pieces
of functionality to be incorporated into end-user applications.
An API can be written for yourself, for other engineers in your organization, or for the develop-
ment community at large. It can be as small as a single function or involve hundreds of classes,
methods, free functions, data types, enumerations, and constants. Its implementation can be proprie-
tary or open source. The important underlying concept is that an API is a well-defined interface that
provides a specific service to other pieces of software.
A modern application is typically built on top of many APIs, where some of these can also
depend on further APIs. This is illustrated in Figure 1.1, which shows an example application that
depends directly on the API for three libraries (1 3), where two of those APIs depend on the API
for a further two libraries (4 and 5). For instance, an image viewing application may use an API
for loading GIF images, and that API may itself be built upon a lower-level API for compressing
and decompressing data.
API development is ubiquitous in modern software development. Its purpose is to provide a logi-
cal interface to the functionality of a component while also hiding any implementation details. For
example, our API for loading GIF images may simply provide a LoadImage() method that accepts
a filename and returns a 2D array of pixels. All of the file format and data compression details
are hidden behind this simple interface. This concept is also illustrated in Figure 1.1, where client
code only accesses an API via its public interface, shown as the dark section at the top of each box.
1.1.1 Contracts and Contractors
As an analogy, consider the task of building your own home. If you were to build a house entirely on
your own, you would need to possess a thorough understanding of architecture, plumbing, electron-
ics, carpentry, masonry, and many other trades. You would also need to perform every task yourself
and keep track of the minutest of details for every aspect of the project, such as whether you have
enough wood for your floorboards or whether you have the right fasteners to fit the screws that
you have. Finally, because you are the only person working on the project, you can only perform
a single task at any point in time and hence the total time to complete the project could be very large.
API design for C++.
© 2011 Elsevier Inc. All rights reserved.
1
API Design for C 1st Edition Martin Reddy
API Design for C 1st Edition Martin Reddy
As an example of a well-known API, Microsoft’s Windows API (often referred to as the Win32
API) is a collection of C functions, data types, and constants that enable programmers to write appli-
cations that run on the Windows platform. This includes functions for file handling, process and
thread management, creating graphical user interfaces, talking to networks, and so on.
The Win32 API is an example of plain C API rather than a C++ API. While you can use a C API
directly from a C++ program, a good example of a specific C++ API is the Standard Template Library
(STL). The STL contains a set of container classes, iterators for navigating over the elements in
those containers, and various algorithms that act on those containers (Josuttis, 1999). For instance,
the collection of algorithms includes high-level operations such as std::search(), std::reverse(),
std::sort(), and std::set intersection(). The STL therefore presents a logical interface to
the task of manipulating collections of elements, without exposing any of the internal details for
how each algorithm is implemented.
TIP
An API is a logical interface to a software component that hides the internal details required to implement it.
1.2 WHAT’S DIFFERENT ABOUT API DESIGN?
Interfaces are the most important code that a developer writes. That’s because problems in an inter-
face are far more costly to fix than problems in the associated implementation code. As a result, the
process of developing shared APIs demands more attention than standard application or Graphical
User Interface (GUI) development. Of course, both should involve best design practices; however,
in the case of API development, these are absolutely critical to its success. Specifically, some of
the key differentiating factors of API development include the following.
• An API is an interface designed for developers, in much the same way that a GUI is an inter-
face designed for end users. In fact, it’s been said that an API is a user interface for program-
mers (Arnold, 2005). As such, your API could be used by thousands of developers around the
world, and it will undoubtedly be used in ways that you never intended (Tulach, 2008). You
must anticipate this in your design. A well-designed API can be your organization’s biggest
asset. Conversely, a poor API can create a support nightmare and even turn your users toward
your competitors (Bloch, 2005), just as a buggy or difficult-to-use GUI may force an end user
to switch to a different application.
• Multiple applications can share the same API. Figure 1.1 showed that a single application can
be composed of multiple APIs. However, any one of those APIs could also be reused in sev-
eral other applications. This means that while problems in the code for any given application
will only affect that one application, errors in an API can affect all of the applications that
depend on that functionality.
• You must strive for backward compatibility whenever you change an API. If you make an
incompatible change to your interface, your clients’ code may fail to compile, or worse their
code could compile but behave differently or crash intermittently. Imagine the confusion and
chaos that would arise if the signature of the printf() function in the standard C library was
4 CHAPTER 1 Introduction
different for different compilers or platforms. The simple “Hello World” program may not
look so simple any more:
#include <stdio.h>
#ifdef WIN32
#include <windows.h>
#endif
#ifdef cplusplus
#include <iostream>
#endif
int main(int, char *argv[])
{
#if STRICT ANSI
printf("Hello Worldn");
#elif defined( WIN32)
PrintWithFormat("Hello Worldn");
#elif defined( PRINTF DEPRECATED )
fprintf(stdout, "Hello Worldn");
#elif defined( PRINTF VECTOR )
const char *lines[2] {"Hello World", NULL};
printf(lines);
#elif defined( cplusplus)
std::cout << "Hello World" << std::endl;
#else
#error No terminal output API found
#endif
return 0;
}
This may seem like a contrived example, but it’s actually not that extreme. Take a look at the stan-
dard header files that come with your compiler and you will find declarations that are just as convo-
luted and inscrutable, or perhaps worse.
• Due to the backward compatibility requirement, it is critical to have a change control process
in place. During the normal development process, many developers may fix bugs or add new
features to an API. Some of these developers may be junior engineers who do not fully under-
stand all of the aspects of good API design. As a result, it is important to hold an API review
before releasing a new version of the API. This involves one or more senior engineers check-
ing that all changes to the interface are acceptable, have been made for a valid reason, and are
implemented in the best way to maintain backward compatibility. Many open source APIs
also enforce a change request process to gain approval for a change before it is added to
the source code.
• APIs tend to live for a long time. There can be a large upfront cost to produce a good API
because of the extra overhead of planning, design, versioning, and review that is necessary.
However, if done well, the long-term cost can be substantially mitigated because you have
the ability to make radical changes and improvements to your software without disrupting
your clients. That is, your development velocity can be greater due to the increased flexibility
that the API affords you.
5
1.2 What’s different about API design?
API Design for C 1st Edition Martin Reddy
• Increases longevity. Over time, systems that expose their implementation details tend to
devolve into spaghetti code where every part of the system depends on the internal details
of other parts of the system. As a result, the system becomes fragile, rigid, immobile, and vis-
cous (Martin, 2000). This often results in organizations having to spend significant effort to
evolve the code toward a better design or simply rewrite it from scratch. By investing in good
API design up front and paying the incremental cost to maintain a coherent design, your soft-
ware can survive for longer and cost less to maintain in the long run. I’ll delve much deeper
into this point at the start of Chapter 4.
• Promotes modularization. An API is normally devised to address a specific task or use case.
As such, APIs tend to define a modular grouping of functionality with a coherent focus.
Developing an application on top of a collection of APIs promotes loosely coupled and mod-
ular architectures where the behavior of one module is not dependent on the internal details of
another module.
• Reduces code duplication. Code duplication is one of the cardinal sins of software engineer-
ing and should be stamped out whenever possible. By keeping all of your code’s logic behind
a strict interface that all clients must use, you centralize the behavior in a single place. Doing
so means that you have to update only one place to change the behavior of your API for all of
your clients. This can help remove duplication of implementation code throughout your code
base. In fact, many APIs are created after discovering duplicated code and deciding to consol-
idate it behind a single interface. This is a good thing.
• Removes hardcoded assumptions. Many programs may contain hardcoded values that are
copied throughout the code, for example, using the filename myprogram.log whenever data
are written to a log file. Instead, APIs can be used to provide access to this information with-
out replicating these constant values across the code base. For example, a GetLogFilename()
API call could be used to replace the hardcoded "myprogram.log" string.
• Easier to change the implementation. If you have hidden all of the implementation details
of your module behind its public interface then you can change those implementation details
without affecting any code that depends on the API. For example, you might decide to change
a file parsing routine to use std::string containers instead of allocating, freeing, and reallo-
cating your own char * buffers.
• Easier to optimize. Similarly, with your implementation details hidden successfully, you can
optimize the performance of your API without requiring any changes to your clients’ code.
For example, you could add a caching solution to a method that performs some computation-
ally intensive calculation. This is possible because all attempts to read and write your under-
lying data are performed via your API, so it becomes much easier to know when you must
invalidate your cached result and recompute the new value.
1.3.2 Code Reuse
Code reuse is the use of existing software to build new software. It is one of the holy grails of mod-
ern software development. APIs provide a mechanism to enable code reuse.
In the early years of software development, it was common for a company to have to write all of
the code for any application they produced. If the program needed to read GIF images or parse a text
file, the company would have to write all that code in-house. Nowadays, with the proliferation of
7
1.3 Why should you use APIs?
API Design for C 1st Edition Martin Reddy
1.3.3 Parallel Development
Even if you are writing in-house software, your fellow engineers will very likely need to write code
that uses your code. If you use good API design techniques, you can simplify their lives and, by
extension, your own (because you won’t have to answer as many questions about how your code
works or how to use it). This becomes even more important if multiple developers are working in
parallel on code that depends upon each other.
For example, let’s say that you are working on a string encryption algorithm that another devel-
oper wants to use to write data out to a configuration file. One approach would be to have the other
developer wait until you are finished with your work and then he can use it in his file writer module.
However, a far more efficient use of time would be for the two of you to meet early on and agree
upon an appropriate API. Then you can put that API in place with placeholder functionality that your
colleague can start calling immediately, such as
#include <string.h>
class StringEncryptor
{
public:
/// set the key to use for the Encrypt() and Decrypt() calls
void SetKey(const std::string &key);
/// encrypt an input string based upon the current key
std::string Encrypt(const std::string &str) const;
/// decrypt a string using the current key calling
/// Decrypt() on a string returned by Encrypt() will
/// return the original string for the same key.
std::string Decrypt(const std::string &str) const;
};
You can then provide a simple implementation of these functions so that at least the module will
compile and link. For example, the associated .cpp file might look like
void StringEncryptor::SetKey(const std::string &key)
{
}
std::string StringEncryptor::Encrypt(const std::string &str)
{
return str;
}
std::string StringEncryptor::Decrypt(const std::string &str)
{
return str;
}
In this way, your colleague can use this API and proceed with his work without being held up
by your progress. For the time being, your API will not actually encrypt any strings, but that’s just
9
1.3 Why should you use APIs?
a minor implementation detail! The important point is that you have a stable interface a contract
that you both agree upon, and that it behaves appropriately, for example, Decrypt(Encrypt
("Hello")) "Hello". When you finish your work and update the .cpp file with the correct
implementation, your colleague’s code will simply work without any further changes required
on his part.
In reality, it’s likely that there will be interface issues that you didn’t anticipate before you started
writing the code and you will probably have to iterate on the API a few times to get it just right.
However, for the most part, the two of you can work in parallel with minimal holdups.
This approach also encourages test-driven, or test-first, development. By stubbing out the API
early on, you can write unit tests to validate the desired functionality and run these continuously
to make sure that you haven’t broken your contract with your colleague.
Scaling this process up to an organizational level, your project could have separate teams that
may be remote from each other, even working to different schedules. By defining each team’s depen-
dencies up front and creating APIs to model these, each team can work independently and with min-
imal knowledge of how the other teams are implementing their work behind the API. This efficient
use of resources, and the corresponding reduction in redundant communication, can correlate to a
significant overall cost saving for an organization.
1.4 WHEN SHOULD YOU AVOID APIS?
Designing and implementing an API usually requires more work than writing normal applica-
tion code. That’s because the purpose of an API is to provide a robust and stable interface for other
developers to use. As such, the level of quality, planning, documentation, testing, support, and
maintenance is far higher for an API than for software that is to be used within a single application.
As a result, if you are writing an internal module that does not require other clients to com-
municate with it, then the extra overhead of creating and supporting a stable public interface
for your module may not be worth the effort, although this is not a reason to write sloppy code. Spend-
ing the extra time to adhere to the principles of API design will not be wasted effort in the long run.
On the flip side of the coin, consider that you are a software developer who wants to use a third-
party API in your application. The previous section discussed a number of reasons why you might
want to reuse external APIs in your software. However, there may be cases where you wish to avoid
using a particular API and pay the cost to implement the code yourself or look for an alternate
solution. For example:
• License restrictions. An API may provide everything that you need functionality-wise, but
the license restrictions may be prohibitive for your needs. For example, if you want to use
an open source package that is distributed under the GNU General Public License (GPL), then
you are required to release any derived works under the GPL also. This means that using this
package in your program would require you to release the entire source code for your appli-
cation, a constraint that may not be acceptable for a commercial application. Other licenses,
such as the GNU Lesser General Public License (LGPL), are more permissive and tend to
be more common for software libraries. Another licensing aspect is that the dollar cost for
a commercial API may be too high for your project or the licensing terms may be too
restrictive, such as requiring a license fee per developer or even per user.
10 CHAPTER 1 Introduction
• Functionality mismatch. An API may appear to solve a problem that you have, but may do
it in a way that doesn’t match the constraints or functional requirements of your application.
For example, perhaps you’re developing an image processing tool and you want to provide a
Fourier transform capability. There are many implementations of the Fast Fourier Transform
(FFT) available, but a large number of these are 1D algorithms, whereas you require a 2D
FFT because you are dealing with 2D image data. Additionally, many 2D FFT algorithms
only work on data sets with dimensions that are a power of 2 (e.g., 256  256 or 512 
512 pixels). Furthermore, perhaps the API that you found doesn’t work on the platforms that
you must support or perhaps it doesn’t match the performance criteria that you have specified
for your application.
• Lack of source code. While there are many open source APIs, sometimes the best API for
your case may be a closed source offering. That is, only the header files for the interface
are made available to you, but the underlying C++ source files are not distributed with the
library. This has several important implications. Among these is the fact that if you encounter
a bug in the library, you are unable to inspect the source code to understand what might be
going wrong. Reading the source can be a valuable technique for tracking down a bug and
potentially discovering a workaround for the issue.
Furthermore, without access to the source code for an API, you lose the ability to change
the source in order to fix a bug. This means that the schedule for your software project could
be affected adversely by unanticipated problems in a third-party API you’re using and by time
spent waiting for the owners of that API to address your bug reports and distribute a fixed
patch.
• Lack of documentation. An API may appear to fulfill a need that you have in your applica-
tion, but if the API has poor or non-existent documentation then you may decide to look else-
where for a solution. Perhaps it is not obvious how to use the API, perhaps you cannot be sure
how the API will behave under certain situations, or perhaps you simply don’t trust the work
of an engineer who hasn’t taken the time to explain how his code should be used.
1.5 API EXAMPLES
APIs are everywhere. Even if you have only been programming for a short amount of time, chances
are that you have written code to use an API or two and maybe you’ve also written one yourself.
1.5.1 Layers of APIs
An API can be any size, from a single function to a large collection of classes. It can also provide
access to functionality at any architectural level, from low-level operating system calls all the way
up to GUI toolkits. The following list presents various common APIs, many of which you’ve
probably heard of already, to give you an appreciation for how prevalent API development is.
• Operating System (OS) APIs. Every OS must provide a set of standard APIs to allow pro-
grams to access OS-level services. For example, the POSIX API defines functions such as
fork(), getpid(), and kill() for managing UNIX-style processes. Microsoft’s Win32 API
11
1.5 API examples
includes functions such as CreateProcess(), GetCurrentProcess(), and TerminateProcess
() for managing Windows processes. These are stable low-level APIs that should never
change, otherwise many programs could break!
• Language APIs. The C language provides a standard API, implemented as the libc library
and supporting man pages, which includes familiar functions such as printf(), scanf(),
and fopen(). The C++ language also offers the Standard Template Library (STL), which pro-
vides an API for various container classes (e.g., std::string, std::vector, std::set, and
std::map), iterators (e.g., std::vectordouble::iterator), and generic algorithms (e.g.,
std::sort, std::for each, and std::set union). For example, the following code snippet
uses the STL API to iterate through all elements in a vector and print them out:
#include vector
#include iostream
void PrintVector(const std::vectorfloat vec)
{
std::vectorfloat::const iterator it;
for (it vec.begin(); it ! vec.end(); þþit)
{
std::cout  *it  std::endl;
}
}
• Image APIs. Gone are the days when developers needed to write their own image reading and
writing routines. There is now a wide range of open source packages out there for you to
download and use in your own programs. For example, there’s the popular libjpeg library that
provides an implementation of a JPEG/JFIF decoder and encoder. There’s the extensive libtiff
library for reading and writing various flavors of TIFF files. And there’s the libpng library for
handling PNG format images. All of these libraries define APIs that let you write code to read
and write the image formats without having to know anything about the underlying file
formats themselves. For example, the follow code snippet uses the libtiff API to find the
dimensions of a TIFF image.
TIFF *tif TIFFOpen(image.tiff, r);
if (tif)
{
uint32 w, h;
TIFFGetField(tif, TIFFTAG IMAGEWIDTH, w);
TIFFGetField(tif, TIFFTAG IMAGELENGTH, h);
printf(Image size %d x %d pixelsn, w, h);
TIFFClose(tif);
}
• Three-Dimensional Graphics APIs. The two classic real-time 3D graphics APIs are
OpenGL and DirectX. These let you define 3D objects in terms of small primitives, such as
triangles or polygons; specify the surface properties of those primitives, such as color, normal,
and texture; and define the environment conditions, such as lights, fog, and clipping panes.
Thanks to standard APIs such as these, game developers can write 3D games that will work
12 CHAPTER 1 Introduction
on graphics cards old and new, from many different manufacturers. That’s because each gra-
phics card manufacturer distributes drivers that provide the implementation details behind the
OpenGL or DirectX API. Before the widespread use of these APIs, a developer had to write a
3D application for a specific piece of graphics hardware, and this program would probably not
work on another machine with different graphics hardware. These APIs also enable a host of
higher-level scene graph APIs, such as OpenSceneGraph, OpenSG, and OGRE. The following
code segment shows the classic example of rendering a triangle, with a different color for
each vertex, using the OpenGL API:
glClear(GL COLOR BUFFER BIT);
glBegin(GL TRIANGLES);
glColor3f(0.0, 0.0, 1.0); /* blue */
glVertex2i(0, 0);
glColor3f(0.0, 1.0, 0.0); /* green */
glVertex2i(200, 200);
glColor3f(1.0, 0.0, 0.0); /* red */
glVertex2i(20, 200);
glEnd();
glFlush();
• Graphical User Interface APIs. Any application that wants to open its own window needs to
use a GUI toolkit. This is an API that provides the ability to create windows, buttons, text fields,
dialogs, icons, menus, and so on. The API will normally also provide an event model to allow
the capturing of mouse and keyboard events. Some popular C/C++ GUI APIs include the
wxWidgets library, Nokia’s Qt API, GTK+, and X/Motif. It used to be the case that if a com-
pany wanted to release an application on more than one platform, such as Windows and
Mac, they would have to rewrite the user interface code using a different GUI API for each plat-
form or they would have to develop their own in-house cross-platform GUI toolkit. However,
these days most modern GUI toolkits are available for multiple platforms including Windows,
Mac, and Linux which makes it far easier to write cross-platform applications. As a sample of
a modern cross-platform GUI API, the following complete program shows a bare minimum Qt
program that pops up a window with a Hello World button:
#include QApplication
#include QPushButton
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QPushButton hello(Hello world!);
hello.resize(100, 30);
hello.show();
return app.exec();
}
Of course, this list is just a brief cross section of all the possible APIs that are out there. You’ll also find
APIs to let you access data over networks, to parse and generate XML files, to help you write multi-
threaded programs, or to solve complex mathematical problems. The point of the aforementioned list
was simply to demonstrate the breadth and depth of APIs that have been developed to help you build
your applications and to give you a flavor for what code based on these APIs looks like.
13
1.5 API examples
TIP
APIs are used everywhere in modern software development, from OS and language level APIs to image, audio,
graphics, concurrency, network, XML, mathematics, Web browsing, or GUI APIs.
1.5.2 A Real-Life Example
The aforementioned list of API examples was purposefully arranged by architectural level to show
the range of APIs that you might use when building an application. You will often use APIs from
several architectural levels when building a large software product. For example, Figure 1.3 presents
an example architecture diagram for the Second Life Viewer developed by Linden Lab. This is a
large open source program that lets users interact with each other in an online 3D virtual world, with
the ability to perform voice chat and text messaging between users. The diagram demonstrates the
use and layering of APIs in a large C++ software project.
Of particular note is the layer of Internal APIs, by which I mean the set of modules that a com-
pany develops in-house for a particular product, or suite of products. While Figure 1.3 simply shows
these as a single layer for the purpose of simplicity, the set of Internal APIs will form an additional
stack of layers. From foundation-level routines that provide in-house string, dictionary, file IO,
threading routines, and so on to APIs that provide the core business logic of the application, all
the way up to custom GUI APIs for managing the application’s user interface.
Obviously, Figure 1.3 doesn’t provide an exhaustive list of all the APIs used in this application. It
simply shows a few examples of each architectural layer. However, Table 1.1 presents the complete
set of third-party dependencies for the application to give you an idea of how many open source and
commercial closed source dependencies a contemporary software project is built upon. When you
factor in system and OS libraries as well, this list grows even further.
Second Life Viewer
IIComon IIMessage IIAudio IIRender
Application Code
Internal APIs
Third Party APIs
Language APIs
OS APIs
OpenGL APR
Standard C Library Standard Template L brary
Win32 / Mac OS X / Linux Kernel API
Boost Expat OpenSSL
FIGURE 1.3
Architecture diagram for the Second Life Viewer.
14 CHAPTER 1 Introduction
API Design for C 1st Edition Martin Reddy
1.6 FILE FORMATS AND NETWORK PROTOCOLS
There are several other forms of communication “contracts” commonly used in computer applica-
tions. One of the most familiar is the file format. This is a way to save in-memory data to a file
on disk using a well-known layout of those data. For example, the JPEG File Interchange Format
(JFIF) is an image file format for exchanging JPEG-encoded imagery, commonly given the .jpg
or .jpeg file extension. The format of a JFIF file header is shown in Table 1.2.
Given the format for a data file, such as the JFIF/JPEG format given in Table 1.2, any pro-
gram can read and write image files in that format. This allows the easy interchange of image data
between different users and the proliferation of image viewers and tools that can operate on those
images.
Similarly, client/server applications, peer-to-peer applications, and middleware services work
by sending data back and forward using an established protocol, usually over a network socket.
For example, the Subversion version control system uses a client/server architecture where the
master repository is stored on the server and individual clients synchronize their local clients with
the server (Rooney, 2005). In order to make this work, the client and the server must agree upon
the format of those data transmitted across the network. This is known as the client/server protocol
or line protocol. If the client sends a data stream that does not conform to this protocol, then the
server will not be able to understand the message. It is therefore critical that the specification of
the client/server protocol is well defined and that both the client and the server conform to the
specification.
Both of these cases are conceptually similar to an API in that they define a standard interface, or
specification, for information to be exchanged. Also, any changes to the specification must consider
the impact on existing clients. Despite this similarity, file formats and line protocols are not actually
APIs because they are not programming interfaces for code that you link into your application. How-
ever, a good rule of thumb is that whenever you have a file format or a client/server protocol, you
should also have an associated API to manage changes to that specification.
Table 1.2 JFIF file format header specification
Field Byte size Description
APP0 marker 2 Always 0xFFE0
Length 2 Length of segment excluding APP0 marker
Identifier 5 Always 0x4A46494600 (“JFIF0”)
Version 2 0x0102
Density units 1 Units for pixel density fields, 0 no units
X density 2 Integer horizontal pixel density
Y density 2 Integer vertical pixel density
Thumbnail width (w) 1 Horizontal size of embedded thumbnail
Thumbnail height (h) 1 Vertical size of embedded thumbnail
Thumbnail data 3  w  h Uncompressed 24-bit RGB raster data
16 CHAPTER 1 Introduction
TIP
Whenever you create a file format or client/server protocol, you should also create an API for it. This allows details
of the specification, and any future changes to it, to be centralized and hidden.
For example, if you specify a file format for your application’s data, you should also write an API
to allow reading and writing files in that format. For one, this is simply good practice so that knowl-
edge of the file format is not distributed throughout your application. More importantly, having an
API allows you to easily change the file format in the future without having to rewrite any code out-
side of the API implementation. Finally, if you do end up with multiple different versions of a file
format, then your API can abstract that complexity away so that it can read and write data in any
version of the format or it can know if the format is written with a newer version of the API and take
appropriate steps. In essence, the actual format of data on the disk becomes a hidden implementation
detail that your application does not need to be concerned with.
This advice applies just as well to client/server applications, where the definition of a common
protocol, and a common API to manage that protocol, can allow the client and server teams to work
relatively independently of each other. For instance, you may begin using UDP as the transport layer
for part of your system but later decide to switch to TCP (as indeed happened with the Second Life
code base). If all network access had already been abstracted behind an appropriate API, then such a
major implementation change would have little to no disruptive impact on the rest of the system.
1.7 ABOUT THIS BOOK
Now that I have covered the basics of what an API is and the pros and cons of API development, I’ll
dive into details such as how to design good APIs, how to implement them efficiently in C++, and
how to version them without breaking backward compatibility. The progression of chapters in this
book roughly follows the standard evolution of an API, from initial design through implementation,
versioning, documentation, and testing.
Chapter 2: Qualities
I begin the main text with a chapter that answers the following question: what is a good API?
This will cover a wide gamut of qualities that you should be aware of when designing your
APIs, such as information hiding, minimal completeness, and loose coupling. As I do through-
out the book, I illustrate these concepts with many C++ source code examples to show how
they relate to your own projects.
Chapter 3: Patterns
The next couple of chapters tackle the question of how you design a good API. Accordingly,
Chapter 3 looks at some specific design patterns and idioms that are particularly helpful in
API design. These include the pimpl idiom, Singleton, Factory Method, Proxy, Adapter,
Façade, and Observer.
Chapter 4: Design
Continuing the topic of how to design a good API, Chapter 4 discusses functional requirement
gathering and use case modeling to drive the design of a clean and usable interface, as well as
17
1.7 About this book
some techniques of object-oriented analysis and object-oriented design. This chapter also
includes a discussion on many of the problems that a large software project faces. These
observations are taken from real-world experiences and provide insight into the issues that
arise when doing large-scale API development.
Chapter 5: Styles
The next few chapters focus on creating high-quality APIs with C++. This is a deep and com-
plex topic and is, of course, the specific focus of this book. I therefore begin by describing
various styles of C and C++ APIs that you could adopt in your projects, such as flat C APIs,
object-oriented APIs, template-based APIs, and data-driven APIs.
Chapter 6: C++ Usage
Next I discuss various C++ language features that can impact good API design. This includes
numerous important issues such as good constructor and operator style, namespaces, pointer
versus reference parameters, the use of friends, and how to export symbols in a dynamic
library.
Chapter 7: Performance
In this chapter I analyze performance issues in APIs and show you how to build high-
performing APIs in C++. This involves the use of const references, forward declarations, data
member clustering, and inlining. I also present various tools that can help you assess the per-
formance of your code.
Chapter 8: Versioning
With the foundations of API design in hand, I start to expand into more complex aspects,
starting with API versioning and how to maintain backward compatibility. This is one of
the most important and difficult aspects of robust API design. Here I will define the vari-
ous terms backward, forward, functional, source, and binary compatibility and describe how
to evolve an API with minimal impact to your clients.
Chapter 9: Documentation
Next I dedicate a chapter to the topic of API documentation. Because an API is ill-defined
without proper supporting documentation, I present good techniques for commenting and doc-
umenting your API, with specific examples using the excellent Doxygen tool.
Chapter 10: Testing
The use of extensive testing lets you evolve an API with the confidence that you are not
breaking your clients’ programs. Here I present various types of automated testing, including
unit, integration, and performance tests, and present examples of good testing methodologies
for you to use in your own projects. This covers topics such as test-driven development, stub
and mock objects, testing private code, and contract programming.
Chapter 11: Scripting
I follow this with a couple of more specialized topics, beginning with API scripting. This is an
optional subject that is not applicable to all APIs. However, you may decide to provide script-
ing access to your API so that power users of your application can write scripts to perform
custom actions. I therefore talk about how to create script bindings for a C++ API so that it
can be called from languages such as Python and Ruby.
Chapter 12: Extensibility
Another advanced topic is that of user extensibility: creating an API that allows programmers
to write custom C++ plugins that extend the basic functionality you ship with the API. This
18 CHAPTER 1 Introduction
can be a critical mechanism to promote adoption of your API and to help it survive for the
long term. Additionally, I cover how to create extensible interfaces using inheritance and
templates.
Appendix A: Libraries
The book concludes with an appendix on how to create static and dynamic libraries. You must
be able to create libraries in order for your code to be used by others. There are also interface
design issues to consider when creating dynamic libraries, such as the set of symbols that you
export publicly. I therefore discuss differences between static and shared libraries and demon-
strate how you can make your compiler produce these libraries to allow the reuse of your code
in other applications.
19
1.7 About this book
CHAPTER
Qualities
2
This chapter aims to answer the following question: What are the basic qualities of a good API?
Most developers would agree that a good API should be elegantly designed but still highly usable.
It should be a joy to use but also fade into the background (Henning, 2009). These are fine qualita-
tive statements, but what are the specific design aspects that enable these? Obviously every API is
different; however, there are certain qualities that promote high-quality API design and should be
adhered to whenever possible, as well as many that make for poor designs that should be avoided.
There are no absolutes in API design: you cannot apply a fixed set of rules to every situation.
However, while there may be individual cases where you decide that it is best for your project to
deviate from certain advice in this chapter, you should do so only after reasoned and considered
judgment. The guidance here should form the bedrock of your API design decisions.
This chapter concentrates on generic, language-neutral qualities of an API, such as information
hiding, consistency, and loose coupling. It provides a C++ context for each of these concepts, but
overall the advice in this chapter should be useful to you whether you are working on a C++, Java,
C#, or Python project. Later chapters deal with C++-specific issues, such as const correctness, name-
spaces, and constructor usage.
Many of the topics of this chapter also provide a jumping off point into deeper treatments later in
the book. For example, while I mention use of the Pimpl idiom as a solution for hiding internal details
in C++, I dedicate more space to this important topic in the following chapter on design patterns.
2.1 MODEL THE PROBLEM DOMAIN
An API is written to solve a particular problem or perform a specific task. So, first and foremost, the
API should provide a coherent solution for that problem and should be formulated in such a way that
models the actual domain of the problem. For example, it should provide a good abstraction of the
problem area and should model the key objects of that domain. Doing so can make the API easier
for your users to use and understand because it will correlate more closely with their preexisting
knowledge and experience.
2.1.1 Provide a Good Abstraction
An API should provide a logical abstraction for the problem that it solves. That is, it should be
formulated in terms of high-level concepts that make sense in the chosen problem domain rather than
exposing low-level implementation issues. You should be able to give your API documentation to a
API design for C++.
© 2011 Elsevier Inc. All rights reserved.
21
non-programmer and that person should be able to understand the concepts of the interface and how
it is meant to work.
Furthermore, it should be apparent to the non-technical reader that the group of operations provided
by the API makes sense and belongs together as a unit. Each class should have a central purpose,
which should be reflected in the name of the class and its methods. In fact, it’s good practice to have
another person review your API early on to make sure that it presents a logical interface to fresh eyes.
Because coming up with a good abstraction is not a simple task, I dedicate most of Chapter 4 to
this complex topic. However, it should be noted that there is no single correct abstraction for any
given problem. Most APIs could be modeled in several different ways, each of which may provide
a good abstraction and a useful interface. The key point is that there is some consistent and logical
underpinning to your API.
For example, let’s consider an API for a simple address book program. Conceptually, an address
book is a container for the details of multiple people. It seems logical then that our API should pro-
vide an AddressBook object that contains a collection of Person objects, where a Person object
describes the name and address of a single contact. Furthermore, you want to be able to perform
operations such as adding a person to the address book or removing them. These are operations that
update the state of the address book and so logically should be part of the AddressBook object. This
initial design can then be represented visually using Unified Modeling Language (UML) as shown in
Figure 2.1.
For those not familiar with UML, Figure 2.1 shows an AddressBook object that contains a one-
to-many composition of Person objects as well as two operations: AddPerson() and DeletePerson
(). The Person object contains a set of public attributes to describe a single person’s name and
address. I will refine this design in a moment, but for the moment it serves as an initial logical
abstraction of the problem domain.
Address Book
Person
+ AddPerson() : boolean
+ DeletePerson() : boolean
+ firstName : string
+ address1 : string
+ address2 : string
+ city : string
+ state : string
+ zipcode : string
personList
0..*
+ middleName : string
+ lastName : string
FIGURE 2.1
High-level UML abstraction of an address book API.
22 CHAPTER 2 Qualities
API Design for C 1st Edition Martin Reddy
4. An address book may contain multiple people with the same name.
5. An existing address book entry can be modified.
These requirements will have a large impact on the object model for the API. Our original design
in Figure 2.1 only supports a single address per person. In order to support more than one address,
you could add extra fields to the Person object (e.g., HomeAddress1, WorkAddress1), but this would
be a brittle and inelegant solution. Instead, you could introduce an object to represent an address, for
example, Address, and allow a Person object to contain multiple of these.
The same is true of telephone numbers: you should factor these into their own object, for exam-
ple, TelephoneNumber, and allow the Person object to hold multiple of these. Another reason to cre-
ate an independent TelephoneNumber object is that we need to support operations such as IsValid(),
to validate a number, and GetFormattedNumber(), to return a nicely formatted version of the num-
ber. These are operations that naturally operate on a telephone number, not a person, which suggests
that telephone numbers should be represented by their own first-class objects.
The requirement that multiple People objects may hold the same name essentially means that a
person’s name cannot be used to uniquely identify an instance of the Person object. You therefore
need some way to uniquely identify a Person instance, for example, so that you can locate and
update an existing entry in the address book. One way to satisfy this requirement would simply be
to generate a universally unique identifier (UUID) for each person. Putting all of this together,
you might conclude that the key objects for our address book API are as follows:
• Address Book: Contains zero or more Person objects, with operations such as AddPerson(),
DeletePerson(), and UpdatePerson().
• Person: Fully describes the details for a single person, including zero or more addresses and
telephone numbers. Each person is differentiated by a UUID.
• Address: Describes a single address, including a type field such as “Home” or “Work.”
• Telephone Number: Describes a single address, including a type field such as “Home” or
“Cell.” Also supports operations such as IsValid() and GetFormattedNumber().
This updated object model can be represented as a UML diagram, as shown in Figure 2.2.
Address Book
Person
Address
+ AddPerson() : boolean
+ DeletePerson() : boolean
+ UpdatePerson() : boolean
+ firstName : string
+ address1 : string
+ address2 : string
+ city : string
+ state : string
+ zipcode : string
+ addressType : string
Telephone Number
+ number : string
+ numberType : string
+ IsValid() : boolean
+ GetFormattedString() : string
+ middleName : string
+ lastName : string
+ id : UUID
0..*
personList
0..*
addressList
0..*
telephoneList
FIGURE 2.2
UML diagram of key objects in our address book API.
24 CHAPTER 2 Qualities
API Design for C 1st Edition Martin Reddy
API Design for C 1st Edition Martin Reddy
API Design for C 1st Edition Martin Reddy
API Design for C 1st Edition Martin Reddy
Instead, you should prefer
class Vector3
{
public:
double GetX() const;
double GetY() const;
double GetZ() const;
void SetX(double val);
void SetY(double val);
void SetZ(double val);
private:
double mX, mY, mZ;
};
The latter syntax is obviously more verbose and involves more typing on your part as the pro-
grammer, but the extra few minutes spent doing this could save you hours, or even days, further
down the line should you decide to change the interface. Some of the additional benefits of using
getter/setter routines, rather than exposing member variables directly, include the following.
• Validation. You can perform validation on the values to ensure that the internal state of the class
is always valid and consistent. For example, if you have a method that lets clients set a new RGB
color, you could check that each of the supplied red, green, and blue values are within the valid
range, for example, 0 to 255 or 0.0 to 1.0.
• Lazy evaluation. Calculating the value of a variable may incur a significant cost, which you
would prefer to avoid until necessary. By using a getter method to access the underlying data
value, you can defer the costly calculation until the value is actually requested.
• Caching. A classic optimization technique is to store the value of a frequently requested calcu-
lation and then directly return that value for future requests. For example, a machine’s total mem-
ory size can be found on Linux by parsing the /proc/meminfo file. Instead of performing a file
read for every request to find the total memory size, it would be better to cache the result after
the first read and then simply return that cached value for future requests.
• Extra computation. If necessary, you can perform additional operations whenever the client tries to
access a variable. For example, perhaps you always want to write the current state of a UserPreferences
object to a configuration file on disk whenever the user changes the value of a preference setting.
• Notifications. Other modules may wish to know when a value has changed in your class. For
example, if you are implementing a data model for a progress bar, the user interface code will
want to know when the progress value has been updated so that it can update the GUI. You might
therefore wish to issue a change notification as part of a setter method.
• Debugging. You may want to add debugging or logging statements so that you can track when
variables are accessed or changed by clients or you may wish to add assert statements to enforce
assumptions.
• Synchronization. You may release the first version of your API and then later find that you need to
make it thread safe. The standard way to do this is to add mutex locking whenever a value is accessed.
This would only be possible if you have wrapped access to the data values in getter/setter methods.
29
2.2 Hide implementation details
• Finer access control. If you make a member variable public, then clients can read and write that
value as they wish. However, by using getter/setter methods, you can provide a finer level of read/
write control. For example, you can make the value be read-only by not providing a setter method.
• Maintaining invariant relationships. Some internal data values may depend on each other. For
example, in a car animation system you may calculate the velocity and acceleration of the car
based on the time it takes to travel between key frames. You can calculate velocity based on the
change in position over time, and acceleration based on the change in velocity over time. However,
if a client can access your internal state for this calculation, they could change the acceleration
value so that it does not correlate to the car’s velocity, thus producing unexpected results.
However, if the member variables are not actually part of the logical interface that is, they rep-
resent internal details that are not relevant to the public interface then they should simply be hidden
from the interface. For example, consider the following definition for a stack of integers:
Class IntegerStack
{
public:
static const int MAX SIZE 100;
void Push(int val);
int Pop();
bool IsEmpty() const;
int mStack[MAX SIZE];
int mCurSize;
};
Clearly this is a really bad API because it exposes the way that the stack has been (poorly) imple-
mented as a fixed array of integers and it exposes the internal state of the stack via the mCurSize var-
iable. If at some future date you decided to improve the implementation of this class, for example, by
using a std::vector or std::list rather than a fixed-size statically allocated array, then you may
find this difficult to do. That’s because you have exposed the existence of the mStack and mCurSize
variables and so client code could be relying on the ability to access these variables directly. By
changing your implementation you could break your clients’ code.
Instead, these member variables should be hidden from the start so that client code cannot access
them:
Class IntegerStack
{
public:
void Push(int val);
int Pop();
bool IsEmpty() const;
private:
static const int MAX SIZE 100;
int mStack[MAX SIZE];
int mCurSize;
};
30 CHAPTER 2 Qualities
I have stated that member variables should never be public, but can they be declared as protected?
If you make a variable protected, then it can be accessed directly by any clients that subclass your
class, and then exactly the same arguments apply as for the public case. As such, you should never
make your member variables protected either. As Alan Snyder states, inheritance severely compro-
mises the benefits of encapsulation in object-oriented programming languages (Snyder, 1986).
TIP
Data members of a class should always be declared private, never public or protected.
The only semiplausible argument for exposing member variables is for performance reasons.
Executing a C++ function call incurs the overhead of pushing the method’s parameters and return
address onto the call stack, as well as reserving space for any local variables in the routine. Then
when the method completes, the call stack has to be unwound again. The cost to perform these
actions may be noticeable for performance-critical regions of code, such as within a tight loop
performing operations on a large number of objects. Code that directly accesses a public member
variable may be two to three times faster than code that has to go through getter/setter methods.
However, even in these cases, you should never expose member variables. First of all, the overhead
of a method call will very likely be insignificant for practically all of your API calls. Even if you are
writing performance-critical APIs, the careful use of inlining, combined with a modern optimizing
compiler, will normally completely eradicate the method call overhead, giving you all the performance
benefits of directly exposing member variables. If you’re still concerned, try timing your API with
inlined getter/setters and then with public member variables. The accompanying source code for this
book includes a sample program to do just this. See http://APIBook.com/ to download this code and try
it out yourself. I’ll also discuss this issue further in the chapter on performance.
2.2.4 Hide Implementation Methods
In addition to hiding all member variables, you should also hide all methods that do not need to be
public. This is the principle of information hiding: segregating the stable interface for a class from
the internal design decisions used to implement it. Early studies of several large programs found that
those using information hiding techniques were four times easier to modify than programs that did
not (Korson and Vaishnavi, 1986). While your own mileage may vary, it should be clear that hiding
the internal details of your API will make for more maintainable and evolvable software.
The key point to remember is that a class should define what to do, not how it is done. For exam-
ple, let’s consider a class that lets you download a file from a remote http server:
#include string
#include stdio.h
#include sys/socket.h
#include unistd.h
class URLDownloader
{
public:
URLDownloader();
31
2.2 Hide implementation details
Exploring the Variety of Random
Documents with Different Content
THE FULL PROJECT GUTENBERG LICENSE
PLEASE READ THIS BEFORE YOU DISTRIBUTE OR USE THIS WORK
To protect the Project Gutenberg™ mission of promoting the
free distribution of electronic works, by using or distributing this
work (or any other work associated in any way with the phrase
“Project Gutenberg”), you agree to comply with all the terms of
the Full Project Gutenberg™ License available with this file or
online at www.gutenberg.org/license.
Section 1. General Terms of Use and
Redistributing Project Gutenberg™
electronic works
1.A. By reading or using any part of this Project Gutenberg™
electronic work, you indicate that you have read, understand,
agree to and accept all the terms of this license and intellectual
property (trademark/copyright) agreement. If you do not agree to
abide by all the terms of this agreement, you must cease using
and return or destroy all copies of Project Gutenberg™
electronic works in your possession. If you paid a fee for
obtaining a copy of or access to a Project Gutenberg™
electronic work and you do not agree to be bound by the terms
of this agreement, you may obtain a refund from the person or
entity to whom you paid the fee as set forth in paragraph 1.E.8.
1.B. “Project Gutenberg” is a registered trademark. It may only
be used on or associated in any way with an electronic work by
people who agree to be bound by the terms of this agreement.
There are a few things that you can do with most Project
Gutenberg™ electronic works even without complying with the
full terms of this agreement. See paragraph 1.C below. There
are a lot of things you can do with Project Gutenberg™
electronic works if you follow the terms of this agreement and
help preserve free future access to Project Gutenberg™
electronic works. See paragraph 1.E below.
1.C. The Project Gutenberg Literary Archive Foundation (“the
Foundation” or PGLAF), owns a compilation copyright in the
collection of Project Gutenberg™ electronic works. Nearly all the
individual works in the collection are in the public domain in the
United States. If an individual work is unprotected by copyright
law in the United States and you are located in the United
States, we do not claim a right to prevent you from copying,
distributing, performing, displaying or creating derivative works
based on the work as long as all references to Project
Gutenberg are removed. Of course, we hope that you will
support the Project Gutenberg™ mission of promoting free
access to electronic works by freely sharing Project
Gutenberg™ works in compliance with the terms of this
agreement for keeping the Project Gutenberg™ name
associated with the work. You can easily comply with the terms
of this agreement by keeping this work in the same format with
its attached full Project Gutenberg™ License when you share it
without charge with others.
1.D. The copyright laws of the place where you are located also
govern what you can do with this work. Copyright laws in most
countries are in a constant state of change. If you are outside
the United States, check the laws of your country in addition to
the terms of this agreement before downloading, copying,
displaying, performing, distributing or creating derivative works
based on this work or any other Project Gutenberg™ work. The
Foundation makes no representations concerning the copyright
status of any work in any country other than the United States.
1.E. Unless you have removed all references to Project
Gutenberg:
1.E.1. The following sentence, with active links to, or other
immediate access to, the full Project Gutenberg™ License must
appear prominently whenever any copy of a Project
Gutenberg™ work (any work on which the phrase “Project
Gutenberg” appears, or with which the phrase “Project
Gutenberg” is associated) is accessed, displayed, performed,
viewed, copied or distributed:
This eBook is for the use of anyone anywhere in the United
States and most other parts of the world at no cost and with
almost no restrictions whatsoever. You may copy it, give it
away or re-use it under the terms of the Project Gutenberg
License included with this eBook or online at
www.gutenberg.org. If you are not located in the United
States, you will have to check the laws of the country where
you are located before using this eBook.
1.E.2. If an individual Project Gutenberg™ electronic work is
derived from texts not protected by U.S. copyright law (does not
contain a notice indicating that it is posted with permission of the
copyright holder), the work can be copied and distributed to
anyone in the United States without paying any fees or charges.
If you are redistributing or providing access to a work with the
phrase “Project Gutenberg” associated with or appearing on the
work, you must comply either with the requirements of
paragraphs 1.E.1 through 1.E.7 or obtain permission for the use
of the work and the Project Gutenberg™ trademark as set forth
in paragraphs 1.E.8 or 1.E.9.
1.E.3. If an individual Project Gutenberg™ electronic work is
posted with the permission of the copyright holder, your use and
distribution must comply with both paragraphs 1.E.1 through
1.E.7 and any additional terms imposed by the copyright holder.
Additional terms will be linked to the Project Gutenberg™
License for all works posted with the permission of the copyright
holder found at the beginning of this work.
1.E.4. Do not unlink or detach or remove the full Project
Gutenberg™ License terms from this work, or any files
containing a part of this work or any other work associated with
Project Gutenberg™.
1.E.5. Do not copy, display, perform, distribute or redistribute
this electronic work, or any part of this electronic work, without
prominently displaying the sentence set forth in paragraph 1.E.1
with active links or immediate access to the full terms of the
Project Gutenberg™ License.
1.E.6. You may convert to and distribute this work in any binary,
compressed, marked up, nonproprietary or proprietary form,
including any word processing or hypertext form. However, if
you provide access to or distribute copies of a Project
Gutenberg™ work in a format other than “Plain Vanilla ASCII” or
other format used in the official version posted on the official
Project Gutenberg™ website (www.gutenberg.org), you must, at
no additional cost, fee or expense to the user, provide a copy, a
means of exporting a copy, or a means of obtaining a copy upon
request, of the work in its original “Plain Vanilla ASCII” or other
form. Any alternate format must include the full Project
Gutenberg™ License as specified in paragraph 1.E.1.
1.E.7. Do not charge a fee for access to, viewing, displaying,
performing, copying or distributing any Project Gutenberg™
works unless you comply with paragraph 1.E.8 or 1.E.9.
1.E.8. You may charge a reasonable fee for copies of or
providing access to or distributing Project Gutenberg™
electronic works provided that:
• You pay a royalty fee of 20% of the gross profits you derive
from the use of Project Gutenberg™ works calculated using
the method you already use to calculate your applicable
taxes. The fee is owed to the owner of the Project
Gutenberg™ trademark, but he has agreed to donate
royalties under this paragraph to the Project Gutenberg
Literary Archive Foundation. Royalty payments must be
paid within 60 days following each date on which you
prepare (or are legally required to prepare) your periodic tax
returns. Royalty payments should be clearly marked as
such and sent to the Project Gutenberg Literary Archive
Foundation at the address specified in Section 4,
“Information about donations to the Project Gutenberg
Literary Archive Foundation.”
• You provide a full refund of any money paid by a user who
notifies you in writing (or by e-mail) within 30 days of receipt
that s/he does not agree to the terms of the full Project
Gutenberg™ License. You must require such a user to
return or destroy all copies of the works possessed in a
physical medium and discontinue all use of and all access
to other copies of Project Gutenberg™ works.
• You provide, in accordance with paragraph 1.F.3, a full
refund of any money paid for a work or a replacement copy,
if a defect in the electronic work is discovered and reported
to you within 90 days of receipt of the work.
• You comply with all other terms of this agreement for free
distribution of Project Gutenberg™ works.
1.E.9. If you wish to charge a fee or distribute a Project
Gutenberg™ electronic work or group of works on different
terms than are set forth in this agreement, you must obtain
permission in writing from the Project Gutenberg Literary
Archive Foundation, the manager of the Project Gutenberg™
trademark. Contact the Foundation as set forth in Section 3
below.
1.F.
1.F.1. Project Gutenberg volunteers and employees expend
considerable effort to identify, do copyright research on,
transcribe and proofread works not protected by U.S. copyright
law in creating the Project Gutenberg™ collection. Despite
these efforts, Project Gutenberg™ electronic works, and the
medium on which they may be stored, may contain “Defects,”
such as, but not limited to, incomplete, inaccurate or corrupt
data, transcription errors, a copyright or other intellectual
property infringement, a defective or damaged disk or other
medium, a computer virus, or computer codes that damage or
cannot be read by your equipment.
1.F.2. LIMITED WARRANTY, DISCLAIMER OF DAMAGES -
Except for the “Right of Replacement or Refund” described in
paragraph 1.F.3, the Project Gutenberg Literary Archive
Foundation, the owner of the Project Gutenberg™ trademark,
and any other party distributing a Project Gutenberg™ electronic
work under this agreement, disclaim all liability to you for
damages, costs and expenses, including legal fees. YOU
AGREE THAT YOU HAVE NO REMEDIES FOR NEGLIGENCE,
STRICT LIABILITY, BREACH OF WARRANTY OR BREACH
OF CONTRACT EXCEPT THOSE PROVIDED IN PARAGRAPH
1.F.3. YOU AGREE THAT THE FOUNDATION, THE
TRADEMARK OWNER, AND ANY DISTRIBUTOR UNDER
THIS AGREEMENT WILL NOT BE LIABLE TO YOU FOR
ACTUAL, DIRECT, INDIRECT, CONSEQUENTIAL, PUNITIVE
OR INCIDENTAL DAMAGES EVEN IF YOU GIVE NOTICE OF
THE POSSIBILITY OF SUCH DAMAGE.
1.F.3. LIMITED RIGHT OF REPLACEMENT OR REFUND - If
you discover a defect in this electronic work within 90 days of
receiving it, you can receive a refund of the money (if any) you
paid for it by sending a written explanation to the person you
received the work from. If you received the work on a physical
medium, you must return the medium with your written
explanation. The person or entity that provided you with the
defective work may elect to provide a replacement copy in lieu
of a refund. If you received the work electronically, the person or
entity providing it to you may choose to give you a second
opportunity to receive the work electronically in lieu of a refund.
If the second copy is also defective, you may demand a refund
in writing without further opportunities to fix the problem.
1.F.4. Except for the limited right of replacement or refund set
forth in paragraph 1.F.3, this work is provided to you ‘AS-IS’,
WITH NO OTHER WARRANTIES OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO
WARRANTIES OF MERCHANTABILITY OR FITNESS FOR
ANY PURPOSE.
1.F.5. Some states do not allow disclaimers of certain implied
warranties or the exclusion or limitation of certain types of
damages. If any disclaimer or limitation set forth in this
agreement violates the law of the state applicable to this
agreement, the agreement shall be interpreted to make the
maximum disclaimer or limitation permitted by the applicable
state law. The invalidity or unenforceability of any provision of
this agreement shall not void the remaining provisions.
1.F.6. INDEMNITY - You agree to indemnify and hold the
Foundation, the trademark owner, any agent or employee of the
Foundation, anyone providing copies of Project Gutenberg™
electronic works in accordance with this agreement, and any
volunteers associated with the production, promotion and
distribution of Project Gutenberg™ electronic works, harmless
from all liability, costs and expenses, including legal fees, that
arise directly or indirectly from any of the following which you do
or cause to occur: (a) distribution of this or any Project
Gutenberg™ work, (b) alteration, modification, or additions or
deletions to any Project Gutenberg™ work, and (c) any Defect
you cause.
Section 2. Information about the Mission of
Project Gutenberg™
Project Gutenberg™ is synonymous with the free distribution of
electronic works in formats readable by the widest variety of
computers including obsolete, old, middle-aged and new
computers. It exists because of the efforts of hundreds of
volunteers and donations from people in all walks of life.
Volunteers and financial support to provide volunteers with the
assistance they need are critical to reaching Project
Gutenberg™’s goals and ensuring that the Project Gutenberg™
collection will remain freely available for generations to come. In
2001, the Project Gutenberg Literary Archive Foundation was
created to provide a secure and permanent future for Project
Gutenberg™ and future generations. To learn more about the
Project Gutenberg Literary Archive Foundation and how your
efforts and donations can help, see Sections 3 and 4 and the
Foundation information page at www.gutenberg.org.
Section 3. Information about the Project
Gutenberg Literary Archive Foundation
The Project Gutenberg Literary Archive Foundation is a non-
profit 501(c)(3) educational corporation organized under the
laws of the state of Mississippi and granted tax exempt status by
the Internal Revenue Service. The Foundation’s EIN or federal
tax identification number is 64-6221541. Contributions to the
Project Gutenberg Literary Archive Foundation are tax
deductible to the full extent permitted by U.S. federal laws and
your state’s laws.
The Foundation’s business office is located at 809 North 1500
West, Salt Lake City, UT 84116, (801) 596-1887. Email contact
links and up to date contact information can be found at the
Foundation’s website and official page at
www.gutenberg.org/contact
Section 4. Information about Donations to
the Project Gutenberg Literary Archive
Foundation
Project Gutenberg™ depends upon and cannot survive without
widespread public support and donations to carry out its mission
of increasing the number of public domain and licensed works
that can be freely distributed in machine-readable form
accessible by the widest array of equipment including outdated
equipment. Many small donations ($1 to $5,000) are particularly
important to maintaining tax exempt status with the IRS.
The Foundation is committed to complying with the laws
regulating charities and charitable donations in all 50 states of
the United States. Compliance requirements are not uniform
and it takes a considerable effort, much paperwork and many
fees to meet and keep up with these requirements. We do not
solicit donations in locations where we have not received written
confirmation of compliance. To SEND DONATIONS or
determine the status of compliance for any particular state visit
www.gutenberg.org/donate.
While we cannot and do not solicit contributions from states
where we have not met the solicitation requirements, we know
of no prohibition against accepting unsolicited donations from
donors in such states who approach us with offers to donate.
International donations are gratefully accepted, but we cannot
make any statements concerning tax treatment of donations
received from outside the United States. U.S. laws alone swamp
our small staff.
Please check the Project Gutenberg web pages for current
donation methods and addresses. Donations are accepted in a
number of other ways including checks, online payments and
credit card donations. To donate, please visit:
www.gutenberg.org/donate.
Section 5. General Information About Project
Gutenberg™ electronic works
Professor Michael S. Hart was the originator of the Project
Gutenberg™ concept of a library of electronic works that could
be freely shared with anyone. For forty years, he produced and
distributed Project Gutenberg™ eBooks with only a loose
network of volunteer support.
Project Gutenberg™ eBooks are often created from several
printed editions, all of which are confirmed as not protected by
copyright in the U.S. unless a copyright notice is included. Thus,
we do not necessarily keep eBooks in compliance with any
particular paper edition.
Most people start at our website which has the main PG search
facility: www.gutenberg.org.
This website includes information about Project Gutenberg™,
including how to make donations to the Project Gutenberg
Literary Archive Foundation, how to help produce our new
eBooks, and how to subscribe to our email newsletter to hear
about new eBooks.
Welcome to our website – the ideal destination for book lovers and
knowledge seekers. With a mission to inspire endlessly, we offer a
vast collection of books, ranging from classic literary works to
specialized publications, self-development books, and children's
literature. Each book is a new journey of discovery, expanding
knowledge and enriching the soul of the reade
Our website is not just a platform for buying books, but a bridge
connecting readers to the timeless values of culture and wisdom. With
an elegant, user-friendly interface and an intelligent search system,
we are committed to providing a quick and convenient shopping
experience. Additionally, our special promotions and home delivery
services ensure that you save time and fully enjoy the joy of reading.
Let us accompany you on the journey of exploring knowledge and
personal growth!
ebookfinal.com

More Related Content

PDF
API Design for C 1st Edition Martin Reddy
PDF
Api Design Patterns Meap V07 Meap V07 Jj Geewax
PDF
Api design
PDF
Keynoteof A P I
PDF
How To Design A Good A P I And Why It Matters G O O G L E
PDF
Software engineering marsic
PPTX
How to define an api
PPTX
OOP -interface and objects.pptx
API Design for C 1st Edition Martin Reddy
Api Design Patterns Meap V07 Meap V07 Jj Geewax
Api design
Keynoteof A P I
How To Design A Good A P I And Why It Matters G O O G L E
Software engineering marsic
How to define an api
OOP -interface and objects.pptx

Similar to API Design for C 1st Edition Martin Reddy (20)

ODP
Designing Good API & Its Importance
PDF
ApiDesign
PDF
API design
PDF
How to Design a Good API and Why it Matters.pdf
PDF
How to design good api
PDF
Software Essentials Design and Construction 1st Edition Adair Dingle
PDF
software engineering
PPTX
Chapter 1 Introduction.pptx
PDF
Kelis king - introduction to s.e.
PPTX
Building Maintainable PHP Applications.pptx
PDF
Modern C For Software Developers Serious C Development 13 Karen Singh Garewal
PDF
Modern C For Software Developers Serious C Development 13 Karen Singh Garewal
PPT
Software Engineering chapter 1-about user and client communication
PPT
Slides chapter 1
PDF
Designing Web Apis Building Apis That Developers Love Jin Brendasahni
DOC
SE-TEXT-BOOK_Material.doc
DOC
SE-TEXT-BOOK_Material.doc
PPTX
SE-L1-Introduction-NJ.pptx
PDF
Module_1-NOTES.pdfModule_1-NOTES.pdfModule_1-NOTES.pdf
PPTX
BSC Software & Software engineering-UNIT-IV
Designing Good API & Its Importance
ApiDesign
API design
How to Design a Good API and Why it Matters.pdf
How to design good api
Software Essentials Design and Construction 1st Edition Adair Dingle
software engineering
Chapter 1 Introduction.pptx
Kelis king - introduction to s.e.
Building Maintainable PHP Applications.pptx
Modern C For Software Developers Serious C Development 13 Karen Singh Garewal
Modern C For Software Developers Serious C Development 13 Karen Singh Garewal
Software Engineering chapter 1-about user and client communication
Slides chapter 1
Designing Web Apis Building Apis That Developers Love Jin Brendasahni
SE-TEXT-BOOK_Material.doc
SE-TEXT-BOOK_Material.doc
SE-L1-Introduction-NJ.pptx
Module_1-NOTES.pdfModule_1-NOTES.pdfModule_1-NOTES.pdf
BSC Software & Software engineering-UNIT-IV
Ad

Recently uploaded (20)

PDF
Sports Quiz easy sports quiz sports quiz
PPTX
human mycosis Human fungal infections are called human mycosis..pptx
PDF
The Lost Whites of Pakistan by Jahanzaib Mughal.pdf
PDF
RMMM.pdf make it easy to upload and study
PPTX
GDM (1) (1).pptx small presentation for students
PPTX
BOWEL ELIMINATION FACTORS AFFECTING AND TYPES
PDF
Basic Mud Logging Guide for educational purpose
PDF
STATICS OF THE RIGID BODIES Hibbelers.pdf
PDF
Saundersa Comprehensive Review for the NCLEX-RN Examination.pdf
PPTX
Lesson notes of climatology university.
PDF
2.FourierTransform-ShortQuestionswithAnswers.pdf
PDF
102 student loan defaulters named and shamed – Is someone you know on the list?
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
TR - Agricultural Crops Production NC III.pdf
PPTX
master seminar digital applications in india
PPTX
IMMUNITY IMMUNITY refers to protection against infection, and the immune syst...
PPTX
Introduction_to_Human_Anatomy_and_Physiology_for_B.Pharm.pptx
PPTX
Pharmacology of Heart Failure /Pharmacotherapy of CHF
PDF
01-Introduction-to-Information-Management.pdf
PDF
VCE English Exam - Section C Student Revision Booklet
Sports Quiz easy sports quiz sports quiz
human mycosis Human fungal infections are called human mycosis..pptx
The Lost Whites of Pakistan by Jahanzaib Mughal.pdf
RMMM.pdf make it easy to upload and study
GDM (1) (1).pptx small presentation for students
BOWEL ELIMINATION FACTORS AFFECTING AND TYPES
Basic Mud Logging Guide for educational purpose
STATICS OF THE RIGID BODIES Hibbelers.pdf
Saundersa Comprehensive Review for the NCLEX-RN Examination.pdf
Lesson notes of climatology university.
2.FourierTransform-ShortQuestionswithAnswers.pdf
102 student loan defaulters named and shamed – Is someone you know on the list?
BÀI TẬP BỔ TRỢ 4 KỸ NĂNG TIẾNG ANH 9 GLOBAL SUCCESS - CẢ NĂM - BÁM SÁT FORM Đ...
TR - Agricultural Crops Production NC III.pdf
master seminar digital applications in india
IMMUNITY IMMUNITY refers to protection against infection, and the immune syst...
Introduction_to_Human_Anatomy_and_Physiology_for_B.Pharm.pptx
Pharmacology of Heart Failure /Pharmacotherapy of CHF
01-Introduction-to-Information-Management.pdf
VCE English Exam - Section C Student Revision Booklet
Ad

API Design for C 1st Edition Martin Reddy

  • 1. Visit https://ebookfinal.com to download the full version and explore more ebooks API Design for C 1st Edition Martin Reddy _____ Click the link below to download _____ https://ebookfinal.com/download/api-design-for-c-1st- edition-martin-reddy/ Explore and download more ebooks at ebookfinal.com
  • 2. Here are some suggested products you might be interested in. Click the link to download RESTful Web API Design with Node js Second Edition Bojinov https://ebookfinal.com/download/restful-web-api-design-with-node-js- second-edition-bojinov/ Pipelined Processor Farms Structured Design for Embedded Parallel Systems 1st Edition Martin Fleury https://ebookfinal.com/download/pipelined-processor-farms-structured- design-for-embedded-parallel-systems-1st-edition-martin-fleury/ Understanding and Applying Research Design 1st Edition Martin Lee Abbott https://ebookfinal.com/download/understanding-and-applying-research- design-1st-edition-martin-lee-abbott/ Statistics and Experimental Design for Toxicologists and Pharmacologists Fourth Edition Shayne C. Gad https://ebookfinal.com/download/statistics-and-experimental-design- for-toxicologists-and-pharmacologists-fourth-edition-shayne-c-gad/
  • 3. Design of Aircraft 1st Edition Thomas C. Corke https://ebookfinal.com/download/design-of-aircraft-1st-edition-thomas- c-corke/ An Introduction to Continuum Mechanics 2ed. Edition Reddy J.N. https://ebookfinal.com/download/an-introduction-to-continuum- mechanics-2ed-edition-reddy-j-n/ Machine Design 2010th Edition U. C. Jindal https://ebookfinal.com/download/machine-design-2010th-edition-u-c- jindal/ Design Theory 2nd Edition Charles C. Lindner https://ebookfinal.com/download/design-theory-2nd-edition-charles-c- lindner/ C 3 0 Design Patterns 1st Edition Judith Bishop https://ebookfinal.com/download/c-3-0-design-patterns-1st-edition- judith-bishop/
  • 5. API Design for C 1st Edition Martin Reddy Digital Instant Download Author(s): Martin Reddy ISBN(s): 9780123850034, 0123850037 Edition: 1 File Details: PDF, 17.71 MB Year: 2011 Language: english
  • 7. Acquiring Editor: Todd Green Editorial Assistant: Robyn Day Project Manager: André Cuello Designer: Eric DeCicco Morgan Kaufmann is an imprint of Elsevier 30 Corporate Drive, Suite 400, Burlington, MA 01803, USA # 2011 Elsevier, Inc. All rights reserved. No part of this publication may be reproduced or transmitted in any form or by any means, electronic or mechanical, including photocopying, recording, or any information storage and retrieval system, without permission in writing from the publisher. Details on how to seek permission, further information about the Publisher’s permissions policies and our arrangements with organizations such as the Copyright Clearance Center and the Copyright Licensing Agency, can be found at our website: www.elsevier.com/permissions. This book and the individual contributions contained in it are protected under copyright by the Publisher (other than as may be noted herein). Notices Knowledge and best practice in this field are constantly changing. As new research and experience broaden our understanding, changes in research methods or professional practices may become necessary. Practitioners and researchers must always rely on their own experience and knowledge in evaluating and using any information or methods described herein. In using such information or methods they should be mindful of their own safety and the safety of others, including parties for whom they have a professional responsibility. To the fullest extent of the law, neither the Publisher nor the authors, contributors, or editors, assume any liability for any injury and/or damage to persons or property as a matter of products liability, negligence or otherwise, or from any use or operation of any methods, products, instructions, or ideas contained in the material herein. Library of Congress Cataloging-in-Publication Data Application submitted British Library Cataloguing-in-Publication Data A catalogue record for this book is available from the British Library. ISBN: 978 0 12 385003 4 Printed in the United States of America 11 12 13 14 10 9 8 7 6 5 4 3 2 1 For information on all MK publications visit our website at www.mkp.com
  • 8. Foreword I should begin by confessing that I do not consider myself a world-class API designer or software engineer. I do, however, consider myself an expert researcher in the areas of computer graphics and geometric modeling. It was in this line of work that I first met Martin at Pixar Animation Studios. As a graphics researcher I was accustomed to writing mathematically sophisticated papers. I was also formally trained as a computer scientist at a major university and had written my share of code. Armed with this background, when I was presented with the opportunity to lead a group of software engineers working on a new generation of animation software for Pixar, I figured that it couldn’t be any more difficult than research. After all, research is, by definition, the creation of the unknown, whereas engineering is the implementation of well-understood subjects. I could not have been more wrong. I came to realize that software engineering was, without a doubt, the most difficult challenge I had ever been presented with. After more years than I care to admit, I eventually gave up and went back to graphics research. I can’t tell you how much I would have benefitted from a book such as “API Design for C++.” Many of the lessons we learned the hard way have been captured by Martin in this insightful, easy-to-use book. Martin approaches the subject not from the perspective of an academic software researcher (although he draws heavily from results and insights gained there), but from the perspec- tive of an in-the-trenches software engineer and manager. He has experienced firsthand the importance of good software design and has emerged as an articulate voice of what “good” means. In this book he presents effective strategies for achieving that goal. I particularly like that Martin is not focusing just on API design, but more broadly on software life cycles, allowing him to cover topics such as versioning, strategies for backward compatibility, and branching methodologies. In short, this book should be of great value to those creating or managing software activities. It is a comprehensive collection of best practices that have proven themselves time and time again. Tony DeRose Senior Scientist and Research Group Lead, Pixar Animation Studios xv
  • 9. Preface Writing large applications in C++ is a complex and tricky business. However, designing reusable C++ interfaces that are robust, stable, easy to use, and durable is even more difficult. The best way to suc- ceed in this endeavor is to adhere to the tenets of good Application Programming Interface (API) design. An API presents a logical interface to a software component and hides the internal details required to implement that component. It offers a high-level abstraction for a module and promotes code reuse by allowing multiple applications to share the same functionality. Modern software development has become highly dependent on APIs, from low-level application frameworks to data format APIs and graphical user interface (GUI) frameworks. In fact, common software engineering terms such as modular development, code reuse, componentization, dynamic link library or DLL, software frameworks, distributed computing, and service-oriented architecture all imply the need for strong API design skills. Some popular C and C++ APIs that you may already be aware of include the Standard Template Library (STL), Boost, the Microsoft Windows API (Win32), Microsoft Foundation Classes (MFC), libtiff, libpng, zlib, libxml++, OpenGL, MySQL++, Trolltech’s Qt, wxWidgets, GTK+, KDE, Sky- peKit, POSIX pthreads, Intel’s Threading Building Blocks, the Netscape Plugin API, and the Apache module API. In addition, many of Google’s open-source projects are C++, as is much of the code on the sourceforge.net, bitbucket.org, and freshmeat.net Web sites. APIs such as these are used in all facets of software development, from desktop applications, to mobile computing and embedded systems, to Web development. For example, the Mozilla Firefox Web browser is built on top of more than 80 dynamic libraries, each of which provides the imple- mentation for one or more APIs. Elegant and robust API design is therefore a critical aspect of contemporary software develop- ment. One important way in which this differs from standard application development is the far greater need for change management. As we all know, change is an inevitable factor in software development; new requirements, feature requests, and bug fixes cause software to evolve in ways that were never anticipated when it was first devised. However, changes to an API that is shared by hundreds of end-user applications can cause major upheaval and ultimately may cause clients to abandon an API. The primary goal of good API design is therefore to provide your clients with the functionality they need while also causing minimal impact to their code ideally zero impact when you release a new version. WHY YOU SHOULD READ THIS BOOK If you write C++ code that another engineer relies upon, you’re an API designer and this book has been written for you. Interfaces are the most important code that you write because a problem with your interface is far more costly to fix than a bug in your implementation. For instance, an interface change may require all of the applications based on your code to be updated, whereas an implementation-only change can be integrated transparently and effortlessly into client applications when they adopt the new xvii
  • 10. API version. Put in more economic terms, a poorly designed interface can seriously reduce the long- term survival of your code. Learning how to create high-quality interfaces is therefore an essential engineering skill, and the central focus of this book. As Michi Henning noted, API design is more important today than it was 20 years ago. This is because many more APIs have been designed in recent years. These also provide richer and more complex functionality and are shared by more end-user applications (Henning, 2009). Despite this fact, no other books currently on the market concentrate on the topic of API design for C++. It’s worth noting that this book is not meant to be a general C++ programming guide there are already many good examples of these on the market. I will certainly cover lots of object-oriented design material and present many handy C++ tips and tricks. However, I will focus on techniques for representing clean modular interfaces in C++. By corollary, I will not dive as deeply into the question of how to implement the code behind these interfaces, such as specific algorithm choices or best practices limited to the code within the curly braces of your function bodies. However, this book will cover the full breadth of API development, from initial design through implementation, testing, documentation, release, versioning, maintenance, and deprecation. I will even cover specialized API topics such as creating scripting and plugin APIs. While many of these topics are also relevant to software development in general, the focus here will be on the particular implications for API design. For example, when discussing testing strategies I will concentrate on automated API testing techniques rather than attempting to include end-user application testing techniques such as GUI testing, system testing, or manual testing. In terms of my own credentials to write this book, I have led the development of APIs for research code shared by several collaborating institutions, in-house animation system APIs that have been used to make Academy Award-winning movies, and open-source client/server APIs that have been used by millions of people worldwide. Throughout all of these disparate experiences, I have consistently wit- nessed the need for high-quality API design. This book therefore presents a practical distillation of the techniques and strategies of industrial-strength API design that have been drawn from a range of real- world experiences. WHO IS THE TARGET AUDIENCE While this book is not a beginner’s guide to C++, I have made every effort to make the text easy to read and to explain all terminology and jargon clearly. The book should therefore be valuable to new programmers who have grasped the fundamentals of C++ and want to advance their design skills, as well as senior engineers and software architects who are seeking to gain new expertise to comple- ment their existing talents. There are three specific groups of readers that I have borne in mind while writing this book. 1. Practicing software engineers and architects. Junior and senior developers who are working on a specific API project and need pragmatic advice on how to produce the most elegant and enduring design. 2. Technical managers. Program and product managers who are responsible for producing an API product and who want to gain greater insight into the technical issues and development processes of API design. xviii Preface
  • 11. 3. Students and educators. Computer science and software engineering students who are learning how to program and are seeking a thorough resource on software design that is informed by prac- tical experience on large-scale projects. FOCUSING ON C++ While there are many generic API design methodologies that can be taught skills that apply equally well to any programming language or environment ultimately an API has to be expressed in a par- ticular programming language. It is therefore important to understand the language-specific features that contribute to exemplary API design. This book is therefore focused on the issues of designing APIs for a single language (C++) rather than diluting the content to make it applicable for all languages. While readers who wish to develop APIs for other languages, such as Java or C#, may still gain much general insight from this text, the book is directly targeted at C++ engineers who must write and maintain APIs for other engineers to consume. C++ is still one of the most widely used programming languages for large software projects and tends to be the most popular choice for performance-critical code. As a result, there are many diverse C and C++ APIs available for you to use in your own applications (some of which I listed earlier). I will therefore concentrate on aspects of producing good APIs in C++ and include copious source code examples to illustrate these concepts better. This means that I will deal with C++-specific topics such as templates, encapsulation, inheritance, namespaces, operators, const correctness, memory management, use of STL, the pimpl idiom, and so on. Additionally, this book will be published during an exciting time in the evolution of C++. A new version of the C++ specification is currently working its way through the ISO/IEC standardization process. Most C++ compilers currently aim to conform to the standard that was first published in 1998, known as C++98. A later revision of this standard was published in 2003 to correct several defects. Since that time, the standards committee has been working on a major new version of the specification. This version is referred to informally as C++0x, until such time that the standard is rati- fied and the date of publication is known. By the time you read this book, the new standard will likely have been published. However, at the time of writing, it is still referred to as C++0x. Nonetheless, C++0x has reached an advanced stage of the standardization process, and many of the new features can be predicted with relatively high confidence. In fact, some of the major C++ compilers have already started to implement many of the proposed new features. In terms of API design, several of these new language features can be used to produce more elegant and sturdy inter- faces. As such, I have endeavored to highlight and explain those areas of C++0x throughout the book. This book should therefore remain a relevant resource for several years to come. CONVENTIONS While it is more traditional to employ the term “user” to mean a person who uses a software appli- cation, such as a user of Microsoft Word or Mozilla Firefox, in the context of API design I will apply the term to mean a software developer who is creating an application and is using an API to achieve xix Preface
  • 12. this. In other words, I will generally be talking about API users and not application users. The term “client” will be used synonymously in this regard. Note that the term “client,” in addition to referring to a human user of your API, can also refer impersonally to other pieces of software that must call functions in your API. While there are many file format extensions used to identify C++ source and header files, such as .cpp, .cc, .cxx, .h, .hh, and .hpp, I will standardize on the use of .cpp and .h throughout this book. “I will also use the terms module and component” interchangeably to mean a single .cpp and .h file pair. These are notably not equivalent to a class because a component or module may contain multi- ple classes. I will use the term library to refer to a physical collection, or package, of components, that is, library > module/component > class. The term method, while generally understood in the object-oriented programming community, is not strictly a C++ term; it originally evolved from the Smalltalk language. The equivalent C++ term is member function, although some engineers prefer the more specific definition of virtual member function. Because I am not particularly concerned with the subtleties of these terms in this book, I will use method and member function interchangeably. Similarly, although the term data member is the more correct C++ expression, I will treat the term member variable as a synonym. In terms of typographical conventions, I will use a fixed-width font to typeset all source code examples, as well as any filenames or language keywords that may appear in the text. Also, I will prefer upper camel case for all class and function names in the examples that I present, that is, CamelCase instead of camelCase or snake case, although obviously I will preserve the case for any external code that I reference, such as std::for each(). I follow the convention of using an “m” prefix in front of data members, for example, mMemberVar, and “s” in front of static variables, for example, sStaticVar. It should be pointed out that the source examples within the book are often only code snippets and are not meant to show fully functional samples. I will also often strip comments from the exam- ple code in the book. This is done for reasons of brevity and clarity. In particular, I will often omit any preprocessor guard statements around a header file. I will assume that the reader is aware that every C/C++ header should enclose all of its content within guard statements and that it’s good prac- tice to contain all of your API declarations within a consistent namespace (as covered in Chapters 3 and 6). In other words, it should be assumed that each header file that I present is implicitly sur- rounded by code, such as the following. #ifndef MY MODULE H #define MY MODULE H // required #include files. . . namespace apibook { // API declarations . . . } #endif xx Preface
  • 13. TIP I will also highlight various API design tips and key concepts throughout the book. These callouts are provided to let you search quickly for a concept you wish to reread. If you are particularly pressed for time, you could simply scan the book for these tips and then read the surrounding text to gain greater insight for those topics that interest you the most. BOOK WEB SITE This book also has a supporting Web site, http://APIBook.com/. On this site you can find general information about the book, as well as supporting material, such as the complete set of source code examples contained within the text. Feel free to download and play with these samples yourself they were designed to be as simple as possible, while still being useful and illustrative. I have used the cross-platform CMake build system to facilitate compiling and linking the examples so they should work on Windows, Mac OS X, and UNIX operating systems. I will also publish any information about new revisions of this book and any errata on this Web site, as well as useful links to other related API resources on the Internet, such as interesting toolkits, articles, and utilities. The book Web site also provides access to a utility that I wrote called API Diff. This program lets you compare two versions of an API and review differences to code or comments in a visual side-by-side format. You can also generate a report of everything that changed in a particular release so that your clients know exactly what to look out for. This utility is available for Windows, Mac OS X, and Linux. xxi Preface
  • 14. Acknowledgments This book has benefited greatly from the technical review and feedback of several of my esteemed colleagues. I am indebted to them for taking the time to read early versions of the manuscript and provide thoughtful suggestions for improvement. In particular, I thank Paul Strauss, Eric Gregory, Rycharde Hawkes, Nick Long, James Chalfant, Brett Levin, Marcus Marr, Jim Humelsine, and Geoff Levner. My passion for good API design has been forged through my relationship with many great soft- ware engineers and managers. As a result of working at several different companies and institutions, I’ve been exposed to a range of design perspectives, software development philosophies, and problem-solving approaches. Throughout these varied experiences, I’ve had the privilege to meet and learn from some uniquely talented individuals. Some of these giants whose shoulders I have stood upon include: • SRI International: Bob Bolles, Adam Cheyer, Elizabeth Churchill, David Colleen, Brian Davis, Michael Eriksen, Jay Feuquay, Marty A. Fischler, Aaron Heller, Lee Iverson, Jason Jenkins, Luc Julia, Yvan G. Leclerc, Pat Lincoln, Chris Marrin, Ray C. Perrault, and Brian Tierney. • Pixar Animation Studios: Brad Andalman, David Baraff, Ian Buono, Gordon Cameron, Ed Catmull, Chris Colby, Bena Currin, Gareth Davis, Tony DeRose, Mike Ferris, Kurt Fleischer, Sebastian Grassia, Eric Gregory, Tara Hernandez, Paul Isaacs, Oren Jacob, Michael Kass, Chris King, Brett Levin, Tim Milliron, Alex Mohr, Cory Omand, Eben Osbty, Allan Poore, Chris Shoeneman, Patrick Schork, Paul Strauss, Kiril Vidimče, Adam Woodbury, David Yu, Dirk van Gelder, Brad West, and Andy Witkin. • The Bakery Animation Studio: Sam Assadian, Sebastien Guichou, Arnauld Lamorlette, Thierry Lauthelier, Benoit Lepage, Geoff Levner, Nick Long, Erwan Maigret, and Bariş Metin. • Linden Lab: Nat Goodspeed, Andrew de Laix, Howard Look, Brad Kittenbrink, Brian McGroarty, Adam Moss, Mark Palange, Jim Purbrick, and Kent Quirk. In particular, I acknowledge the great impact that Yvan G. Leclerc made on my life during my early years at SRI International. Yvan was my first manager and also a true friend. He taught me how to be a good manager of people, how to be a rigorous scientist and engineer, and, at the same time, how to enjoy life to its fullest. It is a great sorrow that incredible individuals such as Yvan are taken from us too soon. Many thanks must also go to Morgan Kaufmann Publishers for all of their work reviewing, copy editing, typesetting, and publishing this book. This work would quite literally not exist without their backing and energy. In particular, I acknowledge the contribution of Todd Green, Robyn Day, André Cuello, and Melissa Revell. Most importantly, I thank my wife, Genevieve M. Vidanes, for encouraging me to write this book and for putting up with me while I spent many late nights hunched over the keyboard. As this is my second book, she knew full well how much it would impact our personal life. Nonetheless, she sup- ported me throughout the whole process, while also knowing exactly when to make me pause and take a break. Thank you Genevieve for your constant love and support. xxiii
  • 15. Author Biography Dr. Martin Reddy is CEO of Code Reddy Inc. He holds a Ph.D. in computer science and has over 15 years of experience in the software industry. During this time, Dr. Reddy has produced more than 40 professional publications, three software patents, and coauthored the book Level of Detail for 3D Graphics. He is a member of the Association of Computing Machinery (ACM) and the Institute of Electrical and Electronic Engineers (IEEE). Dr. Reddy worked for 6 years at Pixar Animation Studios, where he was lead engineer for the studio’s in-house animation system. This work involved the design and implementation of various high-performance APIs to support Academy Award-winning and nominated films, such as Finding Nemo, The Incredibles, Cars, Ratatouille, and Wall-E. He then took on the role of engineering manager at The Bakery Animation Studio, where he led the development of the startup studio’s animation software. This included the design and implemen- tation of many key APIs as well as devising the overall animator workflow and user interface. Earlier in his career, Dr. Reddy worked for 5 years at SRI International on distributed 3D terrain visualization technologies, which involved the development of several open source geospatial APIs. He cofounded a successful effort to create an ISO standard to represent 3D geospatial models on the Web and was elected as a director of the Web3D Consortium for 2 consecutive years. Through his consulting company, Dr. Reddy has provided his technical expertise to various soft- ware companies, including Linden Lab and Planet 9 Studios. The former involved API design and infrastructure improvements for the open source product Second Life, an online 3D virtual world that has been used by over 16 million people around the world. xxv
  • 16. CHAPTER Introduction 1 1.1 WHAT ARE APPLICATION PROGRAMMING INTERFACES? An Application Programming Interface (API) provides an abstraction for a problem and specifies how clients should interact with software components that implement a solution to that problem. The components themselves are typically distributed as a software library, allowing them to be used in multiple applications. In essence, APIs define reusable building blocks that allow modular pieces of functionality to be incorporated into end-user applications. An API can be written for yourself, for other engineers in your organization, or for the develop- ment community at large. It can be as small as a single function or involve hundreds of classes, methods, free functions, data types, enumerations, and constants. Its implementation can be proprie- tary or open source. The important underlying concept is that an API is a well-defined interface that provides a specific service to other pieces of software. A modern application is typically built on top of many APIs, where some of these can also depend on further APIs. This is illustrated in Figure 1.1, which shows an example application that depends directly on the API for three libraries (1 3), where two of those APIs depend on the API for a further two libraries (4 and 5). For instance, an image viewing application may use an API for loading GIF images, and that API may itself be built upon a lower-level API for compressing and decompressing data. API development is ubiquitous in modern software development. Its purpose is to provide a logi- cal interface to the functionality of a component while also hiding any implementation details. For example, our API for loading GIF images may simply provide a LoadImage() method that accepts a filename and returns a 2D array of pixels. All of the file format and data compression details are hidden behind this simple interface. This concept is also illustrated in Figure 1.1, where client code only accesses an API via its public interface, shown as the dark section at the top of each box. 1.1.1 Contracts and Contractors As an analogy, consider the task of building your own home. If you were to build a house entirely on your own, you would need to possess a thorough understanding of architecture, plumbing, electron- ics, carpentry, masonry, and many other trades. You would also need to perform every task yourself and keep track of the minutest of details for every aspect of the project, such as whether you have enough wood for your floorboards or whether you have the right fasteners to fit the screws that you have. Finally, because you are the only person working on the project, you can only perform a single task at any point in time and hence the total time to complete the project could be very large. API design for C++. © 2011 Elsevier Inc. All rights reserved. 1
  • 19. As an example of a well-known API, Microsoft’s Windows API (often referred to as the Win32 API) is a collection of C functions, data types, and constants that enable programmers to write appli- cations that run on the Windows platform. This includes functions for file handling, process and thread management, creating graphical user interfaces, talking to networks, and so on. The Win32 API is an example of plain C API rather than a C++ API. While you can use a C API directly from a C++ program, a good example of a specific C++ API is the Standard Template Library (STL). The STL contains a set of container classes, iterators for navigating over the elements in those containers, and various algorithms that act on those containers (Josuttis, 1999). For instance, the collection of algorithms includes high-level operations such as std::search(), std::reverse(), std::sort(), and std::set intersection(). The STL therefore presents a logical interface to the task of manipulating collections of elements, without exposing any of the internal details for how each algorithm is implemented. TIP An API is a logical interface to a software component that hides the internal details required to implement it. 1.2 WHAT’S DIFFERENT ABOUT API DESIGN? Interfaces are the most important code that a developer writes. That’s because problems in an inter- face are far more costly to fix than problems in the associated implementation code. As a result, the process of developing shared APIs demands more attention than standard application or Graphical User Interface (GUI) development. Of course, both should involve best design practices; however, in the case of API development, these are absolutely critical to its success. Specifically, some of the key differentiating factors of API development include the following. • An API is an interface designed for developers, in much the same way that a GUI is an inter- face designed for end users. In fact, it’s been said that an API is a user interface for program- mers (Arnold, 2005). As such, your API could be used by thousands of developers around the world, and it will undoubtedly be used in ways that you never intended (Tulach, 2008). You must anticipate this in your design. A well-designed API can be your organization’s biggest asset. Conversely, a poor API can create a support nightmare and even turn your users toward your competitors (Bloch, 2005), just as a buggy or difficult-to-use GUI may force an end user to switch to a different application. • Multiple applications can share the same API. Figure 1.1 showed that a single application can be composed of multiple APIs. However, any one of those APIs could also be reused in sev- eral other applications. This means that while problems in the code for any given application will only affect that one application, errors in an API can affect all of the applications that depend on that functionality. • You must strive for backward compatibility whenever you change an API. If you make an incompatible change to your interface, your clients’ code may fail to compile, or worse their code could compile but behave differently or crash intermittently. Imagine the confusion and chaos that would arise if the signature of the printf() function in the standard C library was 4 CHAPTER 1 Introduction
  • 20. different for different compilers or platforms. The simple “Hello World” program may not look so simple any more: #include <stdio.h> #ifdef WIN32 #include <windows.h> #endif #ifdef cplusplus #include <iostream> #endif int main(int, char *argv[]) { #if STRICT ANSI printf("Hello Worldn"); #elif defined( WIN32) PrintWithFormat("Hello Worldn"); #elif defined( PRINTF DEPRECATED ) fprintf(stdout, "Hello Worldn"); #elif defined( PRINTF VECTOR ) const char *lines[2] {"Hello World", NULL}; printf(lines); #elif defined( cplusplus) std::cout << "Hello World" << std::endl; #else #error No terminal output API found #endif return 0; } This may seem like a contrived example, but it’s actually not that extreme. Take a look at the stan- dard header files that come with your compiler and you will find declarations that are just as convo- luted and inscrutable, or perhaps worse. • Due to the backward compatibility requirement, it is critical to have a change control process in place. During the normal development process, many developers may fix bugs or add new features to an API. Some of these developers may be junior engineers who do not fully under- stand all of the aspects of good API design. As a result, it is important to hold an API review before releasing a new version of the API. This involves one or more senior engineers check- ing that all changes to the interface are acceptable, have been made for a valid reason, and are implemented in the best way to maintain backward compatibility. Many open source APIs also enforce a change request process to gain approval for a change before it is added to the source code. • APIs tend to live for a long time. There can be a large upfront cost to produce a good API because of the extra overhead of planning, design, versioning, and review that is necessary. However, if done well, the long-term cost can be substantially mitigated because you have the ability to make radical changes and improvements to your software without disrupting your clients. That is, your development velocity can be greater due to the increased flexibility that the API affords you. 5 1.2 What’s different about API design?
  • 22. • Increases longevity. Over time, systems that expose their implementation details tend to devolve into spaghetti code where every part of the system depends on the internal details of other parts of the system. As a result, the system becomes fragile, rigid, immobile, and vis- cous (Martin, 2000). This often results in organizations having to spend significant effort to evolve the code toward a better design or simply rewrite it from scratch. By investing in good API design up front and paying the incremental cost to maintain a coherent design, your soft- ware can survive for longer and cost less to maintain in the long run. I’ll delve much deeper into this point at the start of Chapter 4. • Promotes modularization. An API is normally devised to address a specific task or use case. As such, APIs tend to define a modular grouping of functionality with a coherent focus. Developing an application on top of a collection of APIs promotes loosely coupled and mod- ular architectures where the behavior of one module is not dependent on the internal details of another module. • Reduces code duplication. Code duplication is one of the cardinal sins of software engineer- ing and should be stamped out whenever possible. By keeping all of your code’s logic behind a strict interface that all clients must use, you centralize the behavior in a single place. Doing so means that you have to update only one place to change the behavior of your API for all of your clients. This can help remove duplication of implementation code throughout your code base. In fact, many APIs are created after discovering duplicated code and deciding to consol- idate it behind a single interface. This is a good thing. • Removes hardcoded assumptions. Many programs may contain hardcoded values that are copied throughout the code, for example, using the filename myprogram.log whenever data are written to a log file. Instead, APIs can be used to provide access to this information with- out replicating these constant values across the code base. For example, a GetLogFilename() API call could be used to replace the hardcoded "myprogram.log" string. • Easier to change the implementation. If you have hidden all of the implementation details of your module behind its public interface then you can change those implementation details without affecting any code that depends on the API. For example, you might decide to change a file parsing routine to use std::string containers instead of allocating, freeing, and reallo- cating your own char * buffers. • Easier to optimize. Similarly, with your implementation details hidden successfully, you can optimize the performance of your API without requiring any changes to your clients’ code. For example, you could add a caching solution to a method that performs some computation- ally intensive calculation. This is possible because all attempts to read and write your under- lying data are performed via your API, so it becomes much easier to know when you must invalidate your cached result and recompute the new value. 1.3.2 Code Reuse Code reuse is the use of existing software to build new software. It is one of the holy grails of mod- ern software development. APIs provide a mechanism to enable code reuse. In the early years of software development, it was common for a company to have to write all of the code for any application they produced. If the program needed to read GIF images or parse a text file, the company would have to write all that code in-house. Nowadays, with the proliferation of 7 1.3 Why should you use APIs?
  • 24. 1.3.3 Parallel Development Even if you are writing in-house software, your fellow engineers will very likely need to write code that uses your code. If you use good API design techniques, you can simplify their lives and, by extension, your own (because you won’t have to answer as many questions about how your code works or how to use it). This becomes even more important if multiple developers are working in parallel on code that depends upon each other. For example, let’s say that you are working on a string encryption algorithm that another devel- oper wants to use to write data out to a configuration file. One approach would be to have the other developer wait until you are finished with your work and then he can use it in his file writer module. However, a far more efficient use of time would be for the two of you to meet early on and agree upon an appropriate API. Then you can put that API in place with placeholder functionality that your colleague can start calling immediately, such as #include <string.h> class StringEncryptor { public: /// set the key to use for the Encrypt() and Decrypt() calls void SetKey(const std::string &key); /// encrypt an input string based upon the current key std::string Encrypt(const std::string &str) const; /// decrypt a string using the current key calling /// Decrypt() on a string returned by Encrypt() will /// return the original string for the same key. std::string Decrypt(const std::string &str) const; }; You can then provide a simple implementation of these functions so that at least the module will compile and link. For example, the associated .cpp file might look like void StringEncryptor::SetKey(const std::string &key) { } std::string StringEncryptor::Encrypt(const std::string &str) { return str; } std::string StringEncryptor::Decrypt(const std::string &str) { return str; } In this way, your colleague can use this API and proceed with his work without being held up by your progress. For the time being, your API will not actually encrypt any strings, but that’s just 9 1.3 Why should you use APIs?
  • 25. a minor implementation detail! The important point is that you have a stable interface a contract that you both agree upon, and that it behaves appropriately, for example, Decrypt(Encrypt ("Hello")) "Hello". When you finish your work and update the .cpp file with the correct implementation, your colleague’s code will simply work without any further changes required on his part. In reality, it’s likely that there will be interface issues that you didn’t anticipate before you started writing the code and you will probably have to iterate on the API a few times to get it just right. However, for the most part, the two of you can work in parallel with minimal holdups. This approach also encourages test-driven, or test-first, development. By stubbing out the API early on, you can write unit tests to validate the desired functionality and run these continuously to make sure that you haven’t broken your contract with your colleague. Scaling this process up to an organizational level, your project could have separate teams that may be remote from each other, even working to different schedules. By defining each team’s depen- dencies up front and creating APIs to model these, each team can work independently and with min- imal knowledge of how the other teams are implementing their work behind the API. This efficient use of resources, and the corresponding reduction in redundant communication, can correlate to a significant overall cost saving for an organization. 1.4 WHEN SHOULD YOU AVOID APIS? Designing and implementing an API usually requires more work than writing normal applica- tion code. That’s because the purpose of an API is to provide a robust and stable interface for other developers to use. As such, the level of quality, planning, documentation, testing, support, and maintenance is far higher for an API than for software that is to be used within a single application. As a result, if you are writing an internal module that does not require other clients to com- municate with it, then the extra overhead of creating and supporting a stable public interface for your module may not be worth the effort, although this is not a reason to write sloppy code. Spend- ing the extra time to adhere to the principles of API design will not be wasted effort in the long run. On the flip side of the coin, consider that you are a software developer who wants to use a third- party API in your application. The previous section discussed a number of reasons why you might want to reuse external APIs in your software. However, there may be cases where you wish to avoid using a particular API and pay the cost to implement the code yourself or look for an alternate solution. For example: • License restrictions. An API may provide everything that you need functionality-wise, but the license restrictions may be prohibitive for your needs. For example, if you want to use an open source package that is distributed under the GNU General Public License (GPL), then you are required to release any derived works under the GPL also. This means that using this package in your program would require you to release the entire source code for your appli- cation, a constraint that may not be acceptable for a commercial application. Other licenses, such as the GNU Lesser General Public License (LGPL), are more permissive and tend to be more common for software libraries. Another licensing aspect is that the dollar cost for a commercial API may be too high for your project or the licensing terms may be too restrictive, such as requiring a license fee per developer or even per user. 10 CHAPTER 1 Introduction
  • 26. • Functionality mismatch. An API may appear to solve a problem that you have, but may do it in a way that doesn’t match the constraints or functional requirements of your application. For example, perhaps you’re developing an image processing tool and you want to provide a Fourier transform capability. There are many implementations of the Fast Fourier Transform (FFT) available, but a large number of these are 1D algorithms, whereas you require a 2D FFT because you are dealing with 2D image data. Additionally, many 2D FFT algorithms only work on data sets with dimensions that are a power of 2 (e.g., 256 256 or 512 512 pixels). Furthermore, perhaps the API that you found doesn’t work on the platforms that you must support or perhaps it doesn’t match the performance criteria that you have specified for your application. • Lack of source code. While there are many open source APIs, sometimes the best API for your case may be a closed source offering. That is, only the header files for the interface are made available to you, but the underlying C++ source files are not distributed with the library. This has several important implications. Among these is the fact that if you encounter a bug in the library, you are unable to inspect the source code to understand what might be going wrong. Reading the source can be a valuable technique for tracking down a bug and potentially discovering a workaround for the issue. Furthermore, without access to the source code for an API, you lose the ability to change the source in order to fix a bug. This means that the schedule for your software project could be affected adversely by unanticipated problems in a third-party API you’re using and by time spent waiting for the owners of that API to address your bug reports and distribute a fixed patch. • Lack of documentation. An API may appear to fulfill a need that you have in your applica- tion, but if the API has poor or non-existent documentation then you may decide to look else- where for a solution. Perhaps it is not obvious how to use the API, perhaps you cannot be sure how the API will behave under certain situations, or perhaps you simply don’t trust the work of an engineer who hasn’t taken the time to explain how his code should be used. 1.5 API EXAMPLES APIs are everywhere. Even if you have only been programming for a short amount of time, chances are that you have written code to use an API or two and maybe you’ve also written one yourself. 1.5.1 Layers of APIs An API can be any size, from a single function to a large collection of classes. It can also provide access to functionality at any architectural level, from low-level operating system calls all the way up to GUI toolkits. The following list presents various common APIs, many of which you’ve probably heard of already, to give you an appreciation for how prevalent API development is. • Operating System (OS) APIs. Every OS must provide a set of standard APIs to allow pro- grams to access OS-level services. For example, the POSIX API defines functions such as fork(), getpid(), and kill() for managing UNIX-style processes. Microsoft’s Win32 API 11 1.5 API examples
  • 27. includes functions such as CreateProcess(), GetCurrentProcess(), and TerminateProcess () for managing Windows processes. These are stable low-level APIs that should never change, otherwise many programs could break! • Language APIs. The C language provides a standard API, implemented as the libc library and supporting man pages, which includes familiar functions such as printf(), scanf(), and fopen(). The C++ language also offers the Standard Template Library (STL), which pro- vides an API for various container classes (e.g., std::string, std::vector, std::set, and std::map), iterators (e.g., std::vectordouble::iterator), and generic algorithms (e.g., std::sort, std::for each, and std::set union). For example, the following code snippet uses the STL API to iterate through all elements in a vector and print them out: #include vector #include iostream void PrintVector(const std::vectorfloat vec) { std::vectorfloat::const iterator it; for (it vec.begin(); it ! vec.end(); þþit) { std::cout *it std::endl; } } • Image APIs. Gone are the days when developers needed to write their own image reading and writing routines. There is now a wide range of open source packages out there for you to download and use in your own programs. For example, there’s the popular libjpeg library that provides an implementation of a JPEG/JFIF decoder and encoder. There’s the extensive libtiff library for reading and writing various flavors of TIFF files. And there’s the libpng library for handling PNG format images. All of these libraries define APIs that let you write code to read and write the image formats without having to know anything about the underlying file formats themselves. For example, the follow code snippet uses the libtiff API to find the dimensions of a TIFF image. TIFF *tif TIFFOpen(image.tiff, r); if (tif) { uint32 w, h; TIFFGetField(tif, TIFFTAG IMAGEWIDTH, w); TIFFGetField(tif, TIFFTAG IMAGELENGTH, h); printf(Image size %d x %d pixelsn, w, h); TIFFClose(tif); } • Three-Dimensional Graphics APIs. The two classic real-time 3D graphics APIs are OpenGL and DirectX. These let you define 3D objects in terms of small primitives, such as triangles or polygons; specify the surface properties of those primitives, such as color, normal, and texture; and define the environment conditions, such as lights, fog, and clipping panes. Thanks to standard APIs such as these, game developers can write 3D games that will work 12 CHAPTER 1 Introduction
  • 28. on graphics cards old and new, from many different manufacturers. That’s because each gra- phics card manufacturer distributes drivers that provide the implementation details behind the OpenGL or DirectX API. Before the widespread use of these APIs, a developer had to write a 3D application for a specific piece of graphics hardware, and this program would probably not work on another machine with different graphics hardware. These APIs also enable a host of higher-level scene graph APIs, such as OpenSceneGraph, OpenSG, and OGRE. The following code segment shows the classic example of rendering a triangle, with a different color for each vertex, using the OpenGL API: glClear(GL COLOR BUFFER BIT); glBegin(GL TRIANGLES); glColor3f(0.0, 0.0, 1.0); /* blue */ glVertex2i(0, 0); glColor3f(0.0, 1.0, 0.0); /* green */ glVertex2i(200, 200); glColor3f(1.0, 0.0, 0.0); /* red */ glVertex2i(20, 200); glEnd(); glFlush(); • Graphical User Interface APIs. Any application that wants to open its own window needs to use a GUI toolkit. This is an API that provides the ability to create windows, buttons, text fields, dialogs, icons, menus, and so on. The API will normally also provide an event model to allow the capturing of mouse and keyboard events. Some popular C/C++ GUI APIs include the wxWidgets library, Nokia’s Qt API, GTK+, and X/Motif. It used to be the case that if a com- pany wanted to release an application on more than one platform, such as Windows and Mac, they would have to rewrite the user interface code using a different GUI API for each plat- form or they would have to develop their own in-house cross-platform GUI toolkit. However, these days most modern GUI toolkits are available for multiple platforms including Windows, Mac, and Linux which makes it far easier to write cross-platform applications. As a sample of a modern cross-platform GUI API, the following complete program shows a bare minimum Qt program that pops up a window with a Hello World button: #include QApplication #include QPushButton int main(int argc, char *argv[]) { QApplication app(argc, argv); QPushButton hello(Hello world!); hello.resize(100, 30); hello.show(); return app.exec(); } Of course, this list is just a brief cross section of all the possible APIs that are out there. You’ll also find APIs to let you access data over networks, to parse and generate XML files, to help you write multi- threaded programs, or to solve complex mathematical problems. The point of the aforementioned list was simply to demonstrate the breadth and depth of APIs that have been developed to help you build your applications and to give you a flavor for what code based on these APIs looks like. 13 1.5 API examples
  • 29. TIP APIs are used everywhere in modern software development, from OS and language level APIs to image, audio, graphics, concurrency, network, XML, mathematics, Web browsing, or GUI APIs. 1.5.2 A Real-Life Example The aforementioned list of API examples was purposefully arranged by architectural level to show the range of APIs that you might use when building an application. You will often use APIs from several architectural levels when building a large software product. For example, Figure 1.3 presents an example architecture diagram for the Second Life Viewer developed by Linden Lab. This is a large open source program that lets users interact with each other in an online 3D virtual world, with the ability to perform voice chat and text messaging between users. The diagram demonstrates the use and layering of APIs in a large C++ software project. Of particular note is the layer of Internal APIs, by which I mean the set of modules that a com- pany develops in-house for a particular product, or suite of products. While Figure 1.3 simply shows these as a single layer for the purpose of simplicity, the set of Internal APIs will form an additional stack of layers. From foundation-level routines that provide in-house string, dictionary, file IO, threading routines, and so on to APIs that provide the core business logic of the application, all the way up to custom GUI APIs for managing the application’s user interface. Obviously, Figure 1.3 doesn’t provide an exhaustive list of all the APIs used in this application. It simply shows a few examples of each architectural layer. However, Table 1.1 presents the complete set of third-party dependencies for the application to give you an idea of how many open source and commercial closed source dependencies a contemporary software project is built upon. When you factor in system and OS libraries as well, this list grows even further. Second Life Viewer IIComon IIMessage IIAudio IIRender Application Code Internal APIs Third Party APIs Language APIs OS APIs OpenGL APR Standard C Library Standard Template L brary Win32 / Mac OS X / Linux Kernel API Boost Expat OpenSSL FIGURE 1.3 Architecture diagram for the Second Life Viewer. 14 CHAPTER 1 Introduction
  • 31. 1.6 FILE FORMATS AND NETWORK PROTOCOLS There are several other forms of communication “contracts” commonly used in computer applica- tions. One of the most familiar is the file format. This is a way to save in-memory data to a file on disk using a well-known layout of those data. For example, the JPEG File Interchange Format (JFIF) is an image file format for exchanging JPEG-encoded imagery, commonly given the .jpg or .jpeg file extension. The format of a JFIF file header is shown in Table 1.2. Given the format for a data file, such as the JFIF/JPEG format given in Table 1.2, any pro- gram can read and write image files in that format. This allows the easy interchange of image data between different users and the proliferation of image viewers and tools that can operate on those images. Similarly, client/server applications, peer-to-peer applications, and middleware services work by sending data back and forward using an established protocol, usually over a network socket. For example, the Subversion version control system uses a client/server architecture where the master repository is stored on the server and individual clients synchronize their local clients with the server (Rooney, 2005). In order to make this work, the client and the server must agree upon the format of those data transmitted across the network. This is known as the client/server protocol or line protocol. If the client sends a data stream that does not conform to this protocol, then the server will not be able to understand the message. It is therefore critical that the specification of the client/server protocol is well defined and that both the client and the server conform to the specification. Both of these cases are conceptually similar to an API in that they define a standard interface, or specification, for information to be exchanged. Also, any changes to the specification must consider the impact on existing clients. Despite this similarity, file formats and line protocols are not actually APIs because they are not programming interfaces for code that you link into your application. How- ever, a good rule of thumb is that whenever you have a file format or a client/server protocol, you should also have an associated API to manage changes to that specification. Table 1.2 JFIF file format header specification Field Byte size Description APP0 marker 2 Always 0xFFE0 Length 2 Length of segment excluding APP0 marker Identifier 5 Always 0x4A46494600 (“JFIF0”) Version 2 0x0102 Density units 1 Units for pixel density fields, 0 no units X density 2 Integer horizontal pixel density Y density 2 Integer vertical pixel density Thumbnail width (w) 1 Horizontal size of embedded thumbnail Thumbnail height (h) 1 Vertical size of embedded thumbnail Thumbnail data 3 w h Uncompressed 24-bit RGB raster data 16 CHAPTER 1 Introduction
  • 32. TIP Whenever you create a file format or client/server protocol, you should also create an API for it. This allows details of the specification, and any future changes to it, to be centralized and hidden. For example, if you specify a file format for your application’s data, you should also write an API to allow reading and writing files in that format. For one, this is simply good practice so that knowl- edge of the file format is not distributed throughout your application. More importantly, having an API allows you to easily change the file format in the future without having to rewrite any code out- side of the API implementation. Finally, if you do end up with multiple different versions of a file format, then your API can abstract that complexity away so that it can read and write data in any version of the format or it can know if the format is written with a newer version of the API and take appropriate steps. In essence, the actual format of data on the disk becomes a hidden implementation detail that your application does not need to be concerned with. This advice applies just as well to client/server applications, where the definition of a common protocol, and a common API to manage that protocol, can allow the client and server teams to work relatively independently of each other. For instance, you may begin using UDP as the transport layer for part of your system but later decide to switch to TCP (as indeed happened with the Second Life code base). If all network access had already been abstracted behind an appropriate API, then such a major implementation change would have little to no disruptive impact on the rest of the system. 1.7 ABOUT THIS BOOK Now that I have covered the basics of what an API is and the pros and cons of API development, I’ll dive into details such as how to design good APIs, how to implement them efficiently in C++, and how to version them without breaking backward compatibility. The progression of chapters in this book roughly follows the standard evolution of an API, from initial design through implementation, versioning, documentation, and testing. Chapter 2: Qualities I begin the main text with a chapter that answers the following question: what is a good API? This will cover a wide gamut of qualities that you should be aware of when designing your APIs, such as information hiding, minimal completeness, and loose coupling. As I do through- out the book, I illustrate these concepts with many C++ source code examples to show how they relate to your own projects. Chapter 3: Patterns The next couple of chapters tackle the question of how you design a good API. Accordingly, Chapter 3 looks at some specific design patterns and idioms that are particularly helpful in API design. These include the pimpl idiom, Singleton, Factory Method, Proxy, Adapter, Façade, and Observer. Chapter 4: Design Continuing the topic of how to design a good API, Chapter 4 discusses functional requirement gathering and use case modeling to drive the design of a clean and usable interface, as well as 17 1.7 About this book
  • 33. some techniques of object-oriented analysis and object-oriented design. This chapter also includes a discussion on many of the problems that a large software project faces. These observations are taken from real-world experiences and provide insight into the issues that arise when doing large-scale API development. Chapter 5: Styles The next few chapters focus on creating high-quality APIs with C++. This is a deep and com- plex topic and is, of course, the specific focus of this book. I therefore begin by describing various styles of C and C++ APIs that you could adopt in your projects, such as flat C APIs, object-oriented APIs, template-based APIs, and data-driven APIs. Chapter 6: C++ Usage Next I discuss various C++ language features that can impact good API design. This includes numerous important issues such as good constructor and operator style, namespaces, pointer versus reference parameters, the use of friends, and how to export symbols in a dynamic library. Chapter 7: Performance In this chapter I analyze performance issues in APIs and show you how to build high- performing APIs in C++. This involves the use of const references, forward declarations, data member clustering, and inlining. I also present various tools that can help you assess the per- formance of your code. Chapter 8: Versioning With the foundations of API design in hand, I start to expand into more complex aspects, starting with API versioning and how to maintain backward compatibility. This is one of the most important and difficult aspects of robust API design. Here I will define the vari- ous terms backward, forward, functional, source, and binary compatibility and describe how to evolve an API with minimal impact to your clients. Chapter 9: Documentation Next I dedicate a chapter to the topic of API documentation. Because an API is ill-defined without proper supporting documentation, I present good techniques for commenting and doc- umenting your API, with specific examples using the excellent Doxygen tool. Chapter 10: Testing The use of extensive testing lets you evolve an API with the confidence that you are not breaking your clients’ programs. Here I present various types of automated testing, including unit, integration, and performance tests, and present examples of good testing methodologies for you to use in your own projects. This covers topics such as test-driven development, stub and mock objects, testing private code, and contract programming. Chapter 11: Scripting I follow this with a couple of more specialized topics, beginning with API scripting. This is an optional subject that is not applicable to all APIs. However, you may decide to provide script- ing access to your API so that power users of your application can write scripts to perform custom actions. I therefore talk about how to create script bindings for a C++ API so that it can be called from languages such as Python and Ruby. Chapter 12: Extensibility Another advanced topic is that of user extensibility: creating an API that allows programmers to write custom C++ plugins that extend the basic functionality you ship with the API. This 18 CHAPTER 1 Introduction
  • 34. can be a critical mechanism to promote adoption of your API and to help it survive for the long term. Additionally, I cover how to create extensible interfaces using inheritance and templates. Appendix A: Libraries The book concludes with an appendix on how to create static and dynamic libraries. You must be able to create libraries in order for your code to be used by others. There are also interface design issues to consider when creating dynamic libraries, such as the set of symbols that you export publicly. I therefore discuss differences between static and shared libraries and demon- strate how you can make your compiler produce these libraries to allow the reuse of your code in other applications. 19 1.7 About this book
  • 35. CHAPTER Qualities 2 This chapter aims to answer the following question: What are the basic qualities of a good API? Most developers would agree that a good API should be elegantly designed but still highly usable. It should be a joy to use but also fade into the background (Henning, 2009). These are fine qualita- tive statements, but what are the specific design aspects that enable these? Obviously every API is different; however, there are certain qualities that promote high-quality API design and should be adhered to whenever possible, as well as many that make for poor designs that should be avoided. There are no absolutes in API design: you cannot apply a fixed set of rules to every situation. However, while there may be individual cases where you decide that it is best for your project to deviate from certain advice in this chapter, you should do so only after reasoned and considered judgment. The guidance here should form the bedrock of your API design decisions. This chapter concentrates on generic, language-neutral qualities of an API, such as information hiding, consistency, and loose coupling. It provides a C++ context for each of these concepts, but overall the advice in this chapter should be useful to you whether you are working on a C++, Java, C#, or Python project. Later chapters deal with C++-specific issues, such as const correctness, name- spaces, and constructor usage. Many of the topics of this chapter also provide a jumping off point into deeper treatments later in the book. For example, while I mention use of the Pimpl idiom as a solution for hiding internal details in C++, I dedicate more space to this important topic in the following chapter on design patterns. 2.1 MODEL THE PROBLEM DOMAIN An API is written to solve a particular problem or perform a specific task. So, first and foremost, the API should provide a coherent solution for that problem and should be formulated in such a way that models the actual domain of the problem. For example, it should provide a good abstraction of the problem area and should model the key objects of that domain. Doing so can make the API easier for your users to use and understand because it will correlate more closely with their preexisting knowledge and experience. 2.1.1 Provide a Good Abstraction An API should provide a logical abstraction for the problem that it solves. That is, it should be formulated in terms of high-level concepts that make sense in the chosen problem domain rather than exposing low-level implementation issues. You should be able to give your API documentation to a API design for C++. © 2011 Elsevier Inc. All rights reserved. 21
  • 36. non-programmer and that person should be able to understand the concepts of the interface and how it is meant to work. Furthermore, it should be apparent to the non-technical reader that the group of operations provided by the API makes sense and belongs together as a unit. Each class should have a central purpose, which should be reflected in the name of the class and its methods. In fact, it’s good practice to have another person review your API early on to make sure that it presents a logical interface to fresh eyes. Because coming up with a good abstraction is not a simple task, I dedicate most of Chapter 4 to this complex topic. However, it should be noted that there is no single correct abstraction for any given problem. Most APIs could be modeled in several different ways, each of which may provide a good abstraction and a useful interface. The key point is that there is some consistent and logical underpinning to your API. For example, let’s consider an API for a simple address book program. Conceptually, an address book is a container for the details of multiple people. It seems logical then that our API should pro- vide an AddressBook object that contains a collection of Person objects, where a Person object describes the name and address of a single contact. Furthermore, you want to be able to perform operations such as adding a person to the address book or removing them. These are operations that update the state of the address book and so logically should be part of the AddressBook object. This initial design can then be represented visually using Unified Modeling Language (UML) as shown in Figure 2.1. For those not familiar with UML, Figure 2.1 shows an AddressBook object that contains a one- to-many composition of Person objects as well as two operations: AddPerson() and DeletePerson (). The Person object contains a set of public attributes to describe a single person’s name and address. I will refine this design in a moment, but for the moment it serves as an initial logical abstraction of the problem domain. Address Book Person + AddPerson() : boolean + DeletePerson() : boolean + firstName : string + address1 : string + address2 : string + city : string + state : string + zipcode : string personList 0..* + middleName : string + lastName : string FIGURE 2.1 High-level UML abstraction of an address book API. 22 CHAPTER 2 Qualities
  • 38. 4. An address book may contain multiple people with the same name. 5. An existing address book entry can be modified. These requirements will have a large impact on the object model for the API. Our original design in Figure 2.1 only supports a single address per person. In order to support more than one address, you could add extra fields to the Person object (e.g., HomeAddress1, WorkAddress1), but this would be a brittle and inelegant solution. Instead, you could introduce an object to represent an address, for example, Address, and allow a Person object to contain multiple of these. The same is true of telephone numbers: you should factor these into their own object, for exam- ple, TelephoneNumber, and allow the Person object to hold multiple of these. Another reason to cre- ate an independent TelephoneNumber object is that we need to support operations such as IsValid(), to validate a number, and GetFormattedNumber(), to return a nicely formatted version of the num- ber. These are operations that naturally operate on a telephone number, not a person, which suggests that telephone numbers should be represented by their own first-class objects. The requirement that multiple People objects may hold the same name essentially means that a person’s name cannot be used to uniquely identify an instance of the Person object. You therefore need some way to uniquely identify a Person instance, for example, so that you can locate and update an existing entry in the address book. One way to satisfy this requirement would simply be to generate a universally unique identifier (UUID) for each person. Putting all of this together, you might conclude that the key objects for our address book API are as follows: • Address Book: Contains zero or more Person objects, with operations such as AddPerson(), DeletePerson(), and UpdatePerson(). • Person: Fully describes the details for a single person, including zero or more addresses and telephone numbers. Each person is differentiated by a UUID. • Address: Describes a single address, including a type field such as “Home” or “Work.” • Telephone Number: Describes a single address, including a type field such as “Home” or “Cell.” Also supports operations such as IsValid() and GetFormattedNumber(). This updated object model can be represented as a UML diagram, as shown in Figure 2.2. Address Book Person Address + AddPerson() : boolean + DeletePerson() : boolean + UpdatePerson() : boolean + firstName : string + address1 : string + address2 : string + city : string + state : string + zipcode : string + addressType : string Telephone Number + number : string + numberType : string + IsValid() : boolean + GetFormattedString() : string + middleName : string + lastName : string + id : UUID 0..* personList 0..* addressList 0..* telephoneList FIGURE 2.2 UML diagram of key objects in our address book API. 24 CHAPTER 2 Qualities
  • 43. Instead, you should prefer class Vector3 { public: double GetX() const; double GetY() const; double GetZ() const; void SetX(double val); void SetY(double val); void SetZ(double val); private: double mX, mY, mZ; }; The latter syntax is obviously more verbose and involves more typing on your part as the pro- grammer, but the extra few minutes spent doing this could save you hours, or even days, further down the line should you decide to change the interface. Some of the additional benefits of using getter/setter routines, rather than exposing member variables directly, include the following. • Validation. You can perform validation on the values to ensure that the internal state of the class is always valid and consistent. For example, if you have a method that lets clients set a new RGB color, you could check that each of the supplied red, green, and blue values are within the valid range, for example, 0 to 255 or 0.0 to 1.0. • Lazy evaluation. Calculating the value of a variable may incur a significant cost, which you would prefer to avoid until necessary. By using a getter method to access the underlying data value, you can defer the costly calculation until the value is actually requested. • Caching. A classic optimization technique is to store the value of a frequently requested calcu- lation and then directly return that value for future requests. For example, a machine’s total mem- ory size can be found on Linux by parsing the /proc/meminfo file. Instead of performing a file read for every request to find the total memory size, it would be better to cache the result after the first read and then simply return that cached value for future requests. • Extra computation. If necessary, you can perform additional operations whenever the client tries to access a variable. For example, perhaps you always want to write the current state of a UserPreferences object to a configuration file on disk whenever the user changes the value of a preference setting. • Notifications. Other modules may wish to know when a value has changed in your class. For example, if you are implementing a data model for a progress bar, the user interface code will want to know when the progress value has been updated so that it can update the GUI. You might therefore wish to issue a change notification as part of a setter method. • Debugging. You may want to add debugging or logging statements so that you can track when variables are accessed or changed by clients or you may wish to add assert statements to enforce assumptions. • Synchronization. You may release the first version of your API and then later find that you need to make it thread safe. The standard way to do this is to add mutex locking whenever a value is accessed. This would only be possible if you have wrapped access to the data values in getter/setter methods. 29 2.2 Hide implementation details
  • 44. • Finer access control. If you make a member variable public, then clients can read and write that value as they wish. However, by using getter/setter methods, you can provide a finer level of read/ write control. For example, you can make the value be read-only by not providing a setter method. • Maintaining invariant relationships. Some internal data values may depend on each other. For example, in a car animation system you may calculate the velocity and acceleration of the car based on the time it takes to travel between key frames. You can calculate velocity based on the change in position over time, and acceleration based on the change in velocity over time. However, if a client can access your internal state for this calculation, they could change the acceleration value so that it does not correlate to the car’s velocity, thus producing unexpected results. However, if the member variables are not actually part of the logical interface that is, they rep- resent internal details that are not relevant to the public interface then they should simply be hidden from the interface. For example, consider the following definition for a stack of integers: Class IntegerStack { public: static const int MAX SIZE 100; void Push(int val); int Pop(); bool IsEmpty() const; int mStack[MAX SIZE]; int mCurSize; }; Clearly this is a really bad API because it exposes the way that the stack has been (poorly) imple- mented as a fixed array of integers and it exposes the internal state of the stack via the mCurSize var- iable. If at some future date you decided to improve the implementation of this class, for example, by using a std::vector or std::list rather than a fixed-size statically allocated array, then you may find this difficult to do. That’s because you have exposed the existence of the mStack and mCurSize variables and so client code could be relying on the ability to access these variables directly. By changing your implementation you could break your clients’ code. Instead, these member variables should be hidden from the start so that client code cannot access them: Class IntegerStack { public: void Push(int val); int Pop(); bool IsEmpty() const; private: static const int MAX SIZE 100; int mStack[MAX SIZE]; int mCurSize; }; 30 CHAPTER 2 Qualities
  • 45. I have stated that member variables should never be public, but can they be declared as protected? If you make a variable protected, then it can be accessed directly by any clients that subclass your class, and then exactly the same arguments apply as for the public case. As such, you should never make your member variables protected either. As Alan Snyder states, inheritance severely compro- mises the benefits of encapsulation in object-oriented programming languages (Snyder, 1986). TIP Data members of a class should always be declared private, never public or protected. The only semiplausible argument for exposing member variables is for performance reasons. Executing a C++ function call incurs the overhead of pushing the method’s parameters and return address onto the call stack, as well as reserving space for any local variables in the routine. Then when the method completes, the call stack has to be unwound again. The cost to perform these actions may be noticeable for performance-critical regions of code, such as within a tight loop performing operations on a large number of objects. Code that directly accesses a public member variable may be two to three times faster than code that has to go through getter/setter methods. However, even in these cases, you should never expose member variables. First of all, the overhead of a method call will very likely be insignificant for practically all of your API calls. Even if you are writing performance-critical APIs, the careful use of inlining, combined with a modern optimizing compiler, will normally completely eradicate the method call overhead, giving you all the performance benefits of directly exposing member variables. If you’re still concerned, try timing your API with inlined getter/setters and then with public member variables. The accompanying source code for this book includes a sample program to do just this. See http://APIBook.com/ to download this code and try it out yourself. I’ll also discuss this issue further in the chapter on performance. 2.2.4 Hide Implementation Methods In addition to hiding all member variables, you should also hide all methods that do not need to be public. This is the principle of information hiding: segregating the stable interface for a class from the internal design decisions used to implement it. Early studies of several large programs found that those using information hiding techniques were four times easier to modify than programs that did not (Korson and Vaishnavi, 1986). While your own mileage may vary, it should be clear that hiding the internal details of your API will make for more maintainable and evolvable software. The key point to remember is that a class should define what to do, not how it is done. For exam- ple, let’s consider a class that lets you download a file from a remote http server: #include string #include stdio.h #include sys/socket.h #include unistd.h class URLDownloader { public: URLDownloader(); 31 2.2 Hide implementation details
  • 46. Exploring the Variety of Random Documents with Different Content
  • 47. THE FULL PROJECT GUTENBERG LICENSE
  • 48. PLEASE READ THIS BEFORE YOU DISTRIBUTE OR USE THIS WORK To protect the Project Gutenberg™ mission of promoting the free distribution of electronic works, by using or distributing this work (or any other work associated in any way with the phrase “Project Gutenberg”), you agree to comply with all the terms of the Full Project Gutenberg™ License available with this file or online at www.gutenberg.org/license. Section 1. General Terms of Use and Redistributing Project Gutenberg™ electronic works 1.A. By reading or using any part of this Project Gutenberg™ electronic work, you indicate that you have read, understand, agree to and accept all the terms of this license and intellectual property (trademark/copyright) agreement. If you do not agree to abide by all the terms of this agreement, you must cease using and return or destroy all copies of Project Gutenberg™ electronic works in your possession. If you paid a fee for obtaining a copy of or access to a Project Gutenberg™ electronic work and you do not agree to be bound by the terms of this agreement, you may obtain a refund from the person or entity to whom you paid the fee as set forth in paragraph 1.E.8. 1.B. “Project Gutenberg” is a registered trademark. It may only be used on or associated in any way with an electronic work by people who agree to be bound by the terms of this agreement. There are a few things that you can do with most Project Gutenberg™ electronic works even without complying with the full terms of this agreement. See paragraph 1.C below. There are a lot of things you can do with Project Gutenberg™ electronic works if you follow the terms of this agreement and help preserve free future access to Project Gutenberg™ electronic works. See paragraph 1.E below.
  • 49. 1.C. The Project Gutenberg Literary Archive Foundation (“the Foundation” or PGLAF), owns a compilation copyright in the collection of Project Gutenberg™ electronic works. Nearly all the individual works in the collection are in the public domain in the United States. If an individual work is unprotected by copyright law in the United States and you are located in the United States, we do not claim a right to prevent you from copying, distributing, performing, displaying or creating derivative works based on the work as long as all references to Project Gutenberg are removed. Of course, we hope that you will support the Project Gutenberg™ mission of promoting free access to electronic works by freely sharing Project Gutenberg™ works in compliance with the terms of this agreement for keeping the Project Gutenberg™ name associated with the work. You can easily comply with the terms of this agreement by keeping this work in the same format with its attached full Project Gutenberg™ License when you share it without charge with others. 1.D. The copyright laws of the place where you are located also govern what you can do with this work. Copyright laws in most countries are in a constant state of change. If you are outside the United States, check the laws of your country in addition to the terms of this agreement before downloading, copying, displaying, performing, distributing or creating derivative works based on this work or any other Project Gutenberg™ work. The Foundation makes no representations concerning the copyright status of any work in any country other than the United States. 1.E. Unless you have removed all references to Project Gutenberg: 1.E.1. The following sentence, with active links to, or other immediate access to, the full Project Gutenberg™ License must appear prominently whenever any copy of a Project Gutenberg™ work (any work on which the phrase “Project Gutenberg” appears, or with which the phrase “Project
  • 50. Gutenberg” is associated) is accessed, displayed, performed, viewed, copied or distributed: This eBook is for the use of anyone anywhere in the United States and most other parts of the world at no cost and with almost no restrictions whatsoever. You may copy it, give it away or re-use it under the terms of the Project Gutenberg License included with this eBook or online at www.gutenberg.org. If you are not located in the United States, you will have to check the laws of the country where you are located before using this eBook. 1.E.2. If an individual Project Gutenberg™ electronic work is derived from texts not protected by U.S. copyright law (does not contain a notice indicating that it is posted with permission of the copyright holder), the work can be copied and distributed to anyone in the United States without paying any fees or charges. If you are redistributing or providing access to a work with the phrase “Project Gutenberg” associated with or appearing on the work, you must comply either with the requirements of paragraphs 1.E.1 through 1.E.7 or obtain permission for the use of the work and the Project Gutenberg™ trademark as set forth in paragraphs 1.E.8 or 1.E.9. 1.E.3. If an individual Project Gutenberg™ electronic work is posted with the permission of the copyright holder, your use and distribution must comply with both paragraphs 1.E.1 through 1.E.7 and any additional terms imposed by the copyright holder. Additional terms will be linked to the Project Gutenberg™ License for all works posted with the permission of the copyright holder found at the beginning of this work. 1.E.4. Do not unlink or detach or remove the full Project Gutenberg™ License terms from this work, or any files containing a part of this work or any other work associated with Project Gutenberg™.
  • 51. 1.E.5. Do not copy, display, perform, distribute or redistribute this electronic work, or any part of this electronic work, without prominently displaying the sentence set forth in paragraph 1.E.1 with active links or immediate access to the full terms of the Project Gutenberg™ License. 1.E.6. You may convert to and distribute this work in any binary, compressed, marked up, nonproprietary or proprietary form, including any word processing or hypertext form. However, if you provide access to or distribute copies of a Project Gutenberg™ work in a format other than “Plain Vanilla ASCII” or other format used in the official version posted on the official Project Gutenberg™ website (www.gutenberg.org), you must, at no additional cost, fee or expense to the user, provide a copy, a means of exporting a copy, or a means of obtaining a copy upon request, of the work in its original “Plain Vanilla ASCII” or other form. Any alternate format must include the full Project Gutenberg™ License as specified in paragraph 1.E.1. 1.E.7. Do not charge a fee for access to, viewing, displaying, performing, copying or distributing any Project Gutenberg™ works unless you comply with paragraph 1.E.8 or 1.E.9. 1.E.8. You may charge a reasonable fee for copies of or providing access to or distributing Project Gutenberg™ electronic works provided that: • You pay a royalty fee of 20% of the gross profits you derive from the use of Project Gutenberg™ works calculated using the method you already use to calculate your applicable taxes. The fee is owed to the owner of the Project Gutenberg™ trademark, but he has agreed to donate royalties under this paragraph to the Project Gutenberg Literary Archive Foundation. Royalty payments must be paid within 60 days following each date on which you prepare (or are legally required to prepare) your periodic tax returns. Royalty payments should be clearly marked as
  • 52. such and sent to the Project Gutenberg Literary Archive Foundation at the address specified in Section 4, “Information about donations to the Project Gutenberg Literary Archive Foundation.” • You provide a full refund of any money paid by a user who notifies you in writing (or by e-mail) within 30 days of receipt that s/he does not agree to the terms of the full Project Gutenberg™ License. You must require such a user to return or destroy all copies of the works possessed in a physical medium and discontinue all use of and all access to other copies of Project Gutenberg™ works. • You provide, in accordance with paragraph 1.F.3, a full refund of any money paid for a work or a replacement copy, if a defect in the electronic work is discovered and reported to you within 90 days of receipt of the work. • You comply with all other terms of this agreement for free distribution of Project Gutenberg™ works. 1.E.9. If you wish to charge a fee or distribute a Project Gutenberg™ electronic work or group of works on different terms than are set forth in this agreement, you must obtain permission in writing from the Project Gutenberg Literary Archive Foundation, the manager of the Project Gutenberg™ trademark. Contact the Foundation as set forth in Section 3 below. 1.F. 1.F.1. Project Gutenberg volunteers and employees expend considerable effort to identify, do copyright research on, transcribe and proofread works not protected by U.S. copyright law in creating the Project Gutenberg™ collection. Despite
  • 53. these efforts, Project Gutenberg™ electronic works, and the medium on which they may be stored, may contain “Defects,” such as, but not limited to, incomplete, inaccurate or corrupt data, transcription errors, a copyright or other intellectual property infringement, a defective or damaged disk or other medium, a computer virus, or computer codes that damage or cannot be read by your equipment. 1.F.2. LIMITED WARRANTY, DISCLAIMER OF DAMAGES - Except for the “Right of Replacement or Refund” described in paragraph 1.F.3, the Project Gutenberg Literary Archive Foundation, the owner of the Project Gutenberg™ trademark, and any other party distributing a Project Gutenberg™ electronic work under this agreement, disclaim all liability to you for damages, costs and expenses, including legal fees. YOU AGREE THAT YOU HAVE NO REMEDIES FOR NEGLIGENCE, STRICT LIABILITY, BREACH OF WARRANTY OR BREACH OF CONTRACT EXCEPT THOSE PROVIDED IN PARAGRAPH 1.F.3. YOU AGREE THAT THE FOUNDATION, THE TRADEMARK OWNER, AND ANY DISTRIBUTOR UNDER THIS AGREEMENT WILL NOT BE LIABLE TO YOU FOR ACTUAL, DIRECT, INDIRECT, CONSEQUENTIAL, PUNITIVE OR INCIDENTAL DAMAGES EVEN IF YOU GIVE NOTICE OF THE POSSIBILITY OF SUCH DAMAGE. 1.F.3. LIMITED RIGHT OF REPLACEMENT OR REFUND - If you discover a defect in this electronic work within 90 days of receiving it, you can receive a refund of the money (if any) you paid for it by sending a written explanation to the person you received the work from. If you received the work on a physical medium, you must return the medium with your written explanation. The person or entity that provided you with the defective work may elect to provide a replacement copy in lieu of a refund. If you received the work electronically, the person or entity providing it to you may choose to give you a second opportunity to receive the work electronically in lieu of a refund.
  • 54. If the second copy is also defective, you may demand a refund in writing without further opportunities to fix the problem. 1.F.4. Except for the limited right of replacement or refund set forth in paragraph 1.F.3, this work is provided to you ‘AS-IS’, WITH NO OTHER WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PURPOSE. 1.F.5. Some states do not allow disclaimers of certain implied warranties or the exclusion or limitation of certain types of damages. If any disclaimer or limitation set forth in this agreement violates the law of the state applicable to this agreement, the agreement shall be interpreted to make the maximum disclaimer or limitation permitted by the applicable state law. The invalidity or unenforceability of any provision of this agreement shall not void the remaining provisions. 1.F.6. INDEMNITY - You agree to indemnify and hold the Foundation, the trademark owner, any agent or employee of the Foundation, anyone providing copies of Project Gutenberg™ electronic works in accordance with this agreement, and any volunteers associated with the production, promotion and distribution of Project Gutenberg™ electronic works, harmless from all liability, costs and expenses, including legal fees, that arise directly or indirectly from any of the following which you do or cause to occur: (a) distribution of this or any Project Gutenberg™ work, (b) alteration, modification, or additions or deletions to any Project Gutenberg™ work, and (c) any Defect you cause. Section 2. Information about the Mission of Project Gutenberg™ Project Gutenberg™ is synonymous with the free distribution of electronic works in formats readable by the widest variety of
  • 55. computers including obsolete, old, middle-aged and new computers. It exists because of the efforts of hundreds of volunteers and donations from people in all walks of life. Volunteers and financial support to provide volunteers with the assistance they need are critical to reaching Project Gutenberg™’s goals and ensuring that the Project Gutenberg™ collection will remain freely available for generations to come. In 2001, the Project Gutenberg Literary Archive Foundation was created to provide a secure and permanent future for Project Gutenberg™ and future generations. To learn more about the Project Gutenberg Literary Archive Foundation and how your efforts and donations can help, see Sections 3 and 4 and the Foundation information page at www.gutenberg.org. Section 3. Information about the Project Gutenberg Literary Archive Foundation The Project Gutenberg Literary Archive Foundation is a non- profit 501(c)(3) educational corporation organized under the laws of the state of Mississippi and granted tax exempt status by the Internal Revenue Service. The Foundation’s EIN or federal tax identification number is 64-6221541. Contributions to the Project Gutenberg Literary Archive Foundation are tax deductible to the full extent permitted by U.S. federal laws and your state’s laws. The Foundation’s business office is located at 809 North 1500 West, Salt Lake City, UT 84116, (801) 596-1887. Email contact links and up to date contact information can be found at the Foundation’s website and official page at www.gutenberg.org/contact Section 4. Information about Donations to the Project Gutenberg Literary Archive
  • 56. Foundation Project Gutenberg™ depends upon and cannot survive without widespread public support and donations to carry out its mission of increasing the number of public domain and licensed works that can be freely distributed in machine-readable form accessible by the widest array of equipment including outdated equipment. Many small donations ($1 to $5,000) are particularly important to maintaining tax exempt status with the IRS. The Foundation is committed to complying with the laws regulating charities and charitable donations in all 50 states of the United States. Compliance requirements are not uniform and it takes a considerable effort, much paperwork and many fees to meet and keep up with these requirements. We do not solicit donations in locations where we have not received written confirmation of compliance. To SEND DONATIONS or determine the status of compliance for any particular state visit www.gutenberg.org/donate. While we cannot and do not solicit contributions from states where we have not met the solicitation requirements, we know of no prohibition against accepting unsolicited donations from donors in such states who approach us with offers to donate. International donations are gratefully accepted, but we cannot make any statements concerning tax treatment of donations received from outside the United States. U.S. laws alone swamp our small staff. Please check the Project Gutenberg web pages for current donation methods and addresses. Donations are accepted in a number of other ways including checks, online payments and credit card donations. To donate, please visit: www.gutenberg.org/donate.
  • 57. Section 5. General Information About Project Gutenberg™ electronic works Professor Michael S. Hart was the originator of the Project Gutenberg™ concept of a library of electronic works that could be freely shared with anyone. For forty years, he produced and distributed Project Gutenberg™ eBooks with only a loose network of volunteer support. Project Gutenberg™ eBooks are often created from several printed editions, all of which are confirmed as not protected by copyright in the U.S. unless a copyright notice is included. Thus, we do not necessarily keep eBooks in compliance with any particular paper edition. Most people start at our website which has the main PG search facility: www.gutenberg.org. This website includes information about Project Gutenberg™, including how to make donations to the Project Gutenberg Literary Archive Foundation, how to help produce our new eBooks, and how to subscribe to our email newsletter to hear about new eBooks.
  • 58. Welcome to our website – the ideal destination for book lovers and knowledge seekers. With a mission to inspire endlessly, we offer a vast collection of books, ranging from classic literary works to specialized publications, self-development books, and children's literature. Each book is a new journey of discovery, expanding knowledge and enriching the soul of the reade Our website is not just a platform for buying books, but a bridge connecting readers to the timeless values of culture and wisdom. With an elegant, user-friendly interface and an intelligent search system, we are committed to providing a quick and convenient shopping experience. Additionally, our special promotions and home delivery services ensure that you save time and fully enjoy the joy of reading. Let us accompany you on the journey of exploring knowledge and personal growth! ebookfinal.com