Julia: module et alias d'importation

Créé le 5 sept. 2012  ·  96Commentaires  ·  Source: JuliaLang/julia

Pour le système de modules, nous pouvons importer et utiliser un module avec une notation par points :

import ArgParse
... 
    ArgParse.add_argument(p, "--opt1") 
...

Cela peut être utile pour éviter la pollution de l'espace de noms. En raison de la verbosité des noms de module, cependant, il serait bien d'avoir des alias de module :

import ArgParse as ap 
... 
    ap.add_argument(p, "--opt1") 
...
design modules speculative

Commentaire le plus utile

ce problème existe depuis longtemps, même si certaines extensions doivent encore être discutées, le

import LongPackage as longpkg

lui-même semble assez raisonnable.

Tous les 96 commentaires

J'ai réalisé il y a quelques minutes que vous pouvez faire ce qui suit :

import ArgParse
ap = ArgParse

ap.add_argument(...)

Je pense toujours qu'il serait bien d'avoir la notation "importer en tant que" comme sucre syntaxique.

Pendant que je suis ici et que j'y réfléchis, ce serait également bien d'avoir un moyen d'importer plusieurs fonctions spécifiques dans la même ligne d'importation, comme mentionné dans le post du forum de @ JeffreySarnoff . Une recherche dans les problèmes n'a pas encore révélé une telle demande.

Quelque chose comme

# from the forum post
import Module.(export1,export2,export3)
# or
import Module.[export1,export2,export3]
# or maybe
import Module.{export1,export2,export3}

C'est un problème différent de celui-ci, mais lié. Devrais-je

  1. mettre à jour ce problème, ou
  2. créer un nouveau problème

(Je suppose que l'utilité d'une telle fonctionnalité n'est pas controversée...)

Edit : Cela fonctionne maintenant avec import Module: export1, export2, export3

Je pense qu'il devrait également prendre en charge par exemple

import ArgParse.add_argument as addarg

pour pouvoir renommer les membres du module lors de l'importation.

Vous vous demandez comment les noms de fonction renommés participeraient à la répartition ?

Cela devrait fonctionner essentiellement comme un alias, équivalent à const foo = Base.bar .

Cela devrait fonctionner essentiellement comme un alias, équivalent à const foo =
Barre.de.base.

Lorsque nous importons une fonction, nous prévoyons soit de l'utiliser, soit de la remplacer. Étant donné
ce qui précède, avec

importer Base.bar en tant que foo

nous pouvons certainement utiliser foo comme Base.bar, mais la définition de foo remplacerait également
Base.bar ? Devrait-il?

C'est un vieux problème, mais je pense qu'il est temps d'y revenir car nous approchons de 0,2

En écrivant des codes, j'ai découvert que j'avais toujours voulu écrire import NumericExtensions as ne et j'ai fini par me rappeler que cela n'était pas pris en charge.

Je suppose que ce n'est pas trop difficile à mettre en œuvre, et à mon avis, c'est beaucoup plus agréable que d'écrire

import NumericExtensions
const ne = NumericExtensions

+1

+1

Est-ce toujours d'actualité ? Personnellement, cela ne me dérange pas de faire le supplément foo = Foo pour l'aliasing de module, mais il semble qu'il y ait eu un consensus pour prendre en charge l'aliasing sugar. Quelqu'un qui se sent assez fort peut devoir faire un PR lui-même.
Notez cependant que x as y était l'un des candidats les plus sérieux pour la syntaxe convert(y,x) mentionnée dans #1470. Il semble qu'il ne serait pas trop difficile de lever l'ambiguïté des deux, mais notez simplement.

La valeur de cette fonctionnalité est que vous pourriez éviter d'importer le nom d'origine.

+1
Ce serait génial d'avoir cette fonctionnalité.

+1

Plutôt que d'introduire un nouveau mot-clé as , que diriez-vous d'utiliser l'opérateur => , comme dans

import Tlahuixcalpantecuhtli => Venus: xxxxxxxxx => x9, yyyyyyyy => y8, zzz

Cela permettrait orthogonalement le crénelage du module et de tout sous-ensemble de variables dans la même syntaxe.

Je ne sais pas, ça me semble vraiment moche.

import Tlahuixcalpantecuhtli as Venus: xxxxxxxxx as x9, yyyyyyyy as y8, zzz

Est-ce mieux ? Je le trouve beaucoup moins lisible.

Personnellement, je trouve as est plus explicite que => , ce qui semble vouloir dire un certain nombre de choses.

divulgation complète : biais python.

J'aime mieux la syntaxe => que as .

J'aime les bikesheds qui restent coincés dans les équilibres de Nash.

Pourquoi relieriez-vous les symboles internes d'un module ? C'est moche parce que vous ne devriez vraiment pas faire ça.

J'aime la syntaxe d'importation de Haskell . Je pense que les espaces de noms de Python sont plus granulaires que les modules de Julia. Le module de Julia se sent plus dans l'esprit des modules de Haskell, alors peut-être devrions-nous y chercher l'inspiration.

Je suis d'accord avec @ssfrr , le mot-clé as est beaucoup plus explicite et est également familier aux utilisateurs de Python/Haskell. Pour résoudre le problème de lisibilité de @StefanKarpinski , une approche de type python aiderait également :

from Tlahuixcalpantecuhtli as Venus import xxxxxxxxx as x9, yyyyyyyy as y8, zzz

J'ai l'impression de parler au REPL. Mais je sais que ce genre de suggestion n'est pas faisable.

from Tlahuixcalpantecuhtli as Venus import xxxxxxxxx as x9, yyyyyyyy as y8, zzz

C'est l'un de mes choix syntaxiques les moins préférés en Python. Pour modifier légèrement le sens, vous devez réorganiser radicalement toute la ligne, en modifiant le mot-clé initial et l'ordre de tout. Il semble complètement différent des autres importations, ce qui masque le fait qu'ils font presque la même chose. C'est une conception syntaxique terrible, imo, donnant beaucoup trop de poids au fait d'être superficiellement anglais.

:+1 : pour as , :-1 : pour from

import a => b: c => d, e => f me semble un peu trop perlé.

Je n'ai jamais entendu parler d'équilibres de Nash et après avoir lu à ce sujet, je ne pense pas que cela en constitue un. Mais le plus drôle c'est que, alors que ce bikeshed a 10 réponses en une heure, une proposition sur le #6984 qui me semble très importante (mais plus difficile) a duré 4 heures sans commentaire !

Quant à as vs. => : l'un ou l'autre sera une belle amélioration par rapport à la situation actuelle.

Bon point @BobPortmann sur #6984.

Je pense que => est super pour ça, FWIW.

Mais le plus drôle c'est que, alors que ce bikeshed a 10 réponses en une heure, une proposition sur le #6984 qui me semble très importante (mais plus difficile) a duré 4 heures sans commentaire !

Dans l'analogie originale de Parkinson, ce problème est le garage à vélos et # 6984 est le réacteur nucléaire.

:)

Je déteste remuer ce pot mais je pense que je préfère as . => est un peu vague, et il est étrange que cela partage la syntaxe avec les dictionnaires. Peut-être que = a du sens : import Foo: x = y , par analogie avec les const x = Foo.y que vous feriez maintenant.

Si rien d'autre, ce tableau dans la documentation Haskell est vraiment utile. J'ai souvent (surtout lorsque j'ai appris Julia pour la première fois) été confus quant à savoir quand utiliser import / using / require , ou quand faire import Mod.thing vs import Mod: thing . En fait, je cherchais simplement l'explication de la syntaxe des deux-points sur les importations et je ne l'ai pas trouvée.

@jakebolewski il semble que la syntaxe Haskell soit assez proche, avec le using de Julia équivalent au import de Haskell (non qualifié) et le import de Julia étant équivalent au import qualified de Haskell


Comme point de départ, quelqu'un qui connaît mieux peut-il confirmer qu'il s'agit d'un bon résumé de la syntaxe d'importation/utilisation actuellement disponible ? Disons que nous avons un module Mod qui exporte les fonctions x et y , et a également des fonctions non exportées p et q .

import Mod rapporte Mod.x , Mod.y , Mod.p et Mod.q . Les fonctions importées sont toutes disponibles pour l'extension de méthode

using Mod apporte x , y , Mod.x , Mod.y , Mod.p et Mod.q . x et y ne sont pas disponibles pour l'extension de méthode, mais Mod.* sont.

import Mod.x, Mod.p apporte x , p , Mod.x , Mod.y , Mod.p et Mod.q . Ils sont tous disponibles pour l'extension de méthode.

import Mod: x, p est identique à import Mod.x, Mod.p

using Mod.x, Mod.p apporte x , p , Mod.x , Mod.y , Mod.p et Mod.q . x et p ne sont pas disponibles pour l'extension de méthode, mais Mod.* sont.

using Mod: x, p est le même que using Mod.x, Mod.p

Autant que je sache, using Mod est la seule utilisation qui se soucie de ce qui est exporté par Mod .

Il serait vraiment utile d'avoir ce résumé sur les docs de Module ! Quelqu'un peut-il confirmer cela, afin que je puisse préparer un PR ?

Il semble que la version la moins controversée soit :

import Tlahuixcalpantecuhtli as Venus: xxxxxxxxx as x9, yyyyyyyy as y8, zzz

Je suis cool avec ça. La version du devoir est intéressante cependant, testez-la:

import Venus = Tlahuixcalpantecuhtli: x9 = xxxxxxxxx, y8 = yyyyyyyy, zzz

Je pensais que j'allais détester ça, mais c'est en fait plutôt sympa. J'aime le fait que les noms qui sont introduits dans ce module viennent en premier et sont les plus importants - à bien des égards, c'est la chose la plus importante.

@jakebolewski : Pourquoi relieriez-vous les symboles internes d'un module ? C'est moche parce que vous ne devriez vraiment pas faire ça.

Vous voudrez peut-être importer des liaisons avec des noms conflictuels à partir de deux modules différents et cela le permet. Vous pouvez également les qualifier pleinement, mais si nous prenons en charge l'aliasing, nous pourrions aussi bien le prendre en charge.

Certaines nouvelles lignes bien placées rendent l'un ou l'autre plus lisible, IMO :

import Tlahuixcalpantecuhtli as Venus:
    xxxxxxxxx as x9, 
    yyyyyyyy as y8,
    zzz

ou

import Venus = Tlahuixcalpantecuhtli: 
    x9 = xxxxxxxxx, 
    y8 = yyyyyyyy, 
    zzz

Je trouve que je préfère assez fortement la version d'affectation. L'importation est une forme d'affectation, après tout.

Il serait vraiment utile d'avoir ce résumé sur les docs de Module ! Quelqu'un peut-il confirmer cela, afin que je puisse préparer un PR ?

@brk00 , allez-y !

@kmsquire , je vais y travailler aujourd'hui !

Mais avant de faire cela, je veux m'assurer que je le comprends bien. Dans l'exemple @ssfrr , supposons que je suis sur le REPL et que je tape using Mod . Les fonctions importées x et y ne sont pas disponibles pour l'extension de méthode. Cela signifie que, si je déclare une autre fonction x et y, je n'aurai plus accès aux méthodes de Mod que j'ai importées une fois, seulement aux nouvelles ?

Voici ce qui se passe si vous essayez d'étendre une fonction sans l'importer :

julia> module Mod

       export x, y

       x() = "x"
       y() = "y"
       p() = "p"
       q() = "q"

       end

julia> using Mod

julia> x()
"x"

julia> p()
ERROR: p not defined

julia> x(n) = n
ERROR: error in method definition: function Mod.x must be explicitly imported to be extended

Vous pouvez ajouter une méthode comme celle-ci :

julia> import Mod: x # or import Mod.x

julia> x(n) = n
x (generic function with 2 methods)

julia> methods(x)
# 2 methods for generic function "x":
x() at none:5
x(n) at none:1

Eh bien, j'étais confus par le comportement de résolution de nom:

julia> module Mod

       export x, y

       x() = "x"
       y() = "y"
       p() = "p"
       q() = "q"

       end

julia> using Mod

julia> x(n) = n
x (generic function with 1 method)

Si j'attribue une nouvelle fonction à x avant d'_utiliser_ celle que je viens d'importer avec using Mod , l'erreur ne se produit pas. Mais si, par exemple, j'appelle x() avant la nouvelle affectation (comme vous l'avez fait dans votre exemple), l'erreur est effectivement générée.

Ah, intéressant ! Je ne savais pas ça. Il m'est arrivé d'appeler x pour démontrer l'espacement de noms après le using .

Peut-être que l'un des principaux développeurs peut nous éclairer. Que se passe-t-il lorsque x est appelé et déclenche l'erreur lors d'une tentative de surcharge ?

Je trouve le crénelage suggéré par @carlobaldassi ci-dessus très utile dans la pratique.

Je me demande si import pourrait simplement renvoyer l'objet module, de sorte qu'il puisse être aliasé directement avec une affectation, avec ou sans const ? Par exemple

const Shortname = import ModuleWithLongName

au lieu de

import ModuleWithLongName
const Shortname = ModuleWithLongName

Cela ne nécessiterait aucune nouvelle syntaxe, juste une combinaison d'éléments de syntaxe existants. Je me rends compte qu'actuellement import est une "déclaration", appelée uniquement pour les effets secondaires, et n'a aucune valeur. Si l'analyseur ne le permet pas, je préférerais import("Module") ou quelque chose de similaire.

Je pense que l'option d'aliaser les modules pourrait être agréable, mais je pense aussi qu'il y a un inconvénient que personne n'a mentionné : cela pourrait considérablement obscurcir le code. Du point de vue d'un lecteur de code, il est agréable de n'avoir qu'un seul nom descriptif pour un module.

Assez trivial à regarder cependant? Les formulaires raccourcis seront également probablement standardisés pour les packages populaires tels que np pour numpy .

Je préférerais toujours numpy à np standardisé et même Arrays à numpy . numpy sonne comme un croisement entre un mouvement de danse des années 1950 et une peste mortelle.

peut facilement écrire simplement:

Base.require("ArgParse")
const ap = Main.ArgParse

cela n'a pas besoin d'une syntaxe pour 1.0

Je pense que nous devrions avoir une syntaxe pour cela. Oui, nous pouvons nous en passer puisque vous pouvez faire require et une affectation const , mais utiliser require est assez moche et l'absence d'une syntaxe pratique décourage les gens de renommer les choses comme ils veulent/ont besoin.

L'astuce const étant facile ne suffit pas quand on a besoin d'aliaser une macro, c'est comme ça que je le fais, et il m'a fallu un certain temps pour comprendre:

julia> macro foo(a, b, c)                                  
           a, b, c                                         
       end                                                 
<strong i="8">@foo</strong> (macro with 1 method)                                 

julia> macro f(args...)                                    
           Expr(:macrocall, Symbol("@foo"), args...) |> esc
       end                                                 
<strong i="9">@f</strong> (macro with 1 method)                                   

julia> <strong i="10">@f</strong> 1 2 3                                            
(1,2,3)                                                    

Dans ImportMacros.jl, j'implémente :

  • <strong i="15">@from</strong> Foo.Bar use foo as f
  • <strong i="18">@from</strong> Foo.Bar use <strong i="19">@foo</strong> as @f

Voir : https://github.com/fredrikekre/ImportMacros.jl/pull/3

@Ismaël-VC

Essayer

<strong i="7">@eval</strong> const $(Symbol("@foo")) = $(Symbol("@bar"))

ce qui est plus laid, mais plus court et peut-être plus clair que de définir une macro localement

@TotalVerb merci encore pour votre aide !

Il semble que la seule fonctionnalité manquante de Julia + ImportMacros est d'aliaser à la fois le module et un mélange d'alias d'un nombre variable d'objets de ce module et d'importation d'autres sans alias :

  • <strong i="9">@from</strong> Foo.Bar as B use foo as f, <strong i="10">@bar</strong> as <strong i="11">@b</strong>, baz

Ou sans le from :

  • import Foo.Bar as B: foo as f, <strong i="17">@bar</strong> as <strong i="18">@b</strong>, baz
  • import B = Foo.Bar: f = foo, <strong i="21">@b</strong> = <strong i="22">@bar</strong>, baz

Le dernier semble impossible avec les macros :

julia> parse("<strong i="26">@from</strong> Foo.Bar as B use foo as f, <strong i="27">@bar</strong> as <strong i="28">@b</strong>, baz")
:(<strong i="29">@from</strong> Foo.Bar as B use foo as (f,@bar(as,(@b(),baz))))

julia> parse("<strong i="30">@import</strong> Foo.Bar as B: foo as f, <strong i="31">@bar</strong> as <strong i="32">@b</strong>, baz")
:(<strong i="33">@import</strong> Foo.Bar as B:foo as (f,@bar(as,(@b(),baz))))

julia> parse("<strong i="34">@import</strong> B = Foo.Bar: f = foo, <strong i="35">@b</strong> = <strong i="36">@bar</strong>, baz")
ERROR: ParseError("unexpected \"=\"")
 in #parse#310(::Bool, ::Bool, ::Function, ::String, ::Int64) at .\parse.jl:184
 in (::Base.#kw##parse)(::Array{Any,1}, ::Base.#parse, ::String, ::Int64) at .\<missing>:0
 in #parse#311(::Bool, ::Function, ::String) at .\parse.jl:194
 in parse(::String) at .\parse.jl:194

Cela n'a en fait pas besoin d'être décidé pour la version 1.0 puisque toutes les syntaxes proposées sont soit des erreurs, soit un non-sens total.

Que doit-il arriver à un alias de module lorsque le module d'origine est redéfini, par exemple, par un reload("...") sur le REPL ? Avec l'approche const M = MyModule , M fait toujours référence à l'ancien module après le rechargement, donc tout nouveau nom défini dans MyModule ne sera accessible que par MyModule.name mais pas M.name .

Dans ce cas, une syntaxe d'alias doit être plus que du sucre syntaxique pour un const M = Module , mais assurez-vous plutôt que M fait toujours référence à la même chose que MyModule .

Cela simplifierait également le flux de travail REPL puisque je peux continuer à import un module pendant le développement, mais je peux y faire référence via un alias plus court sans avoir à rétablir un alias (non const ) à chaque fois que je reload .

À l'heure actuelle, reload est supprimé, ce problème n'est donc plus applicable.

Cela s'applique également à include , ou ai-je raté quelque chose ? En général, lorsqu'un module est redéfini, le nom du module import ed fait référence à la nouvelle définition alors qu'un alias défini par affectation fait référence à l'ancienne définition, n'est-ce pas ?

Non cela ne devrait pas être un souci. Le nom importé ne sera JAMAIS modifié lorsqu'un module est redéfini, y compris le import normal. Ce qui a changé, c'est le module qui sera importé si vous l'importez à nouveau. L'import n'a toujours été qu'une reliure.

Ok, peut-être que je ne me suis pas exprimé clairement, alors voici un exemple : Si vous créez un fichier test.jl avec le contenu

module Tst
f() = 1
end

vous pouvez le charger, importer Tst , définir un alias pour Tst , et tout va bien :

julia> include("test.jl")
Tst

julia> import Tst

julia> const Tst2 = Tst
Tst

julia> Tst.f()
1

julia> Tst2.f()
1

Si vous changez maintenant test.jl en

module Tst
f() = 2
end

et re- include dans le REPL, le module et son alias se comportent différemment :

julia> include("test.jl")
WARNING: replacing module Tst
Tst

julia> Tst.f()
2

julia> Tst2.f()
1

Je vois pourquoi c'est le cas, mais je pense que cela ne devrait pas se produire lorsque vous créez un alias avec quelque chose comme import Tst as Tst2 .

J'ai testé cela sur 0.6.2, et pour le moment je ne peux pas le tester sur 0.7, donc je ne sais pas si c'est toujours le cas.

Vous ne l'importez pas du tout. Le module que vous incluez est déjà défini dans votre portée. Le import est un no-op.

C'est vrai, mais ce n'est pas le sujet. Le point est ce qui se passe quand je fais quelque chose comme l'hypothétique import Tst as Tst2 . Ensuite, cette instruction n'est pas un no-op mais crée un alias.

Si cet alias fonctionne comme un const Tst2 = Tst , alors la redéfinition du module Tst fera pointer l'alias vers l'ancienne version du module. Ce n'est en aucun cas souhaitable. Soit l'alias doit également pointer vers la nouvelle version de Tst , soit l'utilisateur doit être obligé de rétablir l'alias. Mais dans ce dernier cas, l'utilisation de l'ancien alias sans le rétablir devrait générer une erreur au lieu de pointer vers l'ancien module.

C'est tout à fait le point. Ce problème concerne l'ajout d'une fonction à import non à la définition de module. Votre import n'est pas opérationnel et après l'avoir supprimé, votre code n'a plus aucun import ou using , il n'est donc pas lié à ce problème. Veuillez le modifier afin que le module ne soit pas défini dans la même portée que import .

import Tst as Tst2 fonctionnera de la même manière que import Tst en ce qui concerne ce qui est lié à ce nom, qui est toujours une liaison et non quelque chose de magique que vous voulez. Il ne s'agit PAS d'ajouter un alias lors de la définition du module.

Autrement dit, votre code est fondamentalement,

a = Ref(1) # include
a = a # import
b = a # alias
a = Ref(2) # include again

Et cela n'a aucun sens de se plaindre du comportement du b = a puisque le a n'est pas du tout lié par le a = a . Tout ce que vous voyez est l'effet secondaire de la définition du module dans la même portée que l'importation (c'est-à-dire a = a et a = Ref(...) dans la même portée) dans un mauvais exemple.

Ok, je voulais juste souligner que dans certaines situations, un alias défini par une affectation ne fonctionnerait pas comme prévu. J'ai peut-être choisi un mauvais exemple. J'ai pensé que cela pourrait être important pour une syntaxe qui crée un alias de module (qu'il soit lié ou non à import ), mais pour le moment, c'est de toute façon hypothétique. Désolé pour le bruit.

ce problème existe depuis longtemps, même si certaines extensions doivent encore être discutées, le

import LongPackage as longpkg

lui-même semble assez raisonnable.

Cogner. Je me demande à quoi ressemble la meilleure solution - pour l'instant -? Voici ce que je fais :

import LinearAlgebra
const linalg = LinearAlgebra

S'il vous plaît corrigez-moi s'il y a une meilleure solution!

C'est la norme actuelle.

Qu'en est-il d'une syntaxe ~ ? Je ne connais pas les ramifications, mais il a une belle esthétique. En outre, ~ est utilisé comme symbole approximatif.

import LongPackage ~ lp

@JeffreySarnoff citant Stefan

@StefanKarpinski

C'est l'un de mes choix syntaxiques les moins préférés en Python. Pour modifier légèrement le sens, vous devez réorganiser radicalement toute la ligne, en modifiant le mot-clé initial et l'ordre de tout. Il semble complètement différent des autres importations, ce qui masque le fait qu'ils font presque la même chose. C'est une conception syntaxique terrible, imo, donnant beaucoup trop de poids au fait d'être superficiellement anglais.

Dans ce cas, ~ n'aurait rien à voir avec l'aspect anglais de la syntaxe Python. Je pense que quand je vois ~, je reconnais juste le concept mathématique d'approximation. 10.001 ~ 10.

Donc, dans ce sens, je trouve ~ plutôt sympa en fait.

import LongPackage ~ lp
import HugePackage ~ hp
import MassivePackage ~ mp
import GiantPackage ~ gp

:-)

ok - oubliez python - je supprime ce commentaire en faveur de

lp imports LongPlayingRecords
hp imports HewlettPackard
mp imports MilitaryPolice
gp imports PariForNumberTheory

Au départ, je n'aimais pas ça, mais tant de gens semblent naturellement vouloir écrire ceci avec as Je dois dire que cela semble pervers de faire autre chose. Il n'est pas nécessaire de le réserver en tant que mot-clé ou quoi que ce soit puisqu'il s'agit d'un contexte syntaxique clair.

Un langage de programmation qui _essaye_ de faire savoir aux gens ce que cela signifie !?!

@JeffreySarnoff

Un langage de programmation qui essaie d'être meilleur que Python !!!

@neilpanchal Julia est définitivement un langage qui essaie d'être meilleur que Python à bien des égards. D'un autre côté, il est évident qu'il n'est pas hors de question d'être _différent_ de Python où Python a quelque chose de bien. Julia emprunte les conventions syntaxiques de Python à gauche et à droite.

Veuillez adopter le python as . Ils ont bien compris.

julia> importer LightGraphs en tant que lg
ERREUR : syntaxe : jeton supplémentaire "as" après la fin de l'expression

Juste un autre commentaire de 0,02 $ en faveur de as qui s'éloigne de Python. fwiw, maintenant que j'utilise à nouveau Julia avec une certaine régularité, cela me manque. Pas comme dans Python, mais comme dans Clojure (voir exemple ), où les espaces de noms de portée de package (qui sont bons pour la désambiguïsation) peuvent être simplifiés pour rendre l'utilisation explicite des bibliothèques beaucoup plus maniable. Étant donné que j'ai une préférence pour éviter using (c'est-à-dire les importations de caractères génériques) avoir du sucre syntaxique à import Gadlfy as gf sans l'ajout de la ligne const gf = (ce que je fais actuellement) serait être maniable.

Encore un autre commentaire soutenant la syntaxe as :heart: Je lui souhaite vraiment beaucoup pour les futures versions de Julia.

Je souhaite moi aussi que cela se produise. D'autant plus qu'il ne s'agit pas d'un breaking change (n'est-ce pas ?).

Je pense que cela sera implémenté à un moment donné (j'essaierais moi-même si je pouvais prendre le temps), mais en attendant, le paquet ImportMacros a à peu près toutes les fonctionnalités demandées ici (bien qu'il manque de la documentation) :

<strong i="8">@import</strong> ModuleA as ma
<strong i="9">@using</strong> ModuleB as mb
<strong i="10">@from</strong> ModuleC use long_function_name as func
<strong i="11">@from</strong> Module use <strong i="12">@macroname</strong> as <strong i="13">@alias</strong>

Je ne connaissais pas ImportMacros .jl, merci de l'avoir signalé. Si cette fonctionnalité existe dans un package, je suppose qu'il n'est pas si important de l'avoir dans la langue de base.

Je pense toujours que ce serait bien d'avoir dans la langue.

Les importations sont exactement le genre de choses pour lesquelles vous voulez presque _toujours_ vous reporter aux conventions de langage de base et ne pas envelopper de macros ou ajouter une dépendance de package. import ... const est une meilleure chose sur laquelle se rabattre, même (surtout) si le langage de base n'est jamais étendu pour rendre ce processus en deux étapes plus concis.

En particulier, c'est un peu moche à voir

using ImportMacros
<strong i="6">@using</strong> OtherPackage as ...
<strong i="7">@using</strong> ThirdPackage as ...

parce que le non-macro using dépasse.

Que diriez-vous import renvoyant le module/la fonction/tout ce qu'il apporte réellement à la portée ?
Ensuite, vous pouvez écrire
lg = import LightGraphs
baz = import foo.bar
baz, kit, kat = import foo : bar1, bar2, bar3
La seule chose qui doit être changée est la fonction d'importation

J'aime beaucoup la solution de @DhruvaSambrani car elle correspond à l'approche globale "tout est une expression" de Julia.

La seule chose est que, pour être cohérente, l'expression d'importation devrait encore produire l'effet secondaire d'amener le nom complet dans la portée (peut-être pas un désastre). Cela pourrait également être une casse spéciale pour ne pas importer le nom complet, mais la casse spéciale est grossière.

En OCaml (le langage avec les meilleurs modules !), vous pouvez faire quelque chose comme :

module LG = LightGraphs

La différence importante ici est que le nom qualifié de chaque module qui est compilé avec le programme OCaml est automatiquement dans la portée.

Bien sûr, l'utilisation import LightGraphs as LG a l'avantage que "tout le monde" le sait déjà de Python, mais mon goût personnel est qu'il est préférable de réutiliser la syntaxe d'affectation pour quelque chose qui est littéralement une affectation.

Ou un changement plus important consisterait à introduire un "espace de noms" en tant que Type (idk si c'est déjà fait). Ensuite, import peut développer le module/quelque chose dans un espace de noms et renvoyer l'espace de noms. Mais cela cassera tout le code Julia car le simple fait de faire import mod_name ne rendra pas l'espace de noms mod_name disponible dans la portée globale. Si l'on peut d'une manière ou d'une autre rendre l'espace de noms mod_name disponible pour global lorsque l'importation est utilisée sans affectation le précédant, alors ce n'est pas un problème.

Ou ajoutez simplement une nouvelle fonction import_as_ns(mod_name) :: Namespace qui sera une fonction pure qui renvoie toutes les fonctions/modules, etc. dans un seul espace de noms.

cela correspond à l'approche globale "tout est une expression" de Julia

Cependant, import et using sont spéciaux car ils ne sont utilisés que pour leurs effets secondaires, et uniquement au niveau supérieur.

Incidemment, étant donné que ce problème est ouvert depuis longtemps, je me demande si le triage serait prêt à le réexaminer et à prendre une décision. Je préconiserais la fermeture, puisque

  1. import Foo; const Bar = Foo fournit une solution parfaite lorsque l'utilisateur ne se soucie pas Foo dans l'espace de noms,
  2. ImportMacros.jl devrait gérer le reste,
  3. ni l'un ni l'autre ne semble être utilisé très fréquemment dans le code pratique pour justifier une syntaxe spéciale.

Je dirai qu'après tout ce temps, cela me manque toujours (et j'utilise également ImportMacros dans mon propre code).

Je pense que le style de café que vous écrivez affecte le besoin (ou le désir) de cela. Quand j'écris du ML ou du code scientifique, je trouve que ça ne me manque pas beaucoup. Lorsque j'ai écrit d'autres codes qui utilisent un certain nombre de packages avec des noms longs, c'est lorsque j'utilise le plus ImportMacros.

ImportMacros est suffisant. Je suis juste d'accord avec les commentaires selon lesquels il n'a pas l'air si propre.

J'attends aussi avec impatience le jour où je pourrai utiliser un formatteur automatique dans mon éditeur pour trier mes importations... mais il est moins probable de savoir quoi faire avec @using ...

Je suis également d'accord avec @kmsquire que ce n'est pas un si gros problème, et ImportMacros devrait suffire. Mais quelle que soit la méthode, elle doit être documentée afin qu'elle ne se reproduise plus.

Bien que j'aimerais toujours le sucre m=import Module 😅

Je ne voulais pas que mon message laisse entendre que ce n'est pas grave.

Je préférerais toujours une syntaxe pour cela.

ImportMacros est suffisant. Je suis juste d'accord avec les commentaires selon lesquels il n'a pas l'air si propre.

Je suis d'accord. Aussi pour:

using ImportMacros
<strong i="8">@using</strong> OtherPackage as ...

Cela rend un peu ennuyeux lors de la présentation du langage aux nouveaux arrivants ou aux débutants en programmation d'expliquer pourquoi un script donné commence par cette incohérence, car cela complique le flux et déplace l'orientation de l'enseignement.

ni l'un ni l'autre ne semble être utilisé très fréquemment dans le code pratique pour justifier une syntaxe spéciale

La raison pour laquelle les gens n'utilisent pas beaucoup ImportMacros dans le code réel peut être due à un compromis. Par exemple, j'utiliserais import ... as ... presque à chaque fois, mais probablement pas au prix d'avoir à importer d'abord un autre package pour le faire. Plus qu'une dépendance supplémentaire, ça a aussi un impact en terme de "feel" (et certaines personnes aiment que leur code soit épuré (surtout en python ou Julia) 🤷‍♂️ , et ce using/@using donne plutôt un " hacky" à l'introduction d'un script).

Alors oui, "ImportMacros est suffisant". Pour les personnes qui veulent vraiment l'utiliser. Mais c'est le truc, ce n'est pas un problème vital, et les gens peuvent travailler sans ça. Néanmoins, je crois fermement que ce sont généralement ces petites choses qui permettent à la syntaxe d'un langage de coller, d'où ce thread monstre pour ajouter son support à la base.

Je pense que import ... as ... est un sucre syntaxique qui en vaudrait vraiment la peine, c'est vraiment facile à comprendre et à expliquer, et particulièrement utile dans des langages comme Julia dans lesquels les packages ont tendance à avoir des noms plutôt longs (évidemment, cela compte seulement sous l'hypothèse que les gens ne veulent pas faire using ... ).

Et le fait que Python l'ait implémenté en premier ne devrait pas vraiment être pertinent ; Julia devrait s'efforcer d'avoir la meilleure syntaxe avant d'essayer de se démarquer des autres langues et/ou de souligner sa propre identité.

Avoir une syntaxe pour cela et des conventions autour des modules populaires (je pense à la façon dont c'est toujours import numpy as np et import matplotlib.pyplot as plt ) donnerait également une alternative concise à faire using SuchAndSuch et à s'appuyer sur export ed noms (ce que j'évite généralement dans le code "bibliothèque").

@DominiqueMakowski :

présenter le langage aux nouveaux arrivants ou aux débutants en programmation pour expliquer pourquoi un script donné commence par cette incohérence

Je ne comprends pas pourquoi vous pensez que c'est une incohérence, c'est simplement la gestion de l'espace de noms, qui fait partie intégrante de la programmation au sens large.

De plus, renommer les modules n'est peut-être pas quelque chose que les nouveaux venus sur Julia rencontreraient en premier.

Je ne dis pas qu'il n'y a pas de cas d'utilisation, mais il peut être trop rare pour justifier son propre mot-clé. Pour le moment, la recherche de using ImportMacros donne <10 résultats uniques sur Github.

J'utiliserais import ... comme ... presque à chaque fois, mais probablement pas au prix d'avoir à importer d'abord un autre paquet pour le faire

Cela va dans les deux sens : si le coût (très mineur) de l'utilisation d'un package léger comme ImportMacros ou d'un symbole supplémentaire ( import LongFoo; const Foo = LongFoo ) ne vaut pas l'avantage, alors l'avantage peut ne pas être si important .

Julia devrait s'efforcer d'avoir la meilleure syntaxe avant d'essayer de se démarquer des autres langues et/ou de souligner sa propre identité.

Je ne sais pas pourquoi vous pensez que c'est une motivation dans cette discussion.

Il y a des cas où vous voudrez peut-être utiliser as où l'affectation const ne fonctionne pas tout à fait :

julia> using Distributed

julia> import Future; const future = Future
Future

julia> Future === Distributed.Future # oops, this is what we wanted
false

julia> Future === future # not what we wanted `Future` to mean
true

Oui, vous pouvez contourner cela, mais c'est gênant. Étant donné que c'est souvent pratique, parfois nécessaire et que import FooBar as FB est la syntaxe "la moins surprenante" généralement acceptée, cela semble être ce que nous devrions faire. Tout ce qu'il faut, c'est que quelqu'un fasse un PR pour le mettre en œuvre.

Nouvel utilisateur de Julia ici.
Je viens d'un milieu principalement R, utilisant également Python. J'ai de mauvaises expériences avec l'espace de nom commun du package auquel conduisent des mécanismes de chargement tels que using . Le risque de collision en est un, mais du point de vue de la lisibilité, c'est un fardeau mental de penser constamment au module de chaque méthode.

Je ne sais pas à quel point l'ajout de cette syntaxe est complexe ? Est-ce faisable pour un débutant ?

Probablement pas très facile. Cela impliquera de pirater le code de l'analyseur qui est écrit dans Scheme et de câbler le changement via l'AST, ce qui pourrait également toucher du code C.

Ce serait une fonctionnalité intéressante pour éviter les conflits de noms de fonctions dans plusieurs modules.

À partir d'une discussion sur le mou, j'ajoute quelques réflexions

Je me demande si cela rendra les gens moins attentifs au choix des noms de fonction et à l'ajout correct de méthodes aux bonnes fonctions. Le fait que, par exemple,

numpy.sin
sympy.sin

sont des fonctions différentes est un moyen infaillible d'avoir à implémenter deux versions de votre fonction si vous voulez qu'elle fonctionne à la fois pour les entrées numériques et symboliques. Si un tel espacement de noms se généralise également dans Julia en raison de la commodité, nous pourrions manquer beaucoup de réutilisation de code ? C'est-à-dire que j'ai peur que cela nous donne moins de " Cela encourage les gens à travailler ensemble " comme l'a dit Lyndon dans https://www.oxinabox.net/2020/02/09/whycompositionaljulia.html

@baggepinnen Je ne pense pas que cela change quoi que ce soit à cet égard.

Dans Julia, les méthodes implémentées dans différents modules ne sont pas fusionnées en important les deux méthodes dans le même espace de noms.

julia> module Foo
           export sin
           sin(s::String) = uppercase(s)
       end
Main.Foo

julia> sin(1)
0.8414709848078965

julia> using .Foo
WARNING: using Foo.sin in module Main conflicts with an existing identifier.

julia> sin("wat")
ERROR: MethodError: no method matching sin(::String)
Closest candidates are:
  sin(::BigFloat) at mpfr.jl:727
  sin(::Missing) at math.jl:1197
  sin(::Complex{Float16}) at math.jl:1145
  ...
Stacktrace:
 [1] top-level scope at REPL[4]:1
 [2] run_repl(::REPL.AbstractREPL, ::Any) at /build/julia/src/julia-1.5.1/usr/share/julia/stdlib/v1.5/REPL/src/REPL.jl:288

julia> Foo.sin("wat")
"WAT"

Il faut explicitement ajouter un dispatch à la fonction d'origine pour que cela fonctionne :

julia> Base.sin(s::String) = Foo.sin(s)

julia> sin("wat")
"WAT"

Autant que je sache, il n'y a aucun moyen pour l'aliasing de module de changer la façon dont les fonctions sont réparties.

Et honnêtement, certaines fonctions portant le même nom _devraient_ vivre dans des espaces de noms séparés. Une fonction find_delta dans une bibliothèque numérique va faire quelque chose sans rapport avec find_delta dans une bibliothèque de différences de fichiers. Une fois que votre code est si polymorphe qu'il trouvera un moyen de s'exécuter sur une entrée cassée, vous entrez dans le territoire JavaScript, et personne ne veut cela.

@ninjaaron J'ai peut-être omis de transmettre certaines nuances dans ma préoccupation ci-dessus. Je ne suis pas concerné par ce changement qui change quoi que ce soit d'autre que la stratégie que les gens choisissent d'adopter lorsqu'ils implémentent des bibliothèques.
La personne mettant en œuvre Foo rencontrant un avertissement comme

julia> using .Foo
WARNING: using Foo.sin in module Main conflicts with an existing identifier.

peut choisir soit simplement import .Foo.sin as sin2 , soit se demander s'il voulait vraiment ou non fournir une nouvelle dépêche pour Base.sin . Mon point était que s'il devient très facile de simplement les considérer comme différentes fonctions, cela deviendra peut-être trop répandu, même dans des situations où il devrait vraiment s'agir de différentes méthodes de la même fonction. La situation actuelle, où il est légèrement plus gênant de gérer différentes fonctions portant le même nom, a pour effet secondaire que les gens se parlent et font de leur mieux pour déterminer s'il s'agit vraiment de la même fonction ou non. Je ne m'oppose pas à la possibilité d'avoir différentes fonctions avec le même nom, ce qui bien sûr peut être très utile. Je ne sais même pas si ma préoccupation est importante ou non, mais j'ai pensé que cela valait la peine de la soulever pour s'assurer qu'elle a été prise en compte.

@baggepinnen Cela a du sens, et il n'y a pas de mal à en parler. Je ne pense pas que cela fera une énorme différence pour les personnes qui créent des bibliothèques, car l'aliasing de module n'affectera que les utilisateurs de la bibliothèque. Je suppose qu'il est possible que le fait d'avoir un alias de module plus facile se traduira par moins d'utilisateurs se plaignant des conflits de nommage, mais je serais surpris si cela avait un impact énorme sur les API.

Lorsque j'écris une bibliothèque, je suis généralement assez conscient de savoir si je veux ajouter une répartition à une fonction dans Base ou si je veux la garder séparée. Je suppose que la plupart des autres auteurs de bibliothèques le sont également.

@ninjaaron Je pense que si la convention actuelle utilise une implémentation spécifique pour l'envoi comme

numpy.sin
sympy.sin

l'utilisation import numpy.sin as np_sin comme option supplémentaire pour l'utilisateur/développeur ne devrait pas affecter la base de code actuelle.
La seule préoccupation n'affectera que la fonction/interface d'exposition.

Cette page vous a été utile?
0 / 5 - 0 notes