General Questions:
- Are you alive?
Err... yes. I certainly hope so, at least.
- Is GUF alive?
GUF will live as long as I do.
- Why do you never update the news page or release new versions
of GUF?
I'm too busy coding. :)
- What is GUF?
GUF is a general-purpose object-oriented framework library written in
C++ and licensed under the GNU Library General Public Liscense (aka
the "Lesser" General Public Liscense, though I object to that name).
- What is a framework library?
A framework library is a set of program modules that make it easier to
write large-scale software. GUF is a general-purpose library, meaning
that it is intended to be useful in any sort of software. However,
the focus is on large-scale applications; small and simple programs
are unlikely to benifit from using GUF.
- Can I make commercial software with GUF?
Sure. GUF is licensed under the GNU Library/Lesser General
Public License (LPGL). You can write a program using GUF and sell
it without paying any royalties or fees of any kind. Your can
license your application under any license you wish. If you make any
changes to GUF itself, however, you must distribute the source
code for these changes licensed under the terms of the LGPL. See
the file "COPYING" in the source package for more info.
- Why are you doing all this work for free?
If GUF were not free (by any or both definitions of the word), who
would use it? Although GUF has many uses, its greatest strength will
come when (and if) it is widely used. Then, people will write
libraries with GUF that will be trivial to integrate, saving work and
making large-scale software much easier to write. If GUF were not
free, this would be nearly impossible, as only people with money would
have access to it, and only non-free software would use it.
Put simply, my goal is to improve software for everyone, not to make
money for myself.
Technical Questions:
- GUF looks a lot like Java. What's wrong with Java?
GUF may look like Java on the surface, because on the surface it
is very similar. Things like automatic memory management and new
keywords like "synchronized", "interface", "implements", etc. may make
it appear that GUF is just Java in C++.
The similarities end there. GUF aims to be used in very different
types of software than Java does. GUF is for large-scale projects,
whereas Java is ideal for applets and the like. Sure, you can use
Java in a large application, but you may run into problems.
Personally, I can't use Java because it does not support
pass-by-value objects. Take, for example, a 3D game engine
(one of which
I happen to be writing). 3D graphics involves lots of vector
math, so we would like to create a 3D vector class which covers this
stuff for us. Then, we would often like to create an array of vectors
to describe a model. These arrays often contain on the order of
ten thousand vectors. In Java, that would mean creating ten thousand
separate vector objects, each with its own mutex and all the other
data Java attaches to objects. Furthermore, you'd have an array of
ten thousand pointers pointing at these objects. This is an extreme
waste of memory and CPU power.
Java also has the problem that it tends to encourage muli-threading
rather than event-driven programming. For more on event-driven
design, see the goals section.
Of course, then there are all the arguments about efficiency of
bytecode, interpreters, JIT compilers, etc. Whether they are valid
or not, I'm sure I don't need to repeat them here.
- GUF uses reference counting for memory management. Why not use
full-scale garbage collection?
While this is a very debatable topic, I believe that reference
counting is better than full-scale garbage collection (GC).
GC is unpredictable. GC algorithms usually need to make passes
over the program's memory space at periodic intervals, looking for
garbage memory that can be de-allocated. This requires pausing all
threads of the program unexpectedly and often for long periods of
time. Furthermore, this means that memory which is no longer needed
stays allocated until the GC pass is made. Often, programs have to
rely on an object's desctructor being called at a particular time.
Because they can't do so using GC, some classes are instead forced to
provide their destructors as member functions, which clients of the
class have to manually call. This is worse than manual memory
management, which GC is supposed to replace.
Worse yet, GC can't be implemented reliably in C++. A garbage
collector in a C or C++ program is forced to assume that all memory
contains nothing but pointers, unless that memory is explicitly
declared to contain something else. The result is that non-pointer
data which coincidentally looks like pointers pointing at various
data blocks will cause those blocks to never be deleted. A GC program
which loads several megabytes of random data into RAM could
effectively disable the garbage collector all together without
realizing it!
Thus, GC is only possible in languages designed for it. Other
languages have other problems, however, and GUF will remain a C++
library.
- But reference counting doesn't catch circular links! What
do you do about that?
Put simply, any program in which circular links appear is poorly
designed. If you have two objects that can call each other, you are
already putting yourself in more risk than you may realize. For
example, if object A calls object B, and B then calls back A, the
second call to A may be made while A is in an inconsistent state --
just like if two separate threads tried to access A at the same time.
Additionally, in multithreaded systems, improperly managed circular
links could lead to the risk of deadlock, where two threads are stuck
waiting for each other to do something. In a properly designed system
with no circular links, this risk is greatly reduced, if not removed
all together.
Of course, sometimes an object needs to be able to call back its
owner without waiting for the owner to call it. GUF provides a
simple way to do this: events. The owner of an object can ask that
object to fire a particular event when it needs attention. The owner
then responds to that event by calling whatever methods of that object
it needs. No circular links necessary!
- I heard that reference counting was slow. Is this true?
It depends on your definition of slow. Sure, passing around a
reference-counted pointer is slower than passing one that isn't, as
the former requires an atomic increment and decrement, while the
latter is just a copy. The question is, is this extra time relevant?
The answer is most certainly no. When deciding if an operation
takes too much time, you can't just look at the operation itself. You
must look at it in context; you must take an example program, and see
how much time that program spends performing that operation. In my
case, I tested
GAUGE^3D, a 3D
graphics engine. I clocked GAUGE performing over 15,000 reference
count operations per second -- much more than most programs would.
Yet, it spent far less that 1% of its time performing these
operations. Is reference counting worth a 1% performance drain?
Personally, I would gladly sacrifice as much as 50% of my performance
to be able to use reference counting, so a 1% drain means nothing at
all to me.
Furthermore, if you do not use reference counting, you have to use
some other method of memory management. These take time too.
|