Shop OBEX P1 Docs P2 Docs Learn Events
interfaces -- a proposal for a Spin2 extension — Parallax Forums

interfaces -- a proposal for a Spin2 extension

I've been experimenting with a Spin2 extension to make writing generic objects that interact with other objects easier. This adds "interfaces", which are kind of like structs but which only have methods (no variables). The syntax is like structs:

CON
   %interface io(
      PUB tx(c)
      PUB rx(): r
   )

   PUB printstr(^io f, s) | c
      repeat while (c:=byte[s++])
        f.tx(c)

The idea of an interface is that it can match any object which provides all of the methods specified in the interface. So for example, if you have two objects Serial and LCD which both provide tx and rx methods, you could do:

  printstr(@serial, @"Hello on Serial")
  printstr(@lcd, @"Hello on LCD")

That is, the printstr method from above can accept a pointer to any object that implements tx and rx.

IMPLEMENTATION

This is the tricky part, of course. I'm not sure how best to do this in PNut, but in Flexspin (for now) the interface objects are basically just collections of method pointers. When an object parameter has to match an interface, the compiler checks to see if it has an interface skeleton corresponding to that object, and if necessary builds one. Then it inserts runtime code to convert that skeleton, plus the object pointer, into a new object pointer to the interface.

ALTERNATIVE IMPLEMENTATION

Another way to implement interfaces would be to make the interface pointer itself a method pointer, which takes as argument a method index, and returns a new method pointer which should be invoked for the given method. That is, the call:

  f.tx(c)  ' f is an interface pointer

would actually be translated like

  (f(TX_INDEX))(c)

Where f(TX_INDEX) returns the method pointer for tx of whatever object f originally was.

Then for each object that has to implement an interface we'd add a function that just switches on its argument and returns the new method pointer, like:

Serial GetInterface_Io(idx) : r
  case idx
    TX_INDEX: return @tx
    RX_INDEX: return @rx

In some cases it may be possible to optimize this further, by arranging the original object's method dispatch table in a way that makes finding the interface equivalent trivial.

Comments

  • Great, this is better than pointer to objects which is one my wish list.

  • RaymanRayman Posts: 15,212

    How far away is all of this from being a C++ style "class"?

    Maybe can work with FlexProp C style limitations on the class?

Sign In or Register to comment.