Passing objects in Homespun

mparkmpark Posts: 1,146
edited September 2009 in Propeller 1 Vote Up0Vote Down
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

con
_clkmode = xtal1+pll16x
_xinfreq = 5_000_000

obj
  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

obj
  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
210909
r1 = 333
r2 = 2
335




Caveats:
  • 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[noparse][[/noparse] 2 ] : "child" -- passing an object pointer to child[noparse][[/noparse] 0 ] messes up the corresponding pointer in child[noparse][[/noparse] 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.

Comments

  • 8 Comments sorted by Date Added Votes
  • Cluso99Cluso99 Posts: 12,515
    edited January 2009 Vote Up0Vote Down
    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)
    http://forums.parallax.com/showthread.php?p=753439

    My cruising website http://www.bluemagic.biz
    My Prop boards: P8XBlade2, RamBlade, CpuBlade, TriBlade
    Prop OS (also see Sphinx, PropDos, PropCmd, Spinix)
    Website: www.clusos.com
    Prop Tools (Index) , Emulators (Index) , ZiCog (Z80)
  • AleAle Posts: 2,277
    edited January 2009 Vote Up0Vote Down
    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 smile.gif.
  • jazzedjazzed Posts: 11,795
    edited January 2009 Vote Up0Vote Down
    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.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    --Steve
  • mparkmpark Posts: 1,146
    edited January 2009 Vote Up0Vote Down
    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.
  • jazzedjazzed Posts: 11,795
    edited January 2009 Vote Up0Vote Down
    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.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    --Steve
  • mparkmpark Posts: 1,146
    edited September 2009 Vote Up0Vote Down
    Here's a simpler example: a parent and a child both write to a tv_text object.

    _clkmode = xtal1 + pll16x
    _clkfreq = 80_000_000
    
    obj
      term : "tv_text"
      child: "test_child"
    
    pub Main
      term.start( 20 )
      term.str( string( "This is the parent.", 13 ) )
      
      child.Init( term )
      child.Execute
    
      term.str( string( "Done.", 13 ) )
    
    


    ' test_child.spin
    
    obj
      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.
    Done.
  • Cluso99Cluso99 Posts: 12,515
    edited September 2009 Vote Up0Vote Down
    Thanks Michael smile.gif

    Really nice and simple - congratulations smile.gif

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Links to other interesting threads:

    · Home of the MultiBladeProps: TriBlade,·RamBlade, RetroBlade,·TwinBlade,·SixBlade, website
    · Single Board Computer:·3 Propeller ICs·and a·TriBladeProp board (ZiCog Z80 Emulator)
    · Prop Tools under Development or Completed (Index)
    · Emulators: Micros eg Altair, and Terminals eg VT100 (Index) ZiCog (Z80) , MoCog (6809)
    · Search the Propeller forums·(uses advanced Google search)
    My cruising website is: ·www.bluemagic.biz·· MultiBladeProp is: www.bluemagic.biz/cluso.htm
    My Prop boards: P8XBlade2, RamBlade, CpuBlade, TriBlade
    Prop OS (also see Sphinx, PropDos, PropCmd, Spinix)
    Website: www.clusos.com
    Prop Tools (Index) , Emulators (Index) , ZiCog (Z80)
Sign In or Register to comment.