If you contribute code, you must grant copyright of that code to Kenton Varda
(me). There are many reasons for this:
- If, at some future date, it becomes necessary to change the licensing terms
on the code, it will be nearly impossible to do so if many people hold
copyrights on various bits of the code.
The code will *always* be open source. If I change the license on the code,
it will be to some other OSI-approved open source license.
- Most governments (especially that of the United States) have little respect
for unregistered copyrights. However, registering a copyright to multiple
holders around the world would be very difficult. At some point, I will
need to register GUF's copyright, and the only way I can do that is if I own
- If a third party violates the license on the code, it will be very hard for
me to bring a legal suit against them if I am not the copyright holder of
the code in question. I am (somewhat) prepared to bring suit against those
who violate the license (having three uncles who are lawyers, at least one of
which deals in intellectual property, helps). Wouldn't you like me to do
that work for you? :)
- Note that I will NOT take credit for writing your code. You get to keep
that. :) I just need legal ownership. Authors of code will be clearly
indicated at the top of every source file and in various documentation.
- The Free Software Foundation asks the same of their contributors.
- All general coding documents (including this one).
- Documentation on all core GUF classes, especially smart pointers.
- At least some GUF code (to get the feel of it).
Highly recommended reading. I owe all of my C++ programming skill to these
books (and a lot of practice):
- Effective C++ and More Effective C++ by Scott Meyers
- Large Scale C++ Software Design by John Lakos
- Design Patterns by Gamma et al.
Writing a New Module
When writing a new module, you will want to start out by copying the header
and cpp templates found in the templates directory of the source tree. These
will start you off quickly with a framework consistent with the rest of the
library. The next few steps depend on the type of class you are writing.
Pass-by-value classes generally represent new data types, and have little
functionality other than storing and performing basic operations on that data.
If you are writing a pass-by-value class, you'll want to remove some stuff
provided by the templates. The templates are designed for pass-by-smart-pointer
classes, since those are the most used. Some things you will want to remove
- The inheritance of the class from GObject. Pass-by-value classes should not
- The smart pointer type declaration in the header.
- The insulated implementation class in the source file (pass-by-value
classes can't be insulated).
You will then want to start writing your class. Keep the following in mind
when you do:
- Keep the amount of member data to a minimum. Pass-by-value classes are
supposed to be custom data types. Keep your class under 16 bytes in size.
- Avoid allocating memory. Most data type classes shouldn't even deal with
- Try to keep functions short, and inline them when appropriate.
- Copy constructors, assignment operators, and destructors should be as fast
as possible. Remember, pass-by-value types are passed by value. Thus, copy
constructors, destructors, and assignments will be used heavily. If you find
you have to allocate or free memory in these functions, consider using reference
counting to minimize the performance hit. (See GString for an example of a
pass-by-value class that uses reference counting.)
- Use overloaded operators where they make sense.
- If your data type has a logical "null" value, consider integrating it with
GUF's "null" keyword. "null" is actually an object of type "GNullType". All
you have to do to make your class compatible is write a constructor which takes
an operator of type "GNullType" and constructs a null object (this function
should be as fast as a copy constructor, or faster). Be careful when assigning
a "null" value for you type, however. A null variable should have no other
purpose than being null. For example, a null pointer is a pointer to zero. A
pointer to zero is never valid. On the other hand, a 3D vector class can have
the value (0, 0, 0). Should this value be considered null? No! (0, 0, 0) is a
valid vector and could mean something other than null. 3D vectors have no
- Generally, pass-by-value classes should not throw exceptions.
Pass-by-smart-pointer classes are larger classes that represent large data
sets or some sort of functional object. Most classes in GUF are of this type.
There are some things to keep in mind here, too:
- First and foremost, think about the interface for your module. Is there
an existing abstract interface which your module could logically implement? If
so, implement it! If you create a new interface or add to an existing one,
think about your custom functions. Might another module want to implement the
same interface? If so, you may want to separate your interface into a separate
module, so other classes can implement the same interface.
- Keep the interface of your class separate from the implementation. The
templates are set up to help you with this. Your header file should declare an
abstract interface only! This means all virtual functions and no member
variables. In addition, this interface may have a static member
function named "New". This function should return a smart pointer to an
implementation of your class. That implementation should be fully defined in
the implementation file of your module (the cpp file).
When your code is complete, send it to
email@example.com. It will then
be reviewed by myself and possibly one or two others. In all likelyhood, I'll
reply with a list of things that need to be fixed, possibly accompanied by a
modified version of your code. Do not be discouraged by this -- I throw out my
own code all the time! :)
Once the code is reasonably clean and functional, it will be added to GUF's
CVS repository, marking its official addition to the project.