Close

Beginning OLIB: An entirely uneducated look at Psion's proprietary Object Oriented C

A project log for The Last Psion

Resurrecting Psion's SIBO/EPOC16 Platform For The 21st Century

alex-brownAlex Brown 01/04/2024 at 16:040 Comments
Me: I could do with a quick win to get me going again.

Also me: I shall learn a proprietary object oriented dialect of C, where the only way to learn it is to plough through 1150 pages of documentation.

Psion doesn't have a formal name for the object oriented version of C that it created for EPOC16. I've been calling it "Psion OO C", but the main library that it uses is called OLIB, which contains the root class. The others are:

To Psion's credit, their OO ecosystem is well documented in the SIBO C SDK across 5 books (hence the 1150 pages mentioned above). Each of the libraries has its own, dedicated book. There's also an "Object Oriented Programming Guide" which acts as an introduction to the whole ecosystem. I don't have the latest versions of all of these books - they seem to be lost to time. But I have all the 3 and 3a features documented, plus (I think) all of the 3c/Siena extensions. (3mx-era EPOC16 remains sadly undocumented.)

What's nice about Psion's approach to OO is that they assume no prior experience with object oriented programming. They just assume that you know roughly what OO is, and that you can write some C code.

What follows is a collection of a few posts I made on Mastodon, plus some things I posted on the Psion Discord, fleshed out and turned into a proper blog post.

NOTE: If I have any of this wrong and you know better, please get in touch! As the title of the post suggests, I definitely do not know everything. I want the correct knowledge to be out there, and I don't mind if my ego takes a bruising in the process.

First Thoughts... "Ew"

This was my early, uneducated summary/hot take.

Instead of working with JPI/Clarion to add a "proper" OO C module to TopSpeed, they wrote a preprocessor. But it only does preprocessing on the class *definitions*. Methods are just functions that have to take a pointer to the class definition.

It feels bolted on to the side, not a cohesive whole.

To be honest, Psion not wanting to write a plugin for the TopSpeed compiler is understandable. As far as I've been able to find out, plugins for TSC are written in Modula2, much like the compiler itself. This was not the most popular language and it could be that it was just easier for Psion to write a few preprocessors in C and be done with it.

Even so, at this early stage, I wish Psion had gone a bit further.

The "language"

In spite of my discomfort with the tooling, Psion OO ecosystem is a fully object oriented, event driven "language." It's not so much a superset of C, but a separate class-definition language with some extra C functions to handle methods. In the Object Oriented Programming Guide, they say:

Psion's Object Oriented Programming system is similar to Object Pascal.

I don't know why, but this made me chuckle.

The manuals never mention Smalltalk, but Psion's OO uses message passing talk to methods instead of invoking them. If you've noticed Smalltalk and C together and thought of a different language... I'll come to that later.

Psion's Classes

Classes are defined in category (.CAT) files with its own proprietary syntax. It's a similar format to Psion's own resource file syntax, but that's unhelpful if you're new to programming for EPOC16.

Methods are stored in a separate .C file. The .CAT file is passed through a preprocessor called CTRAN.EXE that generates headers (.G), C files and object files. You then create a C file that holds your methods and #include the relevant .G file.

(I need to investigate the preprocessor situation more to clarify, as I think there might be more CLI apps involved. There might also be an intermediary object file generated that needs translating.)

Note that the preprocessor only processes the .CAT files. It doesn't touch your methods.

Of course, proprietary syntax is a pain in the modern world. It means no syntax highlighting, no language server, etc.

EDIT: I've just been told this by a former Psion engineer:

The language was based on the language Eiffel as defined by Bertrand Meyer in his book "Object-oriented Software Construction" (1st edition).

I've heard of Eiffel before but never looked at it. It's now on my research list.

Inheritance is everywhere. If you use HWIM to create a new app, you have to create a new object that inherits the window server WSERV class and then replace its init method with what you want it to do. Same with any other on-screen widget.

There is one annoying thing. There are no private methods or properties. From the Object Oriented Programming Guide:

"... the idea of private and protected data and functions does not exist."
"Although not enforced ... property should be considered as private to a particular class ..."

So if you implement getters and setters, they're just for show.

I guess this is because CTRAN only processes the .CAT (class definition) files, not the main C code. Without processing the main code, there's no way to check for and prevent private things from being accessed from outside of a class. TSC doesn't know you want your method to be private, because it doesn't know what a private method even is.

Methods are named classname_methodname, because they're all defined in regular C. You need to use this naming convention so that it matches the files generated by CTRAN.

Calling Conventions

This isn't specific to Psion's OO C, but it makes use of it more than regular Psion programming with plain old PLIB.

Looking through some Psion C code, I've seen CDECL a few times. Being a noob, I didn't know what they were or why they were there. So, looking at Wikipedia...

https://en.wikipedia.org/wiki/X86_calling_conventions

CDECL is a "caller clean-up" calling convention using the stack. This is pretty common in the x86 world, but is explicitly used in Psion code. Why?

TopSpeed C uses its own "callee clean-up" calling convention, using registers for the first 4 int parameters. The SDK regularly mentions that this method is much faster, and might also fit better with the way that EPOC16 manages memory. Sticking with the "pure" small memory model (preserving the CX register) means that 64K code and data blocks can be moved around memory without interfering with the program running "within."

However, there are other calling conventions that Psion uses, straight from an example in the Object Oriented Programming Guide.

Now, p_enter() is a PLIB call that (I think) allows for returning of error codes separately to whatever is returned by a regular function.

ENTER_CALL is defined in p_std.h as:

Whereas METHOD_CALL is defined in p_object.h as:

So the only difference is that missing mention of the cx register.

I don't know enough about any of this yet to say what's going on here. I'm sure more experienced C programmers will have a better understanding.

"This reminds me of Objective-C..."

Yeah, it's a bit like that, isn't it? Smalltalk plus C normally only means one thing.

A few years back, someone who used to work with me on this project actually suggested to me that whole of Psion's OO C should be reimplemented in Objective-C. At the time, I was pretty skeptical/cynical, as I felt that a direct recreation of TSC and Psion's tooling would be more sensible. With a little more knowledge behind me and having taken a dive into this legacy ecosystem, I'm more open to replacing it all.

This is some sample code that he sent to me. The first is some Psion OO code. The second is a direct transliteration to a theoretical Psion Objective-C. The third is a refactoring of the ObjC code.

As you can see, it's a pretty straightforward translation in this example. I'm not sure how well the .CAT files would translate to Objective-C header files, but I'd be willing to believe that they'd look a lot nicer.

No matter what your thoughts are about Objective-C (in my research, I have seen that people definitely have thoughts!), it is compelling. There would be no need to pre-process your class definitions, as it would all be done in the principal language and understood by the compiler.

And no, I will not be writing an Objective-C compiler that targets EPOC16 unless someone wants to pay me much money to do it and agrees for it to be a FOSS project.

Much money.

Brain fog

It's still early days for me, trying to learn a programming ecosystem straight from text books - something I've never been good at. Psion's OO is slowly making more sense to me, but I'm still struggling to comprehend it. This could simply be because it just doesn't feel 100% cohesive to me, at least not yet. Given time I'm sure I'll feel more comfortable.

I do want to learn to use OLIB, HWIM and FORM, mainly because of the new word processor I'm planning on developing The Psion OO ecosystem does seem to be the best way to create graphical apps for EPOC16 without switching to OPL. And I'm not about to reinvent the wheel by rewriting libraries and compilers.

If you'd like to take a look at Psion's special flavour of object oriented C, it's all in the SDK, available here:

https://archive.org/details/psion-sibo-c-sdk

Discussions