2021/05/28/a kluge using abstract methods

From Woozle Writes Code
Jump to navigation Jump to search
Codeblog

I don't know if I'll end up using this technique or not, but I thought I'd make a note of it because of the underlying problem it illustrates.

  • I have a number of traits which need to be initialized somehow.
  • It turns out to be a bad idea to define constructors inside traits, because the different classes that use those traits may have different constructor arguments.
    • In other words, there's no clean way to have a trait call the constructor of a class that uses it, unless you carefully restrict what classes can use it...
      • ...and even if that were desirable (which it is in some circumstances), there's no way to enforce it.
  • I had resorted to putting notes in the trait documentation -- like "HOSTING: host must call [name_of_trait_initialization_method]"...
    • ...but when a trait is several layers deep in other traits (which happens a lot with the method/routing pattern I use), this can be easy to overlook.

The solution I'm trying is to just define an abstract method named "Call_[name_of_initialization_method]". Whatever host does the calling simply defines this method with no code, to signal that the call has happened. This serves as nothing more than a reminder to the coder that a thing needs to be done when using a given trait.

Example

/*::::
  HOSTING: Host must call CreatePortBank() before calling PortBank().
*/
trait tMaker {
    use tUser;
    abstract protected function Call_CreatePortbank();  // a reminder
    protected function CreatePortBank() {
        $sClass = $this->PortBankClass();
        $os = $this->Space();
        $op = $os->MakePiece($this->PortBankPieceName());
        $of = new $sClass($os);
        $op->SetIt($of);
    }
    abstract protected function PortBankClass() : string;
}