Spin Feature Request
darco
Posts: 86
After looking over the spin bytecode and the interpreter, I realize that with one small additional capability I will be able to much more easily write complex systems. After looking over the bytecode, I know this is possible.
The biggest problem with spin that I have is that object dependencies are always trees. If you have a serial object defined in the top level object, the only object which can use that specific instance of the serial object is the top level object. No other children can use it. Sure, I could define another serial object in those objects, but they would all be independent objects---which is not what was desired.
The child objects of an object are listed at the end of the method table. Each object is represented by two pointers: one to the method table of the child object and the other to the "variables". The only thing that is different between different instances of an object is that VAR pointer.
What I'm suggesting is a way to provide child objects with instances of certain objects.
Syntactically, it would look like this:
main.spin:
subsys.spin:
This would print the following on the TV:
From this example, we can see that main.spin is sharing it's instance of term with subsys.spin. Subsys.spin has marked the term object with a asterisk (*) which lets the compiler know that the instance will be substituted.
Note that the only thing getting substituted is the instance, the "variable base" part of that object's entry in the method table.
This would make it much easier to add debugging code and design complex systems with lots of interdependencies. It is also 100% backward compatible with existing code.
Please, I'm begging you, consider this improvement for a future version of the propeller tool! My number one gripe with spin has been the inflexible object model, but this change will make it much more flexible.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
—
darco
www.deepdarc.com/
[url=mailto:xmpp:darco@deepdarc.com]xmpp:darco@deepdarc.com[/url]
The biggest problem with spin that I have is that object dependencies are always trees. If you have a serial object defined in the top level object, the only object which can use that specific instance of the serial object is the top level object. No other children can use it. Sure, I could define another serial object in those objects, but they would all be independent objects---which is not what was desired.
The child objects of an object are listed at the end of the method table. Each object is represented by two pointers: one to the method table of the child object and the other to the "variables". The only thing that is different between different instances of an object is that VAR pointer.
What I'm suggesting is a way to provide child objects with instances of certain objects.
Syntactically, it would look like this:
main.spin:
OBJ term : "TV_Text" subsys : "subsys" (term) ' Share our instance of TV_Text with subsys PUB init term.start(12) subsys.start term.str(@done) DAT done byte "Done!",13,0
subsys.spin:
OBJ *term : "TV_Text" ' The actual instance of this object will be provided by whoever is instantiating us PUB start term.str(@title) DAT title byte "Starting subsys... ",0
This would print the following on the TV:
Starting subsys... Done!
From this example, we can see that main.spin is sharing it's instance of term with subsys.spin. Subsys.spin has marked the term object with a asterisk (*) which lets the compiler know that the instance will be substituted.
Note that the only thing getting substituted is the instance, the "variable base" part of that object's entry in the method table.
This would make it much easier to add debugging code and design complex systems with lots of interdependencies. It is also 100% backward compatible with existing code.
Please, I'm begging you, consider this improvement for a future version of the propeller tool! My number one gripe with spin has been the inflexible object model, but this change will make it much more flexible.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
—
darco
www.deepdarc.com/
[url=mailto:xmpp:darco@deepdarc.com]xmpp:darco@deepdarc.com[/url]
Comments
Note that if you don't have an VAR sections than you will get the effect you desire as only the VAR sections are created for each new instance of an object. The PUB, PRI and DAT sections are shared by all instances.
The compiler then needs to distinguish between normal parameters and an object reference parameter.
I like Darco's use of *.
OBJ
· term: "TV_TEXT"
· subsys: "subsys"
PUB entry
· subsys.start(term)
In subsys:
PUB start(*tv)
· tv.initialize
'tv is used as placeholder for object reference term
'because of the * the compiler knows to create an object reference field
regards peter
The code in the main object would be something like this
This will need several changes to the compiler
1. New keywork to indicate that an object should not actually be used but just allocate space for a pointer to an object.
2. If you want to be able to change it at run time than the ":=" operator will need to have a different meaning it would need to generate something like this
----term:=(arg.word[noparse][[/noparse]0]-@thisObject.word[noparse][[/noparse]0])|(arg.word-@thisObjectFirstVAR.word) 'would need to check if these are the right way around
3. The "@" operator would need to be changed so that it returns the start address of the object so it can be used like this
----startOfTerm:=@term
However, you run into several problems depending on how you do it.
1. If you want to make it truly dynamic than you run into problems when you are using more than one instance of the same object.
2. Things would turn really bad if you made it dynamic and gave it either a wrong pointer or a pointer to the wrong kind of function.
So to sum up. It should be fairly easy if you just want to make the links static. It is possible to make it dynamic but you run into a couple of problems that can be worked around by careful attention to detail.
It would be nice for Parallax to add full support in an elegant way, but overcoming the obstacles that prevent easy hackery would be the second best.
At the moment, the biggest problem is not being able to get at the required information to implement the hackery without looking at the generated object code. Then altering the code can easily break the hack.
If the compiler could support "CallObj(varObjNum,varMethodNum,varArg1,varArg2...varArgN)" that would make life so much easier ...
Calls to local methods "Call(varMethodNum,varArg1,varArg2...varArgN)" could be done in the same way. These can already be done, but it isn't easy and not being able to determine the values for varObjNum and varMethodNum is the core problem.
Doing this at runtime would waste memory because the compiler would end up allocating variables for an instance which will never be used. Whereas at build time, the compiler can identify that it is a reference and not allocate variable memory for another instance.
Very simple change.
Being able to do it at runtime would be nice I suppose, but isn't necessary and is potentially wasteful. It would also require additional implementation work.
I would love to hear Chip's opinion on this.
EDIT: I'm suddenly having second thoughts about using the '*' character. A '&' would likely have been more appropriate symbol to indicate a reference, similar to C++. Not that it really matters, since spin has a tendency to do things its own way. Like the wacky <> operator. *cringe* >_<
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
—
darco
www.deepdarc.com/
[url=mailto:xmpp:darco@deepdarc.com]xmpp:darco@deepdarc.com[/url]
Post Edited (darco) : 3/28/2008 5:28:06 PM GMT
@Darco, if you specified 2 instances of TV_Text, which one should subsys then use in your approach?
I think the following does allow for static building and solves for the above question:
'main file
OBJ
· term: "TV_Text"
· term2: "TV_Text"
· subsys: "subsys"
PUB main
· subsys.start(@term2) 'pass address of object
· 'or should we use subsys.start(term2) ??
'subsys
OBJ
· tv: "TV_Text"
PUB start(tv)
Note that an object name as formal parameter instructs compiler
to use a passed object reference rather than creating a new instance.
The type of the object is known at compile time by using the object name.
regards peter
main.spin:
Notice the parenthesis.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
—
darco
www.deepdarc.com/
[url=mailto:xmpp:darco@deepdarc.com]xmpp:darco@deepdarc.com[/url]
Objects are compiled seperately, so how does subsys know which to use when you compile subsys?
regards peter
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
—
darco
www.deepdarc.com/
[url=mailto:xmpp:darco@deepdarc.com]xmpp:darco@deepdarc.com[/url]
The question then becomes where to put these in subsys? Maybe a new section something like this?
The compiler would allow only one POBJ section to avoid confusion and potentially bad situations like getting the objects out of order (or it could be solved by using objectiveC style messages where each argument can have a name ).
The object table gets patched during compile time at the moment so it shouldn't be too hard to add. If parallax doesn't add it we can always add it to the open source compiler.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
—
darco
www.deepdarc.com/
[url=mailto:xmpp:darco@deepdarc.com]xmpp:darco@deepdarc.com[/url]
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
—
darco
www.deepdarc.com/
[url=mailto:xmpp:darco@deepdarc.com]xmpp:darco@deepdarc.com[/url]
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
—
darco
www.deepdarc.com/
[url=mailto:xmpp:darco@deepdarc.com]xmpp:darco@deepdarc.com[/url]
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Paul Baker
Propeller Applications Engineer
Parallax, Inc.