Bonnes pratiques développement AutoLISP

Quelques règles à respecter pour faciliter la maintenance de vos programmes AutoLISP.

Utilisez des variables locales autant que possible

Par défaut, les variables créées dans le corps d'une définition de fonction via setq ou set sont globales. Cela pose deux problèmes :

  • L'espace mémoire occupé par ces variables n'est pas libéré à la sortie de la fonction ;
  • Les variables globales "polluent" l'espace global et peuvent générer des bogues difficiles à identifier.

Pour éviter cela, déclarez vos variables dans la deuxième partie de l'argument de la fonction defun :

(defun ma-fonction ( / ma-variable)
  [..]
  (setq ma-variable 1)  
  [..]
)

Utilisez la notation *...* pour les variables globales

Si vous devez quand même utiliser des variables globales pour partager des données entre deux fonctions par exemple, ajoutez un astérisque au début et à la fin de son nom. Cette convention de nommage vous permettra de distinguer aisément une variable locale d'une variable globale. Elle est utilisée par AutoLISP pour la variable globale *error* qui permet de définir une routine personnalisée de gestion des erreurs.

Vous pouvez aussi préfixer vos noms de variables par un caractère particulier comme $ par exemple si vous trouvez la notation *...* trop lourde.

Mettez en majuscule les noms des constantes

AutoLISP ne dispose pas malheureusement de concept de constantes qui permettent de spécifier des valeurs en un seul endroit du programme. On peut utiliser une variable globale dans ce cas. De la même façon qu'on utilise la notation *...* pour une variable qui peut changer, on peut choisir de mettre en majuscules le nom des variables utilisées comme constantes. Exemple pour les constantes définies par AutoLISP :

(setq 90-DEGRES (/ PI 2.0))

Utilisez toujours des réels pour vos divisions

AutoLISP fonctionne comme le langage C pour les divisions. Si tous les opérandes sont des entiers, le résultat de la division est un entier :

(/ 9 2) ; Renvoie 4 au lieu de 4.5

Pour évitez ce problème, utilisez systématiquement des réels dans le cadre d'une division :

(/ 9.0 2.0) ; Renvoie 4.5

Utilisez equal pour comparer des nombres réels

AutoLISP utilise une représentation sur 64 bits pour stocker les nombres réels. Bien que cette représentation fournit une très bonne précision, elle est imparfaite et des erreurs d'arrondi peuvent se produire. Si à un endroit de votre programme vous devez comparez deux nombres réels (zéro y compris) utilisez equal avec une tolérance au lieu de = :

(- 3.6 2.4) ; Renvoie 1.2
(= 1.2 (- 3.6 2.4)) ; Renvoie nil
(equal 1.2 (- 3.6 2.4) 1e-6) ; Renvoie T

Utilisez les différents styles de commentaires proposés par Visual LISP

Visual LISP permet de reformater votre code, ce qui permet de localiser plus facilement les parenthèses manquantes ou les parenthèses qui sont en trop. Pour aider Visual LISP à repositionner correctement vos blocs de commentaires, utilisez les styles suivants :

;;; Avec 3 points virgules, le commentaire est repositionné systématiquement
;;; en début de ligne. Utilisez ces commentaires pour décrire une fonction, ses
;;; paramètres et sa valeur de retour.
(defun ma-fonction ( / a)
  ;; Avec 2 points virgules, le commentaire s'aligne sur l'indentation courante.
  ;; Utilisez ce style de commentaire pour marquer les différentes sections dans 
  ;; votre code.
  (setq a 1.0)	; Un seul point virgule pour les commentaires de fin de ligne.
  (princ)
)

Ajoutez un appel à princ dans vos définitions de commande

Si vous définissez une commande AutoCAD avec defun et le préfixe C:, terminez la liste de vos expressions avec un appel à la fonction princ sans argument. Cela évite d'avoir nil qui s'affiche sur la ligne de commande d'AutoCAD :

(defun C:MACOMMANDE (/)
  (alert "Coucou")
  (princ)
)

Vous pouvez également procéder de la même façon pour les fonctions AutoLISP sans valeur de retour.

Sauvegardez l'état d'AutoCAD au début de votre traitement et restaurez le à la fin

Dans le cadre d'un programme AutoLISP, on est souvent amené à modifier certaines variables comme OSMODE ou CMDECHO. Un programme bien écrit devrait les sauvegarder avant de les modifier pour pouvoir les restaurer à la fin.

Vous pouvez utiliser la fonction suivante pour la sauvegarde :

;;; Sauvegarde les variables systèmes.
;;;   variable-name Liste des variables à sauvegarder.
;;;   Retourne une liste de paires pointées où le premier élément correspond 
;;;   au nom de la variable et le deuxième élément est la valeur de la variable.
(defun save-state (variable-names /)
  (mapcar (function (lambda (variable-name)
		      (cons variable-name (getvar variable-name))
		    )
	  )
	  variable-names
  )
)

Au début de votre programme, appelez la de la façon suivante :

(setq variables (save-state '("CMDECHO" "OSMODE")))

Ensuite, utilisez cette fonction pour rétablir les variables :

;;; Rétablit les variables systèmes.
;;;   variables Liste de paires pointées où le premier élément correspond
;;;   au nom de la variable et le deuxième élément à la valeur de la variable.
(defun restore-state (variables)
  (mapcar
    (function (lambda (name-value)
		(setvar (car name-value) (cdr name-value))
	      )
    )
    variables
  )
  (princ)
)

A la fin de votre fonction, appelez la ainsi :

(restore-state variables)

Etiquettes:

Add new comment