Something I've done in some golang code recently is to fake some OO features. I'd appreciate some commentary on the approach.
So I want a few different, but similar things. These are actually stages in a processing pipeline, each stage doing different processing steps.
What I'm currently doing, which mostly works well, is to have a struct type ('Stage') which does all the generic work (equivalent to an abstract base class in C++). The Stage contains a function ptr ('Each') to actually do the processing step.
I can then have various 'derived' types which embed 'Stage'. Each one is assembled via a ctor which sets up the 'Each' function ptr. Effectively this provides inheritance with method overloading for the Each function.
I also have an interface ('Stager') which is satisfied by the Stage type, and so consequently by all the derived types (since they embed Stage).
So, I seem to have most of the benefits of C++ abstract base class and 'inheritance' (of data and methods), including overriding of methods by subclasses (using explicit assignment to function ptr).
It feels pretty nice to work with. The main concern I have is the slight klunkiness of the Stage/Stager duality. I also don't think I'd like this if I had many overridden methods (I just have one atm).
Anyone care to comment on a better way to this or other critique?
To me, it feels like you're implementing too much of the OO behavior yourself. That is essentially the same as saying that the language isn't really object oriented.
It's really the code to connect the stages. I want to support 1->many, so a single stage can fan out it's output to multiple consumers.
The code which wants to be generic is in the handling of things like setting up channels between stages, handling data passing between them and cancellation (shutdown).
I also want to support a layer of abstraction, where I can compose a graph of stages into a single stage.
The goal is to have a number of primitive processing stages and allow abstraction and composition to build more complex processing.
Basically I could move to a pure interface and associated functions (not methods). That would perhaps be more idiomatic go. It's just a slight shame that a bunch of code which lives to my mind slightly more naturally as a set of methods on a type gets promoted to top-level package functions due to the inabillity to define methods on an interface. But that's probably OK.
So I want a few different, but similar things. These are actually stages in a processing pipeline, each stage doing different processing steps.
What I'm currently doing, which mostly works well, is to have a struct type ('Stage') which does all the generic work (equivalent to an abstract base class in C++). The Stage contains a function ptr ('Each') to actually do the processing step.
I can then have various 'derived' types which embed 'Stage'. Each one is assembled via a ctor which sets up the 'Each' function ptr. Effectively this provides inheritance with method overloading for the Each function.
I also have an interface ('Stager') which is satisfied by the Stage type, and so consequently by all the derived types (since they embed Stage).
So, I seem to have most of the benefits of C++ abstract base class and 'inheritance' (of data and methods), including overriding of methods by subclasses (using explicit assignment to function ptr).
It feels pretty nice to work with. The main concern I have is the slight klunkiness of the Stage/Stager duality. I also don't think I'd like this if I had many overridden methods (I just have one atm).
Anyone care to comment on a better way to this or other critique?