Mengapa mengikat bukan fitur asli di sebagian besar bahasa?


11

IMHO mengikat suatu variabel ke variabel lain atau ekspresi adalah skenario yang sangat umum dalam matematika. Bahkan, pada awalnya, banyak siswa berpikir operator penugasan (=) adalah semacam ikatan. Tetapi di sebagian besar bahasa, pengikatan tidak didukung sebagai fitur asli. Dalam beberapa bahasa seperti C #, mengikat didukung dalam beberapa kasus dengan beberapa persyaratan terpenuhi.

Tetapi IMHO menerapkan ini sebagai fitur asli semudah mengubah kode-berikut

int a,b,sum;
sum := a + b;
a = 10;
b = 20;
a++;

untuk ini-

int a,b,sum;
a = 10;
sum = a + b;
b = 20;
sum = a + b;
a++;
sum = a + b;

Berarti menempatkan instruksi yang mengikat sebagai tugas setelah setiap instruksi mengubah nilai dari salah satu variabel yang terkandung dalam ekspresi di sisi kanan. Setelah ini, memotong instruksi yang berlebihan (atau optimisasi dalam perakitan setelah kompilasi) akan dilakukan.

Jadi, mengapa tidak didukung secara asli di sebagian besar bahasa. Khususnya dalam C-family bahasa?

Memperbarui:

Dari pendapat yang berbeda, saya pikir saya harus mendefinisikan usulan ini "mengikat" lebih tepatnya-

  • Ini adalah salah satu cara mengikat. Hanya jumlah yang terikat ke a + b, bukan sebaliknya.
  • Lingkup pengikatannya adalah lokal.
  • Setelah pengikatan dibuat, itu tidak dapat diubah. Artinya, begitu jumlah terikat ke + b, jumlah akan selalu menjadi + b.

Semoga idenya lebih jelas sekarang.

Pembaruan 2:

Saya hanya ingin fitur P # ini . Semoga itu akan ada di sana di masa depan.


14
Mungkin karena pengembang kompiler yang telah mencoba menambahkan fitur ini ke C telah diburu dan ditembak.
Pete Wilson

Saya berbicara tentang pengikatan satu arah (kanan ke kiri), bukan dua arah. Pengikatan akan selalu mempengaruhi hanya satu variabel.
Gulshan

2
Untuk apa nilainya, sudut pandang terprogram semacam ini terus meningkat: pemrograman reaktif. Apa yang Anda gambarkan juga diwujudkan oleh program spreadsheet seperti Excel, yang pada dasarnya adalah pengikatan data (atau pemrograman reaktif) pada steroid.
Mike Rosenblum

11
Ini mungkin bukan fitur dari "kebanyakan" bahasa pemrograman, tetapi ini adalah fitur dari bahasa pemrograman yang paling populer : Excel.
Jörg W Mittag

2
Berkat pohon ekspresi, ini sudah mungkin di C #. Saya ngeblog tentang hal itu kemarin: happynomad121.blogspot.com/2013/01/...
HappyNomad

Jawaban:


9

Anda membingungkan pemrograman dengan matematika. Bahkan pemrograman fungsional tidak sepenuhnya matematika, meskipun meminjam banyak ide dan mengubahnya menjadi sesuatu yang dapat dieksekusi dan digunakan untuk pemrograman. Pemrograman imperatif (yang mencakup sebagian besar bahasa yang terinspirasi C, pengecualian yang terkenal adalah JavaScript dan tambahan yang lebih baru untuk C #) hampir tidak ada hubungannya dengan matematika, jadi mengapa variabel ini harus berperilaku seperti variabel dalam matematika?

Anda harus mempertimbangkan bahwa ini tidak selalu seperti yang Anda inginkan. Begitu banyak orang digigit oleh penutupan yang dibuat dalam loop khusus karena penutupan menjaga variabel, bukan salinan nilainya di beberapa titik, yaitu for (i = 0; i < 10; i++) { var f = function() { return i; }; /* store f */ }membuat sepuluh penutupan yang kembali 9. Jadi, Anda perlu mendukung kedua cara - yang berarti dua kali lipat dari biaya pada "anggaran kompleksitas" dan operator lain. Mungkin juga ketidaksesuaian antara kode yang menggunakan ini dan kode yang tidak menggunakan ini, kecuali jika sistem jenisnya cukup canggih (lebih rumit!).

Juga, menerapkan ini secara efisien sangat sulit. Implementasi naif menambah overhead konstan untuk setiap tugas, yang dapat bertambah dengan cepat dalam program-program penting. Implementasi lain mungkin menunda pembaruan sampai variabel dibaca, tetapi itu secara signifikan lebih kompleks dan masih memiliki overhead bahkan ketika variabel tidak pernah dibaca lagi. Kompiler yang cukup pintar dapat mengoptimalkan keduanya, tetapi kompiler yang cukup pintar jarang dan membutuhkan banyak upaya untuk membuat (perhatikan bahwa itu tidak selalu sesederhana seperti dalam contoh Anda, terutama ketika variabel memiliki cakupan luas dan multithreading ikut bermain!).

Perhatikan bahwa pemrograman reaktif pada dasarnya tentang ini (sejauh yang saya tahu), jadi memang ada. Hanya saja tidak begitu umum dalam bahasa pemrograman tradisional. Dan saya yakin beberapa masalah implementasi yang saya sebutkan di paragraf sebelumnya diselesaikan.


Saya pikir Anda memiliki 3 poin - 1) Ini bukan pemrograman gaya imperatif. Saat ini sebagian besar bahasa tidak terbatas pada beberapa paradigma. Saya tidak berpikir ini di luar gaya paradigma ini adalah logika yang baik. 2) Kompleksitas. Anda telah menunjukkan banyak hal kompleks yang sudah didukung. Kenapa tidak yang ini? Saya tahu operator yang hampir tidak digunakan sedang didukung. Dan ini adalah fitur yang sama sekali baru. Jadi bagaimana bisa ada masalah kompatibilitas. Saya tidak mengubah atau menghapus sesuatu. 3) Implementasi Keras. Saya pikir kompiler hari ini sudah memiliki kemampuan untuk mengoptimalkan ini.
Gulshan

1
@ Gulshan: (1) Tidak ada paradigma pemrograman matematika. FP dekat, tetapi FP relatif jarang dan bahasa FP tidak murni dengan variabel yang dapat berubah tidak memperlakukan variabel ini seolah-olah mereka berasal dari matematika. Paradigma satu di mana ini ada adalah pemrograman reaktif, tetapi pemrograman reaktif tidak dikenal atau digunakan secara luas (dalam bahasa pemrograman tradisional). (2) Semuanya memiliki biaya dan nilai kompleksitas. Ini memiliki biaya agak tinggi dan nilai IMHO relatif kecil kecuali dalam beberapa domain, jadi itu bukan hal pertama yang saya tambahkan ke bahasa saya kecuali secara khusus menargetkan domain ini.

Mengapa tidak memiliki satu alat lagi di dalam kotak kami? Setelah alat ada di sana, orang akan menggunakannya. Pertanyaan. Jika beberapa bahasa seperti C atau C ++ ingin mengimplementasikan fitur ini dan meminta pendapat Anda, akankah Anda berkata, "Jangan berikan. Karena itu akan terlalu sulit bagi Anda dan orang-orang akan mengacaukan ini."?
Gulshan

@ Gulshan: Mengenai (3): Tidak selalu (tidak untuk mengatakan, jarang) semudah dalam contoh Anda. Masukkan ke dalam lingkup global dan Anda tiba-tiba membutuhkan optimasi tautan-waktu. Kemudian tambahkan tautan dinamis, dan Anda bahkan tidak dapat melakukan apa pun pada waktu yang bersamaan. Anda membutuhkan compiler yang sangat cerdas dan sangat pandai runtime termasuk JIT untuk melakukannya dengan baik. Juga pertimbangkan jumlah penugasan di setiap program non-sepele. Baik Anda maupun saya tidak dapat menulis komponen ini. Paling tidak ada beberapa orang yang dapat dan tertarik pada subjek ini. Dan mereka mungkin memiliki hal-hal yang lebih baik untuk dilakukan.

@ Gulshan: Saya akan meminta mereka untuk tidak menambahkan fitur ke binatang yang sangat rumit C ++ sudah ada, atau saya akan meminta mereka untuk tidak mencoba menggunakan C untuk hal-hal di luar pemrograman sistem (yang bukan salah satu domain di mana ini sangat berguna ). Terlepas dari itu, saya semua untuk fitur baru yang menarik, tetapi hanya ketika ada cukup anggaran kompleksitas yang tersisa (banyak bahasa selalu kehabisan mereka) dan fitur berguna untuk apa bahasa dimaksudkan untuk dilakukan - seperti yang saya katakan sebelumnya, ada hanya beberapa domain tempat ini berguna.

3

Sangat cocok dengan kebanyakan model pemrograman. Ini akan mewakili semacam tindakan yang benar-benar tidak terkendali pada jarak, di mana orang dapat menghancurkan nilai ratusan atau ribuan variabel dan bidang objek dengan membuat satu tugas.


Maka saya akan menyarankan untuk membuat aturan bahwa, variabel terikat yaitu sisi kiri tidak akan diubah dengan cara lain. Dan apa yang saya bicarakan hanyalah satu cara mengikat, bukan dua arah. Jika Anda mengikuti pertanyaan saya, Anda bisa melihatnya. Jadi, tidak ada variabel lain yang akan terpengaruh.
Gulshan

Itu tidak masalah. Setiap kali Anda menulis aatau b, Anda perlu mempertimbangkan dampaknya pada setiap tempat yang sumdigunakan, dan setiap tempat yang Anda baca, sumAnda perlu mempertimbangkan apa yang sedang adan bsedang dilakukan. Untuk kasus non-sepele, itu bisa menjadi rumit, terutama jika ekspresi aktual terikat sumdapat berubah saat runtime.
jprete

Saya akan merekomendasikan aturan bahwa ekspresi pengikatan tidak dapat diubah setelah pengikatan dilakukan. Tugas bahkan tidak akan mungkin. Ini akan menjadi seperti semi-konstan yang terikat pada sebuah ekspresi. Itu berarti, setelah jumlah terikat ke + b, itu akan selalu menjadi + b, selama sisa program.
Gulshan

3

Ya, saya punya firasat yang mengganggu bahwa pemrograman reaktif mungkin keren di lingkungan Web2.0. Mengapa perasaan? Yah, saya punya satu halaman ini yang sebagian besar tabel yang berubah sepanjang waktu dalam menanggapi peristiwa onClick sel-tabel. Dan klik sel sering berarti mengubah kelas semua sel dalam satu kolom atau baris; dan itu berarti loop getRefToDiv () yang tak berujung, dan sejenisnya, untuk menemukan sel terkait lainnya.

TKI, banyak dari ~ 3000 baris JavaScript yang saya tulis tidak menemukan objek. Mungkin pemrograman reaktif dapat melakukan semua itu dengan biaya kecil; dan pada pengurangan besar dalam garis kode.

Apa yang kalian pikirkan tentang itu? Ya, saya perhatikan bahwa meja saya memiliki banyak fitur seperti spreadsheet.


3

Saya pikir apa yang Anda gambarkan disebut Spreadsheet:

A1=5
B1=A1+1
A1=6

... lalu mengevaluasi B1pengembalian 7.

EDIT

Bahasa C kadang-kadang disebut "perakitan portabel". Ini adalah bahasa imperatif, sedangkan spreadsheet, dll., Adalah bahasa deklaratif. Mengatakan B1=A1+1dan berharap B1untuk mengevaluasi kembali ketika Anda berubahA1 jelas bersifat deklaratif. Bahasa deklaratif (yang bahasa fungsionalnya merupakan himpunan bagian) umumnya dianggap bahasa tingkat yang lebih tinggi, karena mereka lebih jauh dari cara kerja perangkat keras.

Pada catatan terkait, bahasa otomatisasi seperti logika tangga biasanya bersifat deklaratif. Jika Anda menulis anak tangga logika yang mengatakan output A = input B OR input Citu akan mengevaluasi kembali pernyataan itu terus-menerus, dan Adapat berubah kapan saja Batau Cberubah. Bahasa otomatisasi lain seperti Diagram Blok Fungsi (yang mungkin Anda kenal jika Anda pernah menggunakan Simulink) juga bersifat deklaratif, dan mengeksekusi secara terus menerus.

Beberapa peralatan otomasi (tertanam) diprogram dalam C, dan jika itu adalah sistem waktu-nyata, mungkin memiliki loop tak terbatas yang mengeksekusi ulang logika berulang kali, mirip dengan bagaimana logika tangga dijalankan. Dalam hal ini, di dalam loop utama Anda, Anda dapat menulis:

A = B || C;

... dan karena itu dieksekusi sepanjang waktu, itu menjadi deklaratif. Aakan terus dievaluasi kembali.


3

C, C ++, Objective-C:

Blok menyediakan fitur penjilidan yang Anda cari.

Dalam contoh Anda:

jumlah: = a + b;

Anda menyetel sumke ekspresi a + bdalam konteks di mana adan bmerupakan variabel yang ada. Anda dapat melakukannya dengan "blok" (alias penutupan, alias ekspresi lambda) di C, C ++, atau Objective-C dengan ekstensi Apple (pdf):

__block int a = 0, b = 0;           // declare a and b
int (^sum)(void);                   // declare sum
sum = ^(void){return a + b;};       // sum := a + b

Ini mengatur sumke blok yang mengembalikan jumlah a dan b. The __blockkelas penyimpanan specifier menunjukkan bahwa adan bdapat berubah. Diberikan di atas, kita dapat menjalankan kode berikut:

printf("a=%d\t b=%d\t sum=%d\n", a, b, sum());
a = 10;
printf("a=%d\t b=%d\t sum=%d\n", a, b, sum());
b = 32;
printf("a=%d\t b=%d\t sum=%d\n", a, b, sum());
a++;
printf("a=%d\t b=%d\t sum=%d\n", a, b, sum());

dan dapatkan hasilnya:

a=0      b=0     sum=0
a=10     b=0     sum=10
a=10     b=32    sum=42
a=11     b=32    sum=43

Satu-satunya perbedaan antara menggunakan blok dan "ikatan" yang Anda usulkan adalah pasangan kurung kosong sum(). Perbedaan antara sumdan sum()adalah perbedaan antara ekspresi dan hasil dari ekspresi itu. Perhatikan bahwa, seperti halnya fungsi, tanda kurung tidak harus kosong - blok dapat mengambil parameter seperti halnya fungsi.


2

C ++

Diperbarui menjadi generik. Parameterisasi pada tipe pengembalian dan input. Dapat menyediakan operasi biner apa pun yang memenuhi tipe parameter. Kode menghitung hasil sesuai permintaan. Mencoba untuk tidak menghitung ulang hasil jika bisa lolos begitu saja. Keluarkan ini jika ini tidak diinginkan (karena efek samping, karena benda yang terkandung besar, karena apa pun.)

#include <iostream>

template <class R, class A, class B>
class Binding {
public:
    typedef R (*BinOp)(A, B);
    Binding (A &x, B &y, BinOp op)
        : op(op)
        , rx(x)
        , ry(y)
        , useCache(false)
    {}
    R value () const {
        if (useCache && x == rx && y == ry) {
            return cache;
        }
        x = rx;
        y = ry;
        cache = op(x, y);
        useCache = true;
        return cache;
    }
    operator R () const {
        return value();
    }
private:
    BinOp op;
    A &rx;
    B &ry;
    mutable A x;
    mutable B y;
    mutable R cache;
    mutable bool useCache;
};

int add (int x, int y) {
    return x + y;
}

int main () {
    int x = 1;
    int y = 2;
    Binding<int, int, int> z(x, y, add);
    x += 55;
    y *= x;
    std::cout << (int)z;
    return 0;
}

Meskipun tidak menjawab pertanyaan, saya suka ide yang Anda sampaikan. Bisakah ada versi yang lebih umum?
Gulshan

@Gulshan: Diperbarui
Thomas Eding
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.