从邮件列表中:
斯特凡:
我认为我们应该完全取消进口,只需要
使用 Foo
使用 Foo: 酒吧第一个将加载并为 Foo 创建一个绑定,使其导出可作为“软”绑定(现在使用 using)。 第二个也将为 Foo 加载并创建一个绑定,并使 bar 可用作“硬”绑定(现在 import 所做的)。
似乎这对于新手来说仍然是一个相当困惑的地方。
我们也需要import Foo
功能,你只需要Foo
就可以了
using Foo:
?
using Foo: Foo
?
要将Foo
绑定到 Foo 模块(仅此而已):
import Foo
将Foo
绑定到模块 Foo, x
到 Foo.x, y
到 Foo.y
import Foo: x, y
要将Foo
绑定到模块 Foo,并且所有 Foo 的导出名称都绑定不合格:
import Foo: *
这可能是using
,但我觉得这更像是import
的精神。
这也消除了将某些东西带入范围和使其可用于方法扩展之间的区别。 我个人认为这是一件好事,使模块系统更易于理解,但我想确保我们提出来。
有一个强有力的理由是,使模块的所有导出绑定可用的构造应该使它们成为软( using
)绑定而不是硬( importall
)绑定。 假设模块 A 使用模块 B 并定义了foo(::Any)
。 如果模块 B 的更高版本还定义和导出foo(::Any)
,您不希望它们相互破坏。 您也不希望模块 B 定义foo(::Int)
并让模块 A 有时调用该方法而不是它定义的方法,因为它更具体,或者必须列出您想要从模块 B 中获得的所有标识符以避免导入单个冲突标识符。
但是,如果您已经明确列出了要导入的标识符,那么就没有理由提供软绑定。 要么您不打算定义标识符的新方法,在这种情况下,硬绑定和软绑定具有相同的行为,要么您要定义它的新方法,在这种情况下,软绑定等效于无绑定,如果您愿意这种行为你应该从列表中删除标识符。
所以,简而言之,我喜欢@StefanKarpinski的提议。 从概念上讲,我们需要硬绑定和软绑定,但我们可以使用单个关键字获得所有有用的行为。
我明白你的意思。 在那种情况下,我喜欢您的建议,即using Foo:
(带有冒号但没有项目)在概念上似乎是一致的。 冒号表示您将限制输入哪些符号,但您只是没有列出任何符号。
空的尾随:
看起来有点滑稽,但我认为人们会习惯它
空尾冒号的问题是我们目前在下一行寻找一个名字——换句话说, using Foo:
被认为是不完整的。
相关:#4600
我知道当前 Julia 的做法是将所有内容导入
当前模块的命名空间,但我真的认为应该还有
是一种简单而自然的方式来导入模块的名称。
我也认为当前使用 Foo 和使用 Foo.Bar 的重载是
有问题的; 它在 Foo 内部但不在 Foo.Bar 内部(除非 Foo.Bar 是
一个模块?)
我认为在 Stefan 的提案中,这是通过以下方式解决的
使用 Foo: Foo
2014 年 8 月 14 日星期四,toivoh [email protected]写道:
我知道当前 Julia 的做法是将所有内容导入
当前模块的命名空间,但我真的认为应该还有
是一种简单而自然的方式来导入模块的名称。我也认为当前使用 Foo 和使用 Foo.Bar 的重载是
有问题的; 它在 Foo 内部但不在 Foo.Bar 内部(除非 Foo.Bar 是
一个模块?)—
直接回复此邮件或在 GitHub 上查看
https://github.com/JuliaLang/julia/issues/8000#issuecomment -52202142。
@kmsquire但是如果 Foo 模块内部有一个 Foo 模块会发生什么? 不幸的是,这是模棱两可的。
这是一个设计错误(并导致警告),所以没关系
我最喜欢@ssfrr提出的版本。
是否存在包具有一个且只有一个模块入口点的基本约定? -- 到import Foo
表示导入包Foo
的模块Foo
#$ 。 任何其他模块必须是Foo
的子模块。 这意味着包 Foo、包中的Foo.jl
和包中的module Foo
之间存在隐式对应关系。
我问 b/c 我想知道import
是否也可以用于本地/相对导入。 假设一个项目有src/foo.jl
和src/bar.jl
然后在foo.jl
:
import bar
将从src/bar.jl
导入。 这是对使用include
的改进,因为它在模块系统中运行。
是的,包、包入口点和模块应该是一对一的。 如果需要,您可以打破这个约定,但没有太多需要,因为模块只是用于命名而不是功能单元。 您提出的想法是#4600,除了相对导入的语法是import .bar
而import bar
是绝对导入。
@StefanKarpinski import .bar
实际上在本地目录中查找“bar.jl”吗? 我的印象是import .Bar
只引用了一个已经存在的父模块的子模块。
更新:Duh,这就是你在#4600 中提出的建议。 对不起。
:+1:. 如果我们要这样做,0.4 将是这样做的好时机。
:+1: 请继续清理其中的一些内容(对于 0.4!)
与其有两种导入机制来区分是否扩展,为什么不通过函数定义处的关键字或注释在扩展站点本身发出扩展信号,例如在函数之前覆盖关键字? 类似于 Java 中的@Override
注释。
这样做的好处是可以清楚地看到该函数正在覆盖另一个函数(因此是一种方法)
这已经是可能的了,@ssagaert。 您可以通过在函数定义中明确写入模块名称(例如, Base.print(…) = …
)来做到这一点,这似乎是很多人都在趋同的一种风格。 唯一的症结是语法不适用于所有可能的名称(例如.+
等)。
(顺便说一句,请注意用反引号 `` 将宏括起来,以防止打扰其他 GitHub 用户)。
:+1: 对于@ssagaert使用@override
的建议,当尝试扩展方法而不首先导入它时的原始错误消息如下所示:
ERROR: error in method definition: function Foo.x must be explicitly imported to be extended
所以也许@extend
可能更适合? 我不是以英语为母语的人,但我的理解是 _override_ 的意思是:取消、无效、无效、否定、取消、取消、终止等。
我认为这更明确:
<strong i="13">@extend</strong> Base.show(...) = ...
比:
import Base: show
# ... several lines here
Base.show(...) = ...
@Ismael-VC Base.show(...) = ...
无需导入任何东西就可以工作。 仅当您希望show(...) = ...
扩展Base.show
import
@Ismael-VC 覆盖词只是一个建议。 它可以是扩展的或任何其他有意义的。 也不应该有@
因为在朱莉娅这意味着它是一个宏( @Override
指的是Java,它是一个注释)。
@simonster谢谢我不知道!
@ssagaert所以你的意思是一个关键字? 我尝试过这样的事情,但我仍然很讨厌宏富:
module Extend
export <strong i="9">@extend</strong>
macro extend(x)
mod = x.args[1].args[1].args[1]
met = x.args[1].args[1].args[2]
imp = :(Expr(:import, $mod, $met))
:(Expr(:toplevel, $imp, $(esc(x))))
end
end
我知道这并不普遍,但我仍然无法创建一个返回 parse 所做的表达式:
julia> using Extend
julia> type Foo end
julia> <strong i="13">@extend</strong> Base.show(x::Foo) = Foo
:($(Expr(:toplevel, :($(Expr(:import, Base, :show))), show)))
julia> parse("import Base.show; Base.show(x::Foo) = Foo")
:($(Expr(:toplevel, :($(Expr(:import, :Base, :show))), :(Base.show(x::Foo) = begin # none, line 1:
Foo
end))))
我认为通用且有效的@extend
宏不会改变导入机制的语义。
@Ismael-VC 我做到了,但我也喜欢@mbauman的“技巧”。
我认为能够单独使用.
来表示“这个”可能会很好。 因此您可以编写如下表达式:
import Base: .
(意思是导入Base.Base
)
要么using ..
但是,我很确定这将需要https://github.com/JuliaLang/julia/pull/11891#issuecomment -116098481。 也许在.
之前允许空格就足够了,但在它之后不允许空格来解决歧义情况?
我相信 require 已经被弃用了。 在 1.0 的模块导入上添加更灵活的点表示法可能会很好,但我怀疑我们是否会通过 0.6 功能冻结来改变这里的任何内容
在昨天对此进行了大量讨论之后,我倾向于像https://github.com/JuliaLang/julia/issues/8000#issuecomment -52142845 和https://github.com/JuliaLang/julia/中的提案
using A: x, y # hard imports x and y from A
using A: A # hard imports just the identifier `A`
using A: ... # soft imports all of A's exports
using A # equivalent to `using A: A, ...`
using A.B # A.B must be a module. equivalent to `using A.B: B, ...`
using A: ..., thing1, thing2 # import all exports plus some non-exported things
另一种方法是保留import
而不是using
:
import A # hard binding for the module `A`
import A: ... # soft bindings for all names exported by `A`
import A: x, y # hard bindings for `x` and `y` from `A`
import A: x, y, ... # equivalent to doing both of the previous two
绑定是硬绑定还是软绑定的一般规则很简单:任何显式请求的名称都是硬绑定,任何隐式给定的绑定都是软绑定。
编辑:有些人希望在这个方案中添加一些import A; import A: ...
的简写,这大约是using A
当前所做的(唯一的区别是using A
当前软导入A
); 这可以继续是using A
或import A...
已被提议。
是的,我认为这也是一个很好的提议。 基本上归结为一个人更喜欢using
还是import
。
附录,我们可以保留using A
作为import A; import A: ...
的简写 - 再加上摆脱每个模块都有自己的导出绑定的当前行为,这就是using A
导致的原因有一个软绑定到A
可用。
如果在这一切之后我们仍然有多个关键字,我会非常失望。
我喜欢import
和export
的对称性。 (正如有人在某处指出的那样。)
就方法扩展而言,总是做“硬绑定”似乎不是最安全的默认设置。 有一个相关但有些独立的提议,要求方法扩展的模块限定可以消除对“硬绑定”的需求。
为此还需要硬绑定:
import Package: x
x = 1 # gives an error
至关重要的是,该提案并不总是进行硬绑定——仅针对您明确列出的内容。 要求说import
而不是using
并不会增加太多安全性。
安全性来自大多数不进行方法扩展的地方,这些地方可以通过软绑定很好地摆脱。 我认为我们仍然应该有一种方法来请求特定的软绑定,而不必导入包的所有导出(或获取未导出的特定软绑定)。
我们仍然有覆盖导入绑定的警告吗?
我认为要求模块资格是个好主意。 现在要知道是否正在引入函数或扩展方法,您必须查看整个包的内容以获取import A: func
语句。
我们仍然有覆盖导入绑定的警告吗?
我相信它现在实际上是一个错误。
还有另一个提案保留了两个关键字,但仍然稍微简化了一些事情:
import A: ...
using A:
using A.B
中,要求A.B
是一个模块,并记录它是import A.B; import A.B: ...
的简写。这样,只需import
就可以完成所有工作,但using X
可以方便地使用。 这也将特别容易过渡到。
顺便说一句,我在此处发布的using
看起来不一致。 如果我们保留using
,则应尽可能将其重命名为use
。
我认为我们应该在扩展函数时要求模块量化,因为它的含义比 import-then-extend 模式更清晰。
我最喜欢的方法:
using A: A
import
及其创建的绑定类型实现https://github.com/JuliaLang/julia/issues/8000#issuecomment -327512355 需要发生的事情:
using A
的行为更改为硬导入A
using A: x
的支持using A.x
的支持,其中x
不是子模块import A.x
的支持,其中x
不是子模块...
语法的支持到import
using A: x
经常使用并且非常有用。 你说你想在你的命名空间中使用x
但你不想扩展它。 在import A: x
中,您说您希望能够扩展x
。 拥有可供使用的功能和能够扩展它之间存在有意义的区别。
想一想,我想说这里最大的问题是using A.B
做了两件事:如果B
是一个模块,它软导入它的所有导出,否则只是软导入B
。 我认为我们应该解决这个问题,让using A.B
只允许用于模块,并让using A: a, b
用于一次软导入特定绑定。
我希望有一种方法可以编写import A: x
,而不是等效于import A.x
。
我投票给import A: x
,因为我们也可以; import A: x, y, @z
但import A.x, A.y, a.@z
看起来很难看。
这是否从 1.0 中删除意味着我们将在 1.0 中同时保留using
和import
? 在我看来,这有点不幸。
怎么样:
using A
变成import A: ...
using A.X
( X
是一个模块)变成 import A.X: ...
using A: X
( X
不是模块)变为import A: X
import A: X
没有改变,但你不能自动扩展X
(见第一点)using
关键字我错过了一些用例吗? 也许这已经被建议了......
我喜欢在扩展时明确说明模块的原因是扩展变得更加本地化。 现在,当一个方法被扩展时,通常将导入放在非常靠近模块顶部的地方(它可能在一个完全不同的文件中!)。 删除扩展方法时,通常会忘记导入语句。
我认为这与我上面的提议基本相同,得到了相当多的支持。 @JeffBezanson真的很想保留using A
至少是为了便于使用和using A: x
因为显然(我不卖这个),这是一个重要的用例能够导入绑定这样你就不能扩展它。 有一些建议走另一个方向,将import
替换为using
,但它们都没有真正获得太大的吸引力( import
似乎更基本)。
我认为区别在于:
x
和y
from A
假设“硬绑定”的含义是您可以在没有模块前缀的情况下对其进行扩展,在我的版本中没有硬绑定。 如果要扩展,请在扩展它的位置添加模块前缀。 其他文件中没有令人毛骨悚然的import
语句会改变某些东西是否是扩展名的含义。
和
using A: x
因为显然(我不卖这个),能够以无法扩展的方式导入绑定是一个重要的用例。
不是强制模块前缀处理吗? 还是我们在谈论非模块,例如:
module M
x = 1
end
import M: x; x = 2
和using M: x; x = 2
都给出了相同的警告信息,所以我看不出有什么问题......
在我看来,为了轻松超过import A: ...
而保留using A
#$ 似乎有点过分。
不是强制模块前缀处理吗?
是的; 如果您必须限定函数以扩展它们,那么这一点将无关紧要。
继续使用 A 以便于过度导入 A: ... 在我看来似乎有点过分。
我的看法正好相反; 让人们从using A
(这很好,很短,我们都习惯了)切换到import A: ...
只是为了满足只有 1 个关键字的人为要求是过度的。
从阅读线程来看,似乎拥有两个关键字的主要价值是区分可以扩展或不可扩展的绑定(硬绑定)。 考虑到这一点,我认为有两种可行的解决方案:
using
和extending
。 import
很好,但是extending
使得存在第二个关键字的原因显而易见在这两种情况下,我建议using
应该像现在一样,添加以下之一以仅绑定模块Foo
:
using Foo: nothing
(现在有效)using Foo: Foo
(现在有效)using Foo:
(可以稍后添加)然后extending
的行为应该与using
相同,唯一的区别是您可以扩展使用extending
引入的绑定,并且可能不允许extending Foo
使其具有要明确。
| | 提供(使用)| 使可扩展(导入)|
| ------------------- | -------------------------- | ---------------------- |
| 唯一模块 | using module: module
或using module: nothing
| import module
|
| 一切出口| using module
(副作用:也像import module
)| ? |
| 特别的事情| using module: x,y
| import module: x,y
|
| | 提供(使用)| 使可扩展(导入)|
| ------------------ | ------------------------------------ | -------------------------- |
| 唯一模块 | using module
| import module
|
| 一切出口| using module: *
| import module: *
|
| 特别的事情| using module: x,y
| import module: x,y
|
这样做的好处是,导入更多对应于编写更多。 即,您从using module
开始,如果您想将变量直接导入命名空间,则添加: x
而不是删除nothing
或module
。 这也意味着您键入的最短内容包含的内容最少。
您还可以执行using: *,x
以使导出的所有内容都可用,而x
则未导出。
| | 提供(使用)| 使可扩展(导入)|
| ------------------ | ------------------------------------ | -------------------------- |
| 唯一模块 | using module:
| import module:
|
| 一切出口| using module: *
| import module: *
|
| 特别的事情| using module: x,y
| import module: x,y
|
保留using module
和import module
与当前行为以实现向后兼容性,但不推荐使用它。
@FelixBenning : import Module
目前(本身)不会使任何可扩展的东西超过using Module
,它只是加载代码并将Module
(仅此而已)带入命名空间.
只是为了反映我在 slack 上所说的内容,这样它就不会在 slack 洞中消失:
我不认为将using X: *
设置为使每个导出的东西都可用的默认值,而不是仅使用using X
会使人们对他们导入的内容更加警惕。 我知道,指出其他人的做法被认为是不好的形式,但是 Python 基本上具有import X
和import X: *
的这些语义,但它们的生态系统中充斥着这些明星进口🤷♂️(和他们以讨厌这一点而闻名)我认为必须输入的稍长的文本不会阻止人们做他们认为最方便的事情:只需导入/使用所有内容并让编译器弄清楚。 这就是为什么我对让人们明确地写出那颗星的灵丹妙药持谨慎态度。
此外, import module: *
和using module: *
不适用于建议的含义。 它已经有意义,因为*
是一个有效的 Julia 标识符,并且可以像+
或单词mul
一样导入/使用。
@tpapp要么我再次误解了文档,要么import Module
使Module.x
可扩展。 虽然using Module: x
不会使Module.x
可扩展。 因此import Module
使某些东西可用于扩展,而using Module
也这样做,这就是为什么我注意到 using 具有这种副作用的原因。
(来自 https://docs.julialang.org/en/v1/manual/modules/)
我们中的哪一个是正确的并不重要——无论哪种情况,如果我们甚至无法弄清楚每件事是做什么的,那么当前的情况显然是一团糟。
@mbauman好点 - 我忘记了。 我并不真正关心*
只是让using
镜像import
所做的事情的结构,不同之处在于导入与使用是否可以扩展。 因此,如果有更合适的符号 - all
, __all__
, everything
, exported
,...? 我完全同意。 我只是认为输入更多可能应该通过输入更多来反映。
但如果你根本不想要那个,你当然也可以去
| | 提供(使用)| 使可扩展(导入)|
| ------------------ | ------------------------------------ | -------------------------- |
| 唯一模块 | using module: module
| import module: module
|
| 一切出口| using module
| import module
|
| 特别的事情| using module: x,y
| import module: x,y
|
要么
| | 提供(使用)| 使可扩展(导入)|
| ------------------ | ------------------------------------ | -------------------------- |
| 唯一模块 | using module
| import module
|
| 一切出口| using module: module
| import module: module
|
| 特别的事情| using module: x,y
| import module: x,y
|
但无论最终结果如何,都应该是一致的。 而目前它不是。
using A
使A.f
可扩展,_not_ f
本身。 为了扩展 _just_ f
而不声明要从哪个模块扩展,您必须明确地import A: f
。 否则,您仍然必须获得资格。
检查以下using
的语义
julia> module A
export f
f() = "no args in A"
end
Main.A
julia> f()
ERROR: UndefVarError: f not defined
Stacktrace:
[1] top-level scope at REPL[2]:1
julia> using .A
julia> f()
"no args in A"
julia> f(1)
ERROR: MethodError: no method matching f(::Int64)
Closest candidates are:
f() at REPL[1]:3
Stacktrace:
[1] top-level scope at REPL[5]:1
julia> f(x) = "one arg where?"
ERROR: error in method definition: function A.f must be explicitly imported to be extended
Stacktrace:
[1] top-level scope at none:0
[2] top-level scope at REPL[6]:1
julia> A.f(x) = "one arg where?"
julia> f(1)
"one arg where?"
这对于import
的语义:
julia> module A
export f
f() = "no args in A"
end
Main.A
julia> f()
ERROR: UndefVarError: f not defined
Stacktrace:
[1] top-level scope at REPL[2]:1
julia> import .A
julia> f()
ERROR: UndefVarError: f not defined
Stacktrace:
[1] top-level scope at REPL[4]:1
julia> A.f()
"no args in A"
julia> f(1)
ERROR: UndefVarError: f not defined
Stacktrace:
[1] top-level scope at REPL[6]:1
julia> A.f(1)
ERROR: MethodError: no method matching f(::Int64)
Closest candidates are:
f() at REPL[1]:3
Stacktrace:
[1] top-level scope at REPL[7]:1
julia> f(x) = "one arg where?"
f (generic function with 1 method)
julia> f(1)
"one arg where?"
julia> A.f(1)
ERROR: MethodError: no method matching f(::Int64)
Closest candidates are:
f() at REPL[1]:3
Stacktrace:
[1] top-level scope at REPL[10]:1
julia> A.f(x) = "one arg where in A"
julia> A.f(1)
"one arg where in A"
@FelixBenning :是的,我认为您误解了。 FWIW,我认为“...使Foo.x
可扩展”是一种令人困惑的方式来处理这种区别——您始终可以将方法定义为完全限定的函数名。 using Foo: x
发生的事情是Foo
本身不会被带入命名空间。
顺便说一句,重读这个主题我想知道 #25306 是否让我们达到了一种局部最优,剩下的唯一决定是我们是否需要将不可扩展的导入到命名空间(目前是using Foo: f
)。 但是由于这很糟糕,手册章节可能会同时从重写中受益,许多用户发现整个事情令人困惑。
这就是我在文档中处理现状的方式:
using M
加载模块,并将M
及其导出的符号带入命名空间。 这是出口很重要的唯一情况。M
,你就可以使用像M.y
这样的限定名称来(a)访问未导出的符号和(b)向函数添加方法,无论它们是否被导出M.f
之类的限定名称,否则 Julia 会阻止您向函数添加方法,或者...import M: f
,那么您可以在定义方法时使用f
。import M
和using M: x
分别用于将M
或x
(而不是M
)分别带入命名空间。 有些人喜欢在包代码中使用这些形式来确保他们的命名空间保持干净(在此处链接相关样式指南)。该顺序或多或少反映了使用更高级用法时遇到的用例。 以上所有内容都适用于子模块,用M.A
代替M
。
那这个呢:
using M
将M
带入作用域using M: x
将M.x
带入范围(如x
)using M: ...
将M
的所有导出符号带入作用域using M: x, ...
将M
的所有导出符号以及x
(可能未导出)import
。 您需要使用限定名称来扩展函数。 (或者using M; const foo = M.foo
就像现在已经可以做到的那样。)M
也可以是子模块,例如Foo.Bar
和x
也可以是当前含义的x as y
。或者我们使用import
而不是using
这使得它等于https://github.com/JuliaLang/julia/issues/8000#issuecomment -355960915。
一个非常常见的用途(尤其是在“脚本”中,但也适用于某些样式的包)
using Foo, Bar, Baz
并且仅依靠导出的符号。 保持这个最简单会带来一些好处,可能和现在一样简单。
@tpapp
我想你误会了。 FWIW,我认为“...使 Foo.x 可扩展”是一种令人困惑的方式来处理这种区别 --- 您始终可以将方法定义为完全限定的函数名称。
好的,那么我可以在using Foo: x
Foo.x
#$ 吗? 因为如果是,那么文档不完整(请参阅我的屏幕截图)。 如果不是,那么我已经完全理解了这些语句是如何工作的,并且很明显import Foo
做了一些事情来使Foo.x
可扩展。 因此,它实际上使Foo.x
可用于扩展。 在这些话的每一个意义上。 当然它不会使x
可用于扩展,但这就是import Foo: x
的用途
好的,那么我可以在
using Foo: x
Foo.x
#$ 吗?
除非您以某种方式将Foo
带入命名空间(例如using Foo
)。
我已经完全理解这些陈述是如何运作的
我对此不太确定——但是,如果您对模块和命名空间有疑问,请使用 Discourse 论坛。
很明显
import Foo
做了一些事情来使Foo.x
可扩展
仅在某种意义上,您必须能够在向其添加方法之前以某种方式使用限定名称来引用函数。
那么文档不完整
我认为它是,以一种古怪的方式。 在那个特定的例子中,如果你所做的只是using MyModule: x, p
; 那么没有可用于扩展的方法,因此该表是正确的。
正如我上面所说,我确实同意它可以写得更好。 很多不习惯命名空间的人会觉得它很混乱。 而且,TBH,整个using
/ import
马戏团有点令人困惑,因此这个问题。
@tpapp
好的,事情就是这样:如果模块位于命名空间中,那么您可以使用全名扩展每个函数绝对不明显。 我知道这是当前的行为,但我认为任何不知道这一点的人都不会假设。 特别是因为在命名空间中并不总是意味着它也是可扩展的。 如果我这样做using module:x
我不能扩展x
。 虽然我可以扩展x
,但如果我使用import module:x
。 因此,一个合理的假设是, using
和import
之间的区别在于您是否可以扩展导入的函数。
使用这个假设是有意义的,如果using module
只允许使用module.x
但不允许扩展module.x
。 而import module
将允许扩展module.x
。 所以如果你采取这个假设并阅读文档,你会发现有两件事是错误的。
using module
确实允许您扩展module.x
。 因此,从学习者的角度来看, using module
有副作用,它也像import module
- 即它使module.x
可扩展。 使事物可扩展是import
的事情,而不是using
的事情import
相比, using
不仅使module
可用,而且使其中的所有内容都可用。所以这就是我试图用我的表来表示的。 如果使用了两个不同的词(导入/使用),那么他们应该做两件不同的事情,而且应该是明确的。 如果using
有时允许扩展,有时则不允许扩展,这不是可预测的行为。
正如@martinholters建议的那样,一个很好的选择是完全删除导入。 你只是不能有两个只是随机用于某些事情的词。 如果import
意味着在导入某些函数时使事物可扩展,而using module: foo
不允许这样做,那么当您仅在命名空间中包含module
时应该会发生相同的行为。
仅仅因为如果模块位于命名空间中,您现在可以通过其全名扩展所有内容,但这并不意味着这是一件显而易见或直接的事情。
要么在命名空间中就足够了,那么如果我用using module:x
将它包含在命名空间中或者在命名空间中是不够的,那么我也应该能够扩展x
,然后我也应该使用using
命令时无法扩展module.x
。
或者第三种选择:没有import
并且您只需要始终使用它们的全名扩展函数。
如果模块位于命名空间中,那么您可以使用全名扩展每个函数,这绝对不是显而易见的。
我同意,这就是为什么我主张重写文档。 但是,这与当前问题无关。 最好将 (1) 改进当前 API 文档的提案和 (2) 重新设计它的提案分开,即使两者有些相关。 我计划很快为 (1) 做一个 PR。
@tpapp您不能记录本质上没有意义的东西。 这些文件都不正确:
using module:x
不允许您扩展x
)using
和import
”(错误,因为对于全名,实际上在命名空间中就足够了 - 停止足够是我的建议)import module:x
停止存在才能成为完整的事实 - @martinholters提案)这些中的任何一个都是可以接受的。 但这些都不是现实。 现实情况是,目前有两个不同的词用于“导入东西”,但它们实际上并没有不同的用例。 它就像一个for
$ 循环,如果你迭代布尔值,它有时表现得像一个while
循环。 再多的文档也不会让人感到困惑
你不能记录本质上没有意义的东西。
当前的模块 API 定义明确,因此可以记录(它已经是,我只是认为应该更好)。
这些文件都不正确:
请耐心等待我(或其他人)的 PR 并评论将出现的实际文本。 提出假设的文档,然后声称它是不正确的,这只会在讨论中增加噪音。
@tpapp也许我应该说,
你不能以一种不令人困惑的方式记录一些东西,这在本质上是没有意义的
我的意思是从某种意义上说,代码就是您需要的所有文档,对吧? 那有什么问题? 消化它所需要的时间。 而且我目前看不到描述它如何工作的简短方法,因为它充满了例外。 一开始就不应该出现的异常。
你真的没有看到我想要表达的意思吗?
我认为人们普遍认为,目前的情况过于复杂且记录不充分。 毫无疑问,简化机器将使记录变得更容易。 但是这样的简化会被打破,所以不能在 2.0 之前完成。 那么你的观点是在那之前改进文档没有意义吗? 那我不同意。 我确实看到了两个不同的问题:使用 2.0 进行简化(这个问题是关于)这将(希望)包括必要的文档更新和改进当前工作的文档,通过阅读这个线程似乎非常需要,但这是另一个问题.
在做#38271之后,我认为悬而未决的问题是
Foo.bar() = ...
),using Foo: bar; bar() = ...
)import Foo: bar; bar() = ...
)using Foo
将Foo
中的所有导出符号带到作用域, import Foo
只是模块(现状)using Foo: ...
或其他类似的语法,然后using Foo
只是模块。(1|2) & 2 将允许统一为单个关键字, using
或import
,代价是丢失单行
using LinearAlgebra, Random, StaticArrays
我不确定这是否值得,即使不考虑重大变化。
这不是提供原始设计刚刚错过的干净解决方案的问题之一。 有取舍。 我会拭目以待,看看更好的文档是否可以在保持当前(1.0)设置的同时改善用户体验。
对于 2.0,我认为只是清理语法以更加一致和描述实际发生的事情会很好。 就像是:
| 之前 | 之后 |
|-|-|
| using Foo
| useall from Foo
|
| import Foo
| use Foo
|
| using Foo: a
| use a from Foo
|
| import Foo: a
和import Foo.a
| extend a from Foo
|
最有用的评论
我喜欢
import
和export
的对称性。 (正如有人在某处指出的那样。)