Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Lisp Discussion :

Require / use-package : différence(s) ?


Sujet :

Lisp

  1. #1
    Membre émérite
    Avatar de Nothus
    Homme Profil pro
    Ex-Attaché politique, en cours de reconversion vers ailleurs
    Inscrit en
    juillet 2009
    Messages
    183
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Charente (Poitou Charente)

    Informations professionnelles :
    Activité : Ex-Attaché politique, en cours de reconversion vers ailleurs
    Secteur : Conseil

    Informations forums :
    Inscription : juillet 2009
    Messages : 183
    Points : 2 308
    Points
    2 308
    Billets dans le blog
    25
    Par défaut Require / use-package : différence(s) ?
    Bonjour,

    Je sollicite une nouvelle fois vos éclairages - la documentation trouvée n'étant pas très claire / complète sur ces sujets.

    Concernant require et use-package, peut-on résumer leur différence au (seul ?) respect des espaces de noms pour les variables (quelque soit le type) ? En effet l'expérience :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #!/usr/bin/sbcl --script 
     
    (require 'sb-bsd-sockets) 
     
    (print #'sb-bsd-sockets:socket-close) 
     
    (use-package 'sb-bsd-sockets) 
     
    (print #'socket-close) 
     
    (print (eq #'socket-close #'sb-bsd-sockets:socket-close)) ; = T
    ... m'invite à penser que la principale différence est à ce niveau-là. J'imagine que c'est un peu plus subtile. La documentation CL ne fait pas dans le détail :

    "Function: require [cl] module-name &optional pathnames. Loads a module, unless it already has been loaded. pathnames, if supplied, is a designator for a list of pathnames to be loaded if the module needs to be. If pathnames is not supplied, functions from the list *module-provider-functions* are called in order with module-name as an argument, until one of them returns non-NIL. User code is responsible for calling provide to indicate a successful load of the module. " - http://www.sbcl.org/manual/index.html#Package-Variance

    J'ai supposé que cet impact se situe aussi au niveau des variables référencées au niveau des packages ? Est-ce une question de portée, de visibilité, les deux... ?

    Pour la documentation française, le Traité de Programmation LISP évoque bien l'espace de nom mais reste silencieux sur les packages (mal fouillé ?) :
    http://dept-info.labri.u-bordeaux.fr...L/node318.html

    Si vous avez des explications et/ou une documentation française sur ce point, ce serait super !

    Vous en remerciant par avance,

    Julien.
    Avec humour, sans exhaustivité, j'ai pu dire ou penser:
    • si un "exploit" est un hack, je n'ose imaginer ce qu'est un système d'exploitation ?!
    • un programme c'est imposer à la machine sa volonté grâce au travail d'un tiers qui, en retour, peut potentiellement exploiter notre volonté.
    • telle la portée des variables, mesurer celle de son propos permet la mesure de celle de son action. Ce que certains appellent la sémantique, n'est jamais ce que d'autres nomment "subjectivité".
    • parler sur Twitter, c'est soit vouloir être compris en peu de termes, la base des belles lettres ; soit l'équivalent de gueuler dans un bus à l'attention de ceux qui ne vous écoutent pas (mais vous qui répondront, peut-être, quand même).

  2. #2
    Membre actif
    Homme Profil pro
    Inscrit en
    mai 2013
    Messages
    144
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : mai 2013
    Messages : 144
    Points : 261
    Points
    261
    Par défaut
    Ils ont des buts différents.

    REQUIRE sert pour faire accessibles des fonctionnalités supplémentaires organisées en modules. Les modules sont une partie quelque peu marginal du standard et il s’agit pour la plupart des extensions de l’implémentation. Par exemple, si les outils pour les sockets ne sont pas disponibles lorsque SBCL démarre, on peut exécuter (require 'sb-bsd-sockets). À vrai dire, je n’ai heurté à REQUIRE que très rarement, et chaque fois je suis surpris.

    Les bibliothèques ordinaires sont généralement organisées d’une façon portable comme systèmes ASDF.

    Les paquets sont une partie intégrale du systeme des symboles. Ils sont similaires à des espaces de noms des autres langages. Mais il s’agit seulement des noms, pas d’une correspondance entre les noms et les objets.

    En quelque sorte, la plupart des symboles ont un « prénom » et un « nom de famille ». Par exemple, le nom du symbole REQUIRE dont nous venons de parler, c’est la chaîne "REQUIRE", alors que « son nom » de famille est le paquet COMMON-LISP.Un paquet est une collection de symboles qui sont regroupés en deux catégories : externes et internes. Par défaut un symbole est interne. Pour le faire externe, on l’exporte. Par convention, les symboles externes sont considerés comme l’API du paquet.

    Un paquet peut hériter les symboles externes d’un autre paquet. Voici un petit programme :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    (defpackage "MY-APP"
      (:use "COMMON-LISP")
      (:export "MAIN"))
     
    (in-package "MY-APP")
     
    (defun salutation (name)
      (format nil "Salut, ~A !~%"))
     
    (defun main ()
      (write-line "Comment t'appelles-tu ?" *query-io*)
      (finish-output *query-io*)
      (let ((name (read-line *query-io)))
        (write-line (salutation name) *query-io*))
      (finish-output *query-io*))
    Je commence par définir un « espace de noms », le paquet "MY-APP". Les paquets sont des objets Lisp, mais ils sont identifiés par les noms qui sont des chaînes. Dans mon programme, je voudrais avoir accès aux symboles habituels tels que DEFUN etc., qui résident dans le paquet "COMMON-LISP" (et sont externes dans ce paquet), donc je les importe en ajoutant la clause (:use "COMMON-LISP) à la définition de mon paquet. Ou bien je pourrais écrire (use-packate "COMMON-LISP") après la définition. Puis, je décide que l’API de ma bibliothèque comportera le seul symbole MAIN donc je l’exporte.

    À la fin, mon paquet va comprendre beaucoup de symboles internes, y compris tous les symboles du paquet COMMON-LISP aussi bien que SALUTATION et MAIN. Les deux derniers appartiennent au paquet même (le paquet est leur « nom de famille »), les autres sont hérités, mais tous sont accessibles dans le paquet, c’est-à-dire, je peux les employer sans préfixes lorsque je travaille dans le paquet MY-APP.

    Si je veux employer un symbole de ce paquet en travaillant dans un autre paquet, ça doit être le symbole MAIN, parce que c’est le seul symbole de l’API. Je peux m’y référer comme my-app:main. Mais en réalité, je peux me référer à n’importe quel symbol de ce paquet en le préfixant avec deux deux-points: my-app::salutation.

    Un langage comme C qui n’a pas des espaces de noms peut employer des préfixes conventionnels pour éviter les conflits : par exemple, g_main_run, etc. En Lisp, ces préfixes font partie du langage. On peut les omettre en travaillant dans le paquet correspondant, et la répartition des symboles en internes et externes facilite leur transmission entre les paquets. Je dirais qu’en pratique on préfère d’employer les noms qualifiés comme my-app:main au lieu de les importer.

    Il y a des langages qui confondent la question de la nomination avec d’autres questions. Par exemple, une classe peut introduire un espace de noms à la fois. En Lisp, ce sont les symboles qui sont utilisés comme noms et ils sont gérés comme tels, sans faire attention à leur éventuelle rapport aux objets. Donc, le systeme des « noms » (les symboles et les paquets) est « orthogonale » à d’autres aspects tel que classes, fichiers, bibliothèques, etc. Ils sont tous, en effet, mutuellement orthogonales, ce qui est bon.

    En fait, quand on parle des espaces de noms en Lisp, on n’a pas en vue les paquets, mais la correspondance entre les symboles et les objets. Évidemment, le nom et l’objet désigné par le nom sont des entités differentes. Un programme se compose de plusieres S-expressions, ou les symboles le plus souvent tiennent le rôle des noms. En Lisp, il y a plusieurs concepts de type « par nom »: « objet par nom », « fonction par nom », « classe par nom » et quelques autres. Par exemple, la façon ordinaire de calculer la valeur de l’expression (foo bar), c’est trouver la « fonction par nom » foo, l’« objet par nom » bar et appliquer la fonction à l’objet. Un autre exemple : (fonction 'foo) est la traduction en Lisp de « la fonction par nom foo », ce que peut être abrévié comme #'foo. Comme je l’ai mentionné, cette correspondance est orthogonale à la structure de l’ensemble des symboles.

  3. #3
    Membre émérite
    Avatar de Nothus
    Homme Profil pro
    Ex-Attaché politique, en cours de reconversion vers ailleurs
    Inscrit en
    juillet 2009
    Messages
    183
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Charente (Poitou Charente)

    Informations professionnelles :
    Activité : Ex-Attaché politique, en cours de reconversion vers ailleurs
    Secteur : Conseil

    Informations forums :
    Inscription : juillet 2009
    Messages : 183
    Points : 2 308
    Points
    2 308
    Billets dans le blog
    25
    Par défaut
    Merci de ton retour, et désolé de ma réponse tardive. J'ai passé pas mal de temps à lire la documentation cette semaine (vraiment beaucoup en réalité), en avançant assez peu. Tout particulièrement à partir de Common Lisp - 2nd Edition (Guy L. Steele JR).

    • "A module is a CL subsystem that is loaded from one or more files. A module is normally loaded as a single unit, regardless of how many files are involved. A module may consist of one package or several packages. The file-loading process is necessarily implementation-dependent (...)"
    • "Each module has a unique name (a string [pas de pathname autorisé]). (...) The 'require' function tests whether a module is already present (using a case-sensitive comparison) ; if the module is not present, 'require' proceeds to load file or set of files."


    On y retrouve donc ta réponse. Si j'ai bien suivi ta réponse et ce que j'ai lu par ailleurs - n'hésitez pas à me signaler si tu le veux bien, toute erreur :
    • un module est une composition arbitraire de paquets. Son nom est unique à une installation de LISP et permet de dépasser certaines contraintes liées à des implémentations différentes de LISP - qui chacune, disposent de liberté sur le déroulé "d'appropriation" du module. Le module a pour fonction de charger un ensemble (unique ou multiple) de fichiers, qui sont le plus souvent des paquets (leur définition).
    • un paquet permet de définir un certain nombre de méthodes -> fonctions ; de symboles internes et externes. On peut charger plusieurs paquets grâce à un module, mais on ne peut pas charger plusieurs paquets depuis un même paquet (en tout cas, même si ça reste possible, ce n'est pas un fonctionnement attendu).


    Là dessus, j'ai commencé à m'intéresser aux extensions de fichiers : FASL est le fichier "compilé" (du moins plus proche du langage machine) et sert généralement au paquet pour accélérer leur chargement (via 'load') - sachant que cela revient à une version améliorée d'un code interprété (symbole pouvant voir leur valeur / leur variable écrasée). C'est aussi utile pour disposer de fonctions compilées accélérant le traitement (cf CL, interpred or compiled ?). C'est facile à obtenir, mais le lien entre FASL, module et paquet me dépasse totalement.

    Reste les fichiers ASD, qui font partie d'ASDF comme tu l'évoques. Si j'ai tout bien compris (hum hum... vraiment pas sûr ), c'est en réalité un mix de ce que j'ai évoqué au-dessus, mais en version normalisée, afin de dépasser justement les problématiques d'implémentations. En soi on peut donc se servir des fonctions "de base" telles que décrites pour CL avec un même objectif (c'est juste idiot de ne pas reprendre ce qui existe).

    Bref : je n'ai toujours pas réussi à faire deux paquets de tests, les mettre dans un module et me servir de ce module. J'ai suivi les tutoriels ("defpackage ..." etc), mais cela ne me crée aucun fichier directement utilisable : ça me crée juste pour la session SBCL que j'utilise, un référence dans l'environnement.

    Je sens bien que je passe à côté de quelque chose de plus fondamental dans LISP : mais quoi ?
    Avec humour, sans exhaustivité, j'ai pu dire ou penser:
    • si un "exploit" est un hack, je n'ose imaginer ce qu'est un système d'exploitation ?!
    • un programme c'est imposer à la machine sa volonté grâce au travail d'un tiers qui, en retour, peut potentiellement exploiter notre volonté.
    • telle la portée des variables, mesurer celle de son propos permet la mesure de celle de son action. Ce que certains appellent la sémantique, n'est jamais ce que d'autres nomment "subjectivité".
    • parler sur Twitter, c'est soit vouloir être compris en peu de termes, la base des belles lettres ; soit l'équivalent de gueuler dans un bus à l'attention de ceux qui ne vous écoutent pas (mais vous qui répondront, peut-être, quand même).

Discussions similaires

  1. use package utf8
    Par boss89 dans le forum Mise en forme
    Réponses: 3
    Dernier message: 26/07/2012, 12h19
  2. Réponses: 0
    Dernier message: 05/12/2007, 10h09
  3. require / readfile, différences de perfs ?
    Par iluv dans le forum Langage
    Réponses: 3
    Dernier message: 12/08/2007, 13h28
  4. Différences entre protected et package friendly
    Par jo_le_coco dans le forum Langage
    Réponses: 8
    Dernier message: 11/03/2007, 15h44
  5. "use strict" et "require"
    Par minusette dans le forum Langage
    Réponses: 4
    Dernier message: 26/07/2006, 18h03

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo