Ravi
Welcome
Documentation
Documentation
About Ravi
Documentation
Introduction
Premiers pas avec Ravi
ravitool
Objets Scheme
Le shell ravi
Starting Ravi
Le module trace
Les ports d'E/S
load, require, modules
Système d'interruptions
Scheme compiler
C++ mode
Generating C++ modules
La déclaration struct
Le type "C-object"
More information
Installation

[PREV][SUIV]

Generating C++ modules

./ug_make_module.scml

On trouve sur cette page:

Creation de modules C++

./ug_make_module.scml

avant de lire ce chapitre, regardez l'exemple: LISEZMOI.C++ravi

1a - Introduction

./ug_make_module.scml

La génération d'interface prend comme données:


	* les déclaration de prototypes des fonctions C++ à interfacer.
	  En général, ces déclarations se trouvent dans un ou plusieurs
	  fichiers .h

* un fichier dit "fichier de phases", de type .ph, qui permet de contrôler plus ou moins finement les détails des fichiers générés.

Plusieurs fichiers sont générés automatiquement, partant d'un fichier nom.ph:


	* un fichier nom.cc avec des fonctions C qui devra être compilé
	* un fichier nom.x.scm qui sera chargé sous Ravi
	* un fichier nom.tags avec des tags pour emacs
	* un fichier nom.libs utile seulement sous SunOS4

La génération d'un module comporte plusieurs étapes:

  1. Analyse syntaxique du source en C++
  2. Création des fonctions d'interface dans un fichier .cc généré de facon entièrement automatique.
  3. Compilation de ce fichier
  4. Edition des liens, chargement du résultat.

Il est facile de comprendre que tout cela ne peut pas etre 100% automatique: par exemple, les librairies nécessaires a l'édition des liens ne peuvent pas etre inventés. En fait, chaque étape peut avoir besoin d'informations qui ne figurent pas dans le fichier .h initial - voilà pourquoi on introduit des déclarations.

La génération est donc semi-automatique : L'essentiel du travail est réalisé par le générateur, mais le concepteur du module doit lui fournir quelques informations supplementaires pour le guider.

1.b La commande r-ig

./ug_make_module.scml


 ravi -mod r-ig nom
 ravi -mod r-ig -cc nom

Nom est le nom du module. On cherche le fichier nom.ph ou nom.h - oui, on peut générer l'interface à partir du seul fichier .h!

2- Le fichier de prototypes

./ug_make_module.scml

Le fichier de prototype contient les éléments pour lesquels on veut générer une interface -fonctions, classes, typedef- au format C++ :


int ma_fonction(int x, int y);
 

class UneClasse{ public: void SetValue(float v); void SetValue(int i); };

2.1 : Ce que peut contenir un fichier de prototype

./ug_make_module.scml

Un fichier de prototype peut contenir des declarations de fonctions, de classes, de types, et des commentaires.


// Declaration des types
class Classe1;
struct Classe2;
typedef int montype;
 int fn1();
void fn2(int, int);

Il y a des restrictions sur les commandes du macro-processeur. cf. ci-apres En tout état de cause, seulement certaines de ces commandes seront exécutées. En particulier, les fichiers #include ne sont pas lus: si un fichier #include définit des types - classes, structures, typdef, ..., ils doivent être introduits par des déclarations explicites, sinon l'analyse syntaxique aura des problèmes!

je repete IMPORTANT

La première phase de la génération effectue une analyse syntaxique des prototypes (plus exactement: de toutes les phase %%input), mais elle ne consulte pas les fichiers inclus avec #include. Or, l'analyseur a besoin de connaitre tous les noms de types.

Conséquence

./ug_make_module.scml

Si un fichier #include contient des déclarations de types qui sont utilisés par la suite, il faut les indiquer dans une déclaration pour le générateur, sous une des formes suivantes :

* plusieurs déclarations dans la phase %%declare impliquent qu'il s'agit d'un type

* dans une phase %%input, inclure class toto; etc.

Ceci est encore plus vrai pour les noms de template! D'où la possibilité de déclarer


   template toto;

2.1 : Ce que DOIT contenir le fichier de prototype

./ug_make_module.scml

Pour l'analyse syntaxique de C ou de C++, il est indispensable de connaitre les identificateurs de types. C'est pourquoi il faut mettre en debut de fichier la declaration de ces differents types :

 
typedef int montype;
class Classe1;
struct Struct1;

Inutile de recopier la declaration complete de la classe si vous ne souhaitez pas générer une interface pour elle. Seule la declaration de l'existence du type est necessaire.

NB: Ceci est le fait de la grammaire de C et de C++ en général et non pas de notre analyseur syntaxique. Tous les compilateurs necessitent la declaration des identificateurs de type avant qu'il y soit fait reference.

3 -Le fichier de phases

./ug_make_module.scml

Le fichier de phases dirige la génération dans ses grandes lignes, donnant des précisions pour chaque "phase" d'entrée et de sortie, car, bien entendu, les fichiers générés sont produits d'une façon bien déterminée. Le fichier phase commence toujours avec des phases d'entrée: %%declare pour des déclarations, %%input pour la lecture de données (c.à d. les prototypes/déclarations C-C++). Les phases d'entrée ne sont pas forcément uniques.

Ensuite on trouve les phases de sortie, dans lesquelles les connaisseurs peuvent insérer des morceaux de codes, afin d'assurer la plus grande souplesse de l'ensemble.

NB : Il faut utiliser le suffixe .ph pour le fichier de phases. Nom et type des fichiers de prototypes sont indifferents.

La structure du fichier de phases est donc la suivante :

 
%%declare (declarations ....)
 

%%input "mon-fichier-de-prototypes" %%input "mon 2ième fichier" etc. <code> %%<phase> <code> %%<phase> ...

3.1 Les phases d'entrée

./ug_make_module.scml

Il y a, en général, une seule phase avec des déclarations; on peut cependant les placer partout. Voir aussi le paragraphe "Declaration ig dans les prototypes"

Il y a une ou plusiers phases %%input, selon 2 formats différents.

%%input "nomfichier" sert à indiquer le nom du fichier de prototypes à utiliser. nomfichier peut contenir des noms des variables Unix.

%%input * , au lieu de faire appel à un fichier, introduit des données directement, terminées par un $$. C'est commode quand il y a juste quelques lignes. (C'est fréquemment utilisé en début de fichier, avec des déclarations).

Exemple:


%%input *

class Line; class Poly; Poly * po_ly(Line**);

$$

La phase %%scheme-input

Inclusion de code Scheme dans le fichier .x.scm Aucune analyse n'est effectuée.

Deux formats, comme pour les phases input :


	%%scheme-input "filename"
	%%scheme-input *
	...
	$$

3-2 Les phases de sortie

./ug_make_module.scml

Lors de la génération du code source, le générateur procède par phases : sortie des includes, puis les variables locales, puis les fonctions d'interface, puis la fonction d'initialisation.

Des commandes de la forme %%<phase> permettent d'insérer du code avant chacune des phases. C'est utile seulement pour des problèmes très particuliers, le "débutant" n'a pas a connaitre tout cela ...

NB : Chacune de ces commandes est optionnelle. Mais si elles sont présentes, elles doivent apparaitre dans l'ordre des dexriptions ci-dessous

phase include (%%include)

Lors de cette phase, le générateur écrit les include standards de Ravi. Le code place avant cette phase sera placé en tête du fichier avant ces include.

phase types (%%types)

Lors de cette phase, le générateur déclare les variables locales au fichier. On peut placer avant ses variables locales et les includes qui doivent apparaitre apres les include standards.

phase fntypes (%%types)

C'est lors de cette phase que le générateur doit mettre en place les méthodes générées automatiquement pour delete et print.

phase functions (%%functions)

Cette phase correspond à l'écriture du code pour toutes les fonctions d'interface. Toutes les fonctions inline appelées par les fonctions d'interface devraient être placées avant cette phase.

phase begin-init (%%begin-init)

Cette phase correspond a l'ecriture de l'en-tete de la fonction d'initialisation. Le code place avant cette phase est insere avant cette fonction et apres les fonctions générees automatiquement.

phase init (%%init) Du code place entre %%begin-init et %%init sera inseré au début de la fonction d'initialisation. Cette commande est reservee aux experts es modules. Il y a peu de raisons de l'utiliser.

phase init (%%end-init)

Le code place avant cette phase est insere a la fin de la fonction d'initialisation. La aussi, il vaut mieux attendre de bien connaitre le fonctionnement du générateur pour aller mettre des choses dedans.

3-3 Déclarations

./ug_make_module.scml

Les déclarations apparaissent dans une (ou plusieurs) phase %%declare sous forme d'une liste directement exploitée en Scheme. Les déclarations peuvent aussi être placées dans des commentaires à l'intérieur des fichiers prototypes (.h), voir le paragraphe "Declaration ig dans les prototypes".

On n'a pas besoin de connaitre toutes les déclarations, mais on se rend rapidement compte de leur utilité. Les déclarations peuvent prendre les formes suivantes :

La déclaration de classe

./ug_make_module.scml

Format: (classe id prop ...)
prop ::= prop-name | (prop-name value)

La déclaration "classe" regroupe toutes les informations concernant une classe identifiée par id; chacune de ces informations est une "propriété" qui est un couple attribut-valeur; le nom de l'attribut tout seul désigne la valeur par défaut (qui existe pour certains attributs seulement). Fini donc le jeu des #t ou #f pour dire oui ou non.

id est: soit un symbole, soit une chaine définissant un type de classe avec la syntaxe C++. Vous notez que cela simplifie beaucoup de détails: plus besoin de savoir s'il faut mettre (* nom) ou nom ou (nom *) ... par contre, pour analyser correctement la chaine avec une classe définie par un template, il faut absolument la faire précéder par une declaration template, syntaxe oblige!

Format de la déclaration template: (template name) (rien à signaler)

Les propriétés sont:

  • print print-function
  • print-method
  • delete delete-function
  • delete-method
  • reference-count
  • reference-count-methods
  • dynamic-type
... a completer,, il y en aura d'autres.

Détails

./ug_make_module.scml

* Fonction d'impression: propriété print-function ou print-method

On sait que chaque typec connu dans Ravi possède une fonction d'impression, que l'on peut préciser avec une déclaration. Pour ce qui est des classes, cette déclaration peut prendre une des 2 formes suivantes.

  • (print nom-fonction) indique le nom de la fonction d'impression rattachée à la classe. (Comme dans la version précédente de l'interface, cf. la déclaration type ci-apres). Cette fonction doit avoir le profil
    
     	void fn(ScPortOut * port,void * x)
    
    {Remarque: ceci devra etre verifie ds une prochaine version}

  • (print-function nom-fonction) est synonyme à la précédente, et préférable.
  • (print-method nom-m) indique que la fonction d'impression doit être générée par l'interface; cette fonction fera appel a' la méthode nom-m qui doit avoir le profil: char* nom-m();

    Cette déclaration réalise un progrès notable: l'interface est enfin capable de générer des fonctions d'impression!

Voici l'exemple de la fonction générée pour la classe toto d'après la déclaration


(classe toto (print-method info) ...)

void print_toto(ScPortOut * port,void * x) { port -> PrintFormat(((toto *)x) -> info()); }

Les compteurs de référence

./ug_make_module.scml

La propriété reference-count déclare que la classe est gérée avec des compteurs de référence, et qu'on utilise les methodes par défaut. La déclaration complète


(reference-count-methods reference unreference)
donne explicitement les noms des m'ethodes à appeler.

On note un choix important: les 2 méthodes sont regroupées en une seule déclaration, pour des raisons de salubrité évidentes.

A regarder de plus près, ceci est bien plus générale que les compteurs de reférence; la méthode reference est appelée lorsqu'on construit l'objet typec dans Ravi, la méthode unreference est appelée par le ramasse-miettes à la destruction du pointeur sur l'objet.

Pour une classe avec reference-count, l'interface comporte toujours une fonction delete; en l'absence de déclaration, la fonction delete est générée.

Remarque: la 2ieme forme reste a implementer, personne ne l'utilise pour l'instant.

Fonction de destruction

./ug_make_module.scml

Chaque typec sous Ravi peut posséder une "fonction de destruction" appelée par le ramasse-miettes. Pour une classe, cette fonction peut être codée à la main, construite par l'interface, ou être absente.

  • delete génère la fonction par défaut. Si la classe est gérée avec compteur de reférence, cette fonction appelle la méthode unreference.

  • (delete func) (delete-function func) donne explicitement la fonction delete.

  • (delete-method meth) indique que la fonction générée doit appeler la méthode meth.

Remarques

Pour une classe avec reference-count, l'interface comporte toujours une fonction delete; en l'absence de déclaration, la fonction delete est générée.

L'ancienne déclaration (delete #f) n'a plus de raison d'être: en absence de déclaration, il n'y a pas de fonction delete.

Exemple d'une fonction delete générée automatiquement pour la classe toto avec compteur de ref'erence:


	void delete_toto(void * x)
	{
	  ((toto *)x) -> unreference("ravi");
	}

Typage dynamique

./ug_make_module.scml

La propriété (dynamic-type GetMethod SetMethod) signifie que toute méthode/fonction ayant un résultat de type classe (déclaré au niveau C++) aura pour résultat un objet typeC dont le type sera déterminé dynamiquement en appelant la méthode (virtuelle) GetMethod. La méthode statique SetMethod est appelée à l'initialisation du module.

Le forme simple de la propriété dynamic-type introduit des noms par défaut: GetRaviType et class_name::SetRaviType.

Génération de classes template

./ug_make_module.scml

Des classes générées à partir d'un template peuvent faire partie de l'interface. Il faut explicitement demander leur génération à l'aide d'une déclaration:


(generate-template-class n1 ...)
Les noms n1 ... se réfèrent à des typedef dans les déclarations de prototypes (fichier .h). La génération de la classe se fera à l'endroit où est placée le typedef.

Exemple:

Déclaration dans le .ph

(generate-template-class afloat)

Puis, dans le .h

typedef array<float> afloat

--> completer l'exemple!

Paramètres résultat

./ug_make_module.scml

Les paramètres références d'une procédure peuvent correspondre à des résultats qu'il peut être utile de recupérer au niveau Ravi. Cela ne peut pas être déduit automatiquement par le système, il faut donc une déclaration; de plus, il faut un moyen des récupérer plusieurs résultats.

La déclaration (result-mode #t) "positionne l'état" du générateur d'interface, en sorte que les paramètres référence des procédures sont considérés comme des résultats. La déclaration (result-mode #f) positionne l'état inverse.

Le résultat au niveau Ravi est une liste comportant le résultat de la fonction, s'il y en a un, suivi des valeurs en sortie des paramètres passés en référence, et de type simples.

Exemple


%%declare ((result-mode #t))

%%input *

void f1(int , float&, int&);

class toto { public: static toto& func1(int,toto*); static void func2(int&,toto&); void GetCoord(float,float&); };

int f2(bool&,char*,int&);

$$

Au niveau Ravi, la fonction f1 donne une liste de 2 float. La fonction toto::func1 donne une liste (toto entier). La fonction toto-GetCoord donne une liste avec un float. La fonction f2 une liste avec (entier booleen entier).

Declaration ig dans les prototypes

./ug_make_module.scml

Pour activer/désactiver le result-mode, on a besoin de mettre des déclarations un peu partout; d'où l'intérêt de la possibilité de les placer carrément dans les déclarations C++ (cad. dans le fichier .h).

Cela a un autre intérêt - celui de pouvoir générer des interfaces directement à partir d'un fichier .h, sans l'intermédiaire d'un fichier "phases" .ph.

Des déclarations Ravi peuvent donc être placées dans un commentaire C selon le format suivant:


/*Ravi declare ( des declarations en format usuel )
  ....   */

Ce commentaire peut s'étendre sur plusieurs lignes. Il faudra voir à l'usage comment cette possibilité peut s'exploiter au mieux.

--> suggestion de Bruno: utiliser le pragma !

Exemple


/*Ravi declare ((result-mode #f)) */
static void func2(int&,toto&);
/*Ravi declare ((result-mode #t) 
	(eval (warning "no comment"))) */
void GetCoord(float,float&); };

Autres déclarations

./ug_make_module.scml

... a completer: ce sont des "cas particuliers" ...

(handle-with-new t1 ...)

(line-no bool)

(no-interface t1 ...)

(instantiate t1 ...)

(force-conversion t)

Modularité - déclaration require

./ug_make_module.scml

Quand on utilise des définitions de classes réparties dans plusieurs fichiers, par exemple une classe de base dans un fichier f1 et des classes dérivées dans un fichier f2, des déclarations concernant f1 doivent figurer dans f2.ph; il n'est pas évident de savoir quelles déclarations sont nécessaires, et cela peut provoquer des erreurs sournoises, notamment en cas de modifications de programmes.

La solution: une unique déclaration (require module) suffit pour introduire toutes les définitions concernant un module.

Fonctionnement

On sait que la génération de modules produit un fichier nom_module.x.scm. Ce fichier contient désormais une déclaration avec toutes les informations utiles, à l'intention de la déclaration require.

Conséquence :

en conséquence, les déclarations nécessaires dans les fichiers .ph devraient devenir beaucoup plus limpides, car elles ne concernent rien que les classes (et autres déclarations C++) du fichier courant; toute information héritée d'ailleurs est repêchée ailleurs. Attention : il faut tout de même que l'ordre de génération des modules soit correct, c'est à régler au niveau du makefile.

Quelles informations est-il nécessaire ou intéressant d'exporter? Voici les choix faits à présent :

Sont exportées telles quelles un certain nombre de déclarations explicites:


	reference-count
	no-interface
	define-type
	syntax-type
	rename-type
	parent-type
	template
	chain-methods
	handle-with-new
	force-conversion
	int-is-float
	use-files

Puis des informations collectées tout au long de l'analyse du module :


	*class-structure*
	*ref-count-classes*
	*instantiate-tdefs*
et lors de la lecture des déclarations C++:

	template
	enum
	typedef

et les require rencontrés récursivement dans les modules indiqués.

Prise en compte de quelques commandes du préprocesseur

./ug_make_module.scml

Un engrenage monstrueux dans lequel il était tout de même tentant de mettre un petit doigt ... voilà ce qui est actuellement possible.

Les commandes du préprocesseur sont toutes reconnues et envoient vers des traitements spécifiques; un seul de ces traitements fait quelque chose - celui du #define.

Plus précisement: une constante définie par un #define est exportée dans le programme Scheme de la même facon qu'une définition de constante en C++.

Exemple:


  %%declare ((no-export rien)
  )
  %%input *

/* un comment*/ #define ROUGE 37 enum{AA,BB}; typedef enum{bleu,blanc,rouge} coul; int fn(coco, c1, coul*, char *); # et encore du comment float * f2 # define BLEU ROUGE+ \ 13 ();

$$

Les constantes générées dans le .x.scm sont:


	(define-constant ROUGE 37)
	(define-constant AA 0)
	(define-constant BB 1)
	(define-constant bleu 0)
	(define-constant blanc 1)
	(define-constant rouge 2)
	(define-constant BLEU (+ ROUGE 13))

Evolution

./ug_make_module.scml

De nombreux traitements sont désormais accessibles, par exemple il serait très facile de traiter les #if #ifdef et compagnie, et même d'avoir un mode de lecture des fichiers #include, de facon à en extraire les définitions utiles - cela modifierait peut-être une partie du require...

Par contre, d'autres aspects du préprocesseurs restent exclus - tout ce qui touche au niveau caractère, et qui est généralement considéré magouilleux.

Anciennes déclarations

./ug_make_module.scml

Ces déclarations "de première génération" sont toujours acceptées. En principe, elles ont été remplacées par les déclarations décrites précédemment, mais il subsiste des cas où elles restent utiles - il faudra trier!


(define-type <classe> <print> <delete>)
<classe> est le nom d'un type C++ pour lequel on veut definir un type Scheme. Comme on utilisera généralement des pointeurs, la forme a utiliser est

(* Toto).

<print> : Definit la fonction d'impression. Cet argument peut etre :

  • Le nom de la fonction definie par le concepteur qui sera utilisee pour afficher l'objet lors d'un display.
  • #f pour indiquer qu'aucune fonction n'est definie. (seule son adresse sera affichee).
  • #t demander la génération automatique de la fonction. (Non encore implemente).
    : Definit la fonction de destruction utilisee par le ramasse-miettes. Cet argument peut etre :
  • Le nom de la fonction definie par le concepteur qui sera utilisee pour desallouer l'objet.
  • #f pour indiquer qu'aucune fonction n'est definie. (le ramasse-miette ne detruira jamais l'objet).
  • #t demander la génération automatique de la fonction. (Implementation tres prochainement).

Exemple


        (define-type (* Image) printImage deleteImage)

Nous verrons plus loin ou et comment ecrire les fonctions d'impression et de destruction.

(syntax-type <Type1> <Type2> ...)

Cette declaration sert a declarer l'existence d'un type a l'analyse syntaxique. Elle a exactement les memes effets qu'un typedef ou une declaration class ou struct dans le fichier de prototypes.

(rename-type <Type1> <Type2>)

(Donner a Type1 le nom Type2) Sert a renommer un type en un autre au niveau de Ravi. Cette declaration permet essentiellement d'eviter les conflits de noms. Si deux bibliotheques utilisent des types differents de meme nom, on peut le renommer dans l'une des deux interfaces.

Exemple : (rename-type (BARAY *) (BARY *))

(libraries "lib1.a" "lib2.a")

- Indique les bibliotheques utiles

Cette declaration n'est utile que sur SunOS pour le chargeur dynamique. Elle precise la liste des bibliotheques a charger avec un module. L'ordre indique est l'ordre de chargement.

(parent-type <Type> <Nom type2>)

- Signale un heritage

Cette commande permet d'indiquer qu'il faut prendre en compte l'heritage d'un type par rapport a un autre. Le deuxieme argument est le nom unique du type utilise par Ravi. Par la suite, une fonction qui attend un argument de type type2 acceptera egalement les arguments de type Type.

Exemple :


     (parent-type (* ScPVMOutputPort) "OutputPort"))

(test-type <type> <nom-scheme> <nom-C>)

- génération d'un predicat de test de type.

Cette déclaration demande au générateur de créer une méthode de nom <nom-scheme> pour tester si une valeur est de type <type>. Pour éviter les conflits de noms, le concepteur donne également le nom de la fonction C qui sera généree automatiquement.

(scheme-name <nom-scheme> <nom-c>) - Impose le nom scheme d'une fonction.

Les noms de fonctions crees par le générateur ne sont pas toujours bien choisis. Cette declaration permet de choisir le nom scheme qui sera affecte a l'interface d'une fonction C.

Exemple : (scheme-name segment-valide? IsSegmentValide)

(scheme-function <name> <c-proc> <nbarg>)

- Ajouter une fonction codee manuellement.

Dans les cas ou la génération d'interface ne suffit pas, il peut etre necessaire de coder completement l'interface a la main. Cette declaration permet d'ajouter directement une fonction C++ dans Ravi en supposant qu'elle respecte les conventions.

<name> est le nom scheme de la fonction. <c-proc> le nom de la fonction C. <nbarg> le nombre d'arguments scheme.

Il ne devrait y avoir aucune raison d'utiliser cette declaration desormais !!!!

Commentaires dans un fichier .ph

./ug_make_module.scml

Etant donné qu'un fichier .ph contient des parties destinées à des processeurs différents, chacun avec sa syntaxe propre, il n'y a pas de format unique pour les commentaires; il faut donc faire attention, mais les possibilités sont raisonnables.

  • Dans un %%declare

    Le mot-clé %%declare est suivi d'une liste lue par la fonction read de Scheme. Entre la parenthèse ouvrante et la parenthèse fermante, le caractère ; introduit donc un commentaire qui va jusqu'à la fin de la ligne.

  • Dans un %%input

    Le mot-clé %%input introduit du C++; sont donc légaux les commentaires acceptés en C++. De plus, toute ligne commenceant avec # est acceptée.

  • Dans un %%scheme-input

    Le contenu de cette phase est transmis sans les commentaires.

En dehors de ces phases, toutes les lignes du fichier .ph sont transmises telles quelles vers le .cc, y compris les lignes-commentaires. Remarque: une phase %%input peut contenir rien que des commentaires. C'est un moyen de placer un commentaire non transmis.

==================================================

Limitations actuelles

./ug_make_module.scml

Vu la complexité de C++, le générateur d'interface n'a pas été construit en un jour; il est, au contraire, développé des façon progressive, ce qui explique les limitations qui subsistent. Ces limitations seront levées en fonctions des circonstances - notamment si quelqu'un en fait la demande!

Initialiseurs ds constructeur

Une vacherie syntaxique: le : xx(e1),yy(e2) dans les constructeurs; faudra régler ça un jour.

Autre détails de syntaxe: throw, syntaxe complète du new, delete Les nouveaux cast

Préprocesseur

Les commandes du préprocesseur sont ignorées par défaut. Voir le paragraphe sur le pp.

const ignoré

Dans l'interface, et dans l'analyse des surcharges, le const est systématiquement ignoré. Cela peut provoquer des erreurs (mais ne nous n'a jamais gênés).

Noms de méthodes à éviter

Lorsqu'on définit des opérateurs, le générateur d'interface les traite de façon analogue aux méthodes; pour la lisibilité du code généré, les fonctions intermédiaires ont des noms assez simples, mais qu'on ne peut pas utiliser par ailleurs - on ne peut donc pas, par exemple, dans une classe définir un opérateur = et une méthode set.

Ceci concerne les noms suivants:


(define *operator-list*
  '((+ . plus) (- . minus) (* . times) (/ . quotient)
    (% . rem) (^ . xor) (& . and) (| . or) (~ . not)
    (! . lognot) (= . set) (< . less) (> . greater)
    (+= . setplus) (-= . setminus) (*= . settimes) (/= . setquotient)
    (%= . setrem) (^= . setxor) (&= . setand) (|= . setor)
    (<< . left) (>> . right) (>>= . setright) (<<= . setleft)
    (== . eq) (!= . noteq) (<= . lesseq) (>= . greatereq)
    (&& . logand) (|| . logor) (++ . incr) (-- . decr)
    (-> . pointer) (->* mpointer)
    (() . call) (c-array . ref)
    (set . v_set)
    ))
Ce limitation est facile à contourner, mais serait facile à éliminer aussi.

Partie private non analysée

Conséquence: si une classe doit être considérée abstraite en raison d'une déclaration dans la partie privée, le générateur produit quand même un constructeur. pour contourner; passer en public.

============================================================