View Full Version : Passing objects in Homespun

01-19-2009, 04:54 PM
One of the purposes of my Homespun Spin compiler is to experiment with Spin language extensions. People are always bemoaning the inability to pass object pointers in Spin, so I implemented that functionality. However, I haven't heard of anyone who's actually tried it out, which I attribute to several possible causes:

1. No one knows about this Homespun feature
2. No one uses Homespun
3. Object-passing in Homespun doesn't do what people want

This post is intended to address point 1. Perhaps it will inspire people to get past point 2, and then maybe I'll find out about point 3, which is what I'm really interested in. Since this feature seems so important to people, I'd like to try to get it right. It's in an early stage of development (see caveats below) so there's plenty of room for improvement, but first I'd like to know if I'm on the right track. If the ability to pass object pointers is important to you, please let me know what works and what doesn't from your point of view.

The following totally contrived example involves a main object and a child object. The main object will be passing two kinds of object pointers to the child. The first is to a tv_text object, so that both main and child can print to the screen. The second type of object pointer implements the following two functions:

' IWorker.spin

pub FunctionFirst( a, b )
pub FunctionSecond( a, b )

IWorker is an interface, and the main object contains two worker objects that implement the IWorker interface (in other words, each worker contains public methods that match the description in IWorker.spin).

Here's the main object:

' main.spin

_clkmode = xtal1+pll16x
_xinfreq = 5_000_000

worker1 : "worker1" ' implements IWorker interface
worker2 : "worker2" ' implements IWorker interface
child : "child"
debug : "tv_text"

pub Main | r
debug.start( 0 )
debug.str( string( "Object-passing test", 13 ) )

' We want child to be able to print to the screen, so pass it a pointer to the debug object:

child.Init( debug )

' Now pass a pointer to worker1. child is expecting something that
' implements the the IWorker interface, which worker1 does.

r := child.TestWorker( worker1, 654, 321 )
debug.dec( r )
debug.out( 13 )

' Same thing with worker2.

r := Child.TestWorker( worker2, 654, 321 )
debug.dec( r )
debug.out( 13 )

The child object:

' child.spin

worker : "IWorker" pointer
debug : "tv_text" pointer

pub Init( pDebug )
debug := pDebug

pub TestWorker( pWorker, a, b ) | r1, r2

worker := pWorker
r1 := worker.FunctionFirst( a, b )
debug.str( string( "r1 = " ) )
debug.dec( r1 )
debug.out( 13 )

r2 := worker.FunctionSecond( a, b )
debug.str( string( "r2 = " ) )
debug.dec( r2 )
debug.out( 13 )

return r1 + r2

The first worker object:

' worker1.spin

pri Sum( a, b )
return a + b

pub FunctionFirst( a, b )
return Sum( a, b )

pri Multiply( a, b )
return a * b

pub FunctionSecond( a, b )
return Multiply( a, b )

The second worker object:

' worker2.spin

pri Difference( a, b )
return a - b

pub FunctionFirst( a, b )
return Difference( a, b )

pub FunctionSecond( a, b )
return a / b

The output:

Object-passing test
r1 = 975
r2 = 209934
r1 = 333
r2 = 2


There's no type-checking
You can't dynamically create objects (but I have some ideas here).
Things break if you have two or more child objects; i.e., obj child[ 2 ] : "child" -- passing an object pointer to child[ 0 ] messes up the corresponding pointer in child[ 1 ].

I know that third caveat did prevent one person from using object-passing, but I'm hoping that it's an unusual situation. But who knows, maybe it's more common than I think.

01-19-2009, 05:13 PM
Michael: I haven't been doing much compiling on the prop lately, but when I do I use homespun V022 if I need a listing. The listing output is fantastic and I did tie it to a VB6 program for debugging spin (it sort-of worked, but my VB6 program was terrible :-( ).

Prop Tools under Development or Completed (Index)

My cruising website http://www.bluemagic.biz

01-19-2009, 06:10 PM
mpark: I'm adding the listing of homespun as a source for pPropellerSim (so I do not have to decompile!). The listing is similar enough to Brad's Spin Tool listing (the first I added). I already have symbol loading when a COG is (ahem) loaded with HUB's content. I have to implement a spin debugger using the real interpreter. The current implementation only allows for assembly debug single-step. Great listing !

I cannot comment on your pointer to "object" passing... because I do not use spin. Assembly is for me the way to go http://forums.parallax.com/images/smilies/smile.gif.

01-20-2009, 01:10 AM
This looks very reasonable. I'm not sure I understand caveat 3 though. If child1 modifies passed object data/content, it is reasonable that the object would show up as modified in child2 - though having both write at the same time might yield bad results. Honestly though, data writes should be protected or encapsulated with method calls ... read should not matter. What happens if both try simultaneously calling debug.str(string("hello")) ? Should just work.


01-20-2009, 01:54 AM
It's not that the object data is modified, the object pointer itself only works for one child or the other. A workaround would be to add "debug := saved_pointer_to_debug" before every debug method call in child. I could make Homespun add that code automatically, if there's interest, though I worry about concurrent access. To do it right I'd also need to use a lock.

01-20-2009, 02:19 AM
Having that work-around is good, but would be unexpected to a new developer with previous experience.

Using DAT rather than VAR in drivers like TV_Text make it possible to share a resource. I would use an object pointer with a hardware abstraction layer object to specify the device driver. Of course one could just compile the driver to use instead, but that is limiting.

From a maintenance standpoint, passing an object eleminates having to change 15 files that use the object, but that's where the model is breaking I guess. I've tried using a stub file in spin and object index boundary violation overloading, but couldn't seem to make that work.


09-11-2009, 10:19 PM
Here's a simpler example: a parent and a child both write to a tv_text object.

_clkmode = xtal1 + pll16x
_clkfreq = 80_000_000

term : "tv_text"
child: "test_child"

pub Main
term.start( 20 )
term.str( string( "This is the parent.", 13 ) )

child.Init( term )

term.str( string( "Done.", 13 ) )

' test_child.spin

term : "tv_text" pointer

pub Init( p )
term := p

pub Execute
term.str( string( "Child object here.", 13 ) )

Output on the screen:
This is the parent.
Child object here.

09-12-2009, 10:04 AM
Thanks Michael http://forums.parallax.com/images/smilies/smile.gif

Really nice and simple - congratulations http://forums.parallax.com/images/smilies/smile.gif

Links to other interesting threads:

· Home of the MultiBladeProps: TriBlade (http://forums.parallax.com/showthread.php?p=786418),·RamBlade (http://forums.parallax.com/showthread.php?p=838091), RetroBlade (http://forums.parallax.com/showthread.php?p=838053),·TwinBlade (http://forums.parallax.com/showthread.php?p=806697),·SixBlade (http://forums.parallax.com/showthread.php?p=780033), website (http://bluemagic.biz/cluso.htm)
· Single Board Computer:·3 Propeller ICs·and a·TriBladeProp board (ZiCog Z80 Emulator) (http://forums.parallax.com/showthread.php?p=790917)
· Prop Tools under Development or Completed (Index) (http://forums.parallax.com/showthread.php?p=753439)
· Emulators: Micros eg Altair, and Terminals eg VT100 (Index (http://forums.parallax.com/showthread.php?p=778427)) ZiCog (Z80) (http://forums.parallax.com/showthread.php?p=788511) , MoCog (6809) (http://forums.parallax.com/showthread.php?p=811043)
· Search the Propeller forums (http://search.parallax.com/search?site=parallax&client=parallax&output=xml_no_dtd&proxystylesheet=parallax&proxycustom=<HOME/>&ie=&oe=&lr=)·(uses advanced Google search)
My cruising website is: ·www.bluemagic.biz (http://www.bluemagic.biz)·· MultiBladeProp is: www.bluemagic.biz/cluso.htm (http://www.bluemagic.biz/cluso.htm)