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:
- HWIM: The OO graphics library
- FORM: On-screen formatting
- XADD: Additional graphics library for 3a onwards (but not the Series 3 "classic")
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:
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.