Julia: Hapus kebutuhan, impor, dan mungkin impor semua dan gabungkan menggunakan

Dibuat pada 14 Agu 2014  ·  72Komentar  ·  Sumber: JuliaLang/julia

Dari milis:

Stefan:

Saya pikir kita harus menghapus impor sama sekali dan hanya memiliki

menggunakan Foo
menggunakan Foo: bar

Yang pertama akan memuat dan membuat pengikatan untuk Foo, membuat ekspornya tersedia sebagai pengikatan "lunak" (apa yang dilakukan sekarang). Yang kedua juga akan memuat dan membuat pengikatan untuk Foo, dan membuat bilah tersedia sebagai pengikatan "keras" (apa yang dilakukan impor sekarang)."

Tampaknya ini masih merupakan titik kebingungan bagi pendatang baru.

breaking design modules speculative

Komentar yang paling membantu

Saya suka simetri import dan export . (Seperti yang ditunjukkan seseorang di suatu tempat.)

Semua 72 komentar

Kami juga membutuhkan fungsionalitas import Foo , di mana Anda hanya mendapatkan Foo dan tidak ada yang lain

using Foo: ?

using Foo: Foo ?

Untuk mengikat Foo ke modul Foo (dan tidak ada yang lain):
import Foo
Untuk mengikat Foo ke modul Foo, x ke Foo.x, y ke Foo.y
import Foo: x, y
Untuk mengikat Foo ke modul Foo, dan semua nama yang diekspor Foo terikat tanpa pengecualian:
import Foo: *

Ini bisa menjadi using sebagai gantinya, tetapi saya merasa ini lebih dalam semangat import .

Ini juga menghilangkan perbedaan antara membawa sesuatu ke dalam ruang lingkup dan membuatnya tersedia untuk ekstensi metode. Saya pribadi berpikir itu hal yang baik dan membuat sistem modul lebih mudah dipahami, tetapi saya ingin memastikan kami membahasnya.

Ada kasus kuat yang harus dibuat bahwa konstruksi yang membuat semua binding modul yang diekspor tersedia harus membuatnya menjadi binding lunak ( using ) dan bukan binding keras ( importall ). Misalkan modul A menggunakan modul B dan mendefinisikan foo(::Any) . Jika rilis modul B selanjutnya juga mendefinisikan dan mengekspor foo(::Any) , Anda tidak ingin mereka saling mengalahkan. Anda juga tidak ingin modul B mendefinisikan foo(::Int) dan memiliki modul A terkadang memanggil metode itu alih-alih metode yang ditentukan karena lebih spesifik, atau harus membuat daftar semua pengidentifikasi yang Anda inginkan dari modul B untuk menghindari pengimporan satu pengidentifikasi yang saling bertentangan.

Tetapi jika Anda secara eksplisit mencantumkan pengidentifikasi yang ingin Anda impor, maka tidak pernah ada alasan untuk memberikan soft binding. Entah Anda tidak akan mendefinisikan metode baru pengidentifikasi, dalam hal ini ikatan keras dan lunak memiliki perilaku yang identik, atau Anda akan mendefinisikan metode barunya, dalam hal ini ikatan lunak setara dengan tanpa ikatan dan jika Anda mau perilaku itu Anda harus menghapus pengidentifikasi dari daftar.

Jadi, singkatnya, saya suka proposal @StefanKarpinski . Secara konseptual kita membutuhkan baik hard dan soft binding, tetapi kita bisa mendapatkan semua perilaku yang berguna dengan satu kata kunci.

Saya mengerti maksud Anda. Dalam hal ini saya suka proposal Anda bahwa using Foo: (dengan titik dua tetapi tidak ada item) tampaknya konsisten secara konseptual. Titik dua menunjukkan bahwa Anda akan membatasi simbol mana yang akan ditarik, tetapi Anda tidak mencantumkannya.

Trailing kosong : terlihat sedikit lucu, tapi saya pikir orang akan terbiasa

Masalah dengan tanda titik dua yang kosong adalah bahwa saat ini kami mencari nama di baris berikutnya – dengan kata lain using Foo: dianggap tidak lengkap.

Terkait: #4600

Saya tahu bahwa praktik Julia saat ini adalah mengimpor semuanya ke dalam
namespace dari modul saat ini, tetapi saya benar-benar berpikir bahwa seharusnya masih ada
menjadi cara sederhana dan alami untuk mengimpor hanya nama modul.

Saya juga berpikir bahwa kelebihan penggunaan Foo dan penggunaan Foo.Bar saat ini adalah
bermasalah; itu terlihat di dalam Foo tetapi tidak di dalam Foo.Bar (kecuali Foo.Bar adalah
modul?)

Saya pikir dalam proposal Stefan, ini ditangani dengan

menggunakan Foo: Foo

Pada hari Kamis, 14 Agustus 2014, toivoh [email protected] menulis:

Saya tahu bahwa praktik Julia saat ini adalah mengimpor semuanya ke dalam
namespace dari modul saat ini, tetapi saya benar-benar berpikir bahwa seharusnya masih ada
menjadi cara sederhana dan alami untuk mengimpor hanya nama modul.

Saya juga berpikir bahwa kelebihan penggunaan Foo dan penggunaan Foo.Bar saat ini adalah
bermasalah; itu terlihat di dalam Foo tetapi tidak di dalam Foo.Bar (kecuali Foo.Bar adalah
modul?)


Balas email ini secara langsung atau lihat di GitHub
https://github.com/JuliaLang/julia/issues/8000#issuecomment -52202142.

@kmsquire tetapi apa yang terjadi jika ada modul Foo di dalam modul Foo? Sayangnya itu ambigu.

Itu kesalahan desain (dan menyebabkan peringatan), jadi tidak masalah

Saya suka versi yang diusulkan oleh @ssfrr di atas yang terbaik.

Apakah ada konvensi yang mendasari bahwa paket memiliki satu dan hanya satu titik masuk modul? -- Ke import Foo berarti mengimpor modul Foo paket Foo . Modul lain harus berupa submodul dari Foo . Yang berarti ada korespondensi implisit antara paket Foo, Foo.jl dalam paket dan module Foo di dalamnya.

Saya bertanya b/c Saya ingin tahu apakah import juga dapat digunakan untuk impor lokal/relatif. Katakanlah sebuah proyek memiliki src/foo.jl dan src/bar.jl lalu di foo.jl :

import bar

akan mengimpor dari src/bar.jl . Ini adalah peningkatan dari penggunaan include karena beroperasi di dalam sistem modul.

Ya, paket, titik masuk paket, dan modul diharapkan menjadi satu-ke-satu. Anda dapat melanggar konvensi ini jika perlu, tetapi tidak perlu banyak karena modul hanya untuk penamaan dan bukan unit fungsional. Gagasan yang Anda kemukakan adalah #4600 kecuali sintaks untuk impor relatif adalah import .bar sedangkan import bar adalah impor absolut.

@StefanKarpinski Apakah import .bar benar-benar mencari "bar.jl" di direktori lokal? Saya mendapat kesan bahwa import .Bar hanya merujuk ke submodul dari modul induk yang sudah ada.

UPDATE: Duh, itu yang Anda usulkan di #4600. Maaf.

:+1:. Jika kita akan melakukan ini, 0,4 akan menjadi waktu yang tepat untuk melakukannya.

:+1: Silakan lanjutkan dan bersihkan beberapa ini (untuk 0,4!)

daripada memiliki dua mekanisme impor untuk membedakan antara memperluas atau tidak, mengapa tidak memberi sinyal ekstensi di situs ekstensi itu sendiri melalui kata kunci atau anotasi pada definisi fungsi, misalnya mengganti kata kunci sebelum fungsi? Mirip dengan anotasi @Override di Java.

Ini memiliki keuntungan bahwa seseorang dengan jelas melihat bahwa fungsinya menimpa yang lain (dan karenanya merupakan metode)

Itu sudah mungkin, @ssagaert. Anda melakukannya dengan secara eksplisit menulis nama modul dalam definisi fungsi (mis., Base.print(…) = … ), dan sepertinya ini adalah gaya yang banyak digunakan orang. Satu-satunya masalah adalah bahwa sintaks tidak bekerja untuk semua kemungkinan nama (seperti .+ , dll.).

(Sebagai tambahan, harap berhati-hati untuk menyertakan makro dengan backticks `` untuk mencegah mengganggu pengguna GitHub lainnya).

:+1: untuk saran @ssagaert untuk menggunakan @override , pesan kesalahan asli ketika seseorang mencoba memperluas metode tanpa mengimpornya terlebih dahulu berbunyi seperti ini:

ERROR: error in method definition: function Foo.x must be explicitly imported to be extended

Jadi mungkin @extend bisa lebih cocok? Saya bukan penutur asli bahasa Inggris, tetapi pemahaman saya adalah bahwa _override_ berarti sesuatu seperti: membatalkan, membatalkan, membatalkan, meniadakan, membatalkan, membatalkan, menghentikan, dll.

Saya pikir ini lebih eksplisit:

<strong i="13">@extend</strong> Base.show(...) = ...

Dibandingkan:

import Base: show

# ... several lines here

Base.show(...) = ...

@Ismael-VC Base.show(...) = ... sudah berfungsi tanpa mengimpor apa pun. import hanya diperlukan jika Anda ingin show(...) = ... untuk memperpanjang Base.show .

@Ismael-VC override Word hanyalah sebuah saran. Itu bisa diperpanjang atau apa pun yang bermakna. Juga seharusnya tidak ada @ karena di julia itu berarti makro ( @Override merujuk ke Java di mana itu adalah anotasi).

@simonster terima kasih saya tidak tahu itu!

@ssagaert jadi maksud Anda kata kunci? Saya mencoba sesuatu seperti ini tetapi saya masih payah di macro-foo:

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

Saya tahu ini tidak umum, saya tetap tidak dapat membuat ekspresi yang mengembalikan apa yang dilakukan 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))))

Saya pikir makro @extend yang umum dan berfungsi tidak akan mengubah semantik mekanisme impor.

@Ismael-VC saya lakukan tapi saya suka 'trik' dari @mbauman juga.

Saya pikir mungkin bagus untuk dapat menggunakan . sendiri untuk mengartikan "ini". sehingga Anda bisa menulis ekspresi seperti:
import Base: . (artinya impor Base.Base )
atau
using ..

saya cukup yakin itu akan membutuhkan https://github.com/JuliaLang/julia/pull/11891#issuecomment -116098481 namun. mungkin cukup untuk memberikan spasi sebelum . , tetapi tidak setelahnya, untuk menyelesaikan kasus ambiguitas?

Saya percaya kebutuhan sudah tidak digunakan lagi. Mungkin bagus untuk menambahkan notasi titik yang lebih fleksibel pada modul yang diimpor dengan 1.0, tapi saya ragu kita akan mengubah apa pun di sini dengan pembekuan fitur 0.6

Setelah banyak diskusi tentang ini kemarin, saya condong ke sesuatu seperti proposal di https://github.com/JuliaLang/julia/issues/8000#issuecomment -52142845 dan https://github.com/JuliaLang/julia/ issue/8000#issuecomment -52143609:

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

Alternatifnya adalah menyimpan import daripada 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

Aturan umum apakah suatu pengikatan itu keras atau lunak akan sederhana: nama apa pun yang diminta secara eksplisit adalah pengikatan keras, pengikatan apa pun yang diberikan secara implisit adalah lunak.

Sunting: ada beberapa keinginan untuk menambahkan ke skema ini beberapa singkatan untuk import A; import A: ... yang kira-kira seperti yang dilakukan using A saat ini (satu-satunya perbedaan adalah bahwa using A saat ini impor lunak A ); ini bisa terus menjadi using A atau import A... telah diusulkan.

Ya, saya pikir itu juga proposal yang bagus. Pada dasarnya tergantung pada apakah seseorang lebih suka using atau import .

Tambahan, kita dapat menyimpan using A sebagai singkatan untuk import A; import A: ... – ditambah dengan menghilangkan perilaku saat ini bahwa setiap modul memiliki pengikatan yang diekspor untuk dirinya sendiri, itulah sebabnya using A menyebabkan akan ada ikatan lunak untuk A tersedia.

Saya akan sangat kecewa jika kami masih memiliki banyak kata kunci setelah semua ini.

Saya suka simetri import dan export . (Seperti yang ditunjukkan seseorang di suatu tempat.)

Selalu melakukan "ikatan keras" sepertinya bukan default teraman dalam hal ekstensi metode. Ada proposal terkait tetapi agak terpisah yang memerlukan kualifikasi modul untuk ekstensi metode yang dapat menghilangkan kebutuhan akan "ikatan keras".

Binding keras juga diperlukan untuk tujuan ini:

import Package: x
x = 1   # gives an error

Dan yang terpenting, proposal ini tidak akan selalu melakukan pengikatan keras --- hanya untuk hal-hal yang Anda daftarkan secara eksplisit. Mengharuskan yang mengatakan import alih-alih using tidak menambah banyak keamanan.

Keamanan berasal dari sebagian besar tempat yang tidak melakukan ekstensi metode yang dapat lolos dengan baik dengan penjilidan yang lembut. Saya pikir kita masih harus memiliki cara untuk meminta penjilidan lunak tertentu tanpa harus mengimpor semua ekspor paket (atau mendapatkan penjilidan lunak tertentu yang tidak diekspor).

Apakah kita masih memiliki peringatan untuk menimpa binding yang diimpor?

Saya pikir membutuhkan kualifikasi modul adalah ide yang bagus. Saat ini untuk mengetahui apakah suatu fungsi sedang diperkenalkan atau metode diperpanjang, Anda harus melihat seluruh isi paket untuk pernyataan import A: func .

Apakah kita masih memiliki peringatan untuk menimpa binding yang diimpor?

Saya percaya itu sebenarnya kesalahan sekarang.

Ada proposal lain yang beredar yang mempertahankan kedua kata kunci, tetapi masih sedikit menyederhanakan:

  1. Tambahkan sintaks import A: ...
  2. Menghentikan using A:
  3. Dalam using A.B , memerlukan A.B untuk menjadi modul, dan mendokumentasikan bahwa itu adalah singkatan dari import A.B; import A.B: ... .

Dengan cara ini, semuanya dapat dilakukan hanya dengan import , tetapi using X tersedia untuk kenyamanan. Ini juga akan sangat mudah untuk ditransisikan.

BTW, using terlihat tidak konsisten seperti yang saya posting di sini . Jika kita menyimpan using , itu harus diubah namanya menjadi use jika memungkinkan.
Saya pikir kita harus memerlukan kuantifikasi modul ketika memperluas fungsi karena artinya jauh lebih jelas daripada pola impor-lalu-perpanjang.

Pendekatan favorit saya:

  • Memerlukan awalan modul eksplisit untuk ekstensi
  • Jika Anda hanya menginginkan nama modul dan bukan simbolnya, gunakan using A: A
  • Hapus import dan jenis ikatan yang dibuatnya

Hal-hal yang perlu terjadi untuk mengimplementasikan https://github.com/JuliaLang/julia/issues/8000#issuecomment -327512355:

  • ubah perilaku using A menjadi hard import A
  • hapus dukungan untuk using A: x
  • hapus dukungan untuk using A.x di mana x bukan submodul
  • hapus dukungan untuk import A.x di mana x bukan submodul
  • tambahkan dukungan untuk sintaks ... ke import

using A: x sering digunakan dan sangat berguna. Anda mengatakan Anda ingin x di namespace Anda tetapi Anda tidak ingin memperpanjangnya. Di import A: x , Anda mengatakan ingin dapat memperpanjang x . Ada perbedaan yang berarti antara memiliki fungsi yang tersedia untuk digunakan dan dapat memperluasnya.

Kalau dipikir-pikir, saya akan mengatakan satu-satunya masalah terbesar di sini adalah bahwa using A.B melakukan dua hal: jika B adalah sebuah modul, ia akan mengimpor semua ekspornya, dan sebaliknya hanya impor lunak B . Saya pikir kita harus memperbaikinya, dan membuat using A.B hanya diperbolehkan untuk modul, dan memiliki using A: a, b untuk mengimport binding spesifik secara lunak satu per satu.

Saya lebih suka jika ada satu cara untuk menulis import A: x daripada itu setara dengan import A.x .

Saya memilih import A: x karena kami juga dapat melakukannya; import A: x, y, @z tetapi import A.x, A.y, a.@z akan terlihat jelek.

Apakah ini dihapus dari 1.0 berarti kita akan memiliki using dan import untuk 1.0? Itu agak disayangkan menurut saya.

Bagaimana tentang:

  • Paksa awalan modul untuk ekstensi. Ini akan membuat kode lebih jelas bahwa ekstensi dimaksudkan alih-alih tidak disengaja dari impor di beberapa file lain.
  • using A menjadi import A: ...
  • using A.X ( X adalah modul) menjadi impor A.X: ...
  • using A: X ( X bukan modul) menjadi import A: X
  • import A: X tidak diubah tetapi Anda tidak dapat secara otomatis memperpanjang X (lihat poin pertama)
  • hapus kata kunci using

Apakah saya melewatkan beberapa kasus penggunaan? Mungkin ini sudah disarankan...

Apa yang saya suka tentang menjadi eksplisit tentang modul ketika memperluas adalah bahwa ekstensi menjadi jauh lebih lokal. Saat ini, ketika suatu metode diperluas, adalah umum untuk menempatkan impor sangat dekat dengan bagian atas modul (yang mungkin dalam file yang sama sekali berbeda!). Ketika metode yang diperluas dihapus, pernyataan impor biasanya dilupakan.

Saya pikir itu pada dasarnya sama dengan proposal saya di atas, yang mendapat cukup banyak dukungan. @JeffBezanson benar-benar ingin menyimpan using A setidaknya untuk kemudahan penggunaan dan using A: x karena ternyata (saya tidak menjual ini), ini adalah kasus penggunaan yang penting untuk dapat mengimpor penjilidan sedemikian rupa sehingga Anda tidak dapat memperpanjangnya. Ada beberapa proposal untuk pergi ke arah lain dan mengganti import dengan using tetapi tidak satupun dari mereka yang benar-benar mendapat banyak daya tarik ( import tampaknya lebih mendasar).

Menurut saya perbedaannya ada pada:

  • import A: x, y # hard binding untuk x dan y dari A

Dengan asumsi arti "pengikatan keras" sedemikian rupa sehingga Anda dapat memperpanjangnya tanpa awalan modul, dalam versi saya tidak ada ikatan keras. Jika Anda ingin memperluas, Anda memasang awalan modul tepat di tempat Anda memperpanjangnya. Tidak ada pernyataan import seram di file lain yang mengubah arti apakah sesuatu itu ekstensi atau bukan.

dan using A: x karena tampaknya (saya tidak setuju dengan ini), ini adalah kasus penggunaan yang penting untuk dapat mengimpor penjilidan sedemikian rupa sehingga Anda tidak dapat memperpanjangnya.

Bukankah memaksa awalan modul berurusan dengan itu? Atau apakah kita berbicara tentang non modul seperti:

module M
    x = 1
end

Baik import M: x; x = 2 dan using M: x; x = 2 memberikan pesan peringatan yang sama jadi saya tidak melihat apa masalahnya...

Menjaga using A untuk kemudahan lebih dari import A: ... tampaknya agak berlebihan menurut saya.

Bukankah memaksa awalan modul berurusan dengan itu?

Ya; jika Anda harus memenuhi syarat fungsi untuk memperluasnya maka poin ini tidak relevan.

Tetap menggunakan A untuk kemudahan over import A: ... sepertinya agak berlebihan menurut saya.

Saya melihatnya sebaliknya; membuat orang beralih dari using A (yang bagus dan pendek dan kita semua sudah terbiasa) ke import A: ... hanya untuk memenuhi persyaratan buatan bahwa hanya ada 1 kata kunci yang berlebihan.

Dari membaca thread, tampaknya nilai utama dalam memiliki dua kata kunci adalah untuk membedakan antara binding yang dapat diperpanjang atau tidak (hard binding). Dengan mengingat hal itu, saya pikir ada dua solusi yang layak:

  • 1 kata kunci + memerlukan awalan untuk perpanjangan
  • dua kata kunci, satu untuk penggunaan normal (tidak diperpanjang), dan yang kedua untuk penggunaan yang diperpanjang, saya sarankan using dan extending dalam kasus ini. import baik-baik saja, tetapi extending membuat alasan keberadaan kata kunci ke-2 menjadi jelas

Dalam kedua kasus saya sarankan using harus seperti sekarang dengan penambahan salah satu dari berikut untuk hanya mengikat modul Foo :

  • using Foo: nothing (berfungsi sekarang)
  • using Foo: Foo (berfungsi sekarang)
  • using Foo: (dapat ditambahkan nanti)

Kemudian extending harus berperilaku identik dengan using dengan satu-satunya perbedaan adalah Anda dapat memperpanjang binding yang dibawa dengan extending , dan mungkin melarang extending Foo sehingga memiliki untuk menjadi eksplisit.

Perilaku saat ini

| | membuat tersedia (menggunakan) | buat dapat diperpanjang (impor)|
| ------------------- | -------------------------- | ---------------------- |
| hanya modul | using module: module atau using module: nothing | import module |
| semuanya diekspor | using module (efek samping: bertindak seperti import module juga) | ? |
| hal-hal tertentu | using module: x,y | import module: x,y |

Saran

| | membuat tersedia (menggunakan) | buat dapat diperpanjang (impor) |
| ----------------- | ------------------------ | -------------------------- |
| hanya modul | using module | import module |
| semuanya diekspor | using module: * | import module: * |
| hal-hal tertentu | using module: x,y | import module: x,y |

Hal yang menyenangkan tentang ini adalah, bahwa mengimpor lebih banyak sama dengan menulis lebih banyak. Yaitu Anda mulai dengan using module dan jika Anda ingin mengimpor variabel langsung ke namespace Anda menambahkan : x alih-alih menghapus nothing atau module . Ini juga berarti bahwa hal terpendek yang Anda ketik termasuk paling sedikit.

Anda juga dapat melakukan using: *,x untuk membuat semua yang diekspor tersedia dan x yang tidak diekspor.

Kompromi untuk kompatibilitas mundur:

| | membuat tersedia (menggunakan) | buat dapat diperpanjang (impor) |
| ----------------- | ------------------------ | -------------------------- |
| hanya modul | using module: | import module: |
| semuanya diekspor | using module: * | import module: * |
| hal-hal tertentu | using module: x,y | import module: x,y |

pertahankan using module dan import module dengan perilaku saat ini untuk kompatibilitas mundur tetapi tidak digunakan lagi.

@FelixBenning : import Module saat ini tidak (dengan sendirinya) membuat sesuatu yang dapat diperpanjang lebih dari using Module , itu hanya memuat kode dan membawa Module (dan tidak ada yang lain) ke dalam namespace .

Hanya untuk mencerminkan apa yang saya katakan di slack dan agar tidak hilang di slack hole:

Saya tidak berpikir menjadikan using X: * sebagai default untuk membuat setiap barang yang diekspor tersedia vs. hanya using X akan membuat orang lebih waspada terhadap apa yang mereka impor. Saya tahu, menunjuk ke bagaimana orang lain melakukannya dianggap sebagai bentuk yang buruk, tetapi Python pada dasarnya memiliki semantik itu dengan import X dan import X: * , namun ekosistem mereka dipenuhi dengan impor bintang itu ️ (dan mereka terkenal membenci itu) Saya tidak berpikir teks yang sedikit lebih panjang yang harus diketik seseorang menghentikan orang dari melakukan apa yang mereka anggap paling nyaman: cukup impor/gunakan semuanya dan biarkan kompiler mencari tahu. Itu sebabnya saya waspada terhadap peluru ajaib untuk membuat orang menulis bintang itu secara eksplisit.

Selanjutnya, import module: * dan using module: * tidak tersedia untuk arti yang diusulkan. Itu sudah memiliki arti sebagai * adalah pengenal Julia yang valid dan dapat diimpor/digunakan seperti + atau kata mul .

@tpapp entah saya salah memahami dokumentasi lagi, atau import Module membuat Module.x dapat diperpanjang. Sementara using Module: x tidak membuat Module.x dapat diperpanjang. Oleh karena itu import Module membuat sesuatu tersedia untuk ekstensi dan using Module melakukannya juga, itulah sebabnya saya mencatat bahwa menggunakan memiliki efek samping itu.
grafik
(dari https://docs.julialang.org/en/v1/manual/modules/)

Tidak masalah siapa di antara kita yang benar - dalam kedua kasus situasi saat ini jelas berantakan jika kita bahkan tidak dapat mengetahui apa yang dilakukan semuanya.

@mbauman poin bagus - saya lupa tentang itu. Saya tidak terlalu peduli dengan * hanya struktur memiliki using mencerminkan hal-hal yang dilakukan import dengan perbedaan impor vs menggunakan apakah sesuatu dapat diperpanjang atau tidak. Jadi jika ada simbol yang lebih tepat - all , __all__ , everything , exported , ...? Saya semua untuk itu. Saya hanya berpikir bahwa mengimpor lebih banyak mungkin harus tercermin dengan mengetik lebih banyak.

Tetapi jika Anda tidak menginginkannya sama sekali, tentu saja Anda juga bisa memilih

| | membuat tersedia (menggunakan) | buat dapat diperpanjang (impor) |
| ----------------- | ------------------------ | -------------------------- |
| hanya modul | using module: module | import module: module |
| semuanya diekspor | using module | import module |
| hal-hal tertentu | using module: x,y | import module: x,y |

atau

| | membuat tersedia (menggunakan) | buat dapat diperpanjang (impor) |
| ----------------- | ------------------------ | -------------------------- |
| hanya modul | using module | import module |
| semuanya diekspor | using module: module | import module: module |
| hal-hal tertentu | using module: x,y | import module: x,y |

Tapi apapun hasil akhirnya, harus konsisten. Dan saat ini tidak.

using A membuat A.f dapat diperpanjang, _not_ f dengan sendirinya. Untuk memperluas _just_ f tanpa menyatakan dari modul mana Anda ingin diperpanjang, Anda harus import A: f secara eksplisit. Jika tidak, Anda masih harus memenuhi syarat.

Periksa berikut ini untuk semantik 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?"

Dan ini untuk semantik 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 : ya, saya pikir Anda salah paham. FWIW, saya pikir "... membuat Foo.x dapat diperpanjang" adalah cara yang membingungkan untuk mendekati perbedaan --- Anda selalu dapat menentukan metode untuk nama fungsi yang sepenuhnya memenuhi syarat. Apa yang terjadi dengan using Foo: x adalah bahwa Foo itu sendiri tidak akan dibawa ke namespace.

Kebetulan, membaca ulang topik ini saya bertanya-tanya apakah #25306 membawa kita ke semacam optimal lokal, dan satu-satunya keputusan yang tersisa adalah apakah kita perlu impor non-extensible ke namespace (saat ini using Foo: f ). Tapi karena itu melanggar, bab manual mungkin akan mendapat manfaat dari penulisan ulang sementara itu, banyak pengguna menemukan semuanya membingungkan.

Inilah cara saya mendekati status quo dalam dokumen:

  1. using M memuat modul, dan membawa M dan simbol yang diekspor ke namespace. Ini adalah satu-satunya kasus di mana ekspor penting.
  2. setelah Anda memiliki M , Anda dapat menggunakan nama yang memenuhi syarat seperti M.y untuk (a) mengakses simbol yang tidak diekspor dan (b) menambahkan metode ke fungsi, terlepas dari apakah itu diekspor atau tidak
  3. Julia mencegah Anda menambahkan metode ke fungsi kecuali Anda menggunakan nama yang memenuhi syarat seperti M.f , atau ...
  4. ... import M: f , maka Anda bisa menggunakan f saat mendefinisikan metode.
  5. import M dan using M: x masing - masing untuk membawa M atau x (dan bukan M ), masing-masing, ke dalam namespace. Beberapa orang suka menggunakan formulir ini dalam kode paket untuk memastikan ruang nama mereka tetap bersih (tautkan panduan gaya yang relevan di sini).

Urutannya kurang lebih mencerminkan kasus penggunaan yang dihadapi dengan penggunaan yang lebih maju. Semua hal di atas berlaku untuk submodul, dengan M.A sebagai ganti M .

Bagaimana dengan ini:

  • using M membawa M ke dalam cakupan
  • using M: x membawa M.x ke dalam cakupan (sebagai x )
  • using M: ... membawa semua simbol yang diekspor dari M ke dalam cakupan
  • using M: x, ... membawa semua simbol yang diekspor dari M ke dalam cakupan dan juga x (yang mungkin tidak diekspor)
  • Tidak ada import . Anda perlu menggunakan nama yang memenuhi syarat untuk memperluas suatu fungsi. (Atau using M; const foo = M.foo seperti yang sudah bisa dilakukan sekarang.)
  • Dalam semua hal di atas, M juga bisa menjadi submodule, misalnya Foo.Bar dan x juga bisa menjadi x as y dengan arti saat ini.

Atau kami menggunakan import alih-alih using yang kemudian membuatnya sama dengan https://github.com/JuliaLang/julia/issues/8000#issuecomment -355960915.

Penggunaan yang sangat umum (terutama dalam "skrip", tetapi juga paket untuk gaya tertentu adalah)

using Foo, Bar, Baz

dan hanya mengandalkan simbol yang diekspor. Akan ada beberapa manfaat dari menjaga ini yang paling sederhana, mungkin sesederhana sekarang.

@tpapp

Saya pikir Anda salah paham. FWIW, saya pikir "... membuat Foo.x dapat diperpanjang" adalah cara yang membingungkan untuk mendekati perbedaan --- Anda selalu dapat menentukan metode untuk nama fungsi yang sepenuhnya memenuhi syarat.

Oke, jadi bisakah saya memperpanjang Foo.x setelah using Foo: x ? Karena jika ya, maka dokumentasinya belum lengkap (lihat screenshot saya). Jika tidak, maka saya sangat memahami cara kerja pernyataan ini dan cukup jelas import Foo melakukan sesuatu untuk membuat Foo.x dapat diperluas. Oleh karena itu secara harfiah membuat Foo.x tersedia untuk ekstensi. Dalam setiap arti kata-kata ini. Tentu itu tidak membuat x tersedia untuk ekstensi, tetapi untuk itulah import Foo: x

Oke, jadi bisakah saya memperpanjang Foo.x setelah using Foo: x ?

Tidak, kecuali jika Anda membawa Foo ke namespace entah bagaimana (misalnya using Foo ).

Saya sangat memahami bagaimana pernyataan ini bekerja

Saya tidak yakin tentang ini — namun, jika Anda memiliki pertanyaan tentang modul dan ruang nama, silakan gunakan forum Wacana.

cukup jelas import Foo melakukan sesuatu untuk membuat Foo.x dapat diperluas

Hanya dalam arti bahwa Anda harus dapat merujuk ke suatu fungsi entah bagaimana menggunakan nama yang memenuhi syarat sebelum menambahkan metode ke dalamnya.

maka dokumentasinya tidak lengkap

Saya pikir itu, dengan cara yang aneh. Dalam contoh khusus itu, jika semua yang Anda lakukan adalah using MyModule: x, p ; maka tidak ada metode yang tersedia untuk ekstensi, jadi tabelnya benar.

Saya setuju bahwa itu bisa ditulis lebih baik, seperti yang saya katakan di atas. Banyak orang yang tidak terbiasa dengan namespace merasa bingung. Dan, TBH, seluruh sirkus using / import agak membingungkan, oleh karena itu masalah ini.

@tpapp

Oke jadi begini: Sama sekali tidak jelas bahwa Anda dapat memperluas setiap fungsi dengan nama lengkap jika modul ada di namespace. Saya tahu bahwa ini adalah perilaku saat ini, tetapi saya tidak berpikir siapa pun yang tidak tahu itu akan berasumsi seperti itu. Terutama karena berada di namespace tidak selalu berarti dapat diperpanjang. Jika saya melakukannya using module:x Saya tidak dapat memperpanjang x . Meskipun saya dapat memperpanjang x , jika saya menggunakan import module:x . Oleh karena itu adalah asumsi yang masuk akal, bahwa perbedaan antara using dan import adalah apakah Anda dapat memperluas fungsi yang diimpor atau tidak.

Menggunakan asumsi ini masuk akal, jika using module hanya mengizinkan penggunaan module.x tetapi tidak mengizinkan ekstensi module.x . Sementara import module akan mengizinkan ekstensi module.x . Jadi jika Anda mengambil asumsi ini dan membaca dokumentasinya, Anda akan menemukan bahwa dua hal tentang itu salah.

  1. using module memungkinkan Anda untuk memperpanjang module.x . Oleh karena itu dari perspektif pelajar using module memiliki efek samping , yang juga bertindak seperti import module - yaitu membuat module.x dapat diperpanjang. Dan membuat sesuatu dapat diperpanjang adalah hal import , bukan using hal
  2. berbeda dengan import , using tidak hanya membuat module tersedia, melainkan semua yang ada di dalamnya.

Jadi inilah yang saya coba wakili dengan tabel saya. Jika dua kata yang berbeda digunakan (impor/menggunakan) maka mereka harus melakukan dua hal yang berbeda dan itu harus jelas. Jika using terkadang mengizinkan ekstensi dan terkadang tidak, itu bukan perilaku yang dapat diprediksi.

Alternatif yang baik adalah menghapus impor sepenuhnya seperti yang disarankan @martinholters . Anda hanya tidak bisa memiliki dua kata yang hanya digunakan secara acak untuk hal-hal tertentu. Jika import berarti membuat sesuatu dapat diperpanjang saat mengimpor fungsi tertentu, sementara using module: foo tidak mengizinkannya, maka perilaku yang sama akan terjadi ketika Anda hanya menyertakan module di namespace.

Hanya karena Anda dapat memperluas semuanya dengan nama lengkapnya sekarang jika modul berada di namespace, tidak berarti bahwa ini adalah hal yang jelas atau langsung.

Baik berada di namespace sudah cukup, maka saya juga harus dapat memperpanjang x jika saya memasukkannya ke dalam namespace dengan using module:x atau berada di namespace tidak cukup, dan kemudian saya juga harus tidak dapat memperpanjang module.x saat menggunakan perintah using .
Atau opsi ketiga: tidak ada import dan Anda hanya perlu memperluas fungsi dengan nama lengkapnya sepanjang waktu.

Sama sekali tidak jelas bahwa Anda dapat memperluas setiap fungsi dengan nama lengkap jika modul berada di namespace.

Saya setuju, itulah sebabnya saya mengusulkan penulisan ulang dokumen. Namun, itu bersinggungan dengan masalah saat ini. Sebaiknya simpan (1) proposal untuk meningkatkan dokumentasi pada API saat ini dan (2) proposal untuk mendesain ulang secara terpisah, meskipun keduanya agak terkait. Saya berencana untuk membuat PR untuk (1) segera.

@tpapp Anda tidak dapat mendokumentasikan sesuatu yang secara inheren tidak masuk akal. Tak satu pun dari dokumentasi ini yang benar:

  1. "Anda dapat memperpanjang apa pun yang ada di namespace" (karena using module:x tidak mengizinkan Anda untuk memperpanjang x )
  2. "Berada di namespace tidak cukup untuk ekstensi, inilah mengapa kata-kata terpisah using dan import ada" (salah karena untuk nama lengkap sebenarnya cukup berada di namespace - hentikan itu cukup adalah saran saya)
  3. "Anda dapat memperluas apa pun di Namespace dengan nama lengkapnya" (yang akan membutuhkan import module:x untuk berhenti menjadi kebenaran penuh - proposal @martinholters )

Semua ini akan diterima. Tapi tak satu pun dari ini benar-benar kenyataan. Kenyataannya saat ini ada dua kata berbeda yang digunakan untuk "mengimpor barang" tetapi mereka sebenarnya tidak memiliki kasus penggunaan yang berbeda. Ini seperti loop for terkadang berperilaku seperti loop while jika Anda mengulangi boolean. Tidak ada jumlah dokumentasi yang akan membuatnya tidak membingungkan

Anda tidak dapat mendokumentasikan sesuatu yang pada dasarnya tidak masuk akal.

API modul saat ini terdefinisi dengan baik, sehingga dapat didokumentasikan (sudah ada, saya hanya berpikir itu harus lebih baik).

Tak satu pun dari dokumentasi ini yang benar:

Harap berbaik hati menunggu PR saya (atau orang lain) dan mengomentari teks aktual yang akan ada di sana. Memposting dokumentasi hipotetis dan kemudian mengklaim bahwa itu tidak benar hanya menambah kebisingan pada diskusi ini.

@tpapp mungkin saya seharusnya mengatakan,

Anda tidak dapat mendokumentasikan sesuatu dengan cara yang tidak membingungkan yang pada dasarnya tidak masuk akal

Maksud saya dalam arti kode adalah semua dokumentasi yang Anda butuhkan bukan? Apa yang salah dengan itu? Waktu yang dibutuhkan untuk mencernanya. Dan saat ini saya tidak melihat cara singkat untuk menjelaskan cara kerjanya, karena penuh dengan pengecualian. Pengecualian yang seharusnya tidak ada di tempat pertama.

Apakah Anda benar-benar tidak melihat apa yang saya coba sampaikan?

Saya pikir ada kesepakatan umum bahwa situasi saat ini tidak perlu rumit dan tidak cukup didokumentasikan. Dan tidak diragukan lagi, menyederhanakan mesin akan mempermudah pendokumentasian. Tapi penyederhanaan seperti itu akan melanggar, jadi tidak bisa dilakukan sebelum 2.0. Jadi, apakah maksud Anda bahwa peningkatan pada dokumentasi sebelumnya tidak masuk akal? Kemudian saya tidak setuju. Saya memang melihat dua masalah terpisah: Penyederhanaan yang harus dilakukan dengan 2.0 (yang membahas masalah ini) yang (semoga) akan menyertakan pembaruan dokumentasi yang diperlukan dan meningkatkan dokumentasi cara kerja saat ini yang dengan membaca utas ini tampaknya sangat diperlukan tetapi merupakan masalah lain .

Setelah melakukan #38271, saya pikir pertanyaan yang luar biasa adalah

Bagaimana menangani penambahan metode ke fungsi di modul lain

  1. selalu membutuhkan nama yang sepenuhnya memenuhi syarat ( Foo.bar() = ... ),
  2. juga hanya mengizinkan ketika simbol berada dalam ruang lingkup ( using Foo: bar; bar() = ... )
  3. (2), tetapi bawa ke ruang lingkup dengan cara khusus ( status quo , import Foo: bar; bar() = ... )

Sintaks mana yang menangani daftar ekspor dan hanya nama modul

  1. using Foo membawa semua simbol yang diekspor dalam Foo ke ruang lingkup, import Foo hanya modul ( status quo )
  2. using Foo: ... atau sintaks serupa lainnya, lalu using Foo hanya modulnya.

(1|2) & 2 akan memungkinkan penyatuan menjadi satu kata kunci, using atau import , dengan biaya kehilangan satu baris

using LinearAlgebra, Random, StaticArrays

Saya tidak yakin itu sepadan, bahkan tanpa mempertimbangkan perubahan yang melanggar.

Ini bukan salah satu masalah yang menawarkan solusi bersih yang terlewatkan oleh desain aslinya; ada trade-off. Saya akan menunggu dan melihat apakah dokumentasi yang lebih baik dapat meningkatkan pengalaman pengguna sambil mempertahankan pengaturan (1.0) saat ini.

Untuk 2.0 saya pikir hanya pembersihan sintaks agar lebih konsisten dan deskriptif tentang apa yang sebenarnya terjadi akan menyenangkan. Sesuatu seperti:

| Sebelum | Setelah |
|-|-|
| using Foo | useall from Foo |
| import Foo | use Foo |
| using Foo: a | use a from Foo |
| import Foo: a dan import Foo.a | extend a from Foo |

Apakah halaman ini membantu?
0 / 5 - 0 peringkat