Pertanyaan Apakah perpustakaan Scala 2.8 koleksi merupakan kasus "catatan bunuh diri terpanjang dalam sejarah"? [Tutup]


Saya baru saja mulai melihat Pengumpulan ulang perpustakaan koleksi Scala yang akan datang dalam waktu dekat 2.8 melepaskan. Mereka yang akrab dengan perpustakaan dari 2,7 akan melihat bahwa perpustakaan, dari perspektif penggunaan, telah berubah sedikit. Sebagai contoh...

> List("Paris", "London").map(_.length)
res0: List[Int] List(5, 6)

... akan berfungsi di kedua versi. Perpustakaan benar-benar bisa digunakan: sebenarnya itu fantastis. Namun, mereka yang sebelumnya tidak akrab dengan Scala dan mengaduk-aduk untuk merasakan bahasa sekarang harus memahami tanda tangan metode seperti:

def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Repr, B, That]): That

Untuk fungsi sederhana seperti ini, ini adalah tanda yang menakutkan dan yang saya temukan sendiri berjuang untuk mengerti. Bukannya saya pikir Scala kemungkinan besar akan menjadi Jawa berikutnya (atau / C / C ++ / C #) - Saya tidak percaya penciptanya membidiknya di pasar itu - tapi saya rasa itu pasti layak bagi Scala untuk menjadi Ruby atau Python berikutnya (yaitu untuk mendapatkan pengguna komersial yang signifikan -mendasarkan)

  • Apakah ini akan membuat orang datang ke Scala?
  • Apakah ini akan memberi Scala nama buruk di dunia komersial sebagai mainan akademis bahwa hanya mahasiswa PhD yang berdedikasi dapat mengerti? Adalah CTOdan kepala perangkat lunak akan merasa takut?
  • Apakah perpustakaan mendesain ulang ide yang masuk akal?
  • Jika Anda menggunakan Scala secara komersial, apakah Anda khawatir tentang ini? Apakah Anda berencana mengadopsi 2,8 segera atau menunggu untuk melihat apa yang terjadi?

Steve Yegge  sekali menyerang Scala (keliru menurut saya) untuk apa yang dia lihat sebagai sistem jenisnya yang terlalu rumit. Saya khawatir seseorang akan memiliki hari lapangan yang menyebar FUD dengan API ini (mirip dengan cara Josh Bloch menakuti JCP keluar dari penambahan penutupan ke Java).

Catatan - Saya harus jelas itu, sementara saya percaya itu Joshua Bloch sangat berpengaruh dalam penolakan proposal penutupan BGGA, saya tidak menganggap ini sebagai sesuatu selain keyakinannya yang dipegang teguh bahwa proposal tersebut mewakili kesalahan.


Meskipun apa pun yang dikatakan oleh istri dan rekan kerja saya, saya tidak berpikir saya idiot: Saya memiliki gelar yang baik dalam matematika dari Universitas Oxford, dan saya telah memprogram secara komersial selama hampir 12 tahun dan di Scala selama sekitar satu tahun (juga secara komersial).

Perhatikan judul subjek inflamasi adalah a kutipan dibuat tentang manifesto partai politik UK pada awal 1980-an. Pertanyaan ini subyektif tetapi itu adalah pertanyaan asli, saya sudah membuatnya CW dan saya ingin beberapa pendapat tentang masalah ini.


809


asal


Jawaban:


Saya harap ini bukan "catatan bunuh diri", tetapi saya bisa melihat maksud Anda. Anda menekan pada apa yang sekaligus kekuatan dan masalah Scala: nya kemungkinan diperpanjang. Ini memungkinkan kami menerapkan sebagian besar fungsi utama di pustaka. Dalam beberapa bahasa lain, urutan dengan sesuatu seperti mapatau collect akan dibangun di dalamnya, dan tidak ada yang harus melihat semua lingkaran yang harus dilalui kompilator untuk membuatnya bekerja dengan lancar. Di Scala, itu semua ada di perpustakaan, dan karena itu di tempat terbuka.

Faktanya fungsi dari map yang didukung oleh jenisnya yang rumit cukup maju. Pertimbangkan ini:

scala> import collection.immutable.BitSet
import collection.immutable.BitSet

scala> val bits = BitSet(1, 2, 3)
bits: scala.collection.immutable.BitSet = BitSet(1, 2, 3)

scala> val shifted = bits map { _ + 1 }
shifted: scala.collection.immutable.BitSet = BitSet(2, 3, 4)

scala> val displayed = bits map { _.toString + "!" }
displayed: scala.collection.immutable.Set[java.lang.String] = Set(1!, 2!, 3!)

Lihat bagaimana Anda selalu mendapatkan tipe terbaik? Jika Anda memetakan Ints untuk IntAnda mendapatkan lagi a BitSet, tetapi jika Anda memetakan Ints untuk Strings, Anda mendapatkan jenderal Set. Baik tipe statis dan representasi runtime hasil peta bergantung pada jenis hasil dari fungsi yang diteruskan ke sana. Dan ini berfungsi bahkan jika set kosong, sehingga fungsi tidak pernah diterapkan! Sejauh yang saya tahu tidak ada kerangka pengumpulan lain dengan fungsi yang setara. Namun dari sudut pandang pengguna, inilah yang terjadi seharusnya bekerja.

Masalah yang kita miliki adalah bahwa semua teknologi pintar yang membuat ini terjadi bocor ke jenis tanda tangan yang menjadi besar dan menakutkan. Tapi mungkin pengguna seharusnya tidak ditampilkan secara default tanda tangan tipe penuh map? Bagaimana kalau dia mendongak map di BitSet dia mendapat:

map(f: Int => Int): BitSet     (click here for more general type)

Dokumen tidak akan berbohong dalam kasus itu, karena dari perspektif pengguna memang peta memiliki tipe (Int => Int) => BitSet. Tapi map juga memiliki tipe yang lebih umum yang dapat diperiksa dengan mengklik tautan lain.

Kami belum menerapkan fungsi seperti ini di alat kami. Tetapi saya yakin kita perlu melakukan ini, untuk menghindari menakut-nakuti orang dan memberikan info yang lebih berguna. Dengan alat seperti itu, semoga framework dan pustaka cerdas tidak akan menjadi catatan bunuh diri.


828



Saya tidak memiliki gelar PhD, atau jenis gelar lainnya baik di CS maupun matematika dan tidak ada bidang lain. Saya tidak memiliki pengalaman sebelumnya dengan Scala atau bahasa serupa lainnya. Saya tidak memiliki pengalaman dengan sistem tipe yang sebanding. Bahkan, satu-satunya bahasa yang saya miliki lebih dari sekedar pengetahuan dangkal yang bahkan punya sistem jenis adalah Pascal, tidak persis dikenal karena sistem jenisnya yang canggih. (Walaupun itu tidak memiliki berbagai tipe, yang AFAIK tidak banyak memiliki bahasa lain, tetapi itu tidak benar-benar relevan di sini.) Tiga bahasa lainnya yang saya tahu adalah BASIC, Smalltalk dan Ruby, tidak ada yang memiliki sistem tipe.

Namun, saya tidak punya masalah sama sekali memahami tanda tangan map fungsi yang Anda posting. Ini terlihat seperti tanda tangan yang sama map dalam setiap bahasa lain yang pernah saya lihat. Perbedaannya adalah versi ini lebih generik. Terlihat lebih mirip C ++ STL daripada, katakanlah, Haskell. Secara khusus, itu abstrak jauh dari jenis koleksi konkret dengan hanya mensyaratkan bahwa argumen tersebut IterableLike, dan juga abstrak jauh dari jenis kembalinya konkret dengan hanya mensyaratkan bahwa fungsi konversi implisit ada yang dapat membangun sesuatu dari koleksi nilai hasil tersebut. Ya, itu cukup kompleks, tetapi itu benar-benar hanya merupakan ekspresi dari paradigma umum pemrograman generik: jangan menganggap apa pun yang sebenarnya tidak perlu Anda lakukan.

Pada kasus ini, map sebenarnya tidak perlu koleksi menjadi daftar, atau diperintahkan atau diurutkan atau semacamnya. Satu-satunya hal itu map peduli adalah bahwa ia bisa mendapatkan akses ke semua elemen koleksi, satu demi satu, tetapi tidak dalam urutan tertentu. Dan tidak perlu tahu koleksi apa yang dihasilkan, hanya perlu tahu cara membuatnya. Jadi, itulah yang dituntut oleh jenisnya.

Jadi, bukannya

map :: (a → b) → [a] → [b]

yang merupakan tanda tangan tipe tradisional untuk map, itu umum untuk tidak memerlukan beton List melainkan hanya sebuah IterableLike struktur data

map :: (IterableLike i, IterableLike j) ⇒ (a → b) → i → j

yang kemudian digeneralisasikan lebih lanjut dengan hanya mensyaratkan bahwa ada fungsi yang bisa mengubah hasil ke struktur data apa pun yang diinginkan pengguna:

map :: IterableLike i ⇒ (a → b) → i → ([b] → c) → c

Saya mengakui bahwa sintaksnya sedikit clunkier, tetapi semantiknya sama. Pada dasarnya, ini dimulai dari

def map[B](f: (A) ⇒ B): List[B]

yang merupakan tanda tangan tradisional untuk map. (Perhatikan bagaimana karena sifat object-oriented Scala, parameter daftar input hilang, karena sekarang parameter penerima implisit yang setiap metode dalam sistem OO single-dispatch.) Kemudian disamaratakan dari beton List ke yang lebih umum IterableLike

def map[B](f: (A) ⇒ B): IterableLike[B]

Sekarang, itu menggantikan IterableLike hasil koleksi dengan fungsi itu menghasilkan, baik, benar-benar tentang apa saja.

def map[B, That](f: A ⇒ B)(implicit bf: CanBuildFrom[Repr, B, That]): That

Yang saya benar-benar percaya tidak bahwa sulit dimengerti. Hanya ada beberapa alat intelektual yang Anda butuhkan:

  1. Anda perlu tahu (kira-kira) apa map aku s. Jika kamu memberi hanya tanda tangan jenis tanpa nama metode, saya akui, akan jauh lebih sulit untuk mencari tahu apa yang sedang terjadi. Tapi karena kamu sudah tahu apa map seharusnya dilakukan, dan Anda tahu tanda tangan jenis apa yang seharusnya, Anda dapat dengan cepat memindai tanda tangan dan fokus pada anomali, seperti "mengapa ini map mengambil dua fungsi sebagai argumen, bukan? "
  2. Anda harus bisa benar-benar Baca baca tanda tangan jenis. Tetapi bahkan jika Anda belum pernah melihat Scala sebelumnya, ini seharusnya cukup mudah, karena itu benar-benar hanya campuran dari jenis sintaks yang sudah Anda ketahui dari bahasa lain: VB.NET menggunakan tanda kurung siku untuk polimorfisme parametrik, dan menggunakan panah untuk menunjukkan kembali jenis dan titik dua untuk memisahkan nama dan jenis, sebenarnya adalah norma.
  3. Anda perlu tahu kira-kira apa pemrograman generik adalah tentang. (Yang tidak bahwa sulit untuk mencari tahu, karena pada dasarnya semuanya dieja dengan nama: itu benar-benar hanya pemrograman secara umum).

Tak satu pun dari ketiganya harus memberi programmer profesional atau bahkan hobbyist sakit kepala yang serius. map telah menjadi fungsi standar di hampir semua bahasa yang dirancang dalam 50 tahun terakhir, fakta bahwa bahasa yang berbeda memiliki sintaks yang berbeda harus jelas bagi siapa saja yang telah mendesain situs web dengan HTML dan CSS dan Anda tidak dapat berlangganan pemrograman jarak jauh sekalipun mailinglist terkait tanpa beberapa fanboy C ++ yang menjengkelkan dari gereja St. Stepanov menjelaskan kebaikan pemrograman generik.

Ya, Scala aku s kompleks. Ya, Scala memiliki salah satu sistem paling canggih yang dikenal manusia, menyaingi dan bahkan melampaui bahasa seperti Haskell, Miranda, Clean, atau Cyclone. Tetapi jika kompleksitas adalah argumen terhadap keberhasilan bahasa pemrograman, C ++ akan mati lama dan kita semua akan menulis Skema. Ada banyak alasan mengapa Scala kemungkinan besar tidak akan berhasil, tetapi kenyataan bahwa programmer tidak dapat terganggu untuk menyalakan otak mereka sebelum duduk di depan keyboard mungkin tidak akan menjadi yang utama.


206



Hal yang sama di C ++:

template <template <class, class> class C,
          class T,
          class A,
          class T_return,
          class T_arg
              >
C<T_return, typename A::rebind<T_return>::other>
map(C<T, A> &c,T_return(*func)(T_arg) )
{
    C<T_return, typename A::rebind<T_return>::other> res;
    for ( C<T,A>::iterator it=c.begin() ; it != c.end(); it++ ){
        res.push_back(func(*it));
    }
    return res;
}

163



Yah, saya bisa mengerti rasa sakit Anda, tetapi, terus terang, orang-orang seperti Anda dan saya - atau hampir semua pengguna Stack Overflow biasa - bukan merupakan aturan.

Yang saya maksud dengan itu adalah ... kebanyakan programmer tidak akan peduli tentang tanda tangan jenis itu, karena mereka tidak akan pernah melihatnya! Mereka tidak membaca dokumentasi.

Selama mereka melihat beberapa contoh bagaimana kode bekerja, dan kode tidak gagal dalam menghasilkan hasil mengharapkan, mereka tidak akan pernah melihat dokumentasi. Ketika itu gagal, mereka akan melihat dokumentasi dan berharap untuk melihat contoh penggunaan di atas.

Dengan hal-hal ini dalam pikiran, saya berpikir bahwa:

  1. Siapa pun (seperti, kebanyakan orang) yang pernah menemukan tanda tangan semacam itu akan mengejek Scala tanpa akhir jika mereka sudah dibuang sebelumnya, dan akan menganggapnya sebagai simbol kekuatan Scala jika mereka menyukai Scala.

  2. Jika dokumentasi tidak disempurnakan untuk memberikan contoh penggunaan dan menjelaskan dengan jelas apa itu metode dan bagaimana menggunakannya, itu dapat mengurangi sedikit penerapan Scala.

  3. Dalam jangka panjang, itu tidak masalah. Scala itu bisa melakukan hal-hal seperti itu akan membuat perpustakaan yang ditulis untuk Scala jauh lebih kuat dan lebih aman untuk digunakan. Pustaka dan kerangka kerja ini akan menarik para pemrogram yang tertarik pada alat-alat canggih.

  4. Programer yang menyukai kesederhanaan dan keterusterangan akan terus menggunakan PHP, atau bahasa yang serupa.

Sayangnya, programmer Java banyak menggunakan perkakas listrik, jadi, dalam menjawab itu, saya baru saja merevisi harapan saya akan adopsi Scala mainstream. Saya tidak ragu sama sekali bahwa Scala akan menjadi bahasa utama. Bukan C-mainstream, tapi mungkin Perl-mainstream atau PHP-mainstream.

Berbicara tentang Java, apakah Anda pernah mengganti kelas loader? Pernahkah Anda melihat apa yang melibatkan? Java dapat menjadi menakutkan, jika Anda melihat tempat-tempat yang dilakukan oleh para penulis kerangka kerja. Hanya saja kebanyakan orang tidak. Hal yang sama berlaku untuk Scala, IMHO, tetapi pengguna awal memiliki kecenderungan untuk melihat di bawah setiap batu yang mereka temui, untuk melihat apakah ada sesuatu yang bersembunyi di sana.


67



Apakah ini akan membuat orang datang ke Scala?

Ya, tetapi itu juga akan mencegah orang-orang ditunda. Saya telah mempertimbangkan kurangnya koleksi yang menggunakan tipe yang lebih tinggi untuk menjadi kelemahan utama sejak Scala memperoleh dukungan untuk tipe yang lebih tinggi. Itu membuat dokumen API lebih rumit, tetapi itu benar-benar membuat penggunaan lebih alami.

Apakah ini akan memberikan scala nama yang buruk di dunia komersial sebagai permainan akademis yang hanya dapat dipahami oleh para mahasiswa PhD? Apakah CTO dan kepala perangkat lunak akan takut?

Beberapa mungkin akan melakukannya. Saya tidak berpikir Scala dapat diakses oleh banyak pengembang "profesional", sebagian karena kompleksitas Scala dan sebagian karena ketidakinginan banyak pengembang untuk belajar. CTO yang mempekerjakan para pengembang seperti itu akan benar-benar ketakutan.

Apakah perpustakaan mendesain ulang ide yang masuk akal?

Benar. Ini membuat koleksi lebih pas dengan sisa bahasa dan sistem jenis, meskipun masih memiliki beberapa sisi kasar.

Jika Anda menggunakan scala secara komersial, apakah Anda khawatir tentang ini? Apakah Anda berencana mengadopsi 2,8 segera atau menunggu untuk melihat apa yang terjadi?

Saya tidak menggunakannya secara komersial. Saya mungkin akan menunggu hingga setidaknya beberapa revs ke dalam seri 2.8.x bahkan sebelum mencoba untuk mengenalkannya sehingga bug-bug tersebut dapat dihilangkan. Saya juga akan menunggu untuk melihat seberapa sukses EPFL dalam meningkatkan pengembangannya dalam proses rilis. Apa yang saya lihat terlihat penuh harapan, tetapi saya bekerja untuk perusahaan yang konservatif.

Salah satu topik yang lebih umum dari "apakah Scala terlalu rumit untuk pengembang mainstream?" ...

Sebagian besar pengembang, mainstream atau lainnya, mempertahankan atau memperluas sistem yang ada. Ini berarti bahwa sebagian besar dari apa yang mereka gunakan ditentukan oleh keputusan yang dibuat lama. Masih banyak orang yang menulis COBOL.

Pengembang utama besok akan bekerja memelihara dan memperluas aplikasi yang sedang dibangun hari ini. Banyak dari aplikasi ini yang tidak dibangun oleh pengembang utama. Pengembang utama besok akan menggunakan bahasa yang digunakan oleh pengembang aplikasi baru yang paling sukses saat ini.


52



Salah satu cara bahwa komunitas Scala dapat membantu meringankan rasa takut para programmer baru ke Scala adalah fokus pada latihan dan untuk mengajar dengan contoh - banyak contoh yang mulai kecil dan tumbuh secara bertahap lebih besar. Berikut beberapa situs yang menggunakan pendekatan ini:

Setelah menghabiskan beberapa waktu di situs-situs ini, seseorang dengan cepat menyadari bahwa Scala dan perpustakaannya, meskipun mungkin sulit untuk dirancang dan diimplementasikan, tidak begitu sulit untuk digunakan, terutama dalam kasus-kasus umum.


46



Saya memiliki gelar sarjana dari universitas AS "mass market" yang murah, jadi saya akan mengatakan saya jatuh ke tengah-tengah kecerdasan pengguna (atau setidaknya pendidikan) skala :) Saya sudah berkecimpung dengan Scala hanya selama beberapa bulan dan telah mengerjakan dua atau tiga aplikasi yang tidak sepele.

Khususnya sekarang karena IntelliJ telah merilis IDE bagus mereka dengan apa yang saat ini IMHO adalah plugin Scala terbaik, pengembangan Scala relatif tidak menyakitkan:

  • Saya menemukan saya dapat menggunakan Scala sebagai "Java tanpa titik koma", yaitu saya menulis kode yang mirip dengan apa yang akan saya lakukan di Jawa, dan mendapat manfaat sedikit dari sintaksis sintaksis seperti yang diperoleh dengan jenis inferensi. Penanganan pengecualian, ketika saya melakukannya sama sekali, lebih nyaman. Definisi kelas jauh lebih sedikit tanpa pengukur / setter boilerplate.

  • Sesekali saya berhasil menulis satu baris untuk menyelesaikan beberapa baris Java yang setara. Jika memungkinkan, rantai metode fungsional seperti peta, lipatan, pengumpulan, filter dll. Menyenangkan untuk dikomposisikan dan elegan untuk dilihat.

  • Hanya jarang saya mendapatkan manfaat dari fitur-fitur Scala yang lebih tinggi: Fungsi penutupan dan parsial (atau kari), pencocokan pola ... hal yang agak.

Sebagai seorang pemula, saya terus berjuang dengan sintaks singkat dan idiomatik. Panggilan metode tanpa parameter tidak perlu tanda kurung kecuali di mana mereka lakukan; kasus dalam pernyataan pertandingan membutuhkan panah yang tebal ( => ), tetapi ada juga tempat-tempat di mana Anda perlu panah tipis ( -> ). Banyak metode yang memiliki nama yang pendek tetapi agak samar seperti /:atau \: - Saya bisa mendapatkan barang-barang saya selesai jika saya membalik halaman manual yang cukup, tetapi beberapa kode saya berakhir tampak seperti Perl atau suara garis. Ironisnya, salah satu potongan yang paling populer dari singkatan sintaksis hilang dalam tindakan: Saya terus digigit oleh fakta bahwa Int tidak mendefinisikan ++ metode.

Ini hanya pendapat saya: Saya merasa seperti Scala memiliki kekuatan C ++ dikombinasikan dengan kompleksitas dan keterbacaan C ++. Kompleksitas sintaksis bahasa juga membuat dokumentasi API sulit dibaca.

Scala sangat dipikirkan dengan baik dan cemerlang dalam banyak hal. Saya menduga banyak akademisi akan senang memprogram di dalamnya. Namun, ini juga penuh dengan kepintaran dan getchas, ia memiliki kurva belajar yang jauh lebih tinggi daripada Java dan lebih sulit untuk dibaca. Jika saya memindai forum dan melihat berapa banyak pengembang yang masih berjuang dengan poin-poin penting di Jawa, Saya tidak bisa membayangkan Scala pernah menjadi bahasa utama. Tidak ada perusahaan yang dapat membenarkan pengiriman pengembangnya dalam kursus Scala 3 minggu ketika sebelumnya mereka hanya membutuhkan kursus Java 1 minggu.


40



Saya pikir masalah utama dengan metode itu adalah bahwa (implicit bf : CanBuildFrom[Repr, B, That]) berjalan tanpa penjelasan apa pun. Meskipun saya tahu apa argumen implisit tidak ada yang menunjukkan bagaimana ini mempengaruhi panggilan. Mengejar skaladoc hanya membuat saya lebih bingung (beberapa kelas terkait CanBuildFrom bahkan memiliki dokumentasi).

Saya pikir sederhana "harus ada objek implisit dalam ruang lingkup bf yang menyediakan pembangun untuk objek tipe B ke dalam tipe kembalinya That"Akan membantu agak, tapi itu semacam konsep memabukkan ketika semua yang Anda benar-benar ingin lakukan adalah peta Auntuk B's. Sebenarnya, saya tidak yakin itu benar, karena saya tidak tahu apa tipenya Repr berarti, dan dokumentasi untuk Traversable tentu tidak memberi petunjuk sama sekali.

Jadi, saya pergi dengan dua pilihan, keduanya tidak menyenangkan:

  • Asumsikan itu hanya akan bekerja bagaimana peta lama bekerja dan bagaimana peta bekerja di sebagian besar bahasa lain
  • Gali kode sumber lagi

Saya mendapatkan bahwa Scala pada dasarnya mengungkapkan keberanian tentang bagaimana hal-hal ini bekerja dan yang pada akhirnya ini menyediakan cara untuk melakukan apa yang digambarkan oleh oxbow_lakes. Tapi itu selingan dalam tanda tangan.


32



Saya seorang Scala beginner dan sejujurnya saya tidak melihat masalah dengan tanda tangan jenis itu. Parameternya adalah fungsi untuk memetakan dan parameter implisit pembangun untuk mengembalikan koleksi yang benar. Jelas dan mudah dibaca.

Semuanya cukup elegan, sebenarnya. Parameter tipe builder membiarkan compiler memilih jenis return yang benar sementara mekanisme parameter implisit menyembunyikan parameter ekstra ini dari pengguna kelas. Saya mencoba ini:

Map(1 -> "a", 2 -> "b").map((t) => (t._2) -> (t._1)) // returns Map("a" -> 1, "b" -> 2)
Map(1 -> "a", 2 -> "b").map((t) =>  t._2)            // returns List("a", "b")

Itu polimorfisme yang dilakukan dengan benar.

Sekarang, diberikan, itu bukan paradigma arus utama dan itu akan menakut-nakuti banyak orang. Tapi, itu juga akan menarik banyak orang yang menghargai ekspresinya dan keanggunannya.


22