🙜 Fugue 🙞

 
🙑   🙗

Objects for Janet

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.

🙦   🙤

Programming with Prototypes

π–‹π–šπ–Œπ–šπ–Š 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.

🙦   🙤

Easy Methods

π–‹π–šπ–Œπ–šπ–Š 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.

🙦   🙤

Multimethods, Open and Closed

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.

🙦   🙤

How to get π–‹π–šπ–Œπ–šπ–Š

Specify a dependency in your project.janet:

  :dependencies ["fugue"]

or

  :dependencies ["https://git.sr.ht/~subsetpark/fugue"]
🙦   🙤

More Examples

You can read an example Regex implementation in π–‹π–šπ–Œπ–šπ–Š here: The Brzozowski Variations

🙦   🙤

Source

π–‹π–šπ–Œπ–šπ–Š is hosted on Sourcehut. You can read the full README too.