Programmation orientée objet en CodeFR

CodeFR propose un support simple de la programmation orientée objet grâce aux mots-clés Classe, Nouveau et Soi. Une classe regroupe des champs (les données) et des méthodes (le comportement) sous un même nom, et Nouveau permet de créer des objets (aussi appelés instances) à partir de cette classe.

Ce support reste volontairement simple : il n'y a pas d'héritage, pas de modificateurs de visibilité (public/privé) et pas de surcharge de méthodes. Tous les champs et toutes les méthodes sont accessibles partout — voir la section Limites actuelles en fin de page.


1. Déclarer une classe

Une classe se déclare avec Classe ... FinClasse, avant le bloc Debut ... Fin du programme. Elle contient des champs (déclarés avec Variable, comme d'habitude) et des méthodes (déclarées avec Fonction ... FinFonction, exactement comme une fonction classique).

Syntaxe

Classe NomClasse
    Variable champ1: Type1
    Variable champ2: Type2

    Fonction NomMethode(param: Type)
        // Instructions
    FinFonction
FinClasse

Exemple

Classe Personne
    Variable nom: Chaine
    Variable age: Entier

    Fonction SePresenter()
        Ecrire("Je suis ", Soi.nom, ", j'ai ", Soi.age, " ans.\n")
    FinFonction
FinClasse

2. Le constructeur

Il n'existe pas de mot-clé dédié pour le constructeur : il s'agit simplement d'une méthode nommée exactement Constructeur. Elle est appelée automatiquement lors de la création d'un objet avec Nouveau, et sert à initialiser les champs. Un constructeur ne peut pas déclarer de type de retour.

Si aucune méthode Constructeur n'est définie et que Nouveau est appelé sans argument, les champs prennent simplement leur valeur par défaut habituelle (0 pour Entier, "" pour Chaine, etc.).

Syntaxe

Fonction Constructeur(param1: Type1, param2: Type2)
    Soi.champ1 = param1
    Soi.champ2 = param2
FinFonction

Exemple

Classe Personne
    Variable nom: Chaine
    Variable age: Entier

    Fonction Constructeur(n: Chaine, a: Entier)
        Soi.nom = n
        Soi.age = a
    FinFonction

    Fonction SePresenter()
        Ecrire("Je suis ", Soi.nom, ", j'ai ", Soi.age, " ans.\n")
    FinFonction
FinClasse

Variable p: Personne

Debut
    p = Nouveau Personne("Ada", 30)
    p.SePresenter()
Fin

Ce programme affiche :

Je suis Ada, j'ai 30 ans.

3. Créer un objet avec Nouveau

Nouveau NomClasse(arguments) crée un nouvel objet et appelle son Constructeur avec les arguments fournis. Le résultat s'affecte à une variable typée avec le nom de la classe, exactement comme on écrirait Variable x: Entier pour un entier.

Variable p: Personne

Debut
    p = Nouveau Personne("Ada", 30)
Fin

Quelques erreurs courantes que l'interpréteur détecte pour vous :

  • Nouveau sur une classe qui n'existe pas → erreur la classe '...' n'est pas définie.
  • Un nombre d'arguments différent de celui attendu par Constructeur → erreur explicite indiquant le nombre attendu et le nombre fourni.

4. Soi : accéder à l'instance courante

À l'intérieur d'une méthode (ou du constructeur), Soi désigne l'objet sur lequel la méthode a été appelée — l'équivalent de self/this dans d'autres langages. Il permet de lire ou modifier les champs de l'objet, et d'appeler ses autres méthodes.

Fonction SePresenter()
    Ecrire("Je suis ", Soi.nom, ", j'ai ", Soi.age, " ans.\n")
FinFonction

Soi n'a de sens qu'à l'intérieur d'une méthode : l'utiliser ailleurs (par exemple directement dans le bloc Debut ... Fin) provoque une erreur, puisque Soi n'y est pas déclaré.


5. Lire, écrire et appeler

Une fois un objet créé, on accède à ses champs et méthodes avec la notation pointée (.), aussi bien depuis l'extérieur de la classe qu'à travers Soi depuis l'intérieur :

p.nom = "Grace"        // écriture d'un champ (la valeur est convertie au type déclaré)
Ecrire(p.nom)           // lecture d'un champ
p.SePresenter()         // appel d'une méthode

Piège à éviter : une variable objet déclarée mais jamais initialisée avec Nouveau ne contient rien d'utilisable. L'utiliser (par exemple lire un de ses champs) avant de lui avoir affecté Nouveau NomClasse(...) provoque une erreur d'exécution explicite plutôt qu'un comportement silencieux.


6. Composition : un objet dans un autre objet

Un champ peut lui-même être typé avec le nom d'une autre classe. On parle alors de composition : un objet « contient » un autre objet. Les accès en chaîne (p.adresse.ville) fonctionnent naturellement.

Classe Adresse
    Variable ville: Chaine

    Fonction Constructeur(v: Chaine)
        Soi.ville = v
    FinFonction
FinClasse

Classe Personne
    Variable nom: Chaine
    Variable adresse: Adresse

    Fonction Constructeur(n: Chaine, a: Adresse)
        Soi.nom = n
        Soi.adresse = a
    FinFonction

    Fonction Ville(): Chaine
        Retourner Soi.adresse.ville
    FinFonction
FinClasse

Variable a: Adresse
Variable p: Personne

Debut
    a = Nouveau Adresse("Paris")
    p = Nouveau Personne("Ada", a)
    Ecrire(p.nom, " habite a ", p.Ville(), ".\n")
Fin

Ce programme affiche :

Ada habite a Paris.

7. Les objets sont des références

Une variable objet ne contient pas une copie de l'objet, mais une référence vers lui. Affecter une variable objet à une autre ne duplique donc pas l'objet : les deux variables désignent le même objet.

Classe Compteur
    Variable n: Entier
FinClasse

Variable c1, c2: Compteur

Debut
    c1 = Nouveau Compteur()
    c2 = c1
    c2.n = 42
    Ecrire(c1.n)
Fin

Ce programme affiche 42, alors que c'est c2 qui a été modifié : c1 et c2 désignent le même objet. Pour la même raison, comparer deux objets avec == compare leur identité (s'agit-il du même objet ?) et non le contenu de leurs champs — contrairement aux Chaine, Entier ou Decimal, qui se comparent par valeur.


8. Classes et modules

Une classe peut être définie dans un module (un fichier .cfr séparé, voir la page Modules) au même titre qu'une fonction, et importée de la même manière.

Exemple – Module FormesGeo.cfr

Classe Cercle
    Variable rayon: Decimal

    Fonction Constructeur(r: Decimal)
        Soi.rayon = r
    FinFonction

    Fonction Aire(): Decimal
        Retourner 3.14159 * Soi.rayon * Soi.rayon
    FinFonction
FinClasse

Import complet du module

Avec Importer, la classe s'utilise préfixée du nom du module, aussi bien dans le type que dans Nouveau :

Importer FormesGeo

Variable c: FormesGeo.Cercle

Debut
    c = Nouveau FormesGeo.Cercle(2.0)
    Ecrire(c.Aire())
Fin

Import ciblé de la classe

Avec Depuis ... Importer, la classe s'utilise sans préfixe :

Depuis FormesGeo Importer Cercle

Variable c: Cercle

Debut
    c = Nouveau Cercle(1.0)
    Ecrire(c.Aire())
Fin

Limite connue : si un module contient plusieurs classes qui se référencent entre elles par leur nom non préfixé (par exemple une classe Roue utilisée comme type de champ dans une classe Voiture du même module), l'import échoue. Une classe seule, ou plusieurs classes indépendantes les unes des autres, s'importent en revanche sans problème.


9. Limites actuelles

Le support de la programmation orientée objet en CodeFR reste volontairement minimal :

  • Pas d'héritage : une classe ne peut pas hériter d'une autre.
  • Pas de modificateurs de visibilité : tous les champs et méthodes sont accessibles depuis n'importe où (pas de public/privé).
  • Pas de surcharge de méthodes : une méthode ne peut pas avoir plusieurs versions selon les types de ses paramètres.

Résumé

Élément Exemple Description
Déclaration de classe Classe Personne ... FinClasse Regroupe champs et méthodes
Constructeur Fonction Constructeur(n: Chaine) Initialise les champs à la création
Création d'un objet p = Nouveau Personne("Ada", 30) Instancie la classe et appelle le constructeur
Référence à soi-même Soi.nom Accède à l'instance courante dans une méthode
Lecture/écriture d'un champ p.nom / p.nom = "Grace" Accède ou modifie un champ
Appel de méthode p.SePresenter() Exécute une méthode de l'objet
Classe importée Depuis FormesGeo Importer Cercle Utilise une classe définie dans un module

La programmation orientée objet permet de regrouper données et comportements liés, et de modéliser des concepts du monde réel de façon claire — un outil précieux dès que vos programmes CodeFR grandissent en complexité.