Julia: Aturan lingkup variabel global menyebabkan perilaku tidak intuitif di REPL/notebook

Dibuat pada 21 Agu 2018  ·  98Komentar  ·  Sumber: JuliaLang/julia

Contoh 1

Ini muncul dengan seorang siswa yang memutakhirkan dari 0,6 ke 1,0 secara langsung, jadi bahkan tidak pernah mendapat kesempatan untuk melihat peringatan penghentian, apalagi menemukan penjelasan untuk perilaku baru:

julia> beforefor = true
true

julia> for i in 1:2
         beforefor = false
       end

julia> beforefor  # this is surprising bit
true

julia> beforeif = true
true

julia> if 1 == 1
         beforeif = false
       end
false

julia> beforeif  # Another surprise!
false

julia> function foo()
         infunc = true
         for i in 1:10
           infunc = false
         end
         <strong i="7">@show</strong> infunc
       end
foo (generic function with 1 method)

julia> foo()  # "I don't get this"
infunc = false 

Contoh 2

julia> total_lines = 0
0

julia> list_of_files = ["a", "b", "c"]
3-element Array{String,1}:
 "a"
 "b"
 "c"

julia> for file in list_of_files
         # fake read file
         lines_in_file = 5
         total_lines += lines_in_file
       end
ERROR: UndefVarError: total_lines not defined
Stacktrace:
 [1] top-level scope at ./REPL[3]:4 [inlined]
 [2] top-level scope at ./none:0

julia> total_lines  # This crushs the students willingness to learn
0

Saya "mengerti" mengapa ini terjadi dalam arti yang saya pikir dapat saya jelaskan, dengan referensi yang cukup ke arcana dalam manual tentang apa yang memperkenalkan cakupan dan apa yang tidak, tetapi saya pikir ini bermasalah untuk penggunaan interaktif.

Dalam contoh satu, Anda mendapatkan kegagalan diam-diam. Dalam contoh dua, Anda mendapatkan pesan kesalahan yang sangat tidak ada. Itu kira-kira sebanding dengan beberapa kode Python yang saya tulis di buku catatan di tempat kerja hari ini.

Saya tidak yakin apa aturannya dalam Python, tetapi saya tahu bahwa secara umum Anda tidak dapat menetapkan hal-hal di lingkup global tanpa menggunakan global. Tetapi di REPL itu berhasil, mungkin karena di REPL aturannya berbeda atau logikanya sama seolah-olah semuanya dalam lingkup fungsi yang diterapkan.

Saya tidak bisa bahasa-pengacara aturan cukup untuk mengusulkan perubahan konkret yang saya inginkan, dan berdasarkan Slack ini bahkan tidak selalu dianggap sebagai masalah oleh beberapa orang, jadi saya tidak tahu ke mana harus pergi dengan ini kecuali untuk bendera itu.

Referensi silang:

19324

https://discourse.julialang.org/t/repl-and-for-loops-scope-behavior-change/13514
https://stackoverflow.com/questions/51930537/scope-of-variables-in-julia

REPL minor change

Komentar yang paling membantu

@JeffBezanson , ingat bahwa banyak dari kita ingin menggunakan Julia sebagai pengganti Matlab dan sebagainya dalam kursus teknis seperti aljabar linier dan statistik. Ini bukan kursus pemrograman dan siswa sering tidak memiliki latar belakang pemrograman. Kami tidak pernah melakukan pemrograman terstruktur — hampir semuanya interaktif dengan cuplikan pendek dan variabel global.

Selain itu, alasan saya menggunakan bahasa dinamis adalah untuk beralih dengan lancar antara eksplorasi interaktif dan pemrograman yang lebih disiplin. Ketidakmampuan untuk menggunakan kode yang sama dalam konteks global dan fungsi adalah penghalang untuk tujuan itu, bahkan untuk seseorang yang terbiasa dengan konsep pelingkupan, dan itu jauh lebih buruk bagi siswa dari latar belakang non-CS.

Semua 98 komentar

(Per @mlubin , ini adalah perubahan yang relevan https://github.com/JuliaLang/julia/pull/19324)

Stefan menyarankan di sini bahwa satu kemungkinan untuk menyelesaikan masalah ini adalah pembungkus otomatis entri REPL di blok let

Tapi bukankah itu membingungkan karena Anda tidak bisa melakukannya?

a = 1

dan gunakan a setelah itu? Kecuali global dimasukkan untuk semua tugas tingkat atas, saya kira?

Perilakunya tidak hanya untuk membungkus semuanya dalam blok let —ini lebih rumit dari itu. Anda perlu membiarkan semua global yang ditetapkan di dalam ekspresi dan kemudian mengekstrak nilai yang terikat ke global di akhir ekspresi.

Jadi Anda akan mengubah a = 1 menjadi sesuatu seperti a = let a; a = 1; end . Dan sesuatu seperti

for i in 1:2
    before = false
end

akan berubah menjadi ini:

before = let before = before
    for i in 1:2
        before = false
    end
end

Terus terang, saya cukup kesal karena orang-orang hanya memberikan umpan balik ini sekarang. Perubahan ini telah di master selama sepuluh bulan.

Saya bersalah karena tidak mengikuti master sangat tertutup sampai saat ini, jadi umpan balik ini memang agak terlambat. Lebih dari sekadar perhatian untuk programmer (kebanyakan for loop akan berada di dalam fungsi dalam kode perpustakaan) Saya khawatir ini adalah masalah untuk mengajar. Seringkali for loop diajarkan sebelum fungsi atau cakupan (tentu saja Anda perlu memahami ruang lingkup untuk benar-benar memahami apa yang terjadi tetapi dalam mengajarkan hal-hal yang sering disederhanakan).

Di sini menjadi agak sulit untuk mengajari seorang pemula cara menjumlahkan angka dari 1 hingga 10 tanpa menjelaskan fungsi atau variabel global.

Terus terang, saya cukup kesal karena orang-orang hanya memberikan umpan balik ini sekarang. Perubahan ini telah di master selama sepuluh bulan.

Agar adil, Julia 0.7 dirilis 13 hari yang lalu. Ini adalah perubahan baru bagi sebagian besar pengguna Julia.

Terus terang, saya cukup kesal karena orang-orang hanya memberikan umpan balik ini sekarang. Ini telah berubah pada master selama sepuluh bulan

Sayangnya bagi kita yang tidak bisa menangani hidup di tepi, itu baru dari sudut pandang kita.

Terus terang, saya cukup kesal karena orang-orang hanya memberikan umpan balik ini sekarang. Perubahan ini telah di master selama sepuluh bulan.

Dan bagi kita yang telah didorong untuk menjauh dari cabang pengembangan, "ini baru dari sudut pandang kita."

Bisakah kita kembali untuk fokus pada masalah yang ada sekarang, daripada melakukan diskusi meta tentang berapa lama orang harus menguji ini. Itulah yang terjadi sekarang, jadi mari kita lihat ke depan.

Saya bersalah karena tidak mengikuti master sangat tertutup sampai saat ini, jadi umpan balik ini memang agak terlambat. Lebih dari perhatian untuk programmer (kebanyakan untuk loop akan berada di dalam fungsi dalam kode perpustakaan) Saya khawatir ini adalah masalah untuk mengajar. Seringkali for loop diajarkan sebelum fungsi atau cakupan (tentu saja Anda perlu memahami ruang lingkup untuk benar-benar memahami apa yang terjadi tetapi dalam mengajarkan hal-hal yang sering disederhanakan).

Di sini menjadi agak sulit untuk mengajari seorang pemula cara menjumlahkan angka dari 1 hingga 10 tanpa menjelaskan fungsi atau variabel global.

Ini adalah poin besar. Setelah mengetahui apa masalahnya sebenarnya, mengejutkan betapa sedikitnya hal itu sebenarnya muncul. Ini bukan masalah dengan banyak kode Julia di alam liar dan dalam pengujian, dan itu mengungkapkan banyak variabel yang secara tidak sengaja bersifat global (dalam pengujian Julia Base menurut PR asli, dan saya perhatikan ini di sebagian besar tes DiffEq). Dalam kebanyakan kasus, tampaknya perilaku yang salah secara halus bukanlah yang Anda dapatkan (mengharapkan perubahan dalam satu lingkaran), melainkan mengharapkan untuk dapat menggunakan variabel dalam satu lingkaran adalah apa yang saya temukan sebagai sebagian besar dari di mana ini muncul dalam memperbarui skrip pengujian ke v1.0. Jadi hal baiknya adalah bahwa dalam banyak kasus pengguna disajikan dengan kesalahan, dan tidak sulit untuk memperbaikinya.

Hal buruknya adalah sedikit bertele-tele untuk memasukkan global x ke dalam loop, dan sekarang kode REPL Anda juga berbeda dari kode fungsi. Apakah itu perilaku yang lebih intuitif daripada sebelumnya adalah pendapat yang sulit karena pasti ada beberapa kasus tepi dalam pelingkupan lokal keras/lunak dan jadi ini jelas lebih mudah dijelaskan. Tetapi pada saat yang sama, sementara memiliki penjelasan yang jauh lebih ringkas daripada perilaku sebelumnya, sekarang lebih mudah untuk mencapai kasus tepi di mana memahami aturan pelingkupan itu penting. ️.

Saya ingin melihat eksperimen dengan pemblokiran let . Ini akan menjaga aspek "Anda tidak benar-benar menginginkan begitu banyak global", bersama dengan penjelasan pelingkupan yang disederhanakan, sementara pada saat yang sama membuat kode REPL berperilaku seperti interior fungsi (yang tampaknya selalu kita inginkan). Atau sebaliknya, membuat orang menentukan variabel yang mereka inginkan untuk bertindak sebagai global

global x = 5
for i = 1:5
  println(x+i)
end

bisa menjadi cara yang bagus untuk menjaga keeksplisitan, dan akan membuat "kode REPL lambat karena global" menjadi jauh lebih jelas. Kelemahannya adalah bahwa sekali lagi memasukkan sesuatu ke dalam suatu fungsi tidak memerlukan penanda global .

Tapi mengingat bagaimana hal ini cenderung muncul, itu tidak benar-benar gamebreaking atau showstopper. Saya akan mengklasifikasikannya sebagai kutil yang harus disebutkan di bengkel mana pun tetapi bukan berarti v1.0 tidak dapat digunakan karena itu. Saya harap mengubah perilaku ini tidak diklasifikasikan sebagai melanggar dan memerlukan v2.0 sekalipun.

Saya tidak begitu yakin saya menyukai gagasan bahwa REPL harus berperilaku seperti interior fungsi. Jelas tidak, jadi saya berharap itu berperilaku seperti lingkup global. Bagi saya REPL yang tidak berperilaku seperti lingkup global akan berpotensi lebih membingungkan daripada perbedaan yang menyebabkan masalah ini.

Terlepas dari itu, setidaknya saya berpikir bahwa dokumentasi harus agak lebih eksplisit tentang masalah ini. Membaca dokumen dengan santai, saya akan berasumsi bahwa Anda perlu menggunakan kata kunci local untuk mendapatkan perilaku yang terjadi dalam lingkup global secara default.

Saya ingin melihat eksperimen dengan pemblokiran let . Ini akan menjaga aspek "Anda tidak benar-benar menginginkan begitu banyak global", bersama dengan penjelasan pelingkupan yang disederhanakan, sementara pada saat yang sama membuat kode REPL berperilaku seperti interior fungsi (yang tampaknya selalu kita inginkan)

Jika kita ingin "REPL sama dengan bagian dalam suatu fungsi" kita juga harus memikirkan outer :

julia> i = 1
1

julia> for outer i = 1:10
       end
ERROR: syntax: no outer variable declaration exists for "for outer"

melawan:

julia> function f()
          i = 0
          for outer i = 1:10
          end
          return i
       end
f (generic function with 1 method)

julia> f()
10

Terus terang, saya cukup kesal karena orang-orang hanya memberikan umpan balik ini sekarang. Perubahan ini telah di master selama sepuluh bulan.

Orang-orang belum menggunakan master untuk penggunaan interaktif atau untuk mengajar, mereka telah menggunakannya untuk meningkatkan paket, yang hanya sedikit terpengaruh oleh ini dan sebagian besar ditulis oleh programmer berpengalaman.

(Saya adalah salah satu dari sedikit orang yang memberikan umpan balik di # 19324, di mana saya berdebat untuk perilaku lama .)

Cara keluar yang tidak putus-putus adalah dengan mengubah kembali ke perilaku lama (idealnya bukan dengan memasukkan blok implisit let atau apa pun — cukup pulihkan kode lama di julia-syntax.scm sebagai opsi) di REPL. Atau lebih tepatnya, untuk membuatnya tersedia di lingkungan seperti IJulia yang mungkin menginginkannya, tambahkan flag soft_global_scope=false ke include , include_string , dan Core.eval untuk memulihkan perilaku lama.

(Saya adalah salah satu dari sedikit orang yang memberikan umpan balik di # 19324, di mana saya berdebat untuk perilaku lama.)

Ya, dan saya sangat menghargainya. Tidak masalah sekarang karena kami membuat pilihan, biarkan panggang selama sepuluh bulan dan sekarang telah merilisnya dengan komitmen jangka panjang untuk stabilitas. Jadi satu-satunya hal yang harus dilakukan sekarang adalah fokus pada apa yang harus dilakukan ke depan.

Memiliki pilihan untuk memilih antara perilaku lama dan yang baru memang menarik tetapi rasanya sangat kacau. Itu berarti kami tidak hanya terkadang memiliki perilaku pelingkupan yang tampaknya membingungkan semua orang, tetapi kami tidak selalu memilikinya dan apakah kami memilikinya atau tidak bergantung pada bendera global. Rasanya sangat tidak memuaskan, saya rasa.

Memiliki pilihan untuk memilih antara perilaku lama dan yang baru memang menarik tetapi rasanya sangat kacau.

Jika seseorang mengimplementasikan transformasi AST soft-scope "unbreak me", akan sangat menggoda untuk menggunakannya di IJulia, OhMyREPL, dan sebagainya, di mana Anda mendapatkan situasi yang lebih bermasalah di mana REPL default dianggap rusak.

Bukan itu yang saya katakan. Jelas kita harus menggunakan solusi yang sama dalam semua konteks itu. Tetapi menerapkannya sebagai dua variasi berbeda pada aturan pelingkupan tampaknya kurang bersih daripada menerapkannya sebagai transformasi kode dengan satu set aturan pelingkupan. Tapi mungkin itu secara fungsional setara. Namun, tampaknya lebih mudah untuk menjelaskan dalam hal aturan pelingkupan baru yang lebih sederhana + transformasi yang mengambil input gaya REPL dan mengubahnya sebelum mengevaluasinya.

Itu bisa dilakukan sebagai Meta.globalize(m::Module, expr::Expr) yang mengubah ekspresi dengan secara otomatis membuat anotasi global apa pun yang ada dalam modul sebagai global jika mereka ditetapkan di dalam lingkup non-fungsi tingkat atas mana pun. Tentu saja, saya pikir itu setara dengan apa yang dilakukan parser lama, tetapi sedikit lebih transparan karena Anda dapat memanggil sendiri Meta.globalize dan melihat apa yang akan dievaluasi oleh REPL.

Itu bisa dilakukan sebagai Meta.globalize(m::Module, expr::Expr) yang mengubah ekspresi dengan secara otomatis membuat anotasi global apa pun yang ada dalam modul sebagai global jika mereka ditetapkan di dalam lingkup non-fungsi tingkat atas mana pun.

Saya sebenarnya mulai mencari penerapan sesuatu seperti ini beberapa menit yang lalu. Namun, sepertinya akan lebih mudah untuk diterapkan sebagai opsi di julia-syntax.jl :

  • Menulis transformasi AST eksternal dimungkinkan, tetapi sepertinya ada banyak kasus sudut yang rumit — Anda pada dasarnya harus menerapkan kembali aturan pelingkupan — sedangkan kami sudah memiliki kode untuk memperbaikinya di julia-syntax.scm .
  • Bahkan lebih rumit untuk sesuatu seperti IJulia yang saat ini menggunakan include_string untuk mengevaluasi seluruh blok kode dan mendapatkan nilai dari ekspresi terakhir. Kita tidak hanya harus beralih ke parsing ekspresi demi ekspresi, tetapi beberapa peretasan mungkin diperlukan untuk mempertahankan nomor baris asli (untuk pesan kesalahan dan sebagainya). (Meskipun saya menemukan peretasan untuk ChangePrecision.jl untuk hal semacam ini yang mungkin juga berfungsi di sini.)
  • Belum lagi kasus orang yang include file eksternal, yang tidak akan ditangkap oleh transformasi AST Anda.

Namun, tampaknya lebih mudah untuk menjelaskan dalam hal aturan pelingkupan baru yang lebih sederhana + transformasi yang mengambil input gaya REPL dan mengubahnya sebelum mengevaluasinya.

Saya sangat ragu ini akan lebih mudah dijelaskan kepada pengguna baru daripada hanya mengatakan bahwa aturannya tidak terlalu pilih-pilih untuk penggunaan interaktif atau untuk include dengan tanda tertentu.

Berikut adalah draf kasar implementasi globalize(::Module, ast) : https://Gist.github.com/stevenngj/255cb778efcc72a84dbf97ecbbf221fe

Oke, saya telah menemukan cara mengimplementasikan fungsi globalize_include_string yang mempertahankan informasi nomor baris, dan telah menambahkannya ke Gist saya .

Kemungkinan (tidak melanggar) jalan ke depan, jika orang menyukai pendekatan ini:

  1. Rilis paket SoftGlobalScope.jl dengan fungsi globalize dll.
  2. Gunakan SoftGlobalScope di IJulia (dan mungkin Juno, vscode, dan OhMyREPL).
  3. Lipat fungsi SoftGlobalScope ke dalam rilis mendatang dari paket stdlib REPL dan gunakan dalam REPL.

Atau praktis langsung roll ke REPL.jl? Saya tidak sepenuhnya jelas tentang cara kerja pembaruan stdlib di 1.0.

Silakan lihat implementasi saya, jika saya kehilangan sesuatu yang akan membuatnya rapuh.

Tidak bisakah kita memilikinya sebagai fitur non-default dari REPL di 1.1?

Duplikat #28523 dan #28750. Bagi mereka yang mengatakan bahwa mereka tidak ingin mengajari orang tentang variabel global, saya sarankan mengajar fungsi terlebih dahulu, sebelum for loop. Fungsi lebih mendasar, dan ini akan membantu menetapkan harapan bahwa kode harus ditulis dalam fungsi. Sementara saya memahami ketidaknyamanan ini, perilaku pelingkupan ini dapat diubah menjadi keuntungan pedagogis: "Faktanya, variabel global adalah ide yang buruk, terutama menggunakannya dalam loop, sehingga bahasa membuat Anda berusaha sekuat tenaga untuk menggunakannya."

Menambahkan fitur non-default ke REPL untuk ini sepertinya tidak masalah bagi saya.

@JeffBezanson , ingat bahwa banyak dari kita ingin menggunakan Julia sebagai pengganti Matlab dan sebagainya dalam kursus teknis seperti aljabar linier dan statistik. Ini bukan kursus pemrograman dan siswa sering tidak memiliki latar belakang pemrograman. Kami tidak pernah melakukan pemrograman terstruktur — hampir semuanya interaktif dengan cuplikan pendek dan variabel global.

Selain itu, alasan saya menggunakan bahasa dinamis adalah untuk beralih dengan lancar antara eksplorasi interaktif dan pemrograman yang lebih disiplin. Ketidakmampuan untuk menggunakan kode yang sama dalam konteks global dan fungsi adalah penghalang untuk tujuan itu, bahkan untuk seseorang yang terbiasa dengan konsep pelingkupan, dan itu jauh lebih buruk bagi siswa dari latar belakang non-CS.

ingat bahwa banyak dari kita ingin menggunakan Julia sebagai pengganti Matlab dan sebagainya dalam kursus teknis seperti aljabar linier dan statistik. Ini bukan kursus pemrograman dan siswa sering tidak memiliki latar belakang pemrograman. Kami tidak pernah melakukan pemrograman terstruktur — hampir semuanya interaktif dengan cuplikan pendek dan variabel global.

Banyak dari kita pengguna Julia memiliki latar belakang 0 CS (termasuk saya sendiri), tetapi bagi saya tampaknya sikap yang tepat ( terutama untuk siswa) adalah kemauan untuk belajar daripada menuntut hal-hal diubah menjadi lebih buruk untuk mengakomodasi kenaifan kita.

Sekarang, aku belum tentu menyiratkan bahwa perubahan tertentu ini akan menjadi lebih buruk karena saya hanya memiliki pemahaman terbatas tentang apa yang terjadi di sini, tetapi jika itu adalah hal ini merupakan komplikasi yang signifikan atau membuatnya berlebihan mudah untuk menulis sia-sia kode berkinerja buruk tampaknya tidak layak untuk membuat perubahan untuk memiliki contoh kuliah yang lebih baik. Anda tidak dapat mengubah hukum fisika sehingga contoh elektrostatika yang Anda tunjukkan kepada mahasiswa baru lebih dapat diterapkan dalam kehidupan nyata.

Jadi pertanyaan saya sebagai pengguna non-CS yang juga peduli dengan kinerja adalah bagaimana kemungkinan saya akan gagal jika ini dijadikan perilaku default. Apakah ini benar-benar jenis contoh yang kita lihat di sini yang merupakan masalah (yang sudah saya ketahui), atau apakah kita cenderung sering mengacaukannya dengan cara yang lebih halus?

Untuk apa nilainya, saya setuju bahwa memiliki kode yang berperilaku berbeda tergantung pada cakupan terlampirnya adalah fitur yang umumnya tidak diinginkan.

Membuat kode lebih sulit untuk ditulis secara interaktif, memaksa pemula menulis loop pertama mereka untuk memahami aturan pelingkupan yang tidak jelas, dan membuat kode yang ditempel dari fungsi tidak berfungsi dalam cakupan global tidak membantu pemrogram menulis kode cepat dalam fungsi. Itu hanya membuat lebih sulit untuk menggunakan Julia secara interaktif dan lebih sulit untuk pemula.

Tidak bisakah kita memilikinya sebagai fitur non-default dari REPL di 1.1?

Membuat opsi "buka saya" sebagai default tampaknya lebih bijaksana, terutama opsi yang ditujukan tepat untuk pengguna pemula. Jika ini adalah opsi non-default, maka justru orang-orang yang paling membutuhkannya adalah mereka yang tidak mengaktifkannya (dan tidak tahu itu ada).

Apa yang akan dilakukan mode REPL yang diusulkan terhadap skrip include ed? Akankah evaluasi pernyataan global tergantung pada apakah mode REPL diaktifkan? Jika demikian, IMO ini akan bertentangan dengan janji stabilitas 1.0.

Jika kami melakukan sesuatu seperti ini, sepertinya masuk akal bagi modul untuk menentukan cara kerjanya. Jadi Main akan menjadi modul "soft scope" sementara secara default modul lain akan menjadi modul "hard scope".

Saya tertarik untuk melihat apakah mungkin untuk menambal monyet REPL untuk menggunakan fungsi globalize @stevengj dan tampaknya itu tanpa terlalu banyak usaha (meskipun cukup rumit). Lihat intinya . Ini tidak berfungsi dengan Juno (atau apa pun yang memanggil Core.eval secara langsung).

Saya tidak akan merekomendasikan ini kepada orang-orang, tetapi ini cukup berguna bagi saya ketika melakukan analisis data yang cepat dan kotor. Saya sangat ingin melihat solusi (lebih baik dipikirkan) karena itu benar-benar cukup membingungkan bagi pembuat kode yang tidak berpengalaman dan sering enggan (yaitu, siswa saya) ketika Anda tidak dapat menyalin dan menempelkan kode dari suatu fungsi ke REPL untuk dilihat apa yang dilakukannya dan sebaliknya.

julia> a = 0                                                                
0                                                                           

julia> for i = 1:10                                                         
         a += i                                                             
       end                                                                  
ERROR: UndefVarError: a not defined                                         
Stacktrace:                                                                 
 [1] top-level scope at .\REPL[2]:2 [inlined]                               
 [2] top-level scope at .\none:0                                            

julia> using SoftGlobalScope                                                
[ Info: Precompiling SoftGlobalScope [363c7d7e-a618-11e8-01c4-4f22c151e122] 

julia> for i = 1:10                                                         
         a += i                                                             
       end                                                                  

julia> a                                                                    
55                                                                          

(BTW: di atas adalah tentang pengujian sebanyak yang telah terjadi!)

Apa yang akan dilakukan mode REPL yang diusulkan terhadap skrip yang disertakan?

Tidak. Pada dasarnya, usulannya adalah bahwa ini hanya untuk kode yang dimasukkan pada prompt interaktif. Segera setelah Anda mulai memasukkan sesuatu ke dalam file, Anda perlu mempelajari aturan "ruang lingkup keras". Mudah-mudahan, ketika Anda mulai memasukkan kode ke dalam file, Anda harus mulai menggunakan fungsi.

Tidak ideal jika ada aturan pelingkupan yang lebih pemilih untuk kode global dalam file daripada di Prompt. Tapi saya pikir #19324 dikombinasikan dengan janji stabilitas Julia 1.0 membuat kita tidak punya pilihan ideal.

@stevengj :

@JeffBezanson , ingat bahwa banyak dari kita ingin menggunakan Julia sebagai pengganti Matlab dan sebagainya dalam kursus teknis seperti aljabar linier dan statistik. Ini bukan kursus pemrograman dan siswa sering tidak memiliki latar belakang pemrograman. Kami tidak pernah melakukan pemrograman terstruktur — hampir semuanya interaktif dengan cuplikan pendek dan variabel global.

Setelah mengajar kursus menggunakan Julia kepada siswa dengan paparan sebelumnya ke Matlab/R/..., saya bersimpati dengan keprihatinan ini. Tetapi pada saat yang sama, saya tidak berpikir bahwa menggunakan Julia hanya sebagai pengganti Matlab dll adalah pendekatan yang layak: seperti yang ditunjukkan berkali-kali oleh pertanyaan tentang Wacana dan StackOverflow, ini dapat menyebabkan jebakan kinerja yang sulit untuk diperbaiki dan dipahami, mungkin memerlukan biaya yang lebih besar daripada berinvestasi dalam memahami bagaimana Julia berbeda dari bahasa lain ini (lih posting dengan topik "Saya menerjemahkan kode ini dari Matlab dan ini 10x lebih lambat").

Saya pikir masalah utamanya adalah kegagalan diam - sendiri mudah dipahami dan diperbaiki. Saya akan menyarankan untuk mempertahankan perilaku baru, tetapi memberikan peringatan di Main (secara default; itu mungkin untuk menonaktifkannya).

Bagi saya, masalah yang lebih besar adalah inkonsistensi yang dirasakan. Artinya, saya baik-baik saja dengan Julia melakukan hal-hal yang berbeda, tetapi:

  • Mengapa kode yang ditempelkan dari suatu fungsi tidak berfungsi di REPL?
  • Tidak ada bahasa lain yang pernah saya gunakan yang memiliki perilaku ini, dan itu adalah penghalang lain untuk adopsi
  • Mengapa blok for berperilaku berbeda dari blok begin dan if ? ( if Saya agak mengerti, tetapi sebuah blok adalah [seharusnya] sebuah blok.).

Mengenai peluru 2, saya pikir ini adalah masalah yang lebih besar daripada yang mungkin bisa kita pahami yang telah menggunakan Julia (dan berkomitmen pada bahasa). Saya dapat memberi tahu Anda bahwa saya saat ini 0 untuk 7 dalam meyakinkan grup saya untuk menulis kode di Julia; dua di antaranya adalah karena masalah loop for yang tidak dapat saya jelaskan karena saya belum pernah mengalaminya sebelumnya. Sisanya saya kira kita dapat menjelaskan kurangnya karisma saya.

Preferensi saya adalah memastikan bahwa kode yang ditempelkan dari suatu fungsi ke dalam REPL berperilaku identik dengan fungsi tersebut, dan bahwa loop for melakukan hal yang diharapkan saat menggunakannya untuk menganalisis data secara interaktif; yaitu, secara khusus, bahwa mereka mengubah variabel eksternal / global ketika diarahkan tanpa kata kunci khusus.

Saya tidak berpikir bahwa menggunakan Julia hanya sebagai pengganti Matlab dll adalah pendekatan yang layak: seperti yang ditunjukkan berkali-kali oleh pertanyaan tentang Wacana dan StackOverflow, ini dapat menyebabkan jebakan kinerja yang sulit untuk diperbaiki dan dipahami, mungkin memerlukan biaya yang lebih besar daripada berinvestasi dalam memahami bagaimana Julia berbeda dari bahasa lain ini.

Maaf, tapi argumen ini konyol bagi saya. Saya tidak berbicara tentang kelas di mana saya mengajar pemrograman. Ada tempat untuk perhitungan interaktif sederhana, dan di kelas non-CS biasanya diperkenalkan ke bahasa pemrograman sebagai "kalkulator yang dimuliakan" untuk memulai. Mengajar komputasi kinerja di Julia adalah proses yang sama sekali berbeda — tetapi tidak ada salahnya jika mereka sudah menggunakan Julia sebagai "kalkulator" mereka.

Jika Anda mulai dengan memperkenalkan Matlab kepada siswa sebagai "kalkulator" mereka, akan jauh lebih sulit untuk melakukan transisi ke pemrograman "nyata", karena insting pertama mereka adalah melakukan sebanyak mungkin dengan Matlab sebelum melompat ke kapal, pada titik itulah kebiasaan buruk mereka sudah mendarah daging dan mereka enggan untuk belajar bahasa baru. Sebaliknya, jika Anda memulai dengan Julia sebagai kalkulator Anda yang dimuliakan, ketika tiba saatnya untuk melakukan pemrograman yang lebih serius, Anda memiliki lebih banyak pilihan yang tersedia. Anda tidak perlu melatih mereka untuk menjejalkan semuanya ke dalam operasi "vektor" atau memaksa mereka melakukan hal-hal buruk sebelum mereka melakukannya dengan benar.

Apakah Anda mengatakan saya tidak boleh menggunakan Julia dalam kursus aljabar linier saya ? Atau bahwa saya hanya boleh menggunakannya jika saya siap untuk mengajar ilmu komputer serta aljabar linier?

Saya setuju dengan @stevenngj baik pada masalahnya (mengajar kepada non programmer menjadi jauh lebih sulit) dan pada solusinya (membuat semuanya berfungsi di REPL dan berbagai IDE). Menyertakan skrip masih akan memiliki aturan pelingkupan Julia 1.0 tetapi itu tidak terlalu menjadi perhatian, kita hanya harus berhati-hati untuk memiliki kelas "kita dapat menempatkan loop for kita dalam suatu fungsi dan kemudian memanggil fungsi" sebelum kelas "kita dapat menempatkan loop for kami dalam file dan sertakan kelas file".

Ini terdengar seperti kompromi yang baik karena debugging interaktif di REPL tidak menjadi lebih menyakitkan daripada yang seharusnya (atau lebih membingungkan bagi pengguna baru), sementara kode normal dalam skrip harus mengikuti aturan pelingkupan yang ketat dan aman dari bug yang menimpa beberapa variabel secara tidak sengaja.

Apakah Anda mengatakan saya tidak boleh menggunakan Julia dalam kursus aljabar linier saya? Atau bahwa saya hanya boleh menggunakannya jika saya siap untuk mengajar ilmu komputer serta aljabar linier?

Anda mungkin salah memahami apa yang saya katakan (atau saya tidak mengungkapkannya dengan jelas). Saya berbicara tentang kursus yang menggunakan Julia untuk mengajarkan sesuatu yang spesifik domain (misalnya saya mengajar metode numerik untuk mahasiswa pascasarjana ekonomi), bukan kursus CS (yang saya tidak punya pengalaman).

Poin yang saya coba sampaikan adalah masuk akal untuk mengharapkan tingkat perbedaan tertentu antara Julia dan bahasa X (yang mungkin Matlab); sebaliknya, mengabaikan ini dapat (dan memang) menyebabkan masalah.

Secara pribadi, ketika belajar bahasa baru, saya lebih suka menghadapi masalah ini sejak dini; juga, saya pikir kesederhanaan dan konsistensi semantik bahasa lebih penting daripada kesamaan dengan bahasa lain dalam jangka panjang. Tetapi saya mengenali preferensi ini sebagai subjektif, dan orang yang masuk akal dapat memiliki preferensi yang berbeda.

Saya telah membuat paket (tidak terdaftar) https://github.com/stevengj/SoftGlobalScope.jl

Jika ini tampaknya masuk akal, saya dapat melanjutkan dan mendaftarkan paket dan kemudian menggunakannya secara default di IJulia (dan mungkin mengirimkan PR ke Juno dan sebagainya).

Poin yang saya coba sampaikan adalah masuk akal untuk mengharapkan tingkat perbedaan tertentu antara Julia dan bahasa X (yang mungkin Matlab)

Jelas sekali. Ketika saya mengatakan "gunakan Julia alih-alih Matlab", saya tidak bermaksud mengajari mereka sintaks Matlab di Julia, saya juga tidak secara khusus menargetkan mantan pengguna Matlab.

Saya lebih suka menghadapi masalah ini sejak dini

Ini bukan tentang perbedaan dari Matlab saja. Saya lebih suka tidak berbicara tentang lingkup global vs lokal dan kegunaan kata kunci global untuk analisis statis saat pertama kali saya menulis loop di depan siswa non-CS, atau pertama kali mereka menempelkan kode dari a fungsi ke dalam REPL untuk mencobanya secara interaktif. Saya lebih suka fokus pada matematika yang saya coba gunakan untuk mengekspresikan loop.

Tidak ada seorang pun di sini yang memperdebatkan ruang lingkup interaktif lunak hanya karena itulah yang diharapkan pengguna Matlab. penyimpangan panjang global saat kita bekerja secara interaktif.)

Satu perbaikan lain yang tidak disebutkan di sini adalah dengan berhenti membuat 'untuk' mendefinisikan blok-lingkup (hanya berfungsi dan biarkan akan membuat ruang lingkup baru)

@vtjnash , saya lebih suka memfokuskan diskusi ini pada hal-hal yang dapat kita lakukan sebelum Julia 2.0. Saya setuju bahwa memiliki mode interaktif yang berperilaku berbeda hanyalah sementara, dan kita harus secara serius mempertimbangkan untuk mengubah aturan pelingkupan dalam beberapa tahun.

Poin bagus, ini juga membutuhkan import Future.scope

(Saya pikir modul/namespace/efek perilaku ini sudah dicadangkan/ada)

Sebagai pengingat di sini, perubahannya adalah untuk memastikan bahwa kode berperilaku sama di semua lingkungan lingkup global, terlepas dari apa pun yang sebelumnya telah dievaluasi dalam modul itu. Sebelum perubahan ini, Anda bisa mendapatkan jawaban yang sama sekali berbeda (dihasilkan dari penetapan ruang lingkup yang berbeda) hanya dengan menjalankan kode yang sama dua kali atau dengan memindahkannya ke dalam file.

Sebelum perubahan ini, Anda bisa mendapatkan jawaban yang sama sekali berbeda (dihasilkan dari penetapan ruang lingkup yang berbeda) hanya dengan menjalankan kode yang sama dua kali atau dengan memindahkannya ke dalam file.

Jumlah keluhan yang saya lihat tentang itu dalam praktik (nol) pasti akan dikerdilkan oleh jumlah keluhan dan kebingungan yang akan Anda lihat (dan sudah melihat) tentang perilaku saat ini.

Sebelum perubahan ini, Anda bisa mendapatkan jawaban yang sama sekali berbeda (dihasilkan dari penetapan ruang lingkup yang berbeda) hanya dengan menjalankan kode yang sama dua kali

Apakah maksud Anda bahwa dalam kode di bawah ini, a berubah antara loop for pertama dan kedua? Dalam pikiran saya, itu adalah perilaku yang diharapkan, bukan bug.

a = 0
for i = 1:5
  a += 1
end

for i = 1:5
  a += 1
end

Apa yang akan dilakukan mode REPL yang diusulkan terhadap skrip yang disertakan?

@mauro3 @stevenngj Saya kira menambahkan fungsi (katakanlah, exec("path/to/script.jl") ) dapat dilakukan hanya dengan versi minor bump? Kami juga dapat memperingatkan exec 'ing file lain dari skrip exec 'ed dan kemudian menaruh beberapa pesan pedagogis di sana untuk mendorong mereka untuk menggunakan include .

Beberapa pemikiran yang saya tulis tadi malam ketika mencoba untuk membungkus kepala saya di sekitar masalah ini (lagi-lagi) untuk mencoba mencari tahu tindakan terbaik apa yang mungkin dilakukan. Tidak ada kesimpulan, tapi saya pikir ini menjelaskan masalahnya dengan cukup jelas. Setelah memikirkan masalah ini selama beberapa tahun, saya tidak berpikir ada "solusi ideal"—ini mungkin salah satu masalah di mana hanya ada pilihan suboptimal.


Orang-orang secara naif melihat lingkup global sebagai jenis yang lucu yang melampirkan lingkup lokal. Inilah sebabnya mengapa cakupan global bekerja seperti yang mereka lakukan di Julia 0.6 dan sebelumnya:

  • Jika lingkup lokal luar membuat variabel lokal dan lingkup lokal dalam menetapkannya, maka penugasan itu memperbarui variabel lokal luar.
  • Jika lingkup global luar membuat variabel global dan lingkup lokal dalam menetapkannya, maka penugasan itu sebelumnya memperbarui variabel global luar.

Perbedaan utama, bagaimanapun, adalah:

  • Apakah ada variabel lokal luar, menurut desain, tidak bergantung pada urutan penampilan atau eksekusi ekspresi dalam lingkup lokal luar.
  • Apakah variabel global ada, bagaimanapun, tidak dapat terlepas dari urutan, karena seseorang mengevaluasi ekspresi dalam lingkup global, satu per satu.

Selain itu, karena cakupan global seringkali cukup panjang—tidak jarang tersebar di beberapa file—memiliki arti ekspresi bergantung pada ekspresi lain yang berjarak sewenang-wenang darinya, adalah efek "aksi seram di kejauhan", dan dengan demikian, sangat tidak diinginkan .


Pengamatan terakhir ini menunjukkan mengapa memiliki dua versi yang berbeda dari for loop pada lingkup global berperilaku berbeda adalah masalah:

# file1.jl
for i = 1:5
  a += 1
end
# file2.jl
a = 1



md5-f03fb9fa19e36e95f6b80b96bac9811e



```jl
# main.jl
include("file1.jl")
include("file2.jl")
include("file3.jl")

Perhatikan juga bahwa isi dari file1.jl dan file3.jl adalah identik dan kita dapat menyederhanakan contoh dengan memasukkan file yang sama dua kali dengan arti dan perilaku yang berbeda setiap kali.

Kasus bermasalah lainnya adalah sesi REPL yang berjalan lama. Coba contoh dari suatu tempat online? Gagal karena Anda kebetulan memiliki variabel global dengan nama yang sama yang digunakan contoh untuk variabel lokal dalam loop for atau konstruksi serupa. Jadi anggapan bahwa perilaku baru adalah satu-satunya yang dapat menyebabkan kebingungan pasti tidak akurat. Saya setuju bahwa perilaku baru adalah masalah kegunaan dalam REPL tetapi saya hanya ingin meredam percakapan dan menyajikan sisi lain dengan jelas di sini.

Saran kecil saya, itu tidak berurusan dengan masalah repl, tetapi akan berguna untuk tujuan didaktik ketika mengajar bahasa secara tidak interaktif, setidaknya: tentukan blok utama bernama "program", seperti yang dapat dilakukan di fortran (itu adalah sama seperti "let...end" di atas, hanya dengan notasi yang lebih natural):

tes program
...
akhir

seseorang bisa mengajarkan bahasa tanpa masuk ke rincian ruang lingkup dan hanya akhirnya membahas hal itu.

Kasus bermasalah lainnya adalah sesi REPL yang berjalan lama. Coba contoh dari suatu tempat online? Gagal karena Anda kebetulan memiliki variabel global dengan nama yang sama yang digunakan contoh untuk variabel lokal dalam loop for atau konstruksi serupa.

Berapa banyak keluhan milis dan masalah github yang telah diajukan tentang hal ini oleh pengguna yang kesal? Nol, menurut hitungan saya. Mengapa? Mungkin karena perilaku ini pada dasarnya tidak mengejutkan orang — jika Anda bekerja dalam lingkup global, Anda bergantung pada keadaan global.

Jadi anggapan bahwa perilaku baru adalah satu-satunya yang dapat menyebabkan kebingungan pasti tidak akurat.

Saya pikir ini adalah kesetaraan yang salah — ada perbedaan besar dalam tingkat kebingungan potensial di sini. Di Julia 0.6, saya dapat menjelaskan contoh Anda kepada seorang siswa dalam hitungan detik: "Oh, lihat loop ini bergantung pada a , yang Anda ubah di sini." Di Julia 1.0, sejujurnya saya khawatir tentang apa yang akan saya lakukan jika saya berada di tengah-tengah kuliah aljabar linier dan harus mengetikkan kata kunci global secara misterius di depan siswa yang belum pernah mendengar kata itu. "lingkup" dalam arti CS.

kita harus serius mempertimbangkan untuk mengubah aturan pelingkupan dalam beberapa tahun.

Sama sekali tidak. Apakah Anda serius ingin kembali ke dunia sebelum v0.2 (lihat #1571 dan #330) lingkup loop?

Kami sebenarnya tidak pernah sepenuhnya mendukung penyalinan dan penempelan kode dari fungsi baris demi baris ke dalam REPL. Jadi kita bisa melihat ini sebagai kesempatan untuk membuat itu berhasil. Secara khusus, ketika "berfungsi" untuk loop for , itu tidak berfungsi untuk fungsi dalam:

x = 0
f(y) = (x=y)

Di dalam sebuah fungsi, f akan mengubah x dari baris pertama. Dalam REPL tidak akan. Tapi dengan transformasi seperti itu di SoftGlobalScope.jl bisa berhasil. Tentu saja, kami mungkin tidak menginginkannya secara default karena menempelkan definisi fungsi yang berdiri sendiri tidak akan berfungsi. Hal pertama yang terlintas dalam pikiran adalah mode REPL untuk debugging fungsi baris demi baris.

Apakah Anda serius ingin kembali ke dunia pra-v0.2

Tidak, saya ingin kembali ke dunia 0.6. 😉

Saya kira saya lebih banyak menanggapi:

Satu perbaikan lain yang tidak disebutkan di sini adalah berhenti membuat 'untuk' mendefinisikan blok lingkup

Kami sebenarnya tidak pernah sepenuhnya mendukung penyalinan dan penempelan kode dari fungsi baris demi baris ke dalam REPL. Jadi kita bisa melihat ini sebagai kesempatan untuk membuat itu berhasil.

Saya sangat menghargai sentimen ini dan untuk kasus penggunaan saya ini akan sangat membantu. Dari sudut pandang saya, ini benar-benar tentang membuat REPL berguna mungkin daripada mengubah aturan pelingkupan bahasa secara langsung.

Yang mengatakan, semakin saya memikirkan masalah ini, semakin saya melihat pandangan yang bertentangan yang saya (secara pribadi) pegang tentang apa yang harus dilakukan REPL.

Untuk menjadi konkret, saya sangat suka jika REPL cocok dengan aturan pelingkupan badan fungsi; yaitu, variabel bersifat lokal daripada global dan Anda dapat menyalin dan menempelkan kode langsung dari suatu fungsi dan mengetahui bahwa itu akan berfungsi. Saya membayangkan implementasi naif akan menjadi sesuatu seperti pembungkus let-block (seperti yang telah disebutkan sebelumnya) dari formulir

julia> b = a + 1

berubah menjadi

let a = _vars[:a]::Float64 # extract the variables used from the backing store
    # Code from the REPL
    b = a + 1
    # Save assigned variables back to the backing store
   _vars[:b] = b
end

Dilakukan dengan benar (yaitu, oleh seseorang yang tahu apa yang mereka lakukan), saya membayangkan bahwa ini akan memiliki sejumlah manfaat dibandingkan REPL yang ada. 1. alur kerja sebelumnya dengan analisis/komputasi data interaktif hanya berfungsi. 2. jauh lebih sedikit posting di Wacana di mana respons dasarnya adalah "berhenti membandingkan dengan variabel global" - semuanya akan bersifat lokal dan semoga cepat! :) 3. salin dan tempel ke/dari badan fungsi berfungsi seperti yang diharapkan. 4. fungsi seperti workspace() tidak penting jika backing store adalah semacam Dict; bersihkan saja. 5. global menjadi eksplisit - hal-hal bersifat lokal kecuali Anda secara khusus memintanya menjadi global; ini adalah keuntungan besar dari sudut pandang saya, saya tidak suka membuat global secara implisit. Poin terakhir yang sangat kecil (dan saya ragu untuk menambahkan ini!), Ini akan cocok dengan perilaku Matlab sehingga memudahkan orang bertransisi - di Matlab REPL semua variabel tampaknya lokal kecuali secara eksplisit dijelaskan sebagai global.

Sampai beberapa jam yang lalu cerita ini terdengar hebat bagi saya. Tetapi setelah komentar Jeff tentang fungsi, saya berpikir tentang menempelkan definisi fungsi yang berdiri sendiri dan bagaimana pendekatan ini pada dasarnya akan mencegahnya karena definisi fungsi harus masuk dalam lingkup global (setidaknya, itu mungkin yang dimaksudkan); tapi kemudian bagaimana jika mereka dimaksudkan untuk pergi ke dalam lingkup lokal (fungsi inner)? Tidak ada informasi untuk membedakan kedua kemungkinan tersebut. Tampaknya dua mode REPL diperlukan, satu dengan lingkup lokal dan satu lingkup global. Di satu sisi itu bisa sangat membingungkan (bayangkan postingan Wacana...) tapi di sisi lain bisa sangat berguna. (Memiliki kedua mode REPL juga tidak akan terputus karena Anda baru saja memperkenalkan fungsionalitas baru :))

Pergi ke rumah singgah SoftGlobalScope.jl mungkin akan menjadi kompromi yang paling tidak membingungkan tetapi kekhawatiran saya adalah bahwa itu hanyalah seperangkat aturan yang perlu diingat (hal-hal mana yang berfungsi di REPL tetapi tidak dalam fungsi tubuh/lingkup global dan dan sebaliknya).

Maaf untuk posting yang panjang tapi saya pikir ini penting untuk kegunaan (dan itu membantu saya memikirkannya!).

Berapa banyak keluhan milis dan masalah github yang telah diajukan tentang hal ini oleh pengguna yang kesal? Nol, menurut hitungan saya. Mengapa? Mungkin karena perilaku ini pada dasarnya tidak mengejutkan orang — jika Anda bekerja dalam lingkup global, Anda bergantung pada keadaan global.

Hmm, apakah Anda benar-benar membuat studi sistematis tentang ini? Saya pasti telah melewatkannya. Namun demikian, ini tidak berarti bahwa perilaku ini bukan sumber bug atau hasil yang tidak diharapkan; hanya saja setelah pengguna mengetahuinya, itu dikenali sebagai perilaku yang benar dan dengan demikian tidak memicu masalah/keluhan.

Di Julia 1.0, sejujurnya saya khawatir tentang apa yang akan saya lakukan jika saya berada di tengah-tengah kuliah aljabar linier dan harus mengetikkan kata kunci global secara misterius

Saya bersimpati dengan masalah ini. Ketika saya mengajar beberapa pemrograman sederhana untuk membantu siswa yang diperlukan untuk suatu kursus, saya biasanya menyarankan agar mereka bolak-balik antara membungkus kode dalam fungsi, dan hanya mengomentari function dan end dan menjalankan sesuatu dalam lingkup global, sehingga mereka dapat memeriksa apa yang terjadi. Ini cukup menutupi kurangnya infrastruktur debugging pada waktu itu di Julia.

Tampaknya pendekatan ini tidak lagi layak. Tapi saya bertanya-tanya apakah itu benar-benar cara yang tepat untuk melakukannya, dan sementara itu berbagai hal telah meningkat pesat (#265 telah diperbaiki, Revise.jl dan baru-baru ini Rebugger.j telah meningkatkan alur kerja/debugging secara signifikan).

Tampaknya masalah ini tidak terlalu mengganggu pengguna berpengalaman, perhatian utama adalah kebingungan dalam pengaturan pedagogis. Saya sendiri belum bereksperimen dengan hal ini, tetapi saya ingin tahu apakah kita dapat mengadaptasi pendekatan kita untuk mengajar sebagai gantinya, misalnya memperkenalkan fungsi sebelum loop, menghindari loop dalam lingkup global. Bagaimanapun, ini adalah elemen gaya yang baik dan akan bermanfaat bagi siswa.

Hanya catatan kecil: sementara casing khusus lingkup global REPL, akan memungkinkan kode copy-paste ke dan dari fungsi, itu tidak akan memungkinkan copy-paste ke/dari lingkup global modul lain.

Saya ingin tahu apakah kita bisa mengadaptasi pendekatan kita untuk mengajar sebagai gantinya, misalnya memperkenalkan fungsi sebelum loop, menghindari loop dalam lingkup global.

Ini sama sekali tidak praktis di kelas yang tidak fokus pada pengajaran pemrograman. Saya mungkin juga tidak menggunakan Julia di kelas saya jika saya tidak dapat menggunakannya secara interaktif dan/atau harus menulis fungsi untuk semuanya terlebih dahulu.

(Dan itu bukan hanya pedagogis. Loop dalam lingkup global berguna untuk pekerjaan interaktif. Dan salah satu alasan utama orang menyukai bahasa dinamis untuk komputasi teknis adalah fasilitas mereka untuk eksplorasi interaktif. Tidak semua pengkodean berorientasi pada kinerja.)

Ada lusinan utas dan masalah selama bertahun-tahun di mana orang bingung atau mengeluh tentang perbedaan "ruang lingkup lunak/keras" yang lama, jadi mengklaim bahwa tidak ada yang pernah bingung atau mengeluh tentang perilaku lama hanyalah... tidak benar. Saya dapat menggali beberapa di antaranya, tetapi Anda ada di sekitar, @stevenngj , sehingga Anda dapat menggalinya dengan mudah dan saya sulit percaya bahwa Anda tidak memperhatikan atau tidak mengingat keluhan dan percakapan ini.

@StefanKarpinski , saya secara khusus merujuk pada orang-orang yang mengeluh bahwa loop global bergantung pada keadaan global. Saya tidak ingat siapa pun yang mengeluh bahwa ini adalah perilaku buruk, saya juga tidak dapat menemukan contohnya.

Saya setuju bahwa orang telah bingung tentang kapan dan di mana penugasan mendefinisikan variabel baru, tetapi biasanya ke arah lain - mereka ingin lingkup lokal bertindak lebih global (daripada sebaliknya), atau tidak memiliki perbedaan antara begin dan let . IIRC, keluhannya tidak pernah bahwa menetapkan variabel global dalam loop global memiliki efek samping yang mengejutkan dari memodifikasi global.

Seluruh masalah pelingkupan membingungkan bagi pengguna baru, dan akan terus demikian. Tetapi bagian yang membingungkan bukanlah kasus di mana menetapkan nama variabel global memengaruhi keadaan global. Perilaku saat ini membuat ini lebih buruk, bukan lebih baik.

@StefanKarpinski : Saya merasa bahwa sebelumnya, kebingungan dengan lingkup lunak/keras lebih bersifat teoretis (orang yang membaca manual) daripada praktis (orang mendapatkan hasil yang tidak terduga). Itu pasti bagaimana bagi saya dan apa, misalnya, hasil pencarian di sini mendukung ini; Saya menemukan satu contoh tandingan di sini .

Di sisi lain, perilaku baru ini tidak akan membingungkan orang saat membaca manual, tetapi saat menggunakan REPL. Bisa dibilang yang terakhir ini lebih buruk.

SoftGlobalScope.jl sekarang menjadi paket terdaftar. Niat saya untuk mengaktifkannya secara default (opt-out) untuk IJulia, setidaknya semester ini.

@ mauro3 , bahkan "contoh tandingan" Anda adalah tentang seseorang yang bingung dengan lingkup keras , bukan oleh lingkup lunak. Membuat lebih banyak cakupan "keras" di 0,7 pasti akan menciptakan lebih banyak kebingungan semacam ini.

Saya akan menunjukkan bahwa IJulia memiliki kemungkinan menarik untuk membuat variabel lokal do blok secara default. Yaitu jika Anda melakukan ini dalam satu blok maka itu berfungsi:

t = 0
for i = 1:n
    t += i
end
t

... dan t hanya terlihat dalam blok evaluasi ini. Jika Anda ingin terlihat di luar, Anda harus melakukan ini:

global t = 0
for i = 1:n
    global t += i
end
t

Saya juga telah mempertimbangkan pendekatan serupa untuk Julia di mana blok adalah file daripada modul. Dengan kata lain hanya melakukan t = 0 di lingkup atas membuat variabel yang file-local daripada global. Untuk mendeklarasikan variabel yang benar-benar global, Anda harus menulis global t = 0 yang kemudian akan terlihat di seluruh modul. Mungkin terlalu aneh, tapi itu sering terjadi pada saya selama bertahun-tahun.

IJulia memiliki kemungkinan menarik untuk membuat variabel lokal do blok secara default

@StefanKarpinski , saya pikir ini akan lebih membingungkan, dan akan bertentangan dengan bagaimana notebook biasanya digunakan. Adalah umum untuk variabel yang sama untuk digunakan/dimodifikasi dalam banyak sel, jadi memerlukan kata kunci global untuk semua variabel antar-sel adalah hal yang tidak menarik bagi saya — itu akan membutuhkan lebih banyak diskusi tentang konsep ruang lingkup daripada masalah dengan for loop yang telah kita diskusikan di sini.

Saya pikir selama kita semua setuju --- seperti yang kita lihat --- bahwa ini sebagian besar atau seluruhnya merupakan masalah interaksi, maka kita memiliki jalan ke depan. Jika kita membuat kasus khusus ini di REPL (seperti yang dilakukan untuk IJulia), satu-satunya kasus buruk adalah mengembangkan sesuatu di REPL dan kemudian memindahkannya ke kode skrip tingkat atas. Bisa dibilang itulah titik di mana Anda harus memperkenalkan fungsi, jadi saya rasa itu tidak terlalu buruk. Salin-tempel kode antara REPL dan badan fungsi akan berfungsi (kebanyakan), yang mungkin cukup baik.

Kemudian kita juga memiliki pilihan untuk membenarkan/mengklarifikasi perbedaan lebih lanjut dengan membuat variabel REPL entah bagaimana lokal ke REPL --- yaitu bukan variabel global normal, tidak tersedia sebagai Main.x . Ini sangat mirip dengan apa yang baru saja diusulkan oleh

Dari sudut pandang praktis, mendapatkan "perbaikan" ini di REPL bukanlah
hanya penting untuk pengguna pengajaran/non-programmer. Perilaku ini juga
membuat debugging interaktif melalui REPL (dengan menyalin-menempelkan bagian) sangat
tidak praktis. Mode debugging ini terkadang lebih disukai (bahkan untuk a
debugger yang baik dan) bahkan untuk pemrogram berpengalaman (dan sering kali salah satunya)
alasan untuk memilih bahasa yang dinamis). Tentu saja untuk yang berpengalaman
programmer, menjadi opsional seharusnya tidak menjadi masalah; Untuk pengguna pemula itu
akan lebih disukai default.

@StefanKarpinski
Sebagai programmer yang naif, saya tidak benar-benar melihat apa yang salah dalam melihat
lingkup global sebagai jenis yang lucu melampirkan lingkup lokal, terutama dalam dinamika
bahasa. Saya mengerti bahwa dari sudut pandang kompiler itu bukan
tentu benar (dalam Julia), tetapi ini adalah model yang bagus, mudah dan berguna
untuk programmer (naif). (Saya juga menduga itu mungkin benar-benar diterapkan seperti itu di
beberapa bahasa).
Julia juga tampaknya menyajikannya seperti itu kepada programmer:
Fungsi fungsi berikut akan memberikan kesalahan "tidak ditentukan", yang
itu tidak akan dilakukan jika a=1 diletakkan sebelum for loop.

tes fungsi()
untuk i = 1:10
a=a+i
akhir
a=1
@tunjukkan
akhir

yang, kecuali saya benar-benar salah paham, tampaknya bertentangan dengan "Apakah
variabel lokal luar ada, dengan desain, tidak tergantung pada urutan
penampilan atau eksekusi ekspresi dalam lingkup lokal luar".

Saya sangat setuju dengan menghindari "aksi seram di kejauhan", dan banyak lagi
lebih suka definisi eksplisit untuk menggunakan global di tumpukan fungsi/panggilan
level dan secara pribadi juga ingin memiliki sesuatu seperti memuat dari file di
lingkupnya sendiri, dan membutuhkan definisi eksplisit untuk menggunakan variabel global.
Pada level loop akan sedikit terlalu jauh bagi saya, karena
definisi/konteks biasanya cukup dekat.
Contoh 3 file agak dibuat-buat (dan gagal dengan yang diharapkan "tidak"
didefinisikan" kesalahan): Anda biasanya akan menempatkan definisi awal di tempat yang sama
mengajukan.
Ada bahaya menakutkan yang sebenarnya dalam hal ini (dan saya telah digigit olehnya
dalam bahasa lain) di dalamnya termasuk dijalankan dalam lingkup global, jadi Anda
secara tidak sengaja mendefinisikan variabel global yang dapat mengganggu
kode. Namun, harus menggunakan global dalam loop bukanlah solusi untuk
masalah ini.

wrt ke sesi REPL yang sudah berjalan lama:
Perilaku saat ini menggantikan mode kegagalan yang sangat langka dan mudah dikenali
untuk menjalankan contoh online di REPL (Anda melewatkan menyalin/menempelkan
definisi awal variabel sebelum loop, dan sudah memiliki
variabel yang sama didefinisikan secara global dari sesuatu sebelumnya) dengan tidak menjadi
dapat menjalankan contoh online dengan benar jika itu adalah bagian dari suatu fungsi
(tanpa menambahkan global di mana-mana), dan tidak menyelesaikan masalah jika itu
tidak (jika global sudah ada di kode online, Anda masih akan menggunakan
nilai yang salah dalam variabel global yang sudah ada)

Saya seharusnya mendengarkan ini lebih awal, tetapi setelah beberapa saat khawatir semuanya tampak baik-baik saja.

Kami sebenarnya tidak pernah sepenuhnya mendukung penyalinan dan penempelan kode dari fungsi baris demi baris ke dalam REPL...Hal pertama yang terlintas dalam pikiran adalah mode REPL untuk debugging fungsi baris demi baris.

Memang Rebugger (yang persis seperti itu) berfungsi dengan baik pada 1.0 hanya karena tidak memiliki penghentian cakupan 0.7, dan tidak pernah dapat dibuat untuk bekerja pada 0.6. Namun, saya senang dapat memverifikasi bahwa SoftGlobalScope.jl tampaknya tidak melanggarnya. Misalnya, jika Anda melangkah cukup dalam ke show([1,2,4]) Anda sampai di sini:

show_delim_array(io::IO, itr::Union{SimpleVector, AbstractArray}, op, delim, cl, delim_one) in Base at show.jl:649
  io = IOContext(Base.TTY(RawFD(0x0000000d) open, 0 bytes waiting))
  itr = [1, 2, 4]
  op = [
  delim = ,
  cl = ]
  delim_one = false
  i1 = 1
  l = 3
rebug> eval(softscope(Main, :(<strong i="10">@eval</strong> Base let (io, itr, op, delim, cl, delim_one, i1, l) = Main.Rebugger.getstored("bbf69398-aac5-11e8-1427-0158b103a88c")
       begin
           print(io, op)
           if !(show_circular(io, itr))
               recur_io = IOContext(io, :SHOWN_SET => itr)
               if !(haskey(io, :compact))
                   recur_io = IOContext(recur_io, :compact => true)
               end
               first = true
               i = i1
               if l >= i1
                   while true
                       if !(isassigned(itr, i))
                           print(io, undef_ref_str)
                       else
                           x = itr[i]
                           show(recur_io, x)
                       end
                       i += 1
                       if i > l
                           delim_one && (first && print(io, delim))
                           break
                       end
                       first = false
                       print(io, delim)
                       print(io, ' ')
                   end
               end
           end
           print(io, cl)
       end
       end)))
[1, 2, 4]

Jadi ini berfungsi dengan baik pada 1.0 (dengan atau tanpa softscope ). Pada 0,7, mengevaluasi ini (dengan atau tanpa softscope ) akan menghasilkan

┌ Warning: Deprecated syntax `implicit assignment to global variable `first``.
│ Use `global first` instead.
└ @ none:0
┌ Warning: Deprecated syntax `implicit assignment to global variable `first``.
│ Use `global first` instead.
└ @ none:0
[ERROR: invalid redefinition of constant first
Stacktrace:
 [1] top-level scope at ./REBUG:9 [inlined]
 [2] top-level scope at ./none:0
 [3] eval(::Module, ::Any) at ./boot.jl:319
 [4] top-level scope at none:0
 [5] eval at ./boot.jl:319 [inlined]
 [6] eval(::Expr) at ./client.jl:399
 [7] top-level scope at none:0

Jadi 0.7/1.0 jelas merupakan langkah maju, dan jika softscope membuat hal-hal tertentu lebih mudah tanpa merusak fungsi penting, itu bagus.

Perhatian terbesar, oleh karena itu, hanyalah bagaimana mencegat ini dengan tepat tanpa menahan paket lain (https://github.com/stevenngj/SoftGlobalScope.jl/issues/2).

@timholy , SoftScope tidak menyentuh argumen panggilan makro (karena tidak ada cara untuk mengetahui bagaimana makro akan menulis ulang), jadi :(<strong i="6">@eval</strong> ...) dilindungi.

tampaknya bertentangan dengan "Apakah
variabel lokal luar ada, dengan desain, tidak tergantung pada urutan
penampilan atau eksekusi ekspresi dalam lingkup lokal luar".

Variabel lokal (luar) a ada, tetapi belum ditetapkan. Jika loop mencoba untuk menetapkan ke a sebelum membacanya, tugas akan terlihat di luar juga.

Secara umum, membuat pengikatan variabel dan menetapkan nilai ke dalamnya adalah langkah terpisah.

Apa garis waktu ini? Tampaknya ini akan menjadi peningkatan besar untuk kegunaan pengguna. Dan pada saat "kritis" Julia dengan 1.0 keluar, tampaknya menguntungkan untuk memperbaiki ini secepatnya (dengan cara yang disarankan oleh Jeff di atas) dan menandai versi Julia baru atau versi REPL. (Maaf untuk komentar kursi berlengan ini, karena saya pasti tidak akan memperbaikinya!)

@JeffBezanson
Saya akan berargumen bahwa meskipun ini benar (untuk implementasi/kompiler), programmer julia yang naif tidak dapat melihat perilaku yang berbeda dari model konseptualnya yang lebih sederhana (variabel mulai ada pada saat itu didefinisikan). Sayangnya Anda benar, kode berikut tidak akan memberikan kesalahan, sementara itu akan memberikan kesalahan jika Anda meninggalkan a=2 di akhir
tes fungsi()
untuk i = 1:10
a=1
akhir
println(a)
a=2
akhir
Saya akan menjelaskan sayangnya: Saya dapat memahami perilaku (karena saya telah bekerja dengan bahasa yang dikompilasi sebelumnya) tetapi masih merasa membingungkan dan tidak terduga. Betapa buruknya bagi seseorang yang hanya memiliki pengalaman skrip atau baru dalam pemrograman. Juga, saya menemukan beberapa kode yang menunjukkan perilaku, saya tidak melihat aplikasi yang berguna (mungkin Anda dapat membantu saya di sana)

Di REPL:
Saya semakin yakin bahwa mengubah pelingkupan kembali ke "normal" setidaknya di REPL (tidak perlu menambahkan global dalam loop) adalah prioritas tinggi: Saya sedang menguji beberapa hal di REPL hari ini dan (lagi) digigit olehnya, membutuhkan waktu untuk menyadarinya. Mengingat bahwa saya sudah mengikuti Julia beberapa waktu, sangat menyukainya, saya bahkan mengikuti utas ini tentang masalah ini, saya bahkan akan menyebutnya sebagai showstopper: Seorang pemula (untuk Julia) yang menguji bahasa kemungkinan besar tidak akan menemukan keluar dari masalah dan menyerah saja.

@jeffbezanson dan saya sama-sama sedang dalam liburan yang telah lama ditunggu-tunggu (saya seharusnya tidak membaca ini). Kita bisa mencari tahu apa yang harus dilakukan dalam seminggu atau lebih.

@derijkp , sementara umpan baliknya dihargai, aturan pelingkupan tidak untuk debat atau revisi yang lebih luas. Satu-satunya hal di atas meja adalah eval interaktif casing khusus. Paket SoftGlobalScope sudah merupakan implementasi eksperimental yang sangat baik dan mungkin hanya masalah membuat bagian Basis itu dan menggunakannya dalam REPL.

@derijkp Jawaban singkatnya adalah saya pikir lebih mudah jika ruang lingkup variabel sesuai dengan beberapa konstruksi blok (misalnya badan fungsi atau loop). Dengan saran Anda, ruang lingkup variabel akan menjadi beberapa bagian dari blok, yang menurut saya pada akhirnya lebih kompleks dan membingungkan --- Anda tidak dapat menunjuk ke bentuk sintaksis yang sesuai dengan ruang lingkup variabel.

Ya, saya percaya ini adalah ketidakcocokan untuk intuisi beberapa orang. Tetapi Anda hanya dapat mengoptimalkan selama sepuluh menit pertama menggunakan bahasa hingga titik tertentu. Pertanyaan sebenarnya adalah, seberapa sulit untuk mengajar/mempelajari cara kerjanya, dan desain mana yang akan menghemat waktu dalam jangka panjang (dengan membuat bahasa lebih sederhana, mempermudah pengembangan perkakas, dll.)?

(sesuai dengan banyak hal di atas tentang memodifikasi perilaku REPL)
Saya ingin melihat REPL dengan cara yang tidak mengarah ke pertanyaan stackoverflow ini
dan lebih cepat akan lebih baik karena banyak mata baru melihat Julia

Saya setuju ... Dan juga berpikir bahwa aturan pelingkupan tidak harus selalu berubah, hanya semua antarmuka interaktif (yaitu kontrol REPL, Jupyter, dan Juno masuk)

Ini bukan hanya tentang pemula yang mempelajari aturan baru. Jika Anda tidak dapat menyalin dan menempelkan fragmen kode ke REPL, jupyter dll dan juga ke dalam fungsi, ini juga merupakan gangguan besar bagi pemrogram perantara.

Tentu saja, saya juga setuju dengan poster lain ... dengan pemula mereka akan mengambil fragmen kode yang mereka lihat di dalam fungsi, menyalin I ke skrip, dan benar-benar bingung ketika tidak memiliki perilaku yang sama ketika disalin di dalam suatu fungsi , di juno, repl, dan jupyter. Akan ada 100 pertanyaan pertukaran tumpukan yang bermuara pada masalah yang sama. Pemrogram menengah akan memiliki segala macam solusi buatan sendiri dengan membungkus blok let , dll yang akan membingungkan banyak hal lebih lanjut

Akan ada 100 pertanyaan pertukaran tumpukan yang bermuara pada masalah yang sama. Pemrogram menengah akan memiliki segala macam solusi buatan sendiri dengan membungkus blok let , dll yang akan membingungkan banyak hal lebih lanjut

Mungkin, tetapi pada tahap ini ini bersifat hipotetis (juga OP dari pertanyaan yang ditautkan adalah menanyakan tentang alasan aturan pelingkupan, sebagai lawan dari kebingungan tentang hal itu).

Juga, sementara saya menghormati pengalaman mengajar setiap orang yang memiliki keprihatinan tentang hal ini, apakah ini ternyata menjadi masalah besar di kelas adalah sesuatu yang waktu akan memberitahu.

si penanya tampaknya bingung karenanya: "Saya ingin tahu apakah ini intuitif untuk pengguna julia pemula. Itu tidak intuitif bagi saya ..."

si penanya tampaknya bingung karenanya:

Belum lagi ini adalah seseorang yang cukup tahu tentang bahasa pemrograman untuk memahami nuansa ruang lingkup. Bagaimana dengan semua pengguna tipe matlab yang sama sekali tidak mengetahui topik ini..., dan mungkin tidak akan pernah menginvestasikan cukup waktu untuk memahami nuansanya.

Mungkin, tetapi pada tahap ini ini bersifat hipotetis

Saya sudah menjawab beberapa pertanyaan yang terkait dengan ini di stackoverflow, sebagian besar oleh pengguna baru, dan bahkan lebih banyak lagi di kehidupan nyata (yang terakhir baru kemarin, dari pengguna Matlab, yang melihat ini sebagai larangan).

Akan ada 100 pertanyaan pertukaran tumpukan yang bermuara pada masalah yang sama.

Di "waktu luang" saya, saya telah menambahkan tag scope , scoping , dan global-variables ke pertanyaan SE. Saya hanya berhenti karena kurangnya waktu, bukan karena tidak ada lagi.

Kesimpulan setelah banyak diskusi termasuk triase: kita akan memasukkan sesuatu di sepanjang baris SoftGlobalScope di Base dan menggunakannya dalam REPL dan semua konteks evaluasi interaktif lainnya. @JeffBezanson telah menunjukkan bahwa cara ini diimplementasikan sebenarnya pada dasarnya sama dengan bagaimana soft scope diimplementasikan sebelumnya, jadi sampai batas tertentu kita mencapai lingkaran penuh. Perbedaannya adalah sekarang tidak ada perilaku lingkup dalam modul atau skrip, hanya dalam konteks seperti REPL. Saya juga berpikir bahwa _explaining_ soft scope sebagai sumber penulisan ulang lebih jelas daripada mencoba membedakan antara hard dan soft scope (yang tidak pernah kami jelaskan bagaimana Jeff menjelaskannya, mungkin saya tunjukkan).

Kedua pernyataan ini sedikit membingungkan saya karena tampaknya agak kontradiktif:

dan menggunakannya dalam REPL dan semua konteks evaluasi interaktif lainnya

tidak ada perilaku lingkup dalam skrip [...], hanya dalam konteks seperti REPL.

Apakah ini berarti bahwa modul Main terkadang memiliki lingkup lunak (katakanlah pada prompt REPL) dan terkadang lingkup keras (katakanlah kapan julia -L script.jl )? Tidakkah masuk akal untuk mengatakan bahwa Main selalu memiliki soft scope? Dan sebuah modul dapat ikut serta dalam soft scope dengan using SoftGlobalScope ?

(Saya kira) aturan pelingkupan tidak dapat diubah dalam skrip karena akan menjadi tidak kompatibel, yaitu akan melanggar janji bahwa kode apa pun yang ditulis untuk 1.0 akan berjalan pada versi 1.* apa pun. Anda benar bahwa masalah yang sama dengan pelingkupan untuk REPL juga berlaku untuk skrip (pengguna yang naif benar-benar bingung mengapa kodenya tidak berfungsi dengan benar ketika dijalankan sebagai skrip). Cara untuk memecahkan/mengurangi masalah ini tanpa ketidaksesuaian utama adalah dengan menambahkan opsi ke julia cmdline untuk menggunakan softscope (atau alternatif), misalnya julia -f programfile, dan perlihatkan opsi ini dalam deskripsi/tutorial apa pun yang mungkin dilakukan oleh seorang pemula menemukan.
Saya juga melihat alternatif potensial untuk softscope yang mungkin memiliki beberapa keuntungan (meskipun saya mungkin mengabaikan kerugian): Bagaimana jika file (skrip yang disebut) akan selalu memperkenalkan ruang lingkup lokalnya sendiri: aturan pelingkupan akan sepenuhnya konsisten dengan yang ada di fungsi, dan dengan harapan banyak pengguna. Itu juga akan menghapus banyak kewajiban kinerja dengan pengguna baru:
Tidak ada lagi global yang tidak dibutuhkan (global harus didefinisikan secara eksplisit), dan kode dapat dikompilasi
(Berapa kali Anda harus mengatakan untuk meletakkan semuanya dalam suatu fungsi, dan untuk menghindari penggunaan global?)

Saya baru saja menemukan ini dan benar-benar terkejut, jujur, belum pernah melihatnya sebelumnya dalam bahasa lain. Saya berencana memperkenalkan kursus Julia opsional untuk pengguna R tingkat lanjut di uni saya akhir tahun ini setelah semuanya beres, dan siswa saya akan mencapai ini pada hari 0 ketika mereka mulai mengetik secara acak di REPL. Dan fakta bahwa for loop berperilaku berbeda dari pernyataan if hanya menggosok garam di luka, betapapun logisnya ini dalam hal pelingkupan. Lingkup di dalam fungsi cukup sulit untuk dipahami oleh siswa biologi, gagasan harus menjelaskan _meskipun dirasakan_ inkonsistensi mencolok di dalamnya dalam REPL / dalam skrip / dalam for loop / dalam pernyataan if (karena itulah yang kita bicarakan tentang di sini) dengan cara yang berbeda dari setiap bahasa lain di bumi membuat saya sangat sedih.

Saya memahami janji kompatibilitas mundur yang dibuat, tetapi memiliki pekerjaan ini _seperti yang diharapkan oleh setiap orang non-cs di planet ini (dan sebagian besar orang cs yang saya curigai)_ sepertinya perbaikan bug daripada masalah kompatibilitas mundur - kami tidak mengatakan bahwa setiap bug akan direproduksi selamanya kan? Perbaikan REPL jelas penting, jadi sangat bagus Anda mengusulkan ini, tetapi kemudian harus menjelaskan bahwa Anda tidak dapat menyalin skrip ke REPL dan mengharapkan perilaku yang sama tampak seburuk atau lebih buruk daripada masalah aslinya.

Tolong, tolong, tolong pikirkan tentang memperlakukan ini sebagai perbaikan bug dan mendorongnya keluar dengan skrip serta REPL - bahkan jika ada sakelar untuk beralih ke perilaku "lama" - dan melakukannya sesegera mungkin di 1.0.1.

Seorang kolega yang saya coba pelajari julia juga baru saja mengalami ini. Harus menjelaskan seluruh variabel global vs. lokal pada langkah pertama tidak ideal ...

Saya tidak berpikir memperlakukan ini sebagai "perbaikan bug" ada di kartu, karena itu akan merusak kontrak stabilitas 1.0. Namun, tampaknya masuk akal bagi saya untuk menggunakan softscope untuk skrip yang dijalankan dengan julia -i (yaitu mode "interaktif").

(Artinya, akan ada flag --softscope={yes|no} dan akan default ke nilai isinteractive .)

Kita harus mempertimbangkan pilihan mode skrip.

Dalam hal ini, tidak gila bagi saya untuk default ke --softscope=yes untuk "skrip" apa pun, yaitu untuk julia foo.jl , dan hanya mengaktifkan aturan pelingkupan "keras" untuk modul dan include (pada titik mana Anda harus benar-benar memasukkan sebagian besar kode ke dalam fungsi).

Dalam hal ini, tidak gila bagi saya untuk default ke --softscope=yes untuk "skrip" apa pun,

Itu. Yang lain yang harus dipertimbangkan dengan serius adalah Juno. Ingat bahwa orang akan <shift-enter> melalui kode mereka untuk melakukan pengembangan interaktif (terutama ketika bekerja dengan tes regresi) dan kemudian berharap dapat menjalankan file yang sama. Haruskah penting jika kodenya ada dalam @testset atau tidak (yang menurut saya mungkin memperkenalkan ruang lingkup)? Akan sangat membingungkan bagi pengguna jika teks yang sama berubah saat dalam @testset vs. tidak saat menggunakan integrasi Atom, dan tidak konsisten dengan melakukan ] test juga.

Bagi saya kedengarannya seperti solusi terbaik adalah bahwa hard-scope hanyalah hal yang ikut serta, di mana jika setiap penggunaan lain (termasuk include dalam skrip) menggunakan softscope kecuali jika Anda mengatakan sebaliknya .

berbeda dari setiap bahasa lain di bumi

Apakah Anda ingin menulis var x = 0 untuk memperkenalkan setiap variabel? Itu juga akan "memperbaiki" ini, dan lebih seperti bahasa lain.

kami tidak mengatakan bahwa setiap bug akan direproduksi selamanya, bukan?

Itu bukan cara kerjanya. Anda tidak bisa mendapatkan perubahan apa pun pada bahasa yang Anda inginkan hanya dengan menyebut perilaku saat ini sebagai bug.

Saya benar-benar tidak berpikir harus ada opsi baris perintah untuk ini. Kemudian setiap bagian kode julia harus disertai dengan komentar atau sesuatu yang memberi tahu Anda opsi mana yang akan digunakan. Beberapa jenis parser directive dalam file sumber akan sedikit lebih baik, tetapi lebih baik lagi memiliki aturan tetap. Misalnya, ruang lingkup keras di dalam modul hanya mungkin masuk akal.

Izinkan saya mencoba lagi untuk memberikan penjelasan tentang ini yang mungkin berguna untuk menghindari mania, histeria, dan pembantaian yang dilihat orang di kelas:

"
Julia memiliki dua jenis variabel: lokal dan global. Variabel yang Anda perkenalkan di REPL atau di tingkat atas, di luar apa pun, bersifat global. Variabel yang diperkenalkan di dalam fungsi dan loop bersifat lokal. Memperbarui variabel global dalam suatu program umumnya buruk, jadi jika Anda berada di dalam loop atau fungsi dan ingin memperbarui global, Anda harus eksplisit tentang hal itu dengan menulis deklarasi global lagi.
"

Mungkin itu bisa diperbaiki; saran diterima. Saya tahu, Anda lebih suka tidak membutuhkan penjelasan apa pun. Saya mengerti. Tapi sepertinya tidak terlalu buruk bagiku.

Saya benar-benar tidak berpikir harus ada opsi baris perintah untuk ini. Kemudian setiap bagian kode julia harus disertai dengan komentar atau sesuatu yang memberi tahu Anda opsi mana yang akan digunakan. Semacam arahan parser dalam file sumber akan sedikit lebih baik, tetapi lebih baik lagi memiliki aturan tetap

Saya setuju. Kedengarannya seperti sakit kepala pengajaran dan komunikasi bagi saya.

Misalnya, ruang lingkup keras di dalam modul hanya mungkin masuk akal.

Supaya saya mengerti: jika saya memiliki skrip pendek (bukan dalam modul!) Dalam file .jl yang telah saya salin dari notebook IJulia, maka jika saya menjalankan kode itu di REPL secara langsung atau shift- masukkan di Juno, maka itu akan berperilaku secara konsisten sebagai soft-scope ... tetapi jika saya menyalinnya alih-alih blok module maka itu akan meneriaki saya tentang global? Tetapi jika saya menyalin kode itu di dalam fungsi di dalam modul, maka itu akan berfungsi.

Jika demikian, itu sangat masuk akal, sangat dapat diajar dan koheren. Skrip tingkat atas adalah antarmuka interaktif untuk eksplorasi, dll. tetapi Anda tidak akan pernah memasukkan kode semacam itu ke dalam modul. Modul adalah sesuatu yang harus Anda isi dengan fungsi yang sangat hati-hati dianggap global. Akan mudah untuk memberi tahu orang-orang tentang aturan itu.

Apakah Anda ingin menulis var x = 0 untuk memperkenalkan setiap variabel? Itu juga akan "memperbaiki" ini, dan lebih seperti bahasa lain.

Tidak, saya lebih suka tidak! Tapi bahasa scripting yang memiliki REPL jarang melakukan itu (misalnya ruby, python, R, ...), mereka berperilaku seperti Julia v0.6.

Julia memiliki dua jenis variabel: lokal dan global. Variabel yang Anda perkenalkan di REPL atau di tingkat atas, di luar apa pun, bersifat global. Variabel yang diperkenalkan di dalam fungsi dan loop bersifat lokal. Memperbarui variabel global dalam suatu program umumnya buruk, jadi jika Anda berada di dalam loop atau fungsi dan ingin memperbarui global, Anda harus eksplisit tentang hal itu dengan menulis deklarasi global lagi.

Saya benar-benar mengerti apa yang Anda katakan di sini, dan saya tidak akan (menyentuh kayu!) membuat kesalahan ini lagi. Tapi seluruh masalah yang saya khawatirkan bukan saya. Saya merasa relatif mudah untuk memperkenalkan ruang lingkup (tanpa menyebutkannya secara langsung) ketika saya menjelaskan bahwa variabel di dalam fungsi tidak dapat melihat yang di luar dan sebaliknya (meskipun itu lebih merupakan aspirasi daripada fakta di R!), karena fungsi sendiri sudah merupakan konsep yang _relatif_ canggih. Tapi ini terjadi jauh lebih awal dalam kurva pembelajaran di sini di mana kita tidak ingin sesuatu yang serumit cakupannya menimpa orang...

Perhatikan juga itu bukan hanya "_variabel yang Anda perkenalkan di REPL atau di tingkat atas, di luar apa pun, adalah global_" dan "_variabel yang diperkenalkan di dalam fungsi dan loop adalah lokal_", itu juga variabel dalam pernyataan if di REPL atau di tingkat atas bersifat global tetapi variabel dalam @testset bersifat lokal. Kami berakhir di lubang kelinci "coba saja dan kerjakan sendiri apakah itu lokal atau global, semoga berhasil".

Namun, saya setuju dengan @jlperla - proposal bahwa "cakupan keras di dalam modul hanya mungkin masuk akal" tampaknya baik-baik saja bagi saya! Modul adalah konsep yang cukup maju lagi ... jika soft scope berfungsi untuk REPL dan skrip, itu baik-baik saja.

kami tidak ingin sesuatu yang rumit seperti ruang lingkup menimpa orang...
di tingkat atas bersifat global tetapi variabel dalam @testset bersifat lokal

Apa yang saya coba dapatkan adalah bahwa saya merasa deskripsi sederhana tentang global vs. lokal sudah cukup untuk pengajaran tahap awal --- Anda bahkan tidak perlu mengucapkan kata "lingkup" (itu tidak muncul sama sekali dalam penjelasan saya di atas). Saat Anda hanya menunjukkan beberapa ekspresi dan loop sederhana di REPL, Anda tidak mengajari orang tentang testset dan Anda tidak memerlukan daftar lengkap perilaku pelingkupan dari segala sesuatu dalam bahasa.

Satu-satunya poin saya adalah, perubahan ini tidak tiba-tiba mengharuskan Anda untuk mengajarkan banyak detail tentang bahasa di awal. Anda masih dapat mengabaikan sebagian besar hal tentang cakupan, testset, dll., dan baris sederhana tentang global vs. lokal sudah cukup.

dan garis sederhana tentang global vs. lokal sudah cukup.

Di dunia di mana semua orang mulai menulis semua kode mereka dari awal, saya setuju sepenuhnya.

Masalahnya adalah Anda perlu mengajari siswa tidak hanya tentang ruang lingkup, tetapi juga tentang memahami ruang lingkup dari mana mereka menyalin kode yang mereka dapatkan. Anda perlu mengajari mereka bahwa jika mereka menyalin-tempel kode yang ada di stackexchange dalam suatu fungsi atau blok let yang mereka perlukan untuk memindainya dan menemukan tempat untuk menambahkan "global" jika mereka menempelkannya ke REPL atau .jl berkas

Dan kemudian siswa mulai bertanya mengapa for membuat lingkup ini yang perlu mereka khawatirkan tetapi bukan hal lain....

Kami berakhir di lubang kelinci "coba saja dan kerjakan sendiri apakah itu lokal atau global, semoga berhasil".

Kuis pop: di julia 0.6, apakah x global atau lokal:

for i = 1:10
    x = i
end

Jawabannya adalah tidak ada cara untuk mengetahuinya, karena itu tergantung pada apakah x global telah didefinisikan sebelumnya. Sekarang, Anda dapat mengatakan dengan pasti bahwa itu adalah lokal.

Teman-teman, diskusi ini hampir tidak lagi produktif. Jeff tahu betul bahwa perilaku lama itu bagus di REPL. Menurut Anda siapa yang pertama kali merancang dan mengimplementasikannya? Kami telah berkomitmen untuk mengubah perilaku interaktif. Keputusan masih perlu dibuat tentang apakah "skrip" itu interaktif atau tidak. Kedengarannya interaktif ketika Anda menyebutnya "sebuah skrip" tetapi kedengarannya jauh kurang interaktif ketika Anda menyebutnya "sebuah program"—namun mereka adalah hal yang persis sama. Mohon jawaban singkat dan konstruktif dan fokus pada hal-hal yang masih harus diputuskan. Jika ada komentar yang menyimpang dari ini, mereka mungkin disembunyikan dan utasnya mungkin dikunci.

Satu pemikiran yang saya miliki tetapi kami anggap "terlalu menjengkelkan" dan "kemungkinan menyebabkan penduduk desa mengeluarkan garpu rumput mereka" adalah bahwa dalam konteks non-interaktif, kami dapat meminta local atau global anotasi di "soft scope". Itu akan menjamin bahwa kode dari modul akan berfungsi sama jika ditempelkan ke REPL. Jika kita menerapkannya pada "skrip"/"program" maka hal yang sama akan berlaku untuk mereka.

Ketika saya pertama kali diperkenalkan dengan Julia (belum lama ini, dan saya sebagian besar berasal dari latar belakang Fortran), saya diajari bahwa "Julia dikompilasi dan cepat di tingkat fungsi, sehingga segala sesuatu yang harus efisien harus dilakukan di dalam fungsi . Dalam 'program' utama itu berperilaku seperti bahasa scripting". Saya menemukan itu cukup adil, karena saya tidak dapat membayangkan orang melakukan sesuatu yang terlalu menuntut komputasi tanpa memahami pernyataan itu. Oleh karena itu, jika ada pengorbanan dalam kinerja di program utama untuk menggunakan notasi dan konstruksi yang sama daripada fungsi, saya menemukan bahwa benar-benar dapat diterima, jauh lebih dapat diterima daripada mencoba memahami dan mengajarkan aturan pelingkupan ini dan tidak dapat menyalin dan tempel kode dari satu tempat ke tempat lain.

Omong-omong, saya seorang pemula di Julia, telah memilihnya untuk mengajar beberapa siswa sekolah menengah dan sarjana beberapa dasar simulasi sistem fisik. Dan saya sudah melompat masalah ini kembali ke perilaku 'normal' dari versi sebelumnya, karena itu membuat kita cukup pusing.

Percakapan ini dikunci sekarang dan hanya Julia committer yang dapat berkomentar.

@JeffBezanson , apa rencana untuk mengimplementasikan semantik yang Anda sarankan di utas wacana ini , awalnya hanya di REPL dan ikut serta di tempat lain?

Sepertinya Anda berencana untuk memasukkannya langsung ke dalam kode penurun ( julia-syntax.scm ), daripada sebagai penulisan ulang sintaks ala SoftScope.jl? Atau apakah Anda lebih suka menjadikannya sebagai penulisan ulang sintaks terlebih dahulu (memodifikasi SoftScope ke aturan yang diusulkan dan mengubahnya menjadi stdlib), dan menunda memasukkannya ke dalam kode penurun untuk rilis Julia selanjutnya?

Apakah halaman ini membantu?
0 / 5 - 0 peringkat