SPIN OO Musings
Kal_Zakkath
Posts: 72
I should probably say upfront that I have no intention of doing anything about this, more of a thought experiment than anything else.
I've been wondering lately if spin could, at least theoretically, be brought more inline (so to speak) with recent object-oriented languages.
My thinking is somewhat like this:
spin uses static ram (for the most part, I know some people have done heaps etc but spin itself is designed for static memory) - thus, the compiler knows for certain where every variable and method resides. It should, therefore, be possible to allow objects to be passed to other objects like variables.
Similarly, I supsect it should also be possible to implement some form of polymorphism, allowing interfaces etc to be defined.
Given that the ram allocation is static all this should be possible to check at compile-time - and thus it would only require changes to the compiler and no changes to the hardware (as far as I can see).
Setting aside the question of whether or not it should be done - could it be done? and if not, why not?
I've been wondering lately if spin could, at least theoretically, be brought more inline (so to speak) with recent object-oriented languages.
My thinking is somewhat like this:
spin uses static ram (for the most part, I know some people have done heaps etc but spin itself is designed for static memory) - thus, the compiler knows for certain where every variable and method resides. It should, therefore, be possible to allow objects to be passed to other objects like variables.
Similarly, I supsect it should also be possible to implement some form of polymorphism, allowing interfaces etc to be defined.
Given that the ram allocation is static all this should be possible to check at compile-time - and thus it would only require changes to the compiler and no changes to the hardware (as far as I can see).
Setting aside the question of whether or not it should be done - could it be done? and if not, why not?
Comments
The question really is "who's going to do the work?" If you have skills in compiler writing, by all means go ahead. If you're asking whether Parallax would do it, I really doubt it. It's not important enough to hire someone or to take the one or another person who might be able to do it off their current projects and put them to work on this.
Essentially what you'd need is the ability to declare an object variable that can take on values that can be one of a list of objects (object constants). This object variable would be an internal method table with the appropriate number of entries for the number of methods. The compiler would check to make sure that all the listed objects have the same structure with the same number of public methods, all with the same numbers of parameters. There would be some kind of new statement like WORDMOVE that copies the initialized method table from some object into the object variable. Any reference to the object variable's methods would go through this table. You wouldn't be able to use the object's constants except by referring to the actual name of the object rather than the object variable.
jazzed: I must have missed that, perhaps I'll rummage though the forums and see what I can dig up.
Can you give us some examples of how your objects would work? Generate some pseudo code that demonstrates the use of the objects. Right now your concept is too abstract for me to understand what your proposing.
Dave
PropBasic was based on Bean's earlier SX-Basic, modified for the Propeller. His Prop-Embedded Basic is partially based on that
The 3rd party Spin compilers/assemblers (BST and Homespun) were intended partially to provide something compatible with the Propeller Tool, yet cross-platform. Conditional compilation was added to both because of demand and has proven to be very useful as expected. Mostly it can be added on easily without changing much of the existing compiler. The sort of thing you suggested would require deeper changes to an existing compiler and wouldn't yield as much benefit.
Also note that the only Spin compiler/assembler that's been released in source form is Sphinx which runs native on the Propeller (with an SD card, PS/2 keyboard, and TV display). Sphinx doesn't have conditional compilation, has some program size and other limitations, and was done partly as a demonstration that it could be done and it does compile itself.
Example of passing objects Obviously the advantage is that you can re-use code, and it makes it easier if you want to share access to something (like several objects that all want to access an SD card for example)
Interface (polymorphism) example:
This allows you to interchange different objects as long as they implement the interface (i.e. in this example any object with an ISerial.Send(string) method could be used).
There is a kind of defacto, manual form of this already in spin - as long as two objects have the same method names they can be swapped in the OBJ section - so you can easily switch between different drivers before compiling - but only one can be used (whereas the approach above allows multiple different objects to be used while running).
Both of these are standard in modern OO languages like C# & Java - there is also the matter of inheritance, but these two will do for now
Object passing is probably the one I long for the most - I often find I have a few objects that I want to have talking back & forth. Obviously there are ways to achieve this as it is now - I just find passing the object as a parameter more natural (as someone coming from an OOP background).
Mike: I thought Catalina was very prop-specific, but I admit I haven't looked at it that closely as I have no desire to use C on the prop. And yes, I realise that the existing 3rd party compilers were designed with prop-tool compatibility in mind, and that the kind of thing I'm talking about would need heavy re-designing of the compiler (and, at the very least, some additions to the syntax).
This doesn't help you though where you have a different implementation underlying even though the public interface is the same.
The question here is similar to my very first question posted to this forum ... boy did I get some funny responses .... Fortunately I found ways to do the things I wanted to do, but they always involve something "clunky" like using a global "data structure" for FullDuplexSerial or others (with locks in some cases) instead of Object scoped data.
The big reality of it all however is that Propeller is a resource limited microcontroller and using real OOP methods are probably not useful because of constraints and just didn't make the cut as an important spin feature. I've implemented Javelin Java1.1 in Propeller PASM and all the features we love in Java bloated the interpreter so badly that I had to resort to overlays to make it work in one COG (3 COGS without overlays).
Maybe mpark will have more to say about his experiments with object enhancements.
http://forums.parallax.com/showthread.php?109600-Passing-objects-in-Homespun&highlight=object+passing+homespun
My technique is pretty limited though; I think Dave Hein's method pointers are more useful.
I don't doubt that getting java on the prop would cause such problems, but what I was thinking more along the lines of putting all the smarts into the compiler, the interpretter would still be the standard propeller one and a sufficiently advanced compiler should be able to optimize away the overhead (or most of it)- mpark's experiments show that OO features done this way are possible, at least to a degree.
mpark: It looks like Homespun does more than I realised, and I shall definitely have to play around with it. Did you ever put any thought towards inheritance? Just curious.
I have no doubt that I'm in a minority here, most people on the forum seem to have previous experience in assembly on other uC's whereas I'm coming from the other direction (C#/Java -> Spin) - I'm sure I'll dive into PASM some day I'm just more comfortable with OO design since that's my background and everything said here has confirmed that there is no reason it couldn't be done on the prop (and evidently thanks to mpark much of it already has!)
Proper data types, signed, unsigned. Signed, unsigned, byte, word, long pointer types, structures etc. Function/method pointers and so on.
A pre-processor with #include, #define, #ifdef etc.
For sure it is possible to do object oriented programming on the Prop, perhaps even using the existing Spin byte codes with a suitable compiler. Putting the "smarts" into the compiler as Kal_Zakkath says.
This is demonstrated by the fact that C and C++ code can be run under Zog. Here the C/C++ is compiled to ZPU byte codes which are of a, somewhat, similar nature to those of Spin.
BUT. Having added all these features to Spin, both object oriented and otherwise, one might ask why bother? Why not use a language, like C++, that has all that already? The essential simplicity of Spin will have been lost and the resulting language of would be of little use outside the Propeller world.
As I say many times already.
SPIN/PASM fit good its need on Propeller - Some additions are welcomme.
BUT It is structure of BIN file that loads to Propeller that needs REBUILD in first place to be more MEMORY sparse. Ad gige some of Memory regions to be REUSABLE after Run-INIT part of program.
Before that even some clever additions to compiler not give much usability !!!!
pointers + method pointers are not used/needed in modern OO languages (I don't consider C++ 'modern' )
preprocessors are also not normally used (not to say that they can't be, but inheritance/polymorphism can be used to acheive the same end)
C++ is not designed for the prop (or rather, the prop is not designed for C++) as far as I'm aware all the C/C++ implementations still use much more RAM than the equivalent Spin code. As for the simplicity - that is only an issue if back-compatibility is broken, if all this OO stuff is done as an addition to the language, such that all previously written code still happily compiles, then it is no less simple than it always was (but with more options for those who want them). Spin is already of no use outside the propeller world so it would be no worse off (though I think you are meaning that it would be a lot of work for a small audience?)
Sapieha:
Presumably for that to work you would need to add some kind of keyword to mark reusable space? So that you could still stop/restart a cog if needed.
Dave:
Would the objects need to have exactly the same PUB methods? Or would it be enough to simply put the common ones at the start (so they all have the same PUB 'interface' methods at the start, then custom methods afterwards) - provided you only call the common methods on the pointer of course.
Hmmm...What about this from C#:
That "outCl" looks like a pointer to me. Or is C# not modern either? That's a serious question because for sure I'm not up to date with progress in OO languages.
I believe you are right. I was hoping that the ZPU instruction set used by Zog to run C code would result in executables of a similar size as Spin but that has not been the case. Catalina, using LMM PASM, is bigger still.
What I was thinking with my comments about Spin's simplicity is that Spin is obviously a minimalist language, whether by design or happenstance, that is very easy for those new to programming to pick up, like BASIC was back in the day. If Spin had all the features of say C++ then the OBEX would now be full of code that would be much harder for beginners to make use of let alone understand.
Yep. Given that we already have an ocean of languages out there there seems little point honing Spin.
If you add a virtual memory and sd card drivers you can do some really fun things like load objects at runtime from the sd card. Virtual memory can also let you do things like implement a string object with a different string length for each instance.
Inheritance from a single parent is possible but all the methods would need to be reimplemented or pointed back to the parent object with a function call. Also, variables would have to be in the same order which will waste some space due to variable sizes (also means that automatic variable sorting needs to be turned off.) Like object pointers this requires support from the compiler to be useful.
Inheritance from more than one parent or interfaces are not really possible.
If you want to make any of this useful than you need to either change one of the existing compilers or write your own which let's you do the following:
- get the object offset in the method table into a constant. I managed to do this in sphinx.
- add a way of not including an object when linking the binary. I never figured out how to do this in sphinx without breaking something. I could tell the linker that I didnt want the object linked but couldn't get the last step. Objects that include themselves are also a problem (I.e. A generic linked list).
- inheritance is tricky, you may need to do a lot of rearranging because you need to include all the same methods with either a call back to the parent object or an overload method all in the same order as the original object, all the same variables in the same order and not sure how to manage sub-objects.
Perhaps I over-simplified my answer - you are correct of course, that outCl will be pointing to a memory location. However, it is not a 'pointer' in the C++ sense in that there is no pointer arithmetic and no pointer manipulation (*,&,->) is used (other than the object.method notation and assignment).
I'm sure one could argue about whether that should be called a pointer or not - but either way a majority of the 'pointer' stuff is essentially done behind-the-scenes, not by the programmer.
C# also has delegates which are similar to method pointers - this depends on language design however, as Java does not have anything like method pointers.
One could make a similar statement about PASM in objects (that is, that objects using PASM are harder for beginners to understand). - I do take your point though, and completely agree: Spin is obviously designed to be beginner-friendly, and the more advanced/complex it becomes, the more daunting it becomes for beginners to look through existing code.
As I said right at the start, I have no intention (as this stage) of putting in the work required to do any of this OO stuff - I was just curious if it could be done using the existing spin interpretter, and I now see that much of it already has been done by various people. Thus the answer to this question, like many in life, is a resounding "Yes... but why would you?"
steven:
I had assumed that cog-safety would become an issue with this kind of setup, particularly with objects being passed around, but presumably is no worse than a standard spin object storing data in the DAT section and being used by multiple cogs.
I've used systems ranging from 16K of core memory up to 16GB servers, using everything from assembler to C#.
Where does SPIN fall in this? In my opinion, above assember, about equal to BASIC, and below C. This is not to say - in any way or form - that I consider SPIN to be inferior. In fact, I like that it is minimalist but still fully supports (within performance reasons, of course) the underlying hardware. It is very handy for prototyping software that I then translate into PASM for speed (if needed).
So, should SPIN be OO? No.
It was, is, and always will be a compromise, as is the situation for any language.
Would it be nice to be able to use pointers for objects? Maybe. I'd rather see any Parallax software development time spent concentrating on supporting the new/improved features of the Prop II chip. With the speed improvements and new instructions it might be possible to code completely in SPIN for some applications.
BTW, I think Parallax has done a very nice job of providing a FREE set of languages for their hardware. (Look at Freescale Semiconductors and what they charge for their development software).
If you want OO, then use C++.
Walter