it-swarm-id.com

Mengapa bahasa yang dikelola dengan memori seperti Java, Javascript, dan C # mempertahankan kata kunci `baru`?

Kata kunci new dalam bahasa seperti Java, Javascript, dan C # menciptakan turunan baru dari suatu kelas.

Sintaks ini tampaknya telah diwarisi dari C++, di mana new digunakan secara khusus untuk mengalokasikan instance baru dari kelas pada heap, dan mengembalikan pointer ke instance baru. Dalam C++, ini bukan satu-satunya cara untuk membangun objek. Anda juga dapat membuat objek di stack, tanpa menggunakan new - dan pada kenyataannya, cara membangun objek ini jauh lebih umum di C++.

Jadi, berasal dari latar belakang C++, kata kunci new dalam bahasa seperti Java, Javascript, dan C # tampak alami dan jelas bagi saya. Kemudian saya mulai belajar Python, yang tidak memiliki kata kunci new. Dalam Python, sebuah instance dibangun hanya dengan memanggil konstruktor, seperti:

f = Foo()

Pada awalnya, ini terasa agak aneh bagi saya, sampai terlintas dalam benak saya bahwa tidak ada alasan untuk Python untuk memiliki new, karena semuanya adalah objek sehingga tidak perlu untuk disambiguasi antara berbagai sintaks konstruktor.

Tapi kemudian saya berpikir - apa gunanya new di Jawa? Mengapa kita mengatakan Object o = new Object();? Mengapa tidak hanya Object o = Object();? Dalam C++ pasti ada kebutuhan untuk new, karena kita perlu membedakan antara mengalokasikan pada heap dan mengalokasikan pada stack, tetapi dalam Java semua objek dibangun pada heap, jadi mengapa bahkan memiliki kata kunci new? Pertanyaan yang sama dapat ditanyakan untuk Javascript. Dalam C #, yang saya tidak terlalu kenal, saya pikir new mungkin memiliki beberapa tujuan dalam hal membedakan antara tipe objek dan tipe nilai, tapi saya tidak yakin.

Bagaimanapun, menurut saya banyak bahasa yang muncul setelah C++ hanya "mewarisi" kata kunci new - tanpa benar-benar membutuhkannya. Ini hampir seperti kata kunci peninggalan . Kami tampaknya tidak membutuhkannya untuk alasan apa pun, namun itu ada di sana.

Pertanyaan: Apakah saya benar tentang ini? Atau adakah alasan kuat bahwa new perlu menggunakan C++ - bahasa yang dikelola dengan memori yang diinspirasi seperti Java, Javascript dan C # tetapi bukan Python?

141
Channel72

Pengamatan Anda benar. C++ adalah binatang yang rumit, dan kata kunci new digunakan untuk membedakan antara sesuatu yang dibutuhkan delete nanti dan sesuatu yang akan secara otomatis direklamasi. Dalam Java dan C #, mereka menjatuhkan kata kunci delete karena pemulung akan mengurusnya untuk Anda.

Masalahnya kemudian mengapa mereka menyimpan kata kunci new? Tanpa berbicara dengan orang-orang yang menulis bahasa itu agak sulit untuk dijawab. Tebakan terbaik saya tercantum di bawah ini:

  • Itu semantik benar. Jika Anda terbiasa dengan C++, Anda tahu bahwa kata kunci new membuat objek di heap. Jadi, mengapa mengubah perilaku yang diharapkan?
  • Itu menarik perhatian pada fakta bahwa Anda adalah instantiating objek daripada memanggil metode. Dengan rekomendasi gaya kode Microsoft, nama metode dimulai dengan huruf kapital sehingga dapat terjadi kebingungan.

Ruby berada di antara Python dan Java/C # dalam penggunaannya new. Pada dasarnya Anda membuat instance objek seperti ini:

f = Foo.new()

Itu bukan kata kunci, ini metode statis untuk kelas. Artinya adalah jika Anda menginginkan singleton, Anda dapat mengesampingkan implementasi default new() untuk mengembalikan instance yang sama setiap waktu. Ini belum tentu direkomendasikan, tetapi itu mungkin.

97
Berin Loritsch

Singkatnya, Anda benar. Kata kunci baru berlebihan dalam bahasa seperti Java dan C #. Berikut adalah beberapa wawasan dari Bruce Eckel yang merupakan anggota C++ Standard Comitee pada 1990-an dan kemudian menerbitkan buku-buku tentang Jawa: http: //www.artima.com/weblogs/viewpost.jsp?thread=260578

perlu ada beberapa cara untuk membedakan objek tumpukan dari objek tumpukan. Untuk mengatasi masalah ini, kata kunci baru diambil dari Smalltalk. Untuk membuat objek stack, Anda cukup mendeklarasikannya, seperti pada Cat x; atau, dengan argumen, Cat x ("mittens") ;. Untuk membuat objek tumpukan, Anda menggunakan yang baru, seperti pada Cat baru; atau Kucing baru ("sarung tangan") ;. Mengingat kendala, ini adalah solusi yang elegan dan konsisten.

Masukkan Java, setelah memutuskan bahwa semuanya C++ dilakukan dengan buruk dan terlalu rumit. Ironi di sini adalah bahwa Java dapat dan memang membuat keputusan untuk membuang alokasi tumpukan (dengan jelas mengabaikan bencana primitif, yang telah saya bahas di tempat lain). Dan karena semua objek dialokasikan pada heap, tidak perlu membedakan antara stack dan alokasi heap. Mereka bisa dengan mudah mengatakan Cat x = Cat () atau Cat x = Cat ("mittens"). Atau bahkan lebih baik, inferensi tipe gabungan untuk menghilangkan pengulangan (tapi itu - - dan fitur-fitur lain seperti penutupan - akan memakan waktu "terlalu lama" sehingga kita terjebak dengan versi biasa-biasa saja dari Java sebagai gantinya; tipe inferensi telah dibahas tetapi saya akan meletakkan peluang itu tidak akan terjadi. Dan seharusnya tidak, mengingat masalah dalam menambahkan fitur baru ke Java).

87

Ada dua alasan yang dapat saya pikirkan:

  • new membedakan antara objek dan primitif
  • Sintaks new sedikit lebih mudah dibaca (IMO)

Yang pertama sepele. Saya pikir tidak sulit untuk membedakan keduanya. Yang kedua adalah contoh dari poin OP, yaitu new adalah semacam redundan.

Mungkin ada konflik namespace; mempertimbangkan:

public class Foo {
   Foo() {
      // Constructor
   }
}

public class Bar {
   public static void main(String[] args) {
      Foo f = Foo();
   }

   public Foo Foo() {
      return Foo();
   }
}

Anda bisa, tanpa terlalu banyak imajinasi, dengan mudah berakhir dengan panggilan rekursif tanpa batas. Kompiler harus menegakkan kesalahan "Nama fungsi sama dengan objek". Ini benar-benar tidak ada salahnya, tetapi jauh lebih mudah untuk menggunakan new, yang menyatakan, Go to the object of the same name as this method and use the method that matches this signature. Java adalah bahasa yang sangat sederhana untuk diurai, dan saya curiga ini membantu di area itu.

15
Michael K

Java, misalnya, masih memiliki dikotomi C++: tidak cukup semuanya adalah objek. Java memiliki tipe bawaan (mis., char dan int) yang tidak harus dialokasikan secara dinamis.

Itu tidak berarti bahwa new benar-benar diperlukan dalam Java - himpunan jenis yang tidak perlu dialokasikan secara dinamis telah diperbaiki dan diketahui. Ketika Anda mendefinisikan sebuah objek, kompilator dapat mengetahui (dan, pada kenyataannya, memang tahu) apakah itu nilai sederhana yang char atau objek yang harus dialokasikan secara dinamis.

Saya akan menahan diri (lagi-lagi) untuk tidak memberi pendapat tentang apa artinya ini tentang kualitas desain Java (atau ketiadaannya, tergantung pada kasusnya).

10
Jerry Coffin

Dalam JavaScript Anda memerlukannya karena konstruktornya terlihat seperti fungsi normal, jadi bagaimana seharusnya JS tahu bahwa Anda ingin membuat objek baru jika bukan karena kata kunci baru?

Menjalankan fungsi JavaScript dengan operator new menghasilkan perilaku yang berbeda daripada menjalankan fungsi tanpa operator new.

Sebagai contoh:

Date()       //Returns a string

new Date()   //Returns a Date object
function foo() {};

foo()        //Returns `undefined`

new foo()    //Returns an empty object
10
user281377

Saya suka banyak jawaban dan hanya ingin menambahkan ini:
Ini membuat pembacaan kode lebih mudah
Bukannya situasi ini akan sering terjadi, tetapi anggap Anda menginginkan metode dalam nama kata kerja yang memiliki nama yang sama dengan kata benda. C # dan bahasa lain secara alami memiliki Word object dicadangkan. Tetapi jika tidak maka akan Foo = object() menjadi hasil dari pemanggilan metode objek atau akankah instantiating objek baru. Semoga kata bahasa tanpa kata kunci new memiliki perlindungan terhadap situasi ini, tetapi dengan memiliki persyaratan kata kunci new sebelum memanggil konstruktor, Anda mengizinkan keberadaan metode dengan nama yang sama dengan Sebuah Objek.

4
Kavet Kerek

Menariknya, VB tidak membutuhkannya - perbedaan antara

Dim f As Foo

yang mendeklarasikan variabel tanpa menugaskannya, setara dengan Foo f; di C #, dan

Dim f As New Foo()

yang mendeklarasikan variabel dan memberikan instance baru dari kelas, yang setara dengan var f = new Foo(); dalam C #, adalah perbedaan substantif. Di pre-.NET VB, Anda bahkan dapat menggunakan Dim f As Foo Atau Dim f As New Foo - karena tidak ada kelebihan pada konstruktor.

4
Richard Gadsden

Ada banyak hal peninggalan dalam banyak bahasa pemrograman. Kadang-kadang ada di sana dengan desain (C++ dirancang agar kompatibel dengan C), kadang-kadang, hanya ada di sana. Untuk contoh yang lebih mengerikan, pertimbangkan seberapa jauh pernyataan C switch yang rusak disebarkan.

Saya tidak tahu Javascript dan C # cukup baik untuk mengatakan, tapi saya tidak melihat alasan untuk new di Java kecuali bahwa C++ memilikinya.

3
David Thornley

Dalam C # itu memungkinkan jenis terlihat dalam konteks di mana mereka mungkin dikaburkan oleh anggota. Memungkinkan Anda untuk memiliki properti dengan nama yang sama dengan tipenya. Pertimbangkan yang berikut ini,

class Address { 
    public string Street { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string Zip { get; set; }
}

class Person {
    public string Name { get; set; }
    public Address Address { get; set; }

    public void ChangeStreet(string newStreet) {
        Address = new Address { 
            Street = newStreet, 
            City = Address.City,
            State = Address.State,
            Zip = Address.Zip
        };
    }
}

Perhatikan penggunaan new memungkinkan untuk menjadi jelas bahwa Address adalah Address mengetik bukan anggota Address. Ini memungkinkan anggota untuk memiliki nama yang sama dengan tipenya. Tanpa ini, Anda perlu awalan nama jenis untuk menghindari tabrakan nama, seperti CAddress. Ini sangat disengaja karena Anders tidak pernah menyukai notasi hungaria atau yang serupa dan ingin C # dapat digunakan tanpa itu. Fakta itu juga akrab adalah bonus ganda.

3
chuckj

Saya tidak yakin apakah Java desainer memikirkan hal ini tetapi ketika Anda menganggap objek sebagai catatan rekursif, maka Anda dapat membayangkan bahwa Foo(123) tidak mengembalikan objek tetapi fungsi yang fixpoint-nya adalah objek yang sedang dibuat (mis. fungsi yang akan mengembalikan objek jika diberikan sebagai argumen objek yang sedang dibangun). Dan tujuan new adalah untuk "mengikat simpul "dan kembalikan fixpoint itu. Dengan kata lain new akan membuat" objek-to-be "sadar akan selfnya.

Pendekatan semacam ini dapat membantu memformalkan pewarisan misalnya: Anda dapat memperluas fungsi-objek dengan fungsi-objek lain dan akhirnya memberikan mereka self yang umum dengan menggunakan new:

cp = new (Colored("Blue") & Line(0, 0, 100, 100))

Di sini & menggabungkan dua fungsi objek.

Dalam hal ini new dapat didefinisikan sebagai:

def new(objectFunction) {
    actualObject = objectFunction(actualObject)
    return actualObject
}
0
Aivar

Menariknya, dengan munculnya penerusan yang sempurna, non-penempatan new tidak diperlukan sama sekali di C++ juga. Jadi, bisa dibilang, itu tidak lagi diperlukan dalam bahasa yang disebutkan di atas.

0
DeadMG