Classes

Classes in legionhjyu use the ritual keyword. The constructor is always named awaken. Methods use blade and take self as the first parameter.

Basic class

lhj
ritual Warrior:
    blade awaken(self, name: str, hp: int = 100):
        self.name = name
        self.hp   = hp

    blade attack(self, target):
        target.hp <- target.hp - 20
        echo "{self.name} attacks {target.name} for 20 damage!"

    blade alive(self) -> yep:
        release self.hp > 0

forge w = Warrior("Aria")
forge e = Warrior("Shadow", 60)

w.attack(e)
echo e.alive()    ## nope (60 - 20 = 40 > 0, so this would be yep actually)

Class variables

Declare variables directly inside the ritual body (outside any blade) to make them class-level:

lhj
ritual Counter:
    forge count = 0

    blade awaken(self):
        Counter.count <- Counter.count + 1
        self.id = Counter.count

    blade total() -> int:
        release Counter.count

forge a = Counter()   ## count = 1
forge b = Counter()   ## count = 2
forge c = Counter()   ## count = 3

echo Counter.count    ## 3
echo a.id             ## 1

Inheritance

lhj
ritual Animal:
    blade awaken(self, name: str):
        self.name = name

    blade speak(self):
        echo "{self.name} makes a sound"

ritual Dog extends Animal:
    blade speak(self):
        echo "{self.name} barks!"

    blade fetch(self):
        echo "{self.name} fetches the ball!"

forge d = Dog("Rex")
d.speak()     ## Rex barks!
d.fetch()     ## Rex fetches the ball!

invoke — calling the parent method

invoke calls the parent class's version of a method. It's the super() equivalent.

lhj
ritual Animal:
    blade awaken(self, name: str):
        self.name = name
        echo "Animal created: {name}"

ritual Dog extends Animal:
    blade awaken(self, name: str, breed: str):
        invoke awaken(self, name)       ## calls Animal.awaken
        self.breed = breed
        echo "Dog breed: {breed}"

forge d = Dog("Rex", "Labrador")
## Animal created: Rex
## Dog breed: Labrador

invoke methodname(self, args...) dispatches to the nearest parent that defines that method.

Method chaining

Return self from a method to enable chaining:

lhj
ritual Builder:
    blade awaken(self):
        self.parts = []

    blade add(self, part):
        self.parts.pack(part)
        release self

    blade build(self):
        release " + ".join(self.parts)

forge result = Builder().add("sword").add("shield").add("potion").build()
echo result    ## sword + shield + potion

Dunder methods

legionhjyu recognizes a set of special methods that let classes work with built-in operations:

MethodWhen called
__str__(self)str(obj) or string interpolation
__len__(self)len(obj)
__eq__(self, other)obj == other
__add__(self, other)obj + other
__lt__(self, other)obj < other
lhj
ritual Vec2:
    blade awaken(self, x, y):
        self.x = x
        self.y = y

    blade __add__(self, other):
        release Vec2(self.x + other.x, self.y + other.y)

    blade __str__(self):
        release "Vec2({self.x}, {self.y})"

forge a = Vec2(1, 2)
forge b = Vec2(3, 4)
forge c = a + b
echo c    ## Vec2(4, 6)

Checking instance type

lhj
forge w = Warrior("Aria")

echo type(w)              ## Warrior
echo isinstance(w, Warrior)   ## yep