MOGWAI v8.6 : Objets et assertions

MOGWAI vient de passer en version 8.6, et cette release apporte deux fonctionnalités attendues de longue date : un système complet de programmation orientée objet, et une primitive d’assertion intégrée. Tour d’horizon.

La POO dans un langage à pile

Si vous suivez MOGWAI depuis un moment, vous savez que le langage est fondamentalement concaténatif et basé sur une pile, inspiré des calculatrices HP RPL. Ajouter la POO à un tel langage soulève une question évidente : est-ce que ça a vraiment du sens ?

La réponse est oui, et voilà pourquoi.

MOGWAI disposait déjà des records (structures clé-valeur nommées), des fonctions, et d’un système de types riche. Ce qui manquait, c’était la possibilité de lier des données et des comportements, de donner un nom à cet ensemble, et de gérer plusieurs instances indépendantes. C’est exactement ce que la v8.6 apporte.

Définir une classe

Les classes se définissent avec le mot-clé class, suivi du nom de la classe, du mot-clé do, et d’un bloc contenant deux sections : private: et public:.

class 'Counter' do
{
private:
{
_step: .number
}

public:
{
value: .number

onInit:
{
[step: (.number 1)] ->params

self->reset:
step self<-_step:
}

increment:
{
self->value: self->_step: + self<-value:
}

reset:
{
0 self<-value:
}
}
}

Les propriétés sont déclarées avec un sigil de type (.number, .string, .bool, .any…). Les méthodes sont déclarées avec un bloc de code { }. La distinction est faite à l’analyse syntaxique sans ambiguïté.

Hooks de cycle de vie

Deux méthodes spéciales sont reconnues par le moteur :

  • onInit: appelée automatiquement à la création d’une instance avec new. Elle reçoit les paramètres nommés passés à la création.
  • onFree: appelée automatiquement juste avant la destruction d’une instance avec free.

Créer et utiliser des instances

# Créer une instance — onInit: est appelée automatiquement
[id: 10 name: "SIBUE"] 'User' new -> '$U1'

# Lire une propriété publique
$U1->name: ?

# Écrire une propriété publique
"DUPONT" &$U1<-name:

# Appeler une méthode publique
$U1->display:

# Vérifier qu'une instance est encore en vie
$U1 isAlive

# Détruire l'instance — onFree: est appelée automatiquement
$U1 free

La notation -> et <- sera naturelle pour quiconque a utilisé la syntaxe des records MOGWAI. Lire depuis une instance, y écrire, appeler une méthode, tout est cohérent avec le reste du langage.

self — l’instance courante dans une méthode

À l’intérieur de n’importe quelle méthode, self est automatiquement disponible et référence l’instance courante :

display:
{
"USER={! self}" eval ?
self->show: # appelle une méthode privée
}

Utiliser self en dehors d’une méthode lève une erreur.

Encapsulation sans héritage

Ce système POO est délibérément simple : pas d’héritage, pas de garbage collector. Vous avez le contrôle total de la création et de la destruction des instances.

Les membres privés sont strictement inaccessibles depuis l’extérieur de la classe. La propriété réservée en lecture seule className: est automatiquement disponible sur chaque instance et retourne le nom de la classe à laquelle elle appartient :

$U1->className: ?   # → 'User'

Plusieurs variables peuvent référencer la même instance. Si l’instance est libérée, toutes les variables qui pointent dessus deviennent invalides. Le prédicat isAlive permet de vérifier en toute sécurité avant d’y accéder :

if ($U1 isAlive) then
{
$U1->display:
}

isAlive est une recherche en O(1), il ne lève jamais d’erreur sur une référence morte, il renvoie simplement false.

Validation des paramètres de méthode

MOGWAI propose trois niveaux de validation des entrées dans les méthodes, tous parfaitement utilisables au sein des classes :

  • ->vars : déstructuration simple, sans vérification de type
  • ->safeVars : déstructuration avec validation de type
  • ->params : record de paramètres nommés avec types et valeurs par défaut optionnelles (le choix naturel pour onInit:)
onInit:
{
[id: .number name: .string index: (.number 0)] ->params

id self<-id:
name self<-name:
index self<-index:
}

mogwai.assert : Les préconditions à la sauce MOGWAI

Le deuxième ajout majeur de la v8.6 est mogwai.assert.

Il vérifie qu’une condition est vraie. Si elle est fausse, il lève l’erreur MW.9 (assert error) et stoppe l’exécution. Si MOGWAI.onError est défini, il sera déclenché automatiquement.

La signature est simple :

condition "message" mogwai.assert

La condition peut être :

  • Une liste évaluée automatiquement. mogwai.assert vérifie qu’exactement un booléen a été poussé sur la pile après l’exécution.
  • Un booléen déjà sur la pile utilisé directement.
# Forme liste, condition évaluée par mogwai.assert
(a 10 ==) "a doit être égal à 10" mogwai.assert

# Forme booléenne, résultat déjà sur la pile
a 0 > "a doit être positif" mogwai.assert
a ->type .list == "a doit être une liste" mogwai.assert

Le message est affiché avec l’erreur, c’est une information de diagnostic, pas une valeur. Il n’est pas accessible programmatiquement via error.last, qui renvoie MW.9.

Le cas d’usage évident : les préconditions dans les fonctions

to 'divide' with [x: .number y: .number] do
{
(y 0 !=) "le diviseur ne doit pas être zéro" mogwai.assert
x y /
}

C’est le pattern pour lequel mogwai.assert a été conçu : protéger le point d’entrée d’une fonction, échouer immédiatement et clairement si le contrat est violé.

Il peut aussi servir pour des tests en script, pour valider des hypothèses sur l’état à un moment donné de l’exécution, sans avoir besoin d’un framework de test externe.

Et maintenant ?

La v8.6 est disponible dès maintenant sur NuGet et GitHub.

La documentation complète a été mise à jour. Exemples, changelog et playground sont disponibles sur mogwai.eu.com.

Si vous découvrez MOGWAI — un moteur de scripting RPN basé sur une pile pour .NET, open-sourcé sous licence Apache 2.0 — le README est le meilleur point de départ.

Vos retours sont les bienvenus dans les Discussions.

Laisser un commentaire

En savoir plus sur CODING 4 PHONE

Abonnez-vous pour poursuivre la lecture et avoir accès à l’ensemble des archives.

Poursuivre la lecture

En savoir plus sur CODING 4 PHONE

Abonnez-vous pour poursuivre la lecture et avoir accès à l’ensemble des archives.

Poursuivre la lecture