Declaring new objects
David A.
Posts: 2
Hi All,
I'm a beginner spin coder, so I need some help. I'm trying to create a LinkedList object
which would allow a user to store a dynamically sized list of objects or variables (could be
wrapped if necessary). My questions are, is it possible to create a pointer to a generic object
(the type of which is unknown)? Are nulls ever encountered in spin and if so, how are they handled?
Also, is it possible to declare a new instance of an object within a Pub or Pri method?
For example:
(BTW: I'm coming from a Java perspective, so if there are any comparisons you can make, that would
be great).
Thanks,
David
I'm a beginner spin coder, so I need some help. I'm trying to create a LinkedList object
which would allow a user to store a dynamically sized list of objects or variables (could be
wrapped if necessary). My questions are, is it possible to create a pointer to a generic object
(the type of which is unknown)? Are nulls ever encountered in spin and if so, how are they handled?
Also, is it possible to declare a new instance of an object within a Pub or Pri method?
For example:
VAR ?Pointer/Object? currentNode OBJ headerNode: "LinkedListNode" PUB init currentNode := headerNode PUB add(object) | nextNode [b] currentNode := ?new? "LinkedListNode" [/b] nextNode.setContents(object) currentNode.setNext(nextNode)
(BTW: I'm coming from a Java perspective, so if there are any comparisons you can make, that would
be great).
Thanks,
David
Comments
You can't declare an object within a method. They're all global to the object. All parameters and local variables for a method are longs. You can declare arrays of longs as local variables, but that's the only exception.
Spin is not a general object-oriented language, particularly it doesn't have dynamic types of any kind.
1. Generic objects
No, Spin doesn't provide any way to do inheritance, function pointers, virtual methods, etc. There are some dirty tricks that let you kinda sorta implement object interfaces, but I won't go there. This is kind of a shortcoming in the language, but just think of it as motivation to try different design strategies [noparse]:)[/noparse]
2. Linked lists
Linked lists are pretty easy to do in either Spin or Assembly. Since Spin doesn't give you any compile-time abstractions, you can't really create a generic linked list object- you have to think lower level than that. One technique I'm fond of is to adopt a memory layout convention that I use in all my "objects". For example, I could plan to use the first word of memory in each "object" as a pointer to the next object in my linked list. Now I can always traverse a linked list in the same way, no matter what kind of object is in it:
3. Dynamic memory allocation
Using the "new" operator and dynamically sizing a list implies that you also want to use a dynamic amount of memory. This isn't a built-in feature of the Propeller, or of any CPU. It's up to some runtime library to define a memory heap, and the algorithms for dynamically allocating memory from it. There's a heap object on the object exchange, but it's actually relatively rare that you actually need dynamic memory allocation in an embedded system like a Propeller project. In fact, allocating all of your memory statically forces you to think ahead about the practical limitations in your system. How long can a line of input actually be? How much buffer space do you actually want to use for your serial port? etc. When you plan your memory usage ahead of time, there are far fewer failure modes to deal with in your finished system.
Hopefully that answered your question [noparse]:)[/noparse]
--Micah
David A
First, however, we have to define what we mean by an "object". An object is really nothing more than a collection of data and the methods that operate upon it. In Spin, the object-particular data are the VARs declared in the object (actually, "object class") itself, and its methods are those of its routines declared as PUBlic. Each statically-declared instance of an object is assigned a separate set of VARiables, the methods and DAT area being allocated only once.
So, if we want to create new objects dynamically, all we really have to do is come up with a way to allocate the object's variables dynamically with a new method, and recycle them back to the pool with a destroy method. (Automatic garbage collection is pretty much out of the question here.) The simplest, but not very efficient, way to do this would be for each Spin object to manage its own repository of memory in DAT space, sufficient to accommodate as many dynamic objects as might be instantiated at runtime. Better, of course, would be a universal dynamic memory allocator, which could service several different object classes at once.
The idea is that, when an object's new method is called, it allocates the necessary memory and returns a pointer (i.e. the address of the memory block's first element), initializing elements in that block as necessary. One thing a new method cannot do in Spin, however, is "bless" the pointer into the object class so that the notation pointer.method(parameter1, ..., parameterN) can be used. Further method calls will have to be of the form classname.method(pointer, parameter1, ... , parameterN).
In the object itself, the first parameter of any PUBlic method will then be the dynamic object pointer, normally referred to as self, viz:
The use of named CONstant displacements helps to make the code more readable. You have to be careful, though, to mind the alignment of word and long displacements. You also have to be careful not to call methods with an object reference that ponts to an object in a different class. Just as a pointer is not "blessed" into an object class, it is also not "condemned" to fail when used with a foreign class method. Finally, object classes defined in this manner should have no VAR section. All variables global to the class need to be defined in a DAT block.
-Phil
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
'Still some PropSTICK Kit bare PCBs left!
Post Edited (Phil Pilgrim (PhiPi)) : 8/21/2008 3:01:11 AM GMT