Shop OBEX P1 Docs P2 Docs Learn Events
SPIN OO Musings — Parallax Forums

SPIN OO Musings

Kal_ZakkathKal_Zakkath Posts: 72
edited 2011-03-15 16:16 in Propeller 1
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?

Comments

  • Mike GreenMike Green Posts: 23,101
    edited 2011-03-13 18:42
    Sure, it could be done. There was even a thread once upon a time where someone used a feature of one of the 3rd party Spin compilers to capture the address of the internal method table for an object and basically substitute one of several objects for a "stub" object.

    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.
  • jazzedjazzed Posts: 11,803
    edited 2011-03-13 19:09
    As I remember mpark added some extra OOP stuff to Homespun at some point, but no one seemed interested and as a result he also lost interest.
  • Kal_ZakkathKal_Zakkath Posts: 72
    edited 2011-03-13 19:23
    Mike: I wasn't suggesting that anyone do it - I was just curious why no one has done it given the effort spent getting C, BASIC, etc on the prop. I thought about playing around with it myself, but I have no experience in compilers and so far as I'm aware none of the existing ones have released the source - though even if they had, at this stage I'd much rather be doing things with the prop rather than making things for the prop.

    jazzed: I must have missed that, perhaps I'll rummage though the forums and see what I can dig up.
  • Dave HeinDave Hein Posts: 6,347
    edited 2011-03-13 19:57
    Kal,

    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
  • Mike GreenMike Green Posts: 23,101
    edited 2011-03-13 20:35
    The C compilers are based on existing compilers for other processors. The code generators had to be re-targeted to the Propeller.

    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.
  • Kal_ZakkathKal_Zakkath Posts: 72
    edited 2011-03-13 20:58
    Dave: Here's a couple of examples I just threw together - forgive me if I'm misusing existing objects here (and don't worry about the actual syntax, this is just to give an idea)

    Example of passing objects
    'Main object:
    
    OBJ
    	fds1 : "FullDuplexSerial"
    	fds2 : "FullDuplexSerial"
    	fds3 : "FullDuplexSerial"
    
    	object : "ExampleObject"
    
    PUB Main
    
    	fds1.start(30, 31)	'start fds1 on pins 30 & 31
    	fds2.start(1, 2)	'start fds2 on pins 1 & 2
    	fds3.start(10, 11)	'start fds3 on pins 10 & 11
    
    
    	object.writeData(fds1)	'send data with fds1
    	object.writeData(fds2)	'send with fds2
    	object.writeData(fds3)	'send with fds3
    
    
    'ExampleObject:
    
    PUB WriteData(FullDuplexSerial fds)
    	fds.tx("abc123")	'send data using whatever FDS object was passed in
    
    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:
    'Main object:
    
    OBJ
    	ser1 : "Serial"
    	ser2 : "TV_Serial"
    	ser3 : "RS485_Serial"
    
    PUB Main
    	'standard initialising stuff...
    	ser1.start...
    	ser2.start...
    	ser3.start...
    
    	Send(ser1)
    	Send(ser2)
    	Send(ser3)
    
    
    PUB Send(ISerial ser)
    	ser.send("X")
    
    
    'ISerial interface:
    
    PUB Send(string)
    
    
    'Serial object
    
    OBJ
    	fds : "FullDuplexSerial"
    
    PUB Start
    ...
    
    PUB ISerial.Send(string)
    	fds.tx(string)	'sends string using standard FDS
    
    
    'TV_Serial object
    OBJ
    	tv : "TV_Text"
    
    PUB Start
    ...
    
    PUB ISerial.Send(string)
    	tv.str(string)	'displays output on TV
    
    
    'RS485_Serial object
    OBJ
    	rs : "RS485Trans"
    
    PUB Start
    ...
    
    PUB ISerial.Send(string) | temp
    	temp := convert(string)
    	rs.send(temp)
    
    PUB Convert(string)
    ...	'some conversion code
    

    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).
  • Mike GreenMike Green Posts: 23,101
    edited 2011-03-13 21:19
    For the sort of example you've picked where you have several instances of the same object, you can already do this with object arrays. You can declare an object array and pass the subscript to a routine like:
    OBJ serial[3] : "FullDuplexSerial"
    
    PRI Send( instance )
       serial[instance].tx("X")
    

    This doesn't help you though where you have a different implementation underlying even though the public interface is the same.
  • Kal_ZakkathKal_Zakkath Posts: 72
    edited 2011-03-13 21:24
    You can - but example #1 is passing the object to another object ("ExampleObject" - I put them all in the same code block as I think it is easier to read on the forum that way) which wouldn't have access to the object array, and example #2 is using different objects that implement an interface (which could also be passed to another object as in #1).
  • Mike GreenMike Green Posts: 23,101
    edited 2011-03-13 21:35
    I've written a lot of Smalltalk code over the years, so I know what can be done and how useful it can sometimes be. Like a lot of things, it's just not useful enough for anyone to devote the time and energy to doing it.
  • jazzedjazzed Posts: 11,803
    edited 2011-03-13 22:20
    Mike Green wrote: »
    I've written a lot of Smalltalk code over the years, so I know what can be done and how useful it can sometimes be. Like a lot of things, it's just not useful enough for anyone to devote the time and energy to doing it.
    I think the usefulness of passing an object by reference and being able to use it the way Kal_Zakkath has described depends on the habits of the audience, and as such most people who visit these forums may have little use for the implemented suggestion. Typically C/C++ people are spoiled by the possibility of passing objects structures around like this. C++ and Java (C#/VB.net) folks happily extend classes or use abstract/interface for polymorphism to achieve similar ends. Of course people don't have to be in love with these concepts to be competent programmers.

    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.
  • mparkmpark Posts: 1,305
    edited 2011-03-13 23:01
    My experiments:
    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.
  • Kal_ZakkathKal_Zakkath Posts: 72
    edited 2011-03-14 03:06
    jazzed wrote:
    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).

    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!)
  • Heater.Heater. Posts: 21,230
    edited 2011-03-14 04:11
    Prior to adding object oriented features to Spin one might want to consider a whole host of other language features first. For example:
    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.
  • SapiehaSapieha Posts: 2,964
    edited 2011-03-14 08:26
    Hi All.

    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 !!!!
  • Dave HeinDave Hein Posts: 6,347
    edited 2011-03-14 08:55
    Method pointers can be used to provide callbacks, implement state machines and other useful things. I posted a method pointer object in the OBEX at http://obex.parallax.com/objects/697/ . It would be easy to create object pointers as well. That requires a single long containing the object's PBASE and VBASE (program/DAT and VAR starting addresses). Object pointers could be used to select between different drivers, such as a serial driver for the PST, or a VGA/TV diriver or virtual connection through the LAN. However, object pointers would require that all of the objects that could be selected must have the same PUB method inferfaces. That is, the PUB methods must be in the same order, and they must use the same number of calling parameters.
  • Kal_ZakkathKal_Zakkath Posts: 72
    edited 2011-03-14 14:22
    heater wrote:
    ...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.

    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)
    heater wrote:
    ...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.

    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.
  • Dave HeinDave Hein Posts: 6,347
    edited 2011-03-14 15:25
    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.
    Yes, it is sufficient to put the PUBs that are in common at the start of the object. All other PUBs would follow after that. PRI methods can be put anywhere, since the Spin compilers re-orders them after the PUBs.
  • Heater.Heater. Posts: 21,230
    edited 2011-03-15 01:00
    Kal_Zakkath,
    pointers + method pointers are not used/needed in modern OO languages

    Hmmm...What about this from C#:
    class ExampleClass
    {
        // Main begins program execution.
        public static void Main()
        {
            // Instance of OutputClass
            OutputClass outCl = new OutputClass("This is printed by the output class.");
    
            // Call Output class' method
            outCl.printString(); 
        }
    }
    

    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.
    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

    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.
    (though I think you are meaning that it would be a lot of work for a small audience?)

    Yep. Given that we already have an ocean of languages out there there seems little point honing Spin.
  • stevenmess2004stevenmess2004 Posts: 1,102
    edited 2011-03-15 04:07
    If you do a search for DOL it may answer some of your questions. Object pointers are possible but need a modified compiler to make them useful. There is a bit of a speed hit whenever you call a method in another object. It also isn't multi cog safe unless you use a lot of locks.

    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.
  • Kal_ZakkathKal_Zakkath Posts: 72
    edited 2011-03-15 14:49
    heater wrote:
    That "outCl" looks like a pointer to me. Or is C# not modern either?

    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.
    heater wrote:
    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.

    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.
  • wmosscropwmosscrop Posts: 409
    edited 2011-03-15 16:16
    Kal,

    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
Sign In or Register to comment.