1

I have a base class in PHP Hack with a function:

// This method is used to return just one Apple Type
protected static function Apple(): AppleType {
    return AppleType;
}

Now I have two types of classes - one using a base trait, one doesn't.

The trait has the below function:

// This method is used to return more than one Apple Type
protected static function Apples(): keyset[AppleType] {
    return keyset[AppleType];
}

The child classes which don't use this trait can override the base class Apple() method. But the classes which do use the trait, must override Apples() and not Apple().

Now I want to provide an invariant exception:

Something like:

invariant(Apple() is not overridden in this class, 'Class must override Apples() and not Apple()');

i.e. invariant to provide enforcement that a class using trait must not be able to override base class's Apple() and throws exception during runtime.

Please help me in writing this invariant. I tried many things, but somehow it doesn't work right.

Wilfred Hughes
  • 29,846
  • 15
  • 139
  • 192
ADT
  • 11
  • 4
  • Traits shouldn't create requirements unless it uses them. You _could_ force subclasses to implement an interface with an `apples()` signature via [trait and interface requirements](https://docs.hhvm.com/hack/classes/trait-and-interface-requirements), but _only if_ methods in that trait use the method `apples()`. Should `apples()` be abstract in your example? Can you share more about why you want to enforce this invariant? – concat Jul 19 '20 at 03:06

1 Answers1

0

You could define a class with a final method, and require that trait users extends that class.

enum AppleType: int {
  Fresh = 1;
  Stale = 2;
}

class Overridable {
  protected static function Apple(): AppleType {
    return AppleType::Fresh;
  }
}

class MustUseApples extends Overridable {
  <<__Override>>
  final protected static function Apple(): AppleType {
    return parent::Apple();
  }
}

trait MyTrait {
  require extends MustUseApples;

  protected static function Apples(): keyset<AppleType> {
    return keyset[AppleType::Stale];
  }
}

However, if you want to require that trait users must provide an implementation of Apples, you should probably make it an abstract method on MustUseApples.

Wilfred Hughes
  • 29,846
  • 15
  • 139
  • 192