Tür Çıkarımıyla Otomatik Downcasting


11

Java'da, bir değişkeni yok etmek için açıkça yayınlamanız gerekir

public class Fruit{}  // parent class
public class Apple extends Fruit{}  // child class

public static void main(String args[]) {
    // An implicit upcast
    Fruit parent = new Apple();
    // An explicit downcast to Apple
    Apple child = (Apple)parent;
}

Java'nın herhangi bir tür çıkarımda bulunmaması dışında, bu gereksinimin herhangi bir nedeni var mı?

Yeni bir dilde otomatik downcasting uygulayan bir "gotchas" var mı?

Örneğin:

Apple child = parent; // no cast required 

Derleyici, indirilen nesnenin her zaman doğru türden olduğunu çıkarabilirse, downcast'i açıkça ifade edemeyeceğinizi söylüyorsunuz? Ancak daha sonra derleyici sürümüne ve bazı programlar ne kadar tür çıkarım yapabileceğine bağlı olarak geçerli olmayabilir ... inferencer türündeki hatalar, geçerli programların yazılmasını engelleyebilir vb ... bazı özel tanıtmak mantıklı değildir bir çok faktöre bağlı olarak, kullanıcılara her sürümde hiçbir neden olmadan dökümler eklemeye veya çıkarmaya devam etmeleri sezgisel olmayacaktır.
Bakuriu

Yanıtlar:


24

Yayınlar her zaman başarılı olur.

Nesne çalışma zamanı türü, dökümde kullanılan türün bir alt türü olmadığında, aşağı yayınlar bir çalışma zamanı hatasına neden olabilir.

İkincisi tehlikeli bir işlem olduğundan, çoğu yazılan programlama dili programcının bunu açıkça istemesini gerektirir. Aslında, programcı derleyiciye "bana güven, daha iyi biliyorum - bu zamanında iyi olacak" diyor.

Tip sistemleri söz konusu olduğunda, upcasts derleyiciye ispat yükünü koyuyor (statik olarak kontrol etmek zorunda), downcasts ispat yükünü programcıya koyuyor (bu konuda çok düşünmek zorunda).

Uygun şekilde tasarlanmış bir programlama dilinin, downcast'leri tamamen yasaklayacağı ya da isteğe bağlı bir türün döndürülmesi gibi güvenli döküm alternatifleri sağlayabileceği iddia edilebilir Option<T>. Bununla birlikte, birçok yaygın dil, Tbaşka türlü bir hata döndürmek ve yükseltmek için daha basit ve daha pragmatik bir yaklaşım seçti .

Özel örneğinizde, derleyici parent, aslında Applebasit bir statik analiz yoluyla ortaya çıkacak ve örtülü yayınlamaya izin verecek şekilde tasarlanmış olabilir . Ancak, genel olarak sorun kararsızdır, bu yüzden derleyicinin çok fazla sihir yapmasını bekleyemeyiz.


1
Sadece referans olarak, seçeneklere indirgenen bir dil örneği Rust'dur, ancak bunun nedeni gerçek mirasa sahip olmaması, sadece bir "herhangi bir tür" olmasıdır .
Kroltan

3

Genellikle, derleyicinin bir şeyin türü hakkında sahip olduğu statik olarak bilinen bilgi, bildiğinizden (veya en azından umarım) daha az spesifik olduğunda, küçümseme yapmaktır.

Örneğiniz gibi durumlarda, nesne bir olarak yaratıldı Appleve daha sonra bu bilgi, referansı bir değişken türünde saklayarak atıldı Fruit. Sonra Appletekrar aynı referansı kullanmak istersiniz .

Bilgiler yalnızca "yerel olarak" atıldığından, derleyici , bildirilen türü olmasına rağmen parentgerçekten bir olan bilgiyi koruyabilirdi .AppleFruit

Ama genellikle kimse bunu yapmaz. Bir oluşturmak Appleve bir olarak kullanmak istiyorsanız Apple, bunu bir Appledeğişkende değil , bir değişkende Fruitsaklarsınız.

Eğer sahip olduğunuzda Fruitve bunu kullanmak istediğinizde , genellikle her türlü dönüşü sağlayabilecek bazı yollarla Appleelde ettiğiniz Fruitanlamına gelir , ancak bu durumda bunun bir olduğunu bilirsiniz . Hemen hemen her zaman onu inşa etmediniz, başka bir kodla geçtiniz.FruitApple

Bunun bariz bir örneği, parseFruit"elma", "portakal", "limon" vb. Gibi dizeleri uygun alt sınıfa çevirebilecek bir fonksiyonum varsa ; Genellikle bu işlevi çeşit döndürdüğünü yaklaşık biz (ve derleyici) bilebiliriz Fruitama ararsanız parseFruit("apple")o zaman ben en bir arayacaktım biliyoruz Appleve kullanmak isteyebilirsiniz Appleı downcast böylece, yöntemleri.

Yine yeterince akıllı bir derleyici , burada parseFruitsabit bir kodla çağırdığım için kaynak kodunu satır içine alarak anlayabiliyordu (başka bir modülde değilse ve Java gibi ayrı bir derlememiz yoksa). Ancak, dinamik bilgileri içeren daha karmaşık örneklerin derleyicinin doğrulaması için daha zor (hatta imkansız!) Olabileceğini kolayca görebilmelisiniz.

Gerçekçi kod downcast'leri genellikle derleyicinin downcast'in jenerik yöntemler kullanarak güvenli olduğunu doğrulayamadığı ve downcasting ile geri almaya çalıştığımız aynı tür bilgileri atarak bir upcast'i takip eden gibi basit durumlarda değil.


3

Çizgiyi nerede çizmek istediğinizle ilgili. Örtülü downcast'in geçerliliğini algılayacak bir dil tasarlayabilirsiniz:

public static void main(String args[]) { 
    // An implicit upcast 
    Fruit parent = new Apple();
    // An implicit downcast to Apple 
    Apple child = parent; 
}

Şimdi bir yöntem çıkaralım:

public static void main(String args[]) { 
    // An implicit upcast 
    Fruit parent = new Apple();
    eat(parent);
}
public static void eat(Fruit parent) { 
    // An implicit downcast to Apple 
    Apple child = parent; 
}

Hala iyiyiz. Statik analiz çok daha zordur, ancak yine de mümkündür.

Ama sorun ikinci kişinin ortaya çıkmasına neden oluyor:

public static void causeTrouble() { 
    // An implicit upcast 
    Fruit trouble = new Orange();
    eat(trouble);
}

Şimdi, hatayı nerede yükseltmek istiyorsunuz? Bu bir ikilem yaratır, sorunun var olduğunu söyleyebiliriz Apple child = parent;, ama bu "Ama daha önce işe yaradı" ile çürütülebilir. Öte yandan, ekleme eat(trouble);soruna neden oldu ", ancak polimorfizmin bütün noktası buna tam olarak izin vermektir.

Bu durumda, programcının bazı işlerini yapabilirsiniz, ancak bunu tamamen yapamazsınız. Vazgeçmeden ne kadar ilerlerseniz, neyin yanlış gittiğini açıklamak o kadar zor olacaktır. Bu nedenle, hataları erken raporlama ilkesine göre mümkün olan en kısa sürede durdurmak daha iyidir.

BTW, Java'da tanımladığınız downcast aslında bir downcast değildir. Bu, elmaları da portakallara dökebilen genel bir dökümdür. Yani, teknik olarak konuşursak @ chi'nin fikri zaten burada, Java'da downcasts yok, sadece "everycasts". Sonuç türü, argüman türünden aşağı yönde bulunamadığında derleme hatası atacak özel bir downcast operatörü tasarlamak mantıklı olacaktır. Programcıların bunu çok iyi bir neden olmadan kullanmasını engellemek için "everycast" in kullanımını çok daha zor hale getirmek iyi bir fikir olacaktır. C ++ 'ın XXXXX_cast<type>(argument)sözdizimi akla geliyor.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.