I discovered Python’s delightful abc module (introduced in PEP 3119) a while back, and have been wondering how a similar functionality could be introduced to other dynamic languages (e.g. Lua and Ruby).
Being more familiar with the former, over the weekend I decided to try and write an equivalent module. Two problems came to mind:
- Python uses an @abstractmethod decorator to mark an otherwise-normal function definition. While a decorator pattern can be used in Lua (though not a standard practice), this Python decorator works by setting an attribute in the function it decorates:
funcobj.__isabstractmethod__ = True
This is not an option in Lua, because functions don’t have individual metatables.
- Python has a standard way of doing OOP, and the enforcement that an instantiated class does not contain any abstract method is done in the __new__ method of the ABCMeta metaclass. Contrast to Lua, where OOP is normally done in an ad-hoc manner — and even the LOOP library provides several OOP inheritance mechanisms.
The solution I adopted is delightfully simple: the abc module provides two functions: an amethod function that throws an exception no matter what arguments it is passed, and a verify function that takes a classname, and reflects on the members (using loop.cached.allmembers if possible, falling back to pairs if loop is not installed) and check if any of them is equal to amethod.
This works even on simple tables, though it shifts the responsibility a bit to the programmer: unit tests should be used to verify each created class. As a fallback, attempts to use the abstract methods will fail at runtime, but that’s taking dynamism a bit too far…
Still working out how to get the Pythonic behavior (instantiating a class with some abstract members should fail) when using LOOP. Meanwhile, try it out for yourself and make sure to file bug reports!