Programlama dillerinde kalıtımdan çıkma


10

Kendi programlama dilimi geliştiriyorum. Genel amaçlı bir dildir (masaüstü için statik olarak yazılan Python'u düşünün, yani int x = 1;) bulut için tasarlanmamıştır.

Miras veya Mixins'e izin vermemenin uygun olduğunu düşünüyor musunuz? (kullanıcının en azından arayüze sahip olması durumunda)

Örneğin: Google Go, mirasa izin vermeyerek programlama topluluğunu şok eden bir sistem dili.

Yanıtlar:


4

Aslında, kalıtım kullanmanın giderek daha az olduğunu görüyoruz, çünkü (diğerleri arasında) sıkı bağlantıya yol açıyor.

Uygulama kalıtımı her zaman arayüz kalıtımı artı kompozisyon ile değiştirilebilir ve daha modern yazılım tasarımları kalıtımın kompozisyon lehine gittikçe daha az kullanılma yönüne girme eğilimindedir.

Bu nedenle evet , özellikle miras sağlamamak tamamen geçerli ve moda tasarım kararıdır.

Katmalar, diğer taraftan, hatta (henüz) bir ana akım dil özelliği değildir ve diller yok “mixin” adlı bir özellik sağlamak sıklıkla onun tarafından çok farklı şeyler anlıyoruz. Bunu sağlamaktan ya da vermekten çekinmeyin. Şahsen ben çok faydalı buluyorum ama doğru şekilde uygulamak çok zor olabilir.


13

Dilin diğer anlambiliminin de anlamsız olduğunu düşünmeden mirasın (ya da gerçekten herhangi bir özelliğin) gerekli olup olmadığı hakkında muhakeme; boşlukta tartışıyorsun.

İhtiyacınız olan şey tutarlı bir dil tasarım felsefesidir; dilin tasarlandığı sorunları zarif bir şekilde çözebilmesi gerekir. Bunu başarmak için model kalıtım gerektirebilir veya gerektirmeyebilir, ancak bunu büyük resim olmadan yargılamak zordur.

Örneğin, dilinizde birinci sınıf işlevler, kısmi işlev uygulaması, polimorfik veri türleri, tür değişkenleri ve genel türler varsa, klasik OOP kalıtımıyla sahip olduğunuz temelleri hemen hemen örtmüşsünüz, ancak farklı bir paradigma kullanırsınız.

Geç bağlama, dinamik yazma, özellik olarak yöntemler, esnek işlev bağımsız değişkenleri ve birinci sınıf işlevleriniz varsa, aynı temelleri, ancak yine farklı bir paradigma kullanarak kapsarsınız.

(Belirtilen iki paradigmaya örnek bulmak okuyucu için bir alıştırma olarak bırakılmıştır.)

Yani, istediğiniz semantiği düşünün, onlarla oynayın ve miras olmadan yeterli olup olmadıklarını görün. Değilse, karışıma miras atmaya karar verebilir veya başka bir şeyin eksik olduğuna karar verebilirsiniz.


9

Evet.

Özellikle diliniz dinamik olarak yazılmışsa, mirasa izin vermemenin iyi olduğunu düşünüyorum. Örneğin, temsilci seçme veya kompozisyon gibi benzer kodların yeniden kullanılmasını sağlayabilirsiniz. Örneğin, JavaScript'te herhangi bir miras olmadan bazı orta derecede karmaşık programlar yazdım - tamam, bu karmaşık değil :)). Temelde bazı fonksiyonlar metot olarak eklenmiş olarak cebirsel veri yapıları olarak nesneleri kullandım. Ayrıca bu nesneler üzerinde çalışan yöntemler olmayan bir grup fonksiyonum vardı .

Dinamik yazmanız varsa - ve bunu yaptığınızı varsayalım - miras olmadan da polimorfizme sahip olabilirsiniz. Ayrıca, çalışma zamanında nesnelere rasgele yöntemler eklemeye izin verirseniz, mixins gibi şeylere gerçekten ihtiyacınız olmaz.

İyi bir seçenek olduğunu düşündüğüm başka bir seçenek de JavaScript'i taklit etmek ve prototipler kullanmak. Bunlar sınıflardan daha basit ama aynı zamanda çok esnektir. Dikkate alınması gereken bir şey.

Yani, her şey anlattı, ben giderdim.


2
Genellikle kalıtımla ele alınan görevleri yerine getirmenin makul bir yolu olduğu sürece, devam edin. Sen (... önlemek kendini önyargı, hatta şimdiye kadar diğerlerinden solicit örnek problemlere olarak gidiş) emin olmak için, birkaç kullanım durumları denemek olabilir
comingstorm

Hayır Statik ve güçlü bir şekilde yazılmış, en üstte bahsedeceğim.
Christopher

Statik olarak yazıldığından, çalışma zamanında nesnelere rastgele yöntemler ekleyemezsiniz. Bununla birlikte, ördek yazmayı da yapabilirsiniz: bir örnek için Gosu protokollerine bakın. Yaz boyunca protokolleri biraz kullandım ve gerçekten faydalıydılar. Gosu'nun da gerçeklerden sonra sınıflara yöntem eklemenin bir yolu olan "geliştirmeleri" vardır. Bunun gibi bir şey de ekleyebilirsiniz.
Tikhon Jelvis

2
Lütfen, lütfen, lütfen, kalıtım ve kodun yeniden kullanımı ile ilgili. Kalıtımın kodun yeniden kullanımı için gerçekten kötü bir araç olduğu uzun zamandır bilinmektedir.
Jan Hudec

3
Kalıtım, kodun yeniden kullanımı için yalnızca bir araçtır. Genellikle çok iyi bir araçtır ve diğer zamanlarda korkunçtur. Kompozisyonun miras yerine tercih edilmesi, asla miras kullanılmaması anlamına gelmez.
Michael K

8

Evet, kalıtımdan kaçınmak son derece makul bir tasarım kararıdır.

Aslında, bazı son derece karmaşık ve bakımı zor kod üretebileceğinden, uygulama mirasını kaldırmak için çok iyi nedenler vardır. Hatta kalıtımı (tipik olarak çoğu OOP dilinde uygulandığı gibi) bir yanlışlık olarak görecek kadar ileri giderdim.

Örneğin Clojure, aynı sonuçları elde etmek için çok daha temiz bir şekilde kullanılabilen bir dizi dikey özellik (protokoller, veriler, işlevler, makrolar) sağlamayı tercih ederek uygulama mirası sağlamaz.

Burada çok zengin Hickey her biri için dil (dahil miras) ve hediyeler alternatifleri programlama karmaşıklık temel kaynaklarını tanımlayan bu genel konu üzerinde aydınlatarak tespit ettiklerini ortaya bir video: Basit kolay


Çoğu durumda, arayüz kalıtımı daha uygundur. Ancak, ılımlılıkla kullanılırsa, implentasyon kalıtım birçok kazan plakasının kaldırılmasına izin verebilir ve en zarif çözümdür. Sadece ortalama Python / JavaScript maymunundan daha akıllı ve daha dikkatli olan programcılar gerektirir.
Erik Alapää

4

VB6 sınıflarının kalıtımı desteklemediğini ilk gördüğümde (sadece arayüzler), bu beni gerçekten rahatsız etti (ve hala destekliyor).

Ancak, bu kadar kötü olmasının nedeni de yapıcı parametrelerine sahip olmamasıdır, bu nedenle normal bağımlılık enjeksiyonu (DI) yapamazsınız. DI'niz varsa, bu kalıtımdan daha önemlidir, çünkü kompozisyonu kalıtım yerine tercih etme ilkesini takip edebilirsiniz. Yine de kodu tekrar kullanmanın daha iyi bir yolu.

Yine de Mixins sahip değil misiniz? Bir arayüz uygulamak ve bu arayüzün tüm çalışmalarını bağımlılık enjeksiyonu yoluyla ayarlanan bir nesneye devretmek istiyorsanız, Mixins idealdir. Aksi takdirde, her yöntem ve / veya özelliği alt nesneye devretmek için tüm kazan plakası kodunu yazmanız gerekir. Ben çok (C # sayesinde) yapmak ve ben yapmak zorunda değildi keşke bir şey.


Evet, bu soruyu soran, kodun yeniden kullanılmasının çok faydalı olduğu SVG DOM uygulamasıdır.
Christopher

2

Başka bir yanıta katılmıyorum: hayır, daha fazla istediğiniz bir şeyle uyumsuz olduklarında özellikler atıyorsunuz. Java (ve diğer GC'd dilleri), tür güvenliğini daha fazla istediği için açık bellek yönetimini dışarı attı. Haskell mutasyon attı çünkü denklemsel akıl yürütme ve fantezi türleri daha fazlasını istiyordu. C bile, derleyici optimizasyonlarını daha fazla istediği için belirli türdeki takma ad ve diğer davranışları attı (veya yasadışı ilan etti).

Yani soru şu: Kalıtımdan daha fazlasını ne istiyorsun?


1
Yalnızca bu açık bellek yönetimi ve tür güvenliği tamamen ilişkisizdir ve kesinlikle uyumsuz değildir. Aynı şey mutasyon ve “fantezi tipleri” için de geçerlidir. Genel muhakemeye katılıyorum, ancak örnekleriniz oldukça kötü seçilmiş.
Konrad Rudolph

@KonradRudolph, bellek yönetimi ve tip güvenliği yakından ilişkilidir. A free/ deleteoperasyonu referansları geçersiz kılma olanağı verir; tür sisteminiz etkilenen tüm referansları izleyemezse, bu dili güvensiz hale getirir. Özellikle, ne C ne de C ++ tip güvenlidir. Onları kabul ettirmek için birinden diğerine (örneğin, doğrusal tipler veya ayırma kısıtlamaları) ödün verebileceğiniz doğrudur. Kesin olmak gerekirse, Java'nın belirli, basit bir tip sistemi ve sınırsız tahsis ile daha fazla tip güvenliği istediğini söylemeliydim .
Ryan Culpepper

Bu daha çok tip güvenliğini nasıl tanımladığınıza bağlıdır. Örneğin, derleme zamanı türü güvenliğinin (tamamen makul) tanımını alırsanız ve başvuru bütünlüğünün tür sisteminizin bir parçası olmasını istiyorsanız, Java da güvenli değildir ( nullbaşvurulara izin verdiği için ). Yasaklama freeoldukça keyfi bir ek kısıtlamadır. Özetle, bir dilin güvenli yazılıp yazılmadığı, dil güvenliği türüne göre dil güvenliği tanımınıza bağlıdır.
Konrad Rudolph

1
@Ryan: İşaretçiler mükemmel şekilde güvenlidir. Her zaman tanımlarına göre davranırlar. Onları nasıl sevdiğiniz olmayabilir, ancak her zaman nasıl tanımlandıklarına göre değişir. Onları olmayan bir şey olarak uzatmaya çalışıyorsunuz. Akıllı işaretçiler, C ++ 'ta bellek güvenliğini oldukça önemsiz bir şekilde garanti edebilir.
DeadMG

@KonradRudolph: Java'da her Treferans null, bir sınıfın ya da bir sınıfın nesnesini ifade eder T; nullçirkindir, ancak nullyukarıdaki tür değişmezliği bozmak yerine iyi tanımlanmış bir istisna oluşturur. C ++ ile kontrast: çağrıldıktan sonra delete, bir T*işaretçi artık Tnesneyi tutmayan belleğe işaret edebilir . Daha da kötüsü, bir ödevdeki o işaretçiyi kullanarak bir alan ataması yaparak, yakın bir adrese yerleştirilmişse, tamamen farklı bir sınıftaki bir nesnenin alanını güncelleyebilirsiniz. Bu terimin herhangi bir yararlı tanımı ile tip güvenliği değildir.
Ryan Culpepper

1

Hayır.

Bir temel dil özelliğini kaldırmak istiyorsanız, evrensel olarak hiçbir zaman, asla gerekli olmadığını (veya burada geçerli olmayan, uygulanamaz bir şekilde zor olduğunu) beyan edersiniz. Ve "asla" yazılım mühendisliğinde güçlü bir kelimedir. Böyle bir açıklama yapmak için çok güçlü bir gerekçe gerekir.


8
Bu neredeyse doğru değil: Java'nın tüm tasarımı, operatörün aşırı yüklenmesi, çoklu kalıtım ve manuel bellek yönetimi gibi özelliklerin kaldırılmasıyla ilgiliydi. Ayrıca, herhangi bir dil özelliğine "kutsal" davranmanın yanlış olduğunu düşünüyorum; bir özelliği kaldırmayı haklı göstermek yerine, eklemeyi haklı çıkarmalısınız - her dilin sahip olması gereken özellikleri düşünemiyorum .
Tikhon Jelvis

6
@TikhonJelvis: Bu yüzden Java korkunç bir dildir ve "GARBAGE-COLLECTED INherITANCE KULLANMA" dışında bir şey olmaması bunun bir numaralı nedenidir. Dil özelliklerinin gerekçelendirilmesi gerekir, katılıyorum, ancak bu temel bir dil özelliğidir - çok sayıda kullanışlı uygulamaya sahiptir ve DRY'yi ihlal etmeden programcı tarafından çoğaltılamaz.
DeadMG

1
@DeadMG vay! Oldukça güçlü bir dil.
Christopher

@DeadMG: Yorum olarak bir çürütme yazmaya başladım ama sonra cevaba (qv) çevirdim.
Ryan Culpepper

1
"Eklenecek bir şey kalmadı, ancak kaldırılacak bir şey kalmadıysa mükemmeliyet elde edilir" (q)
9000

1

Kesinlikle C ++ bakış açısıyla konuşmak, kalıtım iki ana amaç için yararlıdır:

  1. Kodun yeniden kullanılabilirliğine izin verir
  2. Bir alt sınıfta geçersiz kılma ile birlikte, alt sınıf nesnesinin türünü bilmeden işlemek için bir temel sınıf işaretçisi kullanmanızı sağlar.

Çok fazla akrobasi ile uğraşmak zorunda kalmadan kod paylaşmanın bir yolu olduğu sürece 1. nokta için, kalıtımla uzaklaşabilirsiniz. 2. nokta için. Java yoluna gidebilir ve bu özelliği uygulamak için bir arabirimde ısrar edebilirsiniz.

Kalıtımın kaldırılmasının faydaları

  1. uzun hiyerarşileri ve bununla ilişkili sorunları önleyebilir. Kod paylaşım mekanizmanız bunun için yeterince iyi olmalıdır.
  2. Ana sınıflardaki değişikliklerin alt sınıfları kırmasını önleyin.

Dengeleme büyük ölçüde "Kendinizi Tekrarlama" ile bir tarafta Esneklik ve diğer tarafta sorundan kaçınma arasındadır. Şahsen ben miras sadece C ++ diğer bazı geliştirici sorunları görecek kadar akıllı olmayabilir çünkü gitmek görmek nefret ediyorum.


1

Miras veya Mixins'e izin vermemenin uygun olduğunu düşünüyor musunuz? (kullanıcının en azından arayüze sahip olması durumunda)

Uygulama kalıtımı veya karışımları olmadan çok yararlı bir iş yapabilirsiniz , ancak bir çeşit arabirim mirasına mı ihtiyacınız olduğunu merak ediyorum, yani, bir nesne A arabirimini uygularsa B arabirimini de (yani, A, B'nin bir uzmanlığıdır ve bu nedenle bir tür ilişkisi vardır). Öte yandan, sonuçta ortaya çıkan nesnenin yalnızca her iki arabirimi de uyguladığına dair kayda ihtiyacı vardır, bu nedenle orada çok fazla karmaşıklık yoktur. Hepsi mükemmel bir şekilde yapılabilir.

Ancak uygulama mirasının eksikliğinin açık bir dezavantajı vardır: sınıflarınız için sayısal olarak indekslenmiş vtables oluşturamazsınız ve bu nedenle her yöntem çağrısı için karma aramalar yapmak zorunda kalacaksınız (veya bunları önlemek için akıllıca bir yol bulmalısınız). Bu mekanizma yoluyla temel değerleri (örneğin sayılar) bile yönlendiriyorsanız, bu acı verici olabilir. Her iç döngüde birçok kez vurduğunuzda çok iyi bir karma uygulaması bile pahalı olabilir!

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.