Apakah ada bahasa pemrograman yang dirancang khusus untuk injeksi ketergantungan?

21

Banyak bahasa pemrograman umum cukup fleksibel untuk memungkinkan Anda mendukung injeksi ketergantungan. Bahkan tanpa dukungan pustaka atau kerangka kerja. Tetapi bahkan jika suatu bahasa Turing cukup lengkap untuk menyelesaikan masalah pemrograman, bahasa membuat pilihan yang berdampak pada apa yang mudah dan apa yang sulit dilakukan di dalamnya.

Apakah ada bahasa yang dirancang khusus untuk membuat injeksi ketergantungan menjadi mudah, dan sebaliknya, membuat membuat dependensi tersembunyi menjadi sulit?

Klarifikasi:

Karena keterbatasan beberapa bahasa (melihat Anda Java), banyak orang menganggap bantuan dengan kabel dan konstruksi sebagai bagian dari injeksi ketergantungan. Di sini saya hanya bermaksud bahasa yang dirancang untuk DI berarti bahwa ketergantungan tidak mudah disembunyikan dalam efek samping. Memiliki konvensi atas sistem konfigurasi juga hanya akan ditambahkan saus.

Saya tidak mencari rekomendasi bahasa. Itu pertanyaan historis. Pernahkah ada penulis bahasa yang secara eksplisit melakukan ini?

candied_orange
sumber
1
Sangat terkait, jika bukan duplikat langsung: Bagaimana injeksi ketergantungan dapat diintegrasikan ke dalam bahasa?
Robert Harvey
Wah! 3 rb! Sekarang saya bisa melihat mereka memberikan suara untuk menutup pertanyaan ini. :) Terima kasih untuk suaranya.
candied_orange
1
Anda harus tetap membaca posting itu. "Apakah itu ada" adalah pertanyaan yang jauh kurang menarik, kecuali jika Anda mengembangkannya ke sesuatu seperti "bagaimana mereka melakukannya?"
Robert Harvey
1
Apakah Haskell akan dihitung? Dengan fungsi currying dan orde tinggi, Anda dapat menyelesaikan sebagian besar masalah yang umumnya DI diselesaikan dalam bahasa OOP dan dengan ketatnya pada kemurnian Anda dipaksa untuk memisahkan efek samping seperti IO dll dan fungsi tidak dapat secara ajaib menyulap sesuatu yang mereka tidak lulus sebagai argumen. Anda tidak mendapatkan konvensi tentang konfigurasi, tetapi di sisi lain saya perlahan-lahan menjauh dari itu bahkan dalam kode OOP saya saat ini karena saya perhatikan bahwa sebagian besar tim tidak dapat dipercaya dengan itu pada proyek-proyek berukuran sedang dan lebih besar.
wasatz
1
@wasatz: Ya, Haskell penting. Kebanyakan "pola perangkat lunak" benar-benar hanya solusi untuk kekurangan dalam bahasa pemrograman.
Robert Harvey

Jawaban:

21

Ya, memang ada. Semacam.

Newspeak tidak memiliki keadaan statis dan tidak memiliki keadaan global. Ini berarti bahwa satu-satunya cara yang mungkin untuk mendapatkan akses ke ketergantungan adalah dengan menyuntikkannya secara eksplisit. Jelas, ini berarti bahwa bahasa, atau dalam kasus Newspeak lebih tepatnya IDE perlu membuat injeksi ketergantungan mudah, jika tidak bahasa tidak akan dapat digunakan.

Jadi, bahasa tidak dirancang untuk DI, tetapi kebutuhan untuk DI adalah konsekuensi dari desain bahasa.

Jika tidak ada keadaan statis dan tidak ada keadaan global, maka Anda tidak bisa begitu saja "menjangkau" ke dalam eter dan menarik sesuatu keluar. Sebagai contoh, di Jawa, struktur paket adalah keadaan statis. Saya hanya bisa mengatakan java.lang.Stringdan saya memiliki Stringkelas sendiri . Itu tidak mungkin di Newspeak. Segala sesuatu yang Anda kerjakan, harus secara eksplisit diberikan kepada Anda, jika tidak, Anda tidak bisa mendapatkannya. Jadi, semuanya adalah ketergantungan, dan setiap ketergantungan eksplisit.

Kamu ingin string? Nah, Anda harus terlebih dahulu meminta stdlibobjek untuk memberi Anda Stringkelas. Oh, tetapi bagaimana Anda mendapatkan akses ke stdlib? Nah, Anda harus terlebih dahulu meminta platformuntuk menyerahkan stdlibbenda itu kepada Anda . Oh, tetapi bagaimana Anda mendapatkan akses ke platform? Nah, Anda harus terlebih dahulu meminta orang lain untuk menyerahkan platformbenda itu kepada Anda . Oh, tetapi bagaimana Anda mendapatkan akses ke seseorang yang tinggal di sana? Nah, Anda harus terlebih dahulu meminta orang lain untuk menyerahkan benda itu kepada Anda.

Seberapa jauh lubang kelinci ini? Di mana rekursi berhenti? Sepanjang jalan, sebenarnya. Itu tidak berhenti. Lalu, bagaimana Anda bisa menulis program di Newspeak? Sebenarnya, Anda tidak bisa!

Anda memerlukan entitas luar yang mengikat semuanya. Di Newspeak, entitas itu adalah IDE. IDE melihat keseluruhan program. Itu bisa menyatukan potongan-potongan yang berbeda. Pola standar dalam Newspeak adalah bahwa kelas pusat aplikasi Anda memiliki accessor yang disebut platform, dan IDE Newspeak menyuntikkan objek ke accessor yang memiliki metode yang mengembalikan beberapa kebutuhan dasar pemrograman: Stringkelas, Numberkelas, Arraykelas, dan seterusnya.

Jika Anda ingin menguji aplikasi Anda, Anda bisa menyuntikkan platformobjek yang Filemetodenya mengembalikan kelas dengan metode dummy. Jika Anda ingin menyebarkan aplikasi Anda ke cloud, Anda menyuntikkan platform yang Filekelasnya sebenarnya didukung oleh Amazon S3. GUI lintas platform bekerja dengan menyuntikkan kerangka kerja GUI yang berbeda untuk OS yang berbeda. Newspeak bahkan memiliki kompiler Newspeak-to-ECMAScript eksperimental dan kerangka kerja GUI yang didukung HTML yang memungkinkan Anda untuk port aplikasi GUI berfitur lengkap dari desktop asli ke dalam browser tanpa perubahan, hanya dengan menyuntikkan elemen GUI yang berbeda.

Jika Anda ingin menggunakan aplikasi Anda, IDE dapat membuat serialisasi aplikasi menjadi objek di-disk. (Tidak seperti leluhurnya, Smalltalk, Newspeak memiliki format serialisasi objek out-of-image. Anda tidak harus mengambil seluruh gambar dengan Anda, justru karena semua dependensi disuntikkan: IDE tahu persis bagian mana dari sistem aplikasi Anda menggunakan dan yang tidak. Jadi, ia membuat serial persis subgraf yang terhubung dari ruang objek yang terdiri dari aplikasi Anda, tidak lebih.)

Semua ini bekerja hanya dengan mengambil orientasi objek ke ekstrem: semuanya adalah panggilan metode virtual ("pengiriman pesan" dalam terminologi Smalltalk, di mana Newspeak adalah turunan). Bahkan pencarian superclass adalah panggilan metode virtual! Ambil sesuatu seperti

class Foo extends Bar // using Java syntax for familiarity

atau, dalam Newspeak:

class Foo = Bar () () : ()

Di Jawa, ini akan membuat nama Foodi namespace global statis, dan mencari Bardi namespace global statis dan membuat Bar Foosuperclass. Bahkan di Ruby, yang jauh lebih dinamis, ini masih akan membuat konstanta statis di namespace global.

Di Newspeak, deklarasi setara berarti: membuat metode pengambil bernama Foodan membuatnya mengembalikan kelas yang mencari kelas supernya dengan memanggil metode bernama Bar. Catatan: ini tidak seperti Ruby, di mana Anda dapat menempatkan setiap eksekusi kode Ruby sebagai deklarasi superclass, tetapi kode hanya akan dieksekusi sekali ketika kelas dibuat dan nilai kembali kode yang menjadi superclass tetap. Tidak. Metode Barini dipanggil untuk setiap pencarian metode tunggal !

Ini memiliki beberapa implikasi mendalam:

  • karena mixin pada dasarnya adalah kelas yang belum mengetahui superclass-nya, dan di Newspeak, superclass adalah panggilan metode virtual yang dinamis, dan karenanya tidak diketahui, setiap kelas secara otomatis juga merupakan mixin. Anda mendapatkan mixin gratis.
  • karena kelas dalam hanyalah pemanggilan metode yang mengembalikan kelas, Anda bisa mengganti metode itu dalam subkelas dari kelas luar, jadi setiap kelas adalah virtual. Anda mendapatkan kelas virtual gratis:

    class Outer {
      class Inner { /* … */ }
    }
    
    class Sub extends Outer {
      override class Inner { /* … */ }
    }
    

    Newspeak:

    class Outer = () (
      class Inner = () () : ()
    ) : ()
    
    class Sub = Outer () (
      class Inner = () () : ()
    ) : ()
    
  • karena superclass hanyalah pemanggilan metode yang mengembalikan kelas, Anda bisa menimpa metode itu dalam subkelas dari kelas luar, kelas dalam yang ditentukan dalam superclass dapat memiliki superclass yang berbeda di dalam subkelas. Anda mendapatkan warisan hierarki kelas secara gratis:

    class Outer {
      class MyCoolArray extends Array { /* … */ }
    }
    
    class Sub extends Outer {
      override class Array { /* … */ }
      // Now, for instances of `Sub`, `MyCoolArray` has a different superclass 
      // than for instances of `Outer`!!!
    }
    

    Newspeak:

    class Outer = () (
      class MyCoolArray = Array () () : ()
    ) : ()
    
    class Sub = Outer () (
      class Array = () () : ()
    ) : ()
    
  • dan terakhir, yang paling penting untuk diskusi ini: karena (terlepas dari yang Anda tentukan di kelas Anda, tentu saja) Anda hanya dapat memanggil metode di kelas lexically Anda yang tertutup (es) dan superclass Anda (es), kelas terluar tingkat atas tidak bisa memanggil metode sama sekali kecuali orang-orang yang secara eksplisit disuntikkan: kelas tingkat atas tidak memiliki kelas melampirkan yang metodenya bisa menyebutnya, dan tidak dapat memiliki superclass lain dari yang default, karena deklarasi superclass adalah metode panggilan, dan itu jelas tidak bisa pergi ke superclass (itu adalahsuperclass) dan juga tidak dapat pergi ke kelas lexically enclosure, karena tidak ada. Apa artinya ini adalah kelas tingkat atas benar-benar dienkapsulasi, mereka hanya dapat mengakses apa yang mereka disuntikkan secara eksplisit, dan mereka hanya mendapatkan suntikan apa yang mereka minta secara eksplisit. Dengan kata lain: kelas tingkat atas adalah modul. Anda mendapatkan keseluruhan sistem modul secara gratis. Bahkan, lebih tepatnya: kelas tingkat atas adalah deklarasi modul, instansnya adalah modul. Jadi, Anda mendapatkan sistem modul dengan deklarasi modul parametrik dan modul kelas satu gratis, sesuatu yang tidak bisa dilakukan oleh banyak, bahkan sangat canggih, sistem modul.

Untuk membuat semua injeksi ini tidak menyakitkan, deklarasi kelas memiliki struktur yang tidak biasa: mereka terdiri dari dua deklarasi. Salah satunya adalah konstruktor kelas, yang bukan konstruktor yang mengkonstruksikan instance kelas, melainkan konstruktor yang membangun lingkungan di mana tubuh kelas berjalan. Dalam sintaks mirip Java, akan terlihat seperti ini:

class Foo(platform) extends Bar {
  Array  = platform.collections.Array
  String = platform.lang.String
  File   = platform.io.File
| // separator between class constructor and class body
  class MyArray extends Array { /* … */ }
  // Array refers to the method defined above which in turn gets it from the 
  // platform object that was passed into the class "somehow"
}

Newspeak:

class Foo using: platform = Bar (
  Array = platform collections Array
  String = platform streams String 
  File = platform files ExternalReadWriteStream
) (
  class MyArray = Array () () : ()
) : ()

Perhatikan bahwa cara seorang programmer Newspeak benar - benar akan melihat kelas adalah seperti ini:IDE Newspeak menampilkan beberapa kelas bersarang

Aku bahkan tidak bisa mulai melakukannya dengan adil. Anda harus bermain-main dengannya sendiri. Gilad Bracha telah memberikan beberapa ceramah tentang berbagai aspek sistem, termasuk modularitas. Dia memberikan ceramah yang sangat panjang (2 jam) , jam pertama yang merupakan pengantar menyeluruh untuk bahasa, termasuk kisah modularitas. Bab 2 Platform Pemrograman Newspeak mencakup modularitas. Jika Anda membaca Newspeak di Squeak - Panduan untuk yang Bingung (alias Newspeak-101) , Anda dapat merasakan sistem tersebut. Newspeak oleh Contoh adalah dokumen hidup (yaitu sedang berjalan di dalam port Newspeak-on-ECMASCript, setiap baris kode dapat diedit, setiap hasil dapat diperiksa) menunjukkan sintaks dasar.

Tapi sungguh, Anda harus bermain-main dengannya. Ini sangat berbeda dari semua bahasa utama dan bahkan sebagian besar bahasa non-mainstream yang sulit untuk dijelaskan, harus dialami.

Jörg W Mittag
sumber
3
Meh Melarang penggunaan keadaan statis dan keadaan global, dan Anda bisa mengatakan ini tentang hampir semua bahasa pemrograman modern.
Robert Harvey
Penasaran, banyak dari kontainer injeksi buatan tangan saya adalah pabrik statis. Tidak pernah menganggap itu sebagai hal yang buruk sebelumnya.
candied_orange
@ Jorg Bagaimana pun Anda bisa mencadangkan jawaban ini sedikit lagi? Saya telah googled "injeksi ketergantungan koran" dan muncul kosong. Hal terdekat yang bisa saya temukan adalah ini: news.ycombinator.com/item?id=9620561
candied_orange
@CandiedOrange: Saya sedang dalam proses memperluas jawaban tetapi kemudian "dunia nyata" mengganggu. Apakah itu lebih baik?
Jörg W Mittag
3
@ JörgWMittag Omong kosong! Yah itu pasti "lebih". Tunggu sementara saya mengevaluasi "lebih baik". Mungkin perlu kekuatan kunjungan kamar mandi untuk melewati ini.
candied_orange
7

Bahasa Pemrograman Wake dirancang untuk menggunakan injeksi ketergantungan. Pada dasarnya, ini memiliki kerangka injeksi ketergantungan yang setara dengan bahasa itu sendiri. Kelas mendefinisikan parameter yang mereka needdan providekompiler menghubungkan semuanya.

Winston Ewert
sumber
6

Ini bukan bahasa yang praktis berguna, tetapi sistem yang dijelaskan dalam makalah ini. Memiliki efek yang menarik: ini memungkinkan Anda untuk menulis kelas abstrak menggunakan kelas / antarmuka abstrak (termasuk instantiating mereka) Kelas Anda kemudian dapat dibuat konkret dengan mengganti subkelas dari setiap kelas abstrak yang Anda gunakan pada titik instantiation. Melakukan hal itu menghilangkan perlunya injeksi ketergantungan pada setidaknya kasus sederhana, misalnya (menggunakan versi hipotetis Java yang diperluas dengan fitur ini) kita dapat mengambil kode ini:

public interface I {
    void something ();
)

public class Concrete implements I {
    public void something () { ... }
}

public class Client {
    I myI;
    public Client (I injected) { myI = injected; }
    ...
}

...

    Client c = new Client (new Concrete());
    ...

dan ganti Klien dan penggunaannya dengan:

public class Client {
   I myI = new I();
   ...
}

   Client c = new Client { I -> Concrete } ();

Perhatikan bahwa ini menyederhanakan titik penggunaan ketergantungan, bukan penciptaan. Ini juga memungkinkan kita untuk menghindari pola Pabrik (sebagai yang baru saya dapat dibuat sesuai permintaan kapan saja kita mau).

Jules
sumber
Menarik. Ini mengingatkan saya pada Scala's Type Members, yang juga dapat diganti dalam subclass, dan dibiarkan abstrak dalam superclass. Abstrak Anggota Type dikombinasikan dengan Self-Type Annotations membentuk dasar dari pendekatan Scala terhadap modularitas dan injeksi ketergantungan. Saya sama sekali tidak terkejut bahwa makalah ini telah dikutip oleh Martin Odersky , perancang Scala, dan Gilad Bracha , perancang Newspeak.
Jörg W Mittag
0

Saya belum menggunakannya, tetapi tagline resmi bahasa pemrograman Plastik adalah " Apa yang terjadi jika Anda mengambil injeksi ketergantungan dan memanggangnya menjadi bahasa pemrograman? ". Sepertinya cukup menarik

B1CL0PS
sumber