Из списка рассылки:
Стефан:
Я думаю, что мы должны полностью отказаться от импорта и просто иметь
используя Фу
используя Foo: барПервый загрузит и создаст привязку для Foo, сделает его экспорт доступным как «мягкие» привязки (что сейчас делает использование). Второй также загрузит и создаст привязку для Foo и сделает bar доступным как «жесткую» привязку (что сейчас делает импорт)».
Кажется, это все еще довольно путаница для новичков.
Нам тоже как-то понадобится функциональность 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
Я знаю, что текущая практика Джулии состоит в том, чтобы импортировать все в
пространство имен текущего модуля, но я действительно думаю, что все же следует
быть простым и естественным способом импортировать только имя модуля.
Я также думаю, что текущая перегрузка использования Foo и использования Foo.Bar
проблемный; он смотрит внутрь Foo, но не внутрь Foo.Bar (если только Foo.Bar не
модуль?)
Я думаю, что в предложении Стефана это рассматривается с
используя Фу: Фу
В четверг, 14 августа 2014 г., [email protected] написал:
Я знаю, что текущая практика Джулии состоит в том, чтобы импортировать все в
пространство имен текущего модуля, но я действительно думаю, что все же следует
быть простым и естественным способом импортировать только имя модуля.Я также думаю, что текущая перегрузка использования Foo и использования Foo.Bar
проблемный; он смотрит внутрь Foo, но не внутрь Foo.Bar (если только Foo.Bar не
модуль?)—
Ответьте на это письмо напрямую или просмотрите его на GitHub
https://github.com/JuliaLang/julia/issues/8000#issuecomment-52202142 .
@kmsquire, но что тогда произойдет, если внутри модуля Foo есть модуль Foo? Это, к сожалению, двусмысленно.
Это ошибка дизайна (и вызывает предупреждение), так что это не имеет значения
Мне больше всего нравится вариант, предложенный @ssfrr выше.
Существует ли базовое соглашение о том, что пакеты имеют одну и только одну точку входа модуля? -- To 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
относится только к подмодулю уже текущего родительского модуля.
ОБНОВЛЕНИЕ: Да, это то, что вы предлагаете в # 4600. Извиняюсь.
:+1:. Если мы собираемся сделать это, 0.4 будет подходящим временем для этого.
:+1: Пожалуйста, почистите кое-что из этого (для версии 0.4!)
вместо того, чтобы иметь два механизма импорта, чтобы различать расширение или нет, почему бы не сигнализировать о расширении на самом сайте расширения с помощью ключевого слова или аннотации в определении функции, например, переопределить ключевое слово перед функцией? Аналогично аннотации @Override
в Java.
Это имеет то преимущество, что ясно видно, что функция переопределяет другую (и, следовательно, является методом).
Это уже возможно, @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(...) = ...
уже работает, ничего не импортируя. import
необходим только в том случае, если вы хотите, чтобы show(...) = ...
расширил Base.show
.
Слово переопределения @Ismael-VC было просто предложением. Это может быть расширение или что-то еще значимое. Также не должно быть @
, поскольку в julia это означает макрос ( @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
Я знаю, что это не является общим, но я не могу сделать выражение, которое возвращает то, что делает синтаксический анализ:
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
, если это возможно.
Я думаю, что мы должны требовать количественную оценку модуля при расширении функций, так как ее значение намного яснее, чем шаблон импорта, затем расширения.
Мой любимый подход:
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, что у нас останутся как using
, так и import
для 1.0? Это немного неудачно, на мой взгляд.
Как насчет:
using A
становится import A: ...
using A.X
( X
— это модуль) становится импортным 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
из A
Предполагая, что значение «жесткой привязки» таково, что вы можете расширить его без префикса модуля, в моей версии нет жестких привязок. Если вы хотите расширить, вы добавляете префикс модуля именно там, где вы его расширяете. Никаких жутких операторов import
в других файлах, меняющих значение того, является ли что-то расширением или нет.
и
using A: x
, потому что, по-видимому (я не в восторге от этого), важно иметь возможность импортировать привязку таким образом, чтобы вы не могли ее расширить.
Разве принудительный префикс модуля не связан с этим? Или мы говорим о не модулях, таких как:
module M
x = 1
end
Оба import M: x; x = 2
и using M: x; x = 2
дают одно и то же предупреждающее сообщение, поэтому я не вижу, в чем проблема...
Сохранение using A
для простоты более чем import A: ...
кажется мне немного чрезмерным.
Разве принудительный префикс модуля не связан с этим?
Да; если бы вам нужно было квалифицировать функции для их расширения, то этот пункт был бы неактуален.
Сохранение использования A для упрощения импорта A: ... кажется мне чрезмерным.
Я вижу это наоборот; заставлять людей переключаться с using A
(что красиво и коротко, и мы все к этому привыкли) на import A: ...
только для того, чтобы удовлетворить искусственное требование, чтобы было только одно ключевое слово, — это чрезмерно.
Из чтения потока кажется, что основная ценность наличия двух ключевых слов заключается в том, чтобы различать привязки, которые могут быть расширены или нет (жесткая привязка). Имея это в виду, я думаю, что есть два жизнеспособных решения:
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
(и ничего больше) в пространство имен .
Просто чтобы отразить то, что я сказал о слабине, и чтобы это не исчезло в люфте:
Я не думаю, что установка 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
делает то же самое, поэтому я отметил, что использование имеет этот побочный эффект.
(из 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
, чтобы (а) получить доступ к неэкспортируемым символам и (б) добавить методы к функциям, независимо от того, экспортируются они или нет.M.f
или...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 расширяемым» - это запутанный способ приблизиться к различию - вы всегда можете определить методы для полных имен функций.
Итак, могу ли я продлить Foo.x
после using Foo: x
? Потому что если да, то документация неполная (см. мой скриншот). Если нет, то я прекрасно понял, как работают эти операторы, и совершенно очевидно, что import Foo
сделал что-то, чтобы сделать Foo.x
расширяемым. Поэтому он буквально делает Foo.x
доступными для расширения. Во всех смыслах этих слов. Конечно, это не делает x
доступными для расширения, но import Foo: x
для этого и предназначено.
Итак, могу ли я продлить
Foo.x
послеusing 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
в пространство имен.
То, что вы можете прямо сейчас расширить все по его полному имени, если модуль находится в пространстве имен, не означает, что это очевидная или прямая вещь.
Либо быть в пространстве имен достаточно, тогда я также должен иметь возможность расширять x
, если я включил его в пространство имен с помощью using module:x
, либо быть в пространстве имен недостаточно , и тогда я также должен невозможно расширить module.x
при использовании команды using
.
Или третий вариант: нет import
и вам просто нужно все время расширять функции их полным именем.
Совершенно не очевидно, что вы можете расширять каждую функцию полным именем, если модуль находится в пространстве имен.
Я согласен, поэтому я выступаю за переписывание документов. Однако это не имеет отношения к текущему вопросу. Было бы лучше оставить (1) предложения по улучшению документации по текущему API и (2) предложения по его изменению отдельно, даже если они в чем-то связаны. Я планирую сделать PR для (1) в ближайшее время.
@tpapp Вы не можете документировать то, что по своей сути не имеет смысла. Ни один из этих документов не является правильным:
using module:x
не позволяет вам расширять x
)using
и import
» (ложь, потому что для полных имен на самом деле достаточно находиться в пространстве имен — остановив это быть достаточным было мое предложение)import module:x
, чтобы прекратить существование, чтобы быть полной правдой - предложение @martinholters )Любой из них будет приемлемым. Но ничего из этого на самом деле не является реальностью. Реальность такова, что в настоящее время для «импорта материала» используются два разных слова, но на самом деле они не имеют отдельного варианта использования. Это похоже на то, что цикл for
иногда ведет себя как цикл while
, если вы перебираете логические значения. Никакое количество документации не сделает это не запутанным.
Вы не можете задокументировать то, что по своей сути не имеет смысла.
Текущий API модулей четко определен, поэтому его можно задокументировать (уже есть, я просто думаю, что он должен быть лучше).
Ни один из этих документов не является правильным:
Будьте так любезны дождаться моего (или чьего-либо) пиара и прокомментировать собственно текст, который там будет. Выдвигать гипотетическую документацию, а затем заявлять, что она неверна, — это просто добавлять шума в эту дискуссию.
@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
. (Как кто-то где-то указал.)