pinThe EPOC C++ API

Overload Journal #32 - Jun 1999 + Programming Topics   Author: Alan Griffiths

Last year I upgraded my Personal Organiser to a Psion Series 5 and was contemplating spending the money (175UKP) to get the EPOC C++ SDK - EPOC is the operating system that runs the Series 5. To a professional C++ (and hobbyist Java) developer this looked more enticing than learning the alternative OPL "user friendly" programming language.

I'm not really interested in writing applications for the Psion, but there are occasions when I write utilities that it would be nice to have available both on my desktop system and on the Psion. Obviously some EPOC specific code would be required, but since I keep platform specific code (such as user interfaces and input/output) in separate modules from the core application I expected this to be feasible.

The Psion is a small system so it would be unreasonable to expect all the facilities of a desktop system. But since I had already established that the C standard library was available I had hopes of "porting" some of my less demanding programs.

Around the time I was considering buying the SDK Psion had separated their software development under the name of Symbian. On visiting the Symbian website [symbian] I found they advertised an evaluation version of their C++ SDK. I requested a copy but in August 1998 a dispute with STNC led to the SDK becoming unavailable.

Time passed, the dispute with STNC continued and I found other interests. So it was a surprise when sometime around the end of January or early February I finally received this SDK. It then had to sit on a shelf until I had time to look at it.

Contents of the SDK

The evaluation SDK requires Windows95 or NT and Visual C++ 4 or 5 (the learning edition will do) which may be a disappointment to those developers that resist all things Microsoft. There is a patch on the Symbian web site that "cures some of the problems experienced using Visual C++ 6".

The full SDK is built around two tool chains. One of these is based on Visual C++ and targets a version of EPOC implemented on top of Windows and allows debugging using Visual Studio. The second tool chain is based on Cygnus's build tools distribution (gcc etc.) and targets EPOC systems. Key elements of the latter are omitted from the evaluation SDK.

In addition there are instructions for building a range of example programs, coding guidelines, and an API reference. The API covers all the EPOC operating system facilities - such as accessing files, communications ports, and the GUI library.

Getting started

The SDK installed easily - although it annoyed me by creating a number of top level directories on the partition of my choice rather than letting me specify a base directory under which to install everything.

After installation I followed the instructions for building some of the example programs to run using the "Emulator". This is a library that implements the EPOC APIs under Windows and provides a user interface via a window that looks like the Psion. The example programs built and ran happily and I could debug into them using Developer Studio. Looking at the code my first impression was confusion - class instances were initialised using two phase construction, many of the member functions had weird looking names ending in a capital "L" and class names began either with "T" or "C" prefix with no apparent pattern.

This led to a nagging suspicion that all was not as I had hoped - two phase construction is a technique developed in the early days of C++ to deal with the inability of the language to deal with error conditions occurring in constructors. When exception handling was adopted in the early '90s it fell into disuse.

I dived into the documentation seeking an explanation. Here I discovered that the "coding guidelines" require two phase construction, that "L" identifies a function that could "leave" and that "T" and "C" are used to distinguish classes that have no destructor from those that need to free memory at the end of their lifetime. I also discovered "R" a prefix for classes that need to free other system resources.

I deduced that "leaving" isn't like throwing an exception since any function that calls an "L" function has to manually register instances of any "C" or "R" classes with a "cleanup stack". This delivers similar results to exception handling with the following differences: the programmer can get the registration logic wrong (the compiler shouldn't), and there is a runtime cost to all these extra function calls (this can be avoided with compiler support). There is definitely more code to maintain, but I don't have figures to support my suspicion that there is also a space cost.

Hopefully, no-one would introduce the unwieldy mechanisms I'd encountered in preference to using genuine exception handling! But at the time I could find no direct indication that the version of C++ was anything other than compatible with Visual C++ which does have exception handling support. (I later discovered documentation that states that exceptions - and other language features - are not supported, but it is hidden in various parts of the API function reference, not in the introductory material or white papers.)

From the source

Having decided that the supported language probably lacked exceptions I wondered what else was non-standard and decided to email Symbian in the hope of clarifying matters:

Alan Griffiths:

Could you confirm a suspicion that has been growing as I read through the SDK documentation - that the language supported by the SDK is very different from that defined by the current ISO C++ Language Standard.

In particular I was puzzled by the lack of an explanation of when one would use the cleanup stack mechanism in preference to allowing exceptions to unwind the stack. Is this because the C++ exception handling mechanism is not supported? (On a related point the examples seem to suggest that the "new" operator returns 0 in place of throwing a std::bad_alloc exception.)

I appreciate that compiler support for a number of language features is distinctly patchy and that the development of EPOC32 spans a period of rapid evolution in C++. However, I am repeatedly puzzled by the approaches taken. While I can surmise that these are compromises enforced by the available compiler technology I can't be sure since these issues do not appear to be addressed anywhere.

>Martin Tasker(Symbian):

There were essentially two reasons for not adopting the C++ standard library when we started developing EPOC:

  • at the time (mid 95) the standard had not been agreed - though the language standard was substantially in place - clearly that has changed since

  • the standard library, in particular its use of templates and its exception-handling culture, was considered too profligate in terms of space and time for adoption in a small system - that has not changed since Embedded C++ is evidence that we were not the only people that shared this feeling. They didn't even support templates at all! - we do, but we use them exclusively in "thin template" idioms.

AG:

I can understand your reasons for not adopting the standard library, my main concern however is the _language_

I think your choice is wiser than that of the EC++ group [EC]. (Templates in themselves are not harmful and can greatly enhance the type safety and reliability of some code.)

>MT:

By default, we will pick up and deliver some support for standard C++ as time goes by. Later this year, we will take newer drops of Cygnus' GCC toolchain which will include more standard C++ support (our current supported technology dates from 1996). It might then be possible to implement a C++ standard library on EPOC, but we have as yet no plans to do that ourselves.

The accessibility of this information could be improved, and our plans for technical papers in the first half of this year should help.

Incidentally in EPOC C++, operator new() returns 0 on failure, unless you use the override which appears as new(ELeave) - which "leaves" with KErrNoMemory on failure. There was a debate in mid-96 about whether to make ELeave the default behaviour. Largely on the grounds that this would confuse imported C++ programs too much, we decided against.

AG:

Equally, having new return 0 causes portability problems - it would be best if it threw std::bad_alloc. However, there are still many platforms that implement the pre '95 semantics you describe.

I must confess to being disappointed that the supported language was closer to EC++ than C++ but my main difficulty throughout was the lack of documentation of what is and isn't supported.

From the net

I have to thank John Forrest for posting the following summary on usenet nntp://comp.sys.psion.programmer (I've corrected a few typos).

  • Don't use any file scope or local static variables.

  • Don't use any multiply derived types, apart from the limited M classes.

  • Can't use exceptions - use the EPOC Leave mechanism.

  • Don't use any C++ library stuff, just the EPOC stuff. (This is easier since you'd have to go out of your way to link them in).

  • Can't use dynamic casts (or other RTTI)

  • Beware that this version of gcc uses an older syntax for specific templates.

  • Be careful about the IMPORT_C and EXPORT_C usage for dll external declarations - you only get complaints when compiling for gcc.

  • Be careful about DLL UIDs - ditto.

  • Ensure all build information is given via the .mmp file - resist the temptation to add files directly into the VC++ Workspace/Project.

You can use <stdio.h>, but I'd advise against - that and other C library stuff are there for backward compatibility - unless you are trying to port a pure C program. If you mix and match then you have to close down the library in a special way.

Otherwise as a rule stick to the style used in the examples and the manual. This is pretty different from normal, and some people moan like hell, but since all the apps are written in this style you are much less likely to hit bugs. Try to avoid backsliding - some people in the past have hit problems because they (as far as I can make out) have tried to do C style string manipulation directly on the contents of descriptors (used for strings and other things).

My conclusions

I guess I'm one of those that "moan like hell" because I don't want to make a commitment to developing solely for EPOC. I'd rather my programs were available on whatever computer I have to hand (which is why Java interests me). If I were intent on developing applications specifically for EPOC platforms then the non-standard nature of the C++ used would be less important to me.

At the root of my concerns is a problem I first wrote [Griffiths] about in 1995 as a result of reading the first public draft of the ISO C++ standard. I complained about the many ways in which changes to the language invalidated the experience, skills and code base of those working with it. A particular issue is that the presence of exception handling necessitates a different style of coding. (Of course, the decision to include exceptions took place long before this - they are described in the 1990 ARM [Ellis] as "experimental" language features.)

Having spent the intervening four years becoming accustomed to these features I find that I am addicted. My current code base would not compile or work without exceptions, namespaces, or STL (I could live without RTTI). I also find that the resulting programs require less code and are more robust. (If they use <iostream> they take a substantial, but fixed, hit in executable size, but otherwise they tend to be smaller or have more functionality.)

Regarding the programs that it would be nice to have available on my Psion I'd be willing to do some rework to have them. However, as it stands I would also need to redevelop the core application in the supported dialect of C++ and for me this is not worthwhile.

"The EPOC C++ SDK" - A response from Symbian's Martin Tasker

I've had several discussions with Martin about the issues raised by the above (which he has read in draft form) you may be interested in the following response: - Alan

Your comments are understandable from your perspective but consider the following:

  1. the C++ facilities weren't there in GCC when we designed our leave support

  2. our system is entirely effective re its original design goals and - re those goals alone - is more economical than native C++ exception facilities

  3. compared to other palmtop systems, we're better: Windows CE, for instance, kills apps and loses data in order to save memory: we never do that, precisely because our exception handling stuff is built in so deep

Compatibility with "standard" C++ (the quotes were justified in 1995) was not a design goal of the original system: we could see the design goals of the C++ library and exception handling mechanism diverging grossly from ours, and the GCC toolchain didn't support exceptions as late as 1996. Our version of the toolchain will add support for native exceptions - possibly before the year is out. That will enable others to port the standard library, and code using it, onto EPOC.

I actually look forward to more dyed-in-the-wool C++ programmers such as ACCU members using EPOC for both academic/research purposes and commercial development. Much of commercial work we've fostered or known about hitherto has been by people from a SIBO/C/UNIX/Java/Win32-type background - including our own in-house developers - for whom EPOC poses an entirely different set of learning and porting issues.

References

[EC] Embedded C++ is an ARM like dialect of C++ being promoted by a Japanese consortium - details may be found at http://www.caravan.net/ec2plus/

[Griffiths] "No such thing as a free lunch" Alan Griffiths Overload 7 ISSN 1354-3172

[Ellis] "The Annotated C++ Reference Manual" Ellis & Stroustrup ISBN 0-201-51459-1

Overload Journal #32 - Jun 1999 + Programming Topics