Janet is an easy-to-use and powerful programming language in the Lisp tradition. It provides a simple, effective core of functionality to build object-oriented systems on top of; Janet tables can have prototypes from which they inherit fields, and tables can store functions that are called as methods.
πππππ is a library that builds on top of Janetβs OO features to provide a fuller object system. Itβs inspired most directly by the Common Lisp Object System, but itβs structured differently and exposes different features.
πππππ provides a useful and comfortable way of declaring prototypes and prototype hierarchies. For instance: letβs build the traditional OO example and set up a little taxonomy.
repl> (defproto Animal ()
kingdom {:allocate-value "Animalia"})
repl> (defproto Bird Animal
class {:allocate-value "Aves"})
repl> (def warbler (:new Bird))
@Bird{:_meta @{:object-id Bird_00000t
:object-type :instance}}
repl> (kingdom warbler)
"Animalia"
repl> (class warbler)
"Aves"
We create a one prototype Animal, then a prototype Bird that inherits from Animal, and instantiate a single Bird. That instance has access to the fields on its parent and grandparent.
πππππ provides generic functions, which allow the programmer to easily specialize the behaviour of functions for different prototypes.
To continue the traditional example:
repl> (defgeneric move [x] "*moves*")
repl> (defmethod move Animal [x] "*gallumphs*")
repl> (defmethod move Bird [x] "*flaps*")
repl> (move (:new Animal))
"*gallumphs*"
repl> (move warbler)
"*flaps*"
repl> (move :something-else)
"*moves*"
The same function, when called on different data types, can behave differently.
Finally, πππππ provides multimethodsβpowerful ways to define typed behaviour for all the arguments in a function.
repl> (defmulti interact [Bird Bird]
[self other]
(string (self :name)
" puts on a mating display"))
repl> (defmulti interact [Bird Animal]
[self other]
(string (self :name)
" flies away"))
repl> (def tweety (:new Bird :name "Tweety"))
repl> (interact tweety (:new Bird))
"Tweety puts on a mating display"
repl> (interact tweety (:new Animal))
"Tweety flies away"
This allows us to write highly generic, flexible behaviour.
Multimethods can be defined and fixed in a single module, or can be declared open, so that other later execution environments can extend their behaviour with new cases.
Specify a dependency in your project.janet
:
:dependencies ["fugue"]
or
:dependencies ["https://git.sr.ht/~subsetpark/fugue"]
You can read an example Regex implementation in πππππ here: The Brzozowski Variations
πππππ is hosted on Sourcehut. You can read the full README too.