Tim programs LegalTrax, a document management application, for
Software Intelligence, Inc. His web page is at
http://ourworld.compuserve.com/homepages/timp/
Letwin lists the following advantages:
- Smaller EXE files
- Change or upgrade the dynamically linked code at any time
- Automatic code sharing (RAM efficiency)
- "A final advantage of dynamic linking is that it's totally
invisible to the user, and it can even be invisible to the
programmer."
I must admit, it sounded great at the time, and based on the
explosion of DLLs, VBXs, OCXs, ActiveXs, and so forth in the last
decade, my reaction was not unique. But it's time to face the facts:
The idea of DLLs is a failure with almost no redeeming benefits in
today's systems.
Smaller EXE files
There are two flaws with the promise of smaller executables.
First, it hasn't happened. Are recent Microsoft Word for Windows
executables smaller than Word for DOS ones ever were? Did the Word
for Windows executables get smaller as it became more integrated with
other Office applications? I'll wait if you want to go check, but the
answer is a big "no." I admit I'm comparing apples to
oranges--current versions do a lot more than the older versions. But
an increasing proportion of that size is not code at all. How many
megabytes do you figure that animated paperclip takes up? Any savings
from sharing DLL code have been dwarfed by the growth of overall code
size.
The second failure of the smaller executable size goal is that it
doesn't matter nearly as much as it did ten years ago. Back then, 10
MB of storage could easily cost you $1,000, while today, a 100 MB Zip
disk costs $10.
Many of you may be thinking, "I'm always running out of disk space.
If all my DLLs were embedded in the executable, it would be even more
of a hassle!" While it's true that people often seem to be low on disk
space, integrating DLLs into a large executable would not aggravate
the situation. Consider how many of those DLLs are general purpose.
Maybe it's a third-party library, and the application only uses a
portion of its code. In those cases, static linkage would remove
unused portions of that library from the executable.
Also consider the problem of duplicate and orphaned DLLs, which has
created a whole new software category of cleanup programs devoted to
addressing this problem. Many applications install DLLs into the
application's directory rather than in a central location, creating
the possibility of duplicate DLLs for multiple applications. And when
an application installs its DLLs in the Windows or System directory,
there's a good chance the DLL will still be there long after the
application is gone. Cleanup software adds its own problems. The
software may overlook a duplicate or orphaned DLL, or it may remove a
DLL that is used by an existing application.
Are you sure that DLLs are saving you more space than bloated,
duplicate, or orphaned DLLs are wasting? Even if they are, the money
spent on a cleanup program probably costs the equivalent of a
gigabyte of storage space.
Change or upgrade dynamically linked code at any time
That's right, just plug in a new version of the DLL and presto,
your application has new features. Try to think of how many times
that's come in handy. It's OK, I'll wait. Stumped? Maybe I can help
jar your memory. Perhaps you've bought one of the spell-checking
upgrade packages for your word processing program. Never heard of
one? Maybe you don't shop around much. Or maybe you're like me, and
the best such an upgrade has ever really delivered is not to break
every application that was built for an older DLL.
Occasionally, developers do release bug fixes and even enhancements
in DLLs. How could this be possible if all the code was in a single
executable? Simple -- you would need to replace the whole executable.
While replacing an executable rather than a DLL would mean
redistributing a larger file, the simplicity of replacing a single
executable cannot be beat. And if the size is a significant problem,
there are patch tools that allow you to distribute the delta of the
changes to the binary.
Automatic Code Sharing
In Inside OS/2, Letwin explains that "automatic code
sharing" refers to sharing code in RAM, although it also has
connotations as a valuable design-time development practice. However,
as is the case with hard disks, the cost of RAM has dropped
dramatically since this design decision was made. A few years after
Letwin's book was written, I made the difficult (and expensive)
decision to invest in a full 640 KB of RAM. Today I have 36 MB in
assorted SIMMs that have been sitting on my desk for weeks.
Despite the extreme economic changes, it is always best for an
application to use as little RAM as necessary. However, DLLs only
save RAM when you have two or more applications that use the same DLL
running simultaneously. There are developer utilities that can help
you identify such cases. Take a look at the applications you're
running right now and try to identify the overlaps. I suspect you'll
see this come into play about as infrequently as I do, but I concede
that whatever presence it has is a benefit. In the cases where only
one running application is using a DLL, however, the DLL is probably
bloated with unused general-purpose code, and probably uses more RAM
than necessary.
"Totally Invisible"
Users cannot easily identify which application components make use
of which DLLs, and which parts are in the main executable. And
programmers can generally use the code in DLLs almost exactly as if it
were linked right into the main application.
However, I think "invisibility" should go a lot farther than that.
Do you think users understand what DLLs are and how they cause
problems? I think so. How do they know? How could they not? Have
you ever seen an application complain about a DLL not found? How
about a GPF after another application changes the DLL? The system my
kids use has batch files to swap around QuickTime DLLs depending on
the program that needs to be run. Before I hacked together this
workaround, they weren't invisible to my four-year-old son, who
couldn't even read at the time.
How about application downloads that are available in different
configurations, depending on the DLLs you already have. ICQ offers a
smaller download for "advanced users" who are sure they already have
the correct MSVC runtime DLLs. Visual Basic can also require
literally megabytes of DLLs for the simplest of applications, and
applications developed with it are frequently distributed without
these critical components.
Users shouldn't need to be aware of these nasty details, any more
than they should know if your code uses recursion or linked lists.
Like the promise of smaller executables, the promise of "invisibility"
simply hasn't come true.
The Dark Side
The biggest effects of rampant DLL usage in 1998 are:
- Duplicate and orphaned DLL files
- Applications break each other, sometimes in ways that preclude
coexistence
- Applications require DLL code they never use
What benefit do we get in exchange for all of this suffering? End
users really don't get any direct benefit. However, newer flavors of
DLLs (VBXs, OCXs, and so on) do include some very nice design-time
features for developers. Most support a variety of languages and
compiler brands, allowing the programmer to choose the tools best
suited for a particular application (or the particular programmer).
Additionally, advanced DLLs integrate very smoothly into modern
development environments, so DLL components can be visually arranged
into a user interface. Code integration is similarly slick, allowing
simple implementation of DLL code options and events. These advances
in programming tools do result in better programs for end users--every
programmer doesn't have to write his own serial communication library
or grid control or whatever. This is what "code sharing" immediately
brings to my mind, and development systems have made good progress in
this area during the last ten years.
But DLLs are not the only path to these features. Back in the
pre-DLL days, there were commercial code libraries, too. The
publishers usually had to support each language and compiler,
requiring significant extra work. But the bottom line was that every
programmer didn't have to write his own communication library or user
interface back then, either. The extra burden was limited to the
library publishers. Development environments were crude or
nonexistent, so the lack of polished integration was not surprising.
Just as Microsoft specified the interface between VBXs and development
environments, such a specification could certainly have been made for
statically linked libraries. Visual C++ is loaded with Wizards to
drop MFC code into your application, and you can choose to leave most
of the MFC library in a DLL or link it statically.
I think the hugely popular Visual Basic compilers (let's not
quibble; they turn source code into EXE files) make a powerful case
against the promise of DLLs. You're supposed to get magic upgrades,
right? Then why can't you make a VB3 app run better by using the VB4
DLLs? Microsoft made that option impossible, and it was probably a
wise choice. Every version of VB has used different names for its
assortment of runtime DLLs. This was not a trivial decision; most of
the runtime DLLs had only eight characters for file names, and used
two of those for "MS."
Using run-time DLLs with different names prevents version
compatibility problems. Couldn't Microsoft have made the different
versions backward compatible instead? While the newer versions of VB
have all added appreciable features, there don't appear to be major
differences in the core features. The source code has stayed very
compatible; VB5 can handle just about all of the valid code from
previous versions. How hard could it be to keep backward
compatibility with the VB functions like Mid(),
MsgBox(), and so on? Apparently, Microsoft decided it was a
combination of too much effort and too much risk.
A Simple Solution
The answer to the almost limitless problems of DLLs is obvious:
Don't use them. Wherever possible, use static linking. Imagine the
benefits. Some other developer's boneheaded installation or poorly
designed updated DLL will not break your application. Your
application won't fail because a component is missing, or because a
registry setting has been lost or modified incorrectly. Your
application won't behave differently depending on the applications
already loaded, as a DLL-based application can if another application
has already loaded a different copy of one of its components. Your
installation will be exceptionally simple, and an uninstall will be
just as easy.
I should warn you of one small hassle if you try DLL-free
development. Your users won't believe that there is only one file to
install.
Bibliography
Letwin, Gordon. Inside OS/2. Microsoft Press, 1988. ISBN
1-55615-117-9. (See Chapter 7, "Dynamic Linking.")
These op/eds do not necessarily reflect the opinions of the author's
employer or of Dr. Dobb's Journal. If you have comments, questions,
or would like to contribute your own opinions, please contact us at