Par Serge Camiré, ing. (disponible en MP3)

Cet article commence par une rétrospective des langages avant de mieux aborder le vif du sujet, soit le .Net dynamique dans AutoCAD 2013. Pour les initiés, vous pourriez donc sauter les premiers paragraphes. Si j’ai choisi cette approche, c’est que c’est plus facile de savoir où l’on est rendu lorsqu’on connait l’historique du trajet. Dans son livre « Une brève histoire du temps », Stephen Hawking avait fait remarquer que pour chaque équation qu’il insérerait, il diminuerait ses ventes de moitié et que par conséquent, il n’en avait insérée aucune. Je tenterai de trouver le juste équilibre entre ne pas être trop technique car l’article a déjà le défaut d’être long mais assez pour susciter votre intérêt de creuser davantage certains éléments.

  • L’absence de typage de données avec AutoLISP
  • Langage interprété vs langage compilé
  • L’avènement de DotNet
  • Bref rappel de COM (Component Object Model)
  • Liaison hâtive vs liaison tardive
  • La réflexion dans DotNet
  • Les 3 grands paradigmes de programmation  et le F#
  • AutoCAD et les services Web
  • Quoi de neuf avec Visual Studio 2010
  • Utilisation du type dynamic
  • Plus ça change, plus c’est semblable

L’absence de typage de données avec AutoLISP

La plupart d’entre nous avons commencé à programmer dans AutoCAD avec AutoLISP. Lorsqu’on fait usage d’une variable, elle n’est jamais typée, c’est-à-dire qu’on n’a jamais besoin de déclarer qu’il s’agit d’un nombre, d’une chaine, d’une liste ou de d’autres espèces de donnée. Bien pire (ou bien mieux), la même variable peut changer de type dynamiquement. Dans la même expression, on peut déclarer (setq a 1.0 a "ABC"), ce qui altère le type à l’interne avant même que setq ne la retourne. Pourtant, AutoLISP demeure très performant pour la très grande majorité des projets et ce, même si langage est issu des années 50 (1958 pour être plus exact).

Langage interprété vs langage compilé

Qu’est-ce qu’il y a de différent avec les autres langages? Pour répondre à cette question, il faut revenir à certaines bases, toujours en gardant à l’esprit que les lecteurs de ce forum  sont issus d’un monde Autocadien. Il existe 2 paradigmes : les langages compilés et les langages interprétés.

Commençons par les langages interprétés. Vous avez probablement tous travaillé avec les fichiers LSP au travers de l’interface IDE (Integrated Development Environment) via la commande VLIDE. Peut-être avez-vous aussi travaillé avec des fichiers VBA (fichiers à extension DVB – ceux-ci étant maintenant caducs). Dans les 2 cas, vous utilisez le code sans compilateur. Vous pouvez faire des modifications et c’est toujours le même fichier que vous rechargez. Cette adaptabilité a un coût en performance parce que, pour réduire les risques que le programme ne plante, il doit prévoir le pire à chaque ligne. Lorsqu’il y a une erreur, elle est de type « runtime error » sans distinction qu’elle soit due à une erreur de logique ou à une erreur liée à l’incompatibilité de type et qui aurait pu être évitée par un compilateur.

Le typage des données n’est pas fonction que le langage soit interprété ou compilé. Dans le cas de VBA (ou même VB), les variables n’ont pas à être déclarées en omettant la déclaration Option Explicit ou encore, elles peuvent être déclarées mais non typées explicitement (elles le seront implicitement en Object comme Dim A équivaut à Dim A as Object). Dans le cas d’AutoLISP, toutes les variables ont un type implicite non déclarable mais cela dépasse la portée de cet article (il faut que je pense à mes ventes). Il s’agit d’avoir fait des projets en ObjectARX ou en DotNet pour le savoir.

Un langage compilé implique que la version finale produise un fichier d’exécution différent du code source. Comme le compilateur a pris soin de vérifier certaines compatibilités de type, il prend plus de risque lors de l’exécution et est donc plus rapide. Les erreurs possibles sont alors principalement des erreurs de logique. Dans la même veine, il est possible de compiler des fichiers LSP au format FAS (pour FASt, i.e. rapide) ou VLX (Visual Lisp compiled). La différence entre les 2 formats tient du fait que le premier est la compilation un pour un d’un LSP en un FAS tandis que le second est la compilation d’un ou plusieurs fichiers de types divers en un seul fichier VLX.

Malgré qu’on ait mentionné que VBA ne soit pas compilé mais interprété, il existe depuis longtemps le langage VB qu’il ne faut pas confondre, lequel permet de créer des fichiers exécutables (des EXE ou des DLL.) Mentionnons rapidement que ce type de fichier existait avant l’arrivée de DotNet et était donc forcément de type non géré par un Framework que nous expliquerons plus loin. Le poste de travail qui devait les faire fonctionner devait cependant avoir un module d’exécution préalablement installé (en anglais runtime, soit un ensemble des librairies (DLL) dont ceux-ci pour VB : asycfilt.dll, COMCAT.DLL, msvbvm60.dll, OLEAUT32.DLL, OLEPRO32.DLL, STDOLE2.TLB, Vb6fr.dll ou d’autres pour d’autres langages). La dernière version de VB utilisant ce runtime était la version 6 en 1998. Notons au passage qu’AutoLISP a lui aussi son runtine (vl.arx) et que certains on comprit comment utiliser un équivalent avec AutoCAD LT (mais ceci est un sujet de discussion en soi).

L’avènement de DotNet

En 2002, coup de théâtre, Microsoft dévoile la sortie de la technologie DotNet (alias .Net). Celle-ci s’attaque de façon plus globale aux postes de travail ainsi qu’au monde de l’Internet. En gros, c’est quoi? On a voulu offrir un environnement de programmation qui permette rapidement d’adapter le même code source pour l’un ou l’autre des destinataires précités, avec la contrainte qu’on ne connait pas d’avance quel sera leur système d’exploitation final ni s’il sera utilisé de façon autonome ou via un navigateur de type Internet Explorer. Quand on sait qu’un programme compilé ne doit pas trop se poser de questions lors de son contexte d’exécution, cela demande certaines pirouettes.

Ainsi donc, DotNet repose d’abord sur l’installation d’un Framework (ci-après abrégé FW). Celui-ci comporte entre autre chose le Common Language Runtime (ou CLR) et des très nombreux autres composants.  Il existe une version spécifique de Framework pour chaque système d’exploitation. Vous n’avez pas à vous inquiéter, les mises à jour de Windows (ou autres système d’exploitation) l’ont installé pour vous. C’est peut-être une surprise pour certains d’apprendre ceci mais vos programmes EXE ou DLL que vous écrirez avec Visual Studio 20XX ne sont pas compilés mais d’abord réécrits dans un langage propre à Microsoft (recherchez CIL ou MSIL pour plus de détails si le sujet vous intéresse) puis pris en charge par le CLR une fois distribué sur le poste de vos utilisateurs afin d’être compilés lors de leur première exécution. Pourquoi je le mentionne ? Parce qu’on peut faire de l’ingénierie inverse avec vos fichiers, c’est-à-dire, on peut retrouver le code source. Pour vous protéger, il existe des logiciels d'obfuscation et de compactage (recherchez Dotfuscator Software Services CE pour plus de détails). Une autre implication de ce qui vient d’être dit est que la première exécution de votre programme prend plus de temps puisqu’elle inclut le temps de compilation.

Mentionnons au passage que DotNet est officiellement supporté depuis la version AutoCAD 2005 de façon expérimentale mais n’a été efficace qu’en 2006. Pour chaque version d’AutoCAD existe une version de FrameWork donc une version de Visual Studio (Visual Studio 2008 et suivants permettent de démarrer un projet avec d’anciens Frameworks). Historiquement, Autodesk a respecté le maintien de la même version de FrameWork pour chacune des 3 années que forme une version majeure du logiciel AutoCAD (R17, R18, etc.) sauf qu’entre 2011 et 2012 on est passé du FW 3.5 au FW 4.0. Heureusement, vos applications peuvent migrer vers le haut donc si vous les avez créées avec le FW 3.5 pour AutoCAD 2010 ou 2011, elles fonctionneront toujours avec AutoCAD 2012. Par contre, si vous les avez créées en utilisant le FW 4.0, elles fonctionneront avec AutoCAD 2012 mais pas en 2010 ni en 2011. Aussi, si vos applications partent de loin, soit du FW 2.0 (i.e. pour AutoCAD 2007-2009) vous pourriez devoir faire certains ajustements (recherchez useLegacyV2RuntimeActivationPolicy à ce sujet).

Ce préambule nous a ramené progressivement vers le sujet de cet article soit le .Net dynamique dans AutoCAD 2013. Cette version d’AutoCAD utilise Visual Studio 2010 et le FW 4.0 Comme nous l’avons vu précédemment, AutoCAD 2012 utilisait déjà le FW 4.0 donc l’article aurait pu tout aussi bien faire référence à 2012 si ce n’était du support spécifique de certains objets comme les ObjectID et ceux qui en dérivent (les xxxTableId , les xxxDictionaryId et autres) apparu en 2013.

La question est savoir qu’est-ce que ce « Dynamic » apporte ou enlève et dans quel contexte on peut l’utiliser avantageusement. Suite à cet article, peut-être que certains d’entre vous seront découragés de l’utiliser, pas à cause de sa complexité mais de sa pertinence, en tout cas, j’espère que ce ne sera pas parce que je vous ai embrouillé. Pour ne pas vous faire perdre votre temps, disons que l’intérêt augmente si vous utilisez AutoCAD WS, le Cloud ou toute technologie Web ou de langage script (Python, Ruby, Perl, VB Script, Java Script, Microsoft Silverlight, etc.). On y reviendra.

Bref rappel de COM (Component Object Model)

Pour comprendre la nouveauté, il faut encore une fois refaire une rétrospective de la technologie visée. Nous allons parler très brièvement de COM et de DotNet et comment ces interfaces communiquent avec d’autres applications.

Nous avons probablement tous entendu parler de COM (Component Object Model)  et d’ActiveX. Au sens large, la famille des technologies COM comprend OLE, COM, COM +, DCOM (Distributed COM) et les contrôles ActiveX et on confond parfois les termes alors que ce sont diverses évolutions. Si vous avez travaillé avec AutoLISP, vous avez sans doute remarqué les fonctions débutant par VLA (le A pour ActiveX) ainsi que la fonction (vl-load-com). Vous avez peut-être aussi travaillé avec des contrôles OCX (OLE (Object Linking and Embedding) Control) Extension) pour afficher la liste des calques en VBA. En gros, COM offre un mécanisme permettant de diffuser des objets dans des environnements inconnus au moment de leur création et du contexte où ils seront utilisés. Une application COM est un serveur de données en ce sens qu’elle va servir des données à son client.

Pour que la communication puisse s’établir avec le client (votre application AutoLISP, VB ou autre), il doit y avoir une interface de communication. Il y en a même souvent 2 : l’une obligatoire et complètement générique (IDispatch) et l’autre facultative et qui est très typée. De l’autre côté, lorsque vous programmez et faites référence à ces objets, vous pouvez soit typer vos variables ou ne pas le faire (c’est-à-dire les typer implicitement en Object). C’est suite à votre déclaration de type que votre compilateur choisira l’interface appropriée. Pour réussir sa tâche, le compilateur se base sur un petit lexique appelé Type Library.  Ces librairies de type sont des fichiers à extension TLB ou TLE. Évidemment, ne pas typer vos variables rend le traitement plus lent.

Rappelons au passage qu’un composant COM a été créé avec l’objectif d’être utilisé dans un environnement inconnu. C’est pourquoi l’échange de données requiert un format neutre soit les Variants, SafeArrays (avec AutoLISP) ainsi que les IDispatch et BSTRs dans d’autres langages. Une fois un variant récupéré, on peut interroger celui-ci afin de lui un type plus précis tel que vlax-vbEmpty, vlax-vbNull, vlax-vbInteger, vlax-vbLong, vlax-vbSingle, vlax-vbDouble, vlax-vbString, vlax-vbObject, vlax-vbBoolean, vlax-vbArray en AutoLISP ou en VT_BOOL, VT_BSTR, VT_CY, VT_DATE, VT_DISPATCH, VT_I2, VT_I4, VT_I8, VT_R4, VT_R8 dans d’autres langages.

Liaison hâtive contre liaison tardive

Lorsque vous omettez de déclarer le type de donnée, on parle de liaison tardive ou late binding. Par opposition, quand vous le faites, on parle de liaison hâtive ou early binding. Dans le premier cas, on parle aussi de façon informelle de duck typing ou de  name binding (recherchez Alex Martelli pour les origines du terme).

Les avantages de déclarer le type de variables sont nombreux : le code s’exécute plus rapidement, le compilateur peut vous assister dans la résolution et la prévention des erreurs; vous disposez de la technologie IntelliSense pour la composition du code et vous profitez de l’aide dynamique. Pour ce qui est de l’IntelliSense, il est encore trop tôt pour me prononcer mais comme je travaille beaucoup avec ObjectARX ces temps-ci, j’ai mis à jour ma licence du logiciel Visual Assist X de Whole Tomato Software. Cet outil réussi à faire des miracles. Peut-être fait-il de l’IntelliSense là ou Visual Studio ne le fait pas. Pour ceux qui font de la programmation sur une base régulière, je vous invite à le découvrir.

Sauf si vous désirez bénéficier des avantages de la liaison tardive expliqués tout de suite après, je vous incite très fortement à déclarer et à typer toutes vos variables quand cela est possible et utile et à utiliser les méthodes de nettoyage et de fermeture appropriées afin de ne pas laisser des objets en mémoire. En plus, cela rend le code plus clair.

Il ne faut pas croire que la liaison tardive n’a que des inconvénients. Le principal avantage d'utiliser la liaison tardive avec COM est qu'il ne requiert pas du compilateur de référencer les bibliothèques qui contiennent l'objet au moment de la compilation. Cela rend le processus de compilation plus résistant à des conflits de version. Il est également idéal pour l’usage de scripts avec des applications telles que l’Internet Explorer ou les programmes de la suite Office, car il jouit d’une interface plus flexibles en n’exigeant pas de connaitre l'API correspondant au moment de la compilation.

La réflexion dans DotNet

Lorsque DotNet est apparu, on a voulu reprendre le concept d’interface utilisé par COM mais en repartant à zéro. Dans sa première version, DotNet avait même omis de supporter COM, ce qui avait soulevé les protestations justifiées de la communauté de développeurs.  Pour découvrir les types de données et d'invoquer leurs membres à l'exécution, DotNet utilise la réflexion. Celle-ci permet d'inspecter dynamiquement le contenu d'assemblages, d'en lire ses types, de créer des instances de ces types durant l'exécution du programme et d'appeler leurs méthodes ou champs dynamiquement. Ce n’est peut-être pas révolutionnaire pour ceux qui sont habitués à faire des programmes pour un poste de travail mais ça l’est pour ceux qui travaillent avec les applications Web.

Traiter de la réflexion dépasse la portée de cet article mais pour ceux que ça intéresse, recherchez les termes manifest, System.Reflection, marshaling, C++ mangling et Dependency Walker. Cela pourrait vous servir car il existe plusieurs méthodes qui ne sont pas exposées via le fichier acdbmgd.dll et qu’il faut les puiser à même le fichier acad.exe.

En principe, COM ne devait pas faire partie de DotNet mais heureusement que ce n’est pas le cas. Il se peut que vous ayez besoin de combiner les 2 technologies. Prenons par exemple la commande NORMES dans AutoCAD qui vérifie la qualité de certaines normes. Puisque cette commande est incomplète (en fait, ce n’est pas un défaut : les normes sont comme les flocons de neige, elles se ressemblent toutes mais en les regardant de près, il n’y en a pas une pareille), vous devez créer des plugins personnalisés. Le même processus s’applique à la gestion des fenêtres nommées Palettes.

La première étape pour la réalisation d’un tel plugin est d’exposer les composants COM du serveur (ici, acad.exe) depuis axdb17enu.tlb  (ou axdb18enu.tlb ou suivants)  et de acstmgr.tlb au Framework via l’outil tlbimp de Visual Studio. Vous obtenez ainsi un assembly PIA (Primary Interop Assembly). Il vous reste ensuite à importer ces références dans votre solution DotNet puis à créer un fichier *.reg pour vos utilisateurs (ou pour vous-même) pour l’enregistrement du composant dans la base de registres (ou encore d’utiliser un Assistant de déploiement comme InstallShield ou InstallAware). Vous devez finalement implémenter toutes les méthodes que le composant COM utilisera pour communiquer avec votre programme. C’est exactement comme lorsque vous définissez la fonction *error* en AutoLISP avec un paramètre obligatoire msg, ou encore la fonction S::STARTUP, ou encore certaines fonctions de rappel (callback function) avec le langage DCL ou les réacteurs que vous définissez mais que vous n’appelez jamais vous-même.


'Exemple de déclaration
Imports System.Runtime.InteropServices
<System.Runtime.InteropServices.ProgId("MonEspaceDeNom.MaClasse"), _ ComClass()> Public Class MaClasse
  Implements AcStMgr.IAcStPlugin2

' Déclaration des variables ici.

' Déclaration des fonctions d’échange ici.

' Initialize -- Initializes the plugin
  ' This is the only member function in which the interface is
  ' passed an IAcStManager interface.
  Public Sub Initialize(ByVal pMgr As AcStMgr.AcStManager) _
    Implements AcStMgr.IAcStPlugin2.Initialize
    ' Store pointer to Manager object
    m_pManager = pMgr
    m_pPlugin = Me
  End Sub

'GetObjectFilter -- Plugin populates the provided array
  'with class names of objects that it can check
  'In this case we're only interested in circles
  Public Function GetObjectFilter() As Object _
    Implements AcStMgr.IAcStPlugin2.GetObjectFilter
    Dim sFilterArray(0) As String
    sFilterArray(0) = "AcDbCircle"
    GetObjectFilter = sFilterArray
  End Function

' La liste des fonctions à définir est beaucoup plus longue.

End Class

Comme nous l’avons vu, ne pas déclarer de type, c’est-à-dire les déclarer implicitement en Object,  a parfois ses avantages. C’est ainsi que les langages script (ne pas confondre avec les fichiers à extension SCR d’AutoCAD) s’adaptent très facilement aux environnements Web.

Les 3 grands paradigmes de programmation et le F#

Le courant actuel de programmation vante les mérites de l’omission des types de données (duck typing) et ici, on ne parle pas de tirer avantages en liaison tardive tel que nous l’avons montré précédemment. Qu’est-ce qu’il y a de nouveau cette fois? Pour suivre le courant de pensées où l’on a parfois l’impression de revoir le film « Retour vers le futur » (en anglais « Back to the future »), il est bon de présenter comment les choses ont évolué.

En 2005 est apparu le langage F#. La motivation derrière l'apprentissage de F# semble un mystère total. Quel est en effet l'intérêt de F# pour les développeurs, surtout pour ceux qui travaillent avec AutoCAD et qui sont familiers soit avec VB ou C#? Pourtant, on a vu plusieurs blogs de Kean Walmsley à ce sujet. Cela mérite donc qu’on s’y attarde.

Pour répondre, il faut encore une fois revenir à la base. Il existe 3 grands paradigmes de programmation (sur une trentaine possible) : impérative, fonctionnel, et orienté objet.

  • La programmation impérative inclut les langages évolués non orientés objet tel que FORTRAN, PASCAL, VB, C, etc. Ces langages de haut niveau comportent essentiellement quatre types d'instructions principales : l'assignation ; le branchement conditionnel ; le branchement sans condition ; le bouclage.
  • La programmation fonctionnelle est le plus ancien des trois, en commençant IPL (Information Processing Language) en 1956 puis rendu populaire avec l'apparition de LISP (LISt of parenthesis) en 1958 (l’ancêtre du Common LISP en 1984 et d’AutoLISP en 1986) puis  le langage SQL (Structured Query Language) et XSLT (eXtensible Stylesheet Language Transformation). Le paradigme fonctionnel permet l’emboîtement de fonctions que l'on imbriquer les unes dans les autres. (Note : vous avez certainement constaté mon aptitude à écrire du code en AutoLISP puisque j’ai souvent ouvert des parenthèses (comme celle-ci) et je les ai toutes refermées (enfin, je crois (il faudrait que je fasse un copier-coller du présent document Word dans l’interface de Visual Lisp pour le vérifier))).
  • La programmation orientée objet consiste en la définition et l’assemblage de briques logicielles appelées objets, lesquels contiennent à la fois des données et des méthodes qui peuvent être soit privées, soit publiques ou même soit protégées. Elle permet également de créer des objets plus complexes en les dérivant d’une ou de plusieurs classes de base plus simple.

Pendant des années, le domaine des langages fonctionnels était considéré moins noble pour le développement professionnel. Le manque d'intérêt dans ces langages s'expliquait surtout par le fait qu'ils s'adressaient à des plates-formes peu intéressantes pour les développeurs écrivant des programmes pour Windows ou qu'ils ne prenaient pas en charge des fonctionnalités clés telles que l'accès à des données relationnelles, l'analyse XML et des mécanismes de communication out-of-process (rappel à ce sujet : VBA sur AutoCAD 32 bits faisait des appels in-process jusqu’à ce qu’il soit intégré à une version 64 bits où il est devenu out-of-process).

Cependant, avec le CLR et son approche « plusieurs langages pour une seule plate-forme », l'introduction d'autres langages tel que F#  dans l'univers du développement Windows était inévitable. Il était tout aussi inévitable qu'ils commencent à se faire connaître auprès des programmeurs.

Visual Studio 2008 a commencé à utiliser de façon hybride les paradigmes impératif et fonctionnel dans la technologie LINQ en permettant d’effectuer des requêtes sur à peu près n’importe quel objet.

F# est un nouveau langage qui utilise de façon hybride les 2 paradigmes. En plus, il décourage fortement l'utilisation de valeurs nulles et encourage l'utilisation de structures de données immuables ou persistantes, c’est-à-dire que les opérations ne les modifient pas en place  mais renvoient au contraire de nouvelles structures. La structure de données persistante la plus simple est sans doute celle de liste simplement chaînée, où chaque élément contient une référence vers l'élément suivant dans la liste (en AutoLISP, on pale de liste et en DotNet ou ObjectARX, on parle de Result Buffer ou Resbuff). Ceci aide à réduire la fréquence des bogues dans la programmation en réduisant la quantité de code de cas particuliers requise.

Les programmes écrits en F# ont également tendance à être plus concis. Vous tapez et typez moins (ah bon!) : moins de frappes et moins d'endroits où le compilateur doit connaître le type de la variable, des arguments ou du retour. F# est donc un langage ayant un profil de performances similaire à VB ou C#, ce qui est bien supérieur aux langages concis comparables, en particulier les langages dynamiques et de script. C’est la raison pour laquelle il devient un choix plus qu’intéressant lorsque vient le temps de penser à LandXML, AutoCAD WS (Web Service), et les applications résidant sur le Cloud-computing.

Malgré qu’on n’ait pas à le faire explicitement, F# demeure un langage fortement typé utilisant l'inférence de type. Ceci est un mécanisme permettant au compilateur de trouver automatiquement les types le plus général associés à des expressions, sans qu'ils ne soient indiqués explicitement dans le code source. Pour ceux qui ont programmé avec l’ancêtre d’ObjectARX, l’AutoCAD Development System (ADS), ceci s’apparente davantage à la déclaration Union que l’on retrouvait dans les listes chainées de type Resbuff. Avec l’inférence de type, l'expression est évaluée dès qu'elle peut être liée à une variable.

L'inférence de types va de pair avec le polymorphisme, puisque le compilateur génère des types abstraits au besoin d’où sa très grande adaptabilité. Contrairement à la technologie COM ou l’on traitait un cas générique (IDispatch) et un cas typé, le compilateur conserve à l’interne une liste des variables fortement typés.

Les avantages à disposer de ce mécanisme sont multiples : le code source est plus aéré, le développeur n'a pas à se soucier de retenir les noms de types, l'interpréteur fournit un moyen au développeur de vérifier (en partie) le code qu'il a écrit et le programme est peu modifié en cas de changement de structure de données. Les expressions restent les plus générales possibles.

Quoi de neuf avec Visual Studio 2010

Nous voici enfin presque préparé à comprendre un peu mieux ce que voulait dire le « Dynamic » au début de cet article. Auparavant, il nous reste une étape à franchir, celle de faire un résumé des nouveautés de Visual Studio 2010.

Comme nous l’avons vu, lorsque le langage F# est apparu, il offrait un nouveau concept de paradigmes hybrides permettant de définir les traitements algorithmiques sur les données plutôt que de s’acharner à les traiter via de très nombreuses conditions linéaires. Cette légèreté lui conférait une certaine longueur d’avance sur ses compétiteurs. Nous avons vu cependant que Visual Studio 2008 avait commencé à bonifier les langages C# et VB afin qu’ils utilisent LINQ, un concept lui-même hybride ainsi que les types anonymes (comme en F#). Visual Studio 2010 raccourcit davantage l’écart entre ces langages en introduisant de nouveaux concepts de paradigme fonctionnel comme les fonctions Lambda (et oui, on revient à notre bon vieux AutoLISP) ainsi que la covariance et contravariance (échange entre des objets de même parentés mais soit de la classe de base vers une classe dérivée ou l’inverse). Il y a bien d’autres nouveautés mais elles ne sont pas pertinentes pour cet article. Vous pouvez facilement faire des recherches en ligne pour les découvrir.

Nonobstant ce qui a été dit, le langage F# demeure attrayant pour les situations précitées et parce qu’il est très simple de l’utiliser lorsque vient temps de traiter de complexes et grandes banques données grâce à sa verbosité simplifiée.

Utilisation du type dynamic

Il existe 2 techniques de typage de données : statique et dynamique. Le typage statique est une technique utilisée dans certains langages de programmation impératifs que nous avons vu (VB, C#, ++, etc) et qui consiste à déclarer le type à l’avance. Le typage dynamique est une technique utilisée dans certains langages de programmation fonctionnelle comme AutoLISP et est une solution très commode pour le développement rapide de programmes, où le type des objets manipulés n'est pas forcément connu à l'avance.

Visual Studio 2010 introduit maintenant une nouvelle déclaration de type appelé dynamic. Contrairement à ce que son nom laisse présager, il s'agit d'un type statique, donc performant, sauf que pour un objet de type dynamic, l’environnement de développement fait abstraction de la vérification des types et le compilateur fait le travail de typer à votre place selon le meilleur usage. En fait, sans être un objet de type Object, il se comporte dans la plupart des cas comme s'il en était un mais sans sa lenteur. Au moment de la compilation, un élément de ce type est supposé prendre en charge n'importe quelle opération. Par conséquent, tel qu’avec la liaison tardive, vous n'avez pas besoin de savoir si l'objet obtient sa valeur à partir d'une API COM, les API d'automation Office, Visual Studio Tools for Office (VSTO), d'un langage de script tel que Python, Ruby, etc., du modèle d'objet de document (DOM, Document Object Model) HTML, XML ou LandXML, de la réflexion, d’une requête LINQ ou d'une autre partie du programme. Toutefois, si le code n'est pas valide, des erreurs sont détectées au moment de l'exécution (les runtime error).

Il existe une différence fondamentale entre une déclaration statique normale et une dynamique. La première, comme nous l’avons vu fait en sorte que le programme est pris en charge par le Common Language Runtime (CLR). Avec le type dynamique, le programme est pris en charge par le Dynamic Language Runtime (DLR). La CLR ne gère que les langages propres à Microsoft tandis que la DLR de Microsoft a été créée pour prendre en charge d'autres langages.

Comme nous l’avons vu, la programmation fonctionnelle (comme AutoLISP) est orientée dans l’interprétation des données tandis que la programmation impérative (VB et C#) est orientée instructions. On peut voir dans les 3 prochains tableaux comment les 3 langages communs pour AutoCAD commencent drôlement à se ressembler lorsqu’ils utilisent le même paradigme. Dans aucun des cas, on n’a besoin de se soucier des transactions ou du mécanisme d’ouverture et de fermeture des objets.

C#

public static void ChangeLayerNamesDynamically()

{

   dynamic layers =

      HostApplicationServices.WorkingDatabase.LayerTableId;

   foreach (dynamic l in layers)

      if (l.Name != "0")

        Debug.Print("First Floor " + l.Name);

}

 

VB

Public Shared Sub ChangeLayerNamesDynamically()

   Dim layers As dynamic = _

      HostApplicationServices.WorkingDatabase.LayerTableId

   For Each l As dynamic In layers

      If l.Name <> "0" Then

         Debug.Print("First Floor " & l.Name)

      End If

   Next

End Sub

 

AutoLISP

(defun c:test (

 / CurrentName layer

   )

   (setq layer (tblnext "layer" t))

   (while layer

      (setq CurrentName (cdr (assoc 2 layer)))

      (if (/= CurrentName "0")

         (princ (strcat "\nFirst Floor " CurrentName))

      )

      (setq layer (tblnext "layer"))

   )

   (princ)

)

Au moment d’écrire cet article, il ne me reste qu’une chose à vérifier soit comment le tout se comporte avec la gestion des erreurs (Try Catch Finally) et le ramasse-miettes (garbage collection). Question de performance, il est vrai que très peu de gens se soient plaint de la performance d’AutoLISP jusqu’à maintenant. Il y a encore moins de chance que cela se produise avec le nouveau paradigme. Je crois d’emblée que plusieurs adeptes d’AutoLISP qui n’avait pas encore fait le saut vers DotNet seront tentés de le faire. Par contre, d’expérience je peux vous dire que lorsque quelque chose commence à aller mal, c’est toujours plus facile de résoudre le problème quand on sait ce qui se passe sous le capot.

Plus ça change, plus c’est semblable

Vous croyez revoir le film « Retour vers le futur » ? Dans la même veine, dans les années 80, nous nous sommes réjoui de pouvoir délaisser les ordinateurs centraux au profit des ordinateurs personnels pour revenir à des super-ordinateurs sur la toile ou encore le Cloud-Computing. On a aussi déjà été capable, jusqu’en 1995 et AutoCAD R13 d’installer de nouveaux postes en effectuant une simple copie des fichiers avant d’être obligé d’utiliser un Assistant d’installation puis on nous a annoncé en grande pompe que le DLL Hell (l'enfert des DLL)était enfin révolu parce qu’on pouvait désormais copier nos DLL de DotNet sans avoir à les installer. Vous me direz que plus ça change et plus c’est pareil. Disons que c’est comme les premiers Européens qui ont franchis l’Atlantique : ils voulaient quitter l’ancien monde mais il ont tout fait pour l’imiter dans le nouveau.

Vues : 449

Etiquettes : .net, 2013, autocad, binding, dynamic, développement, late, liaison, programmation, tardive

Les commentaires sont fermés pour ce billet

Commentaire de Patrick EMIN le 7 mars 2012 à 15:56

Veuillez poursuivre la lecture des commentaires de Serge sur ce fil de discussion, il devenait peu pratique de continuer à utiliser les zones de commentaires de ce billet, ces zones sont en effet prévues pour des commentaires courts.

Commentaire de Gérald LEMOINE le 7 mars 2012 à 10:47

salut Serge, et bravo,

tout ce que tu explique là, je n'avais jamais réussi à le comprendre en lisant des dizaines d'article.

tu aide la communauté francophone, qui est handicapée parceque ce genre d'informations, on les trouve surtout en anglais, et si beaucoup de français arrivent à lire de l'anglais qui parle de choses simples, comprendre un sujet complexe en anglais, c'est souvent difficile.

Comme patrick, je n'ai pas tout compris à la fin de l'article, mais c'est parceque je connais très peut la programmation .net, et d'ordinaire, on ne comprend que les explication aux question que l'on s'est posé ...

Au passage, je remercie également Gile qui fait ce travaille de vulgarisation.

Gérald

Commentaire de gile le 6 mars 2012 à 19:10

Ce que je disais à propos des expressions lambda concernait C# (je connais assez mal VB) et, à ma connaissance, en C#, il n'y a pas eu de changement de ce côté entre le FW3.0 et le FW 4.0.

Concernant le type dynamic, je ne pense pas qu'on puisse l'assimiler à l'inférence de type telle qu'utilisée dans F# ou avec le mot clé var en C# ou l'option Infer de VB. Avec l'inférence, le type des objets est déduit dès l'édition du code (avant même la compilation) et il est immuable. F# qui utilise l'inférence de type par défaut est plus fortement typé que C# (et c'est probablement pour ça que le type peut être déduit plus facilement).
Quand aux performances, lors de tests que j'ai pu faire avec deux petites bibliothèques semblables pour lire et écrire dans Excel, une utilisant la liaison tardive avec Reflection (et quelques méthodes d'extension pour rendre le code plus lisible) et l'autre utilisant le type dynamique, j'ai pu noter que la liaison tardive était très légèrement plus rapide (voir ici).

Commentaire de Serge Camiré le 6 mars 2012 à 15:23

Plusieurs raisons me motivaient à écrire un article, d’abord parce que ça faisait longtemps que je n’en avais pas fait, le sujet tombait pile, j’avais du temps, etc.

Quand je me suis pondu un petit canevas, je ne savais pas trop qu’elle serait la taille de l’article. Quand j’ai vu le résultat, j’ai eu peur que ce ne soit trop long et que personne ne le lise. Un gros merci à ceux qui l’ont fait.

Au début, je pensais laisser cet article sur une tablette pour y revenir un peu plus tard et faire des ajustements, un peu comme quand on sort une pièce de viande du four et qu’on lui laisse reprendre ses sucs. C’est peut-être une bonne chose que l’assiette du client se soit rendue sur la table plus tôt que prévue, cela « alimente » les discussions et va me laisser plus de temps pour un prochain article (je n’aime pas me commettre de la sorte :-)).

Gile a vu juste. Les expressions Lambda ont vu le jour avec VS2008 parce qu’il fallait supporter les requêtes SQL dans  LINQ mais ont été grandement améliorée avec la version 2010. Les nouveautés en 2010 sont énormes, sans compter qu’on n’a plus à se taper les caractères de continuation (underscore) à chaque fin de ligne. Par exemple, on peut définir des Sub et des Function de façon « inline » et par conséquent disposer des instructions Return. Certains pourront se demander à quoi sert de faire une longue fonction à l’intérieur d’une variable alors qu’on peut en faire de vraie et y mettre des points d’arrêt. Disons que quand on n’exagère pas, cela peut être une façon simple de créer des fonctions déléguées ou des fonctions qui ont une visibilité limitée. Ça remplace les Goto-Resume.

Pour plus de précision, dynamic est une troisième et nouvelle façon de déclarer des variables et qui ressemble à la liaison tardive à première vue mais qui obéit à la liaison hâtive à l’exécution d’où son intérêt et sa performance. On appelle cela l’inférence de type. L'inférence de type assigne un type fort à la variable mais qu'au moment de l'exécution, au lieu de la conserver en tant qu'Object. C’est pourquoi il n’y a pas d’IntelliSense car on n’est plus dans l’IDE. La liaison hâtive a ses avantages au niveau de la performance et de l’IntelliSense mais s’adapte mal aux environnements inconnus; la tardive est bonne pour son adaptabilité à un environnement inconnu mais souffre de lenteur; l’hydride (la dynamic) pour être entre les deux, il ne lui manque que l’IntelliSense.

Commentaire de gile le 5 mars 2012 à 13:15

Excellent article, merci Serge pour toutes ces précisions.

Juste un petit truc, à ma connaissance et si on parle bien de la même chose, les expressions lambda sont arrivées en même temps que LINQ et ses méthodes d'extension avec le FW 3.0.

Je n'ai pas encore utilisé le "Dynamic .NET" de la version 2013, mais j'ai un peu utilisé le type dynamic avec A2012 et si c'est effectivement parfois un plus avec l'interface COM, comme je le disais ici, je trouve le typage statique plus sûr et plus pratique dans un environnement aussi vaste que les bibliothèque .NET.

Pour une écriture plus concise et, à mon avis, plus descriptive, tout en conservant les avantages du typage statique et le contrôle des transaction (qui sont aussi un groupe d'annulation) je préfère l'utilisation de LINQ et de quelques méthodes d'extensions comme j'ai essayé de le montrer ici.

Dans la même optique, j'utiliserais volontiers plus souvent F# si ce langage n'était pas encore si confidentiel chez les développeurs AutoCAD .NET et s'il n'était pas nécessaire d'installer le runtime F# (qui n'est pas installé avec le .NET Framework) pour pouvoir utiliser des application écrites avec ce langage.

Commentaire de Braud Patrice le 5 mars 2012 à 10:34

Hello Serge

Un seul mot : Bravo et Merci

Je suis comme Patrick "pas tout compris" mais j'admire !

A+, Pat

 

Commentaire de Patrick EMIN le 5 mars 2012 à 10:06

Oui chapeau également à Serge d'avoir fait l'effort de partager ses connaissances à un public qui n'est la plupart du temps pas à son niveau mais qui bénéficie toujours de l'aspect didactique de sa prose émaillée de traits d'humour. Je ne comprends pas tout, complètement, mais je comprend tout, mieux.

Commentaire de Patrick_35 le 5 mars 2012 à 9:50

Super article.

Je n'ai pas le temps de tout lire, mais je vais y revenir.

chapeau

@+

Membres

Bibliothèque TraceParts - Fichiers 2D & 3D GRATUITS

© 2014   Créé par AUGIfr

Badges  |  Signaler un problème  |  Conditions d'utilisation