Chic documentation
Houlder Technologies


Tutorial 1: A first introduction
Home
Features
Tutorial
Examples
FAQ
Reference
Download
Mailing list
Contact

Chic lets you put your code in a single source file. From this file Chic generates one header file and up to two implementation files, basically one file for inline functions and templates and one file for out-of-line functions and variable definitions. The declarations and include directives needed to produce a complete header file are deduced from a database that has initially been set up for the given project. The database is in turn automatically updated when the files are generated.

A small example

In the following example we have created a class Medium in a file called medium.hic. The Medium class contains two functions: one inline and one out-of-line. In addition, Medium has an instance variable and a static variable.

File medium.hic:

  namespace Hardware
  {
    using namespace MusicSpace;

    class Medium
    {
    public:
      void
      play(Song* song)
      {
        // ...
      }

      inline
      Status
      getStatus() const
      {
        return status;
      }

    private:
      Status status;
      static MediumManager* mediumManager = 0;
    };
  }

When we invoke Chic on this file, Chic creates three files: a header file, a file that contains the body of the inline function getStatus and a file with the rest of the definitions. By default the files are named medium.hh, medium.ii and medium.cc respectively. We refer to these "compile files" as the "hh-file", the "ii-file" and the "cc-file". Analogously we call the original file the "hic-file". Here's the resulting hh-file:

File medium.hh:

  //chic version 1.0

  #ifndef INCLUDED_HARDWARE_MEDIUM_HH
  #define INCLUDED_HARDWARE_MEDIUM_HH

  #include "basicdefs.hh"

  namespace Hardware
  {
    class MediumManager;
  }
  namespace MusicSpace
  {
    class Song;
  }

  namespace Hardware
  {
    using namespace MusicSpace;

    class Medium
    {
    public:
      void
      play(Song* song);

      inline
      Status
      getStatus() const;

    private:
      Status status;
      static MediumManager* mediumManager;
    };
  }

  #include "medium.ii"

  #endif

The first line is a special comment that marks this file as generated by Chic. The next we notice is that Chic has made an include guard that wraps around the class definition. The guard name has been deduced from the file name and the namespace name. Below the guard there is an include directive for basicdefs.hh and forward declarations of Song and MediumManager. These are needed for the header file to compile as a stand alone file. We had to include basicdefs.hh since Status is defined therein as the following enum:

File basicdefs.hh:

  #ifndef INCLUDED_BASICDEFS_HH
  #define INCLUDED_BASICDEFS_HH

  enum Status { Playing, Stopped };

  #endif
Chic knew what to insert since it had initially scanned a number of hic and header files, among them basicdefs.hh and the files that contain the Song and MediumManager classes. When Chic saw the using directive
  using namespace MusicSpace;
it considered all classes in the MusicSpace namespace eligible and matched the Song argument to the MusicSpace::Song class. We'll go into more details about the database and lookup in general later. Finally, we note that the function bodies and the initializer of the mediumManager variable have been removed.

The ii-file contains the implementation of getStatus():

File medium.ii:
  //chic version 1.0

  #ifndef INCLUDED_HARDWARE_MEDIUM_HH
  #include "medium.hh"
  #endif

  #line 15 "medium.hic"
  Status
  Hardware::Medium::getStatus() const
  #line 18 "medium.hic"
  {
    return status;
  }

The function has been qualified with both the namespace name Hardware and the class name Medium. Chic has also inserted two #line macro directives. When you compile an erroneous file this makes sure your compiler generates error messages that refer to the position of the offending code in the hic-file and not in the ii-file. This way you won't need to actually look at the generated implementation files.

The first part of the cc-file is analogous to the ii-file. It contains the definition of play:

File medium.cc:
  //chic version 1.0
  #include "medium.hh"

  #line 9 "medium.hic"
  void
  Hardware::Medium::play(Song* song)
  #line 11 "medium.hic"
  {
    // ...
  }

  MediumManager* Hardware::Medium::mediumManager = 0;
At the end of the cc-file Chic has also inserted the initialization of the static variable mediumManager. If the variable had been in the header and several files had included the header we would get link errors complaining that mediumManager had been multiply defined. Thus we put it in the cc-file just as the function bodies.

Namespaces

If you're not familiar with namespaces, you might wonder if they are a necessary part of Chic. They are not. Chic does not in any way force you to use namespaces, but you're rewarded if you do. For instance, if there had been two or more entities called Status defined in the global scope Chic couldn't have decided which one of them to use. You would have had to explicitly include the right one.

Some people think namespaces impose an additional maintenance burden without much other benefit than preventing name clashes, something you can prevent by diligent inclusion. But since Chic keeps the three compile files synchronized with the hic-file there is no additional burden. All you have to do is to come up with a namespace name, wrap your code into that namespace, and manipulate using directives or using declarations. That's a cleaner and more flexible way than using #includes.

Alternative implementations

The using directive in the above example is not the only way to make Chic create the correct forward declaration for Medium. We could instead have used a using declaration:

  namespace Hardware
  {
    using MusicSpace::Song;

    class Medium
    {
    public:
      void
      play(Song* song)
      {
        // Rest of file...
or we could have explicitly qualified the argument:
  namespace Hardware
  {
    class Medium
    {
    public:
      void
      play(MusicSpace::Song* song)
      {
        // Rest of file...
Both approaches would give the same result as the example.

Completing the implementation files

You may have noticed that no include directives or forward declarations were generated for the implementation files. The reason is that this initial version of Chic does not search for all the dependencies needed to compile the function bodies. That means you still have to use #include for these (although a special utility can do most of the work for you). All preprocessor directives in the hic-file are by default moved to the cc-file. In our example the cc-file would typically need to include both the file containing Song and the file containing MediumManager. So in a more realistic code the start of the hic-file might look like:

File medium.hic:

  #include "music.hh"
  #include "manager.hh"

  namespace Hardware
  {
  // Rest of file...
Please note that the include directives do not influence the look up or generation in any other way. They're simply copied to the cc-file.

Summary

Previous Next




Home