Dinamik yazma hangi işlevselliği sağlar? [kapalı]


91

Birkaç gündür python kullanıyorum ve dinamik ve statik yazım arasındaki farkı anladığımı düşünüyorum. Anlamadığım şey, hangi şartlar altında tercih edileceğidir. Esnek ve okunabilir, ancak daha fazla çalışma zamanı kontrolü ve gerekli ek birim testi pahasına.

Esneklik ve okunabilirlik gibi fonksiyonel olmayan kriterlerin yanı sıra, dinamik yazmayı seçmenin nedenleri nelerdir? Aksi halde mümkün olmayan dinamik yazarak ne yapabilirim? Dinamik yazmanın somut bir avantajını gösteren hangi özel kod örneğini düşünebilirsiniz?


5
Teorik olarak, diller Turing Complete olduğu sürece, ikisinde de yapamayacağınız hiçbir şey yoktur . Bana göre daha ilginç olan soru, birinde diğerinde kolay ya da doğal olan şey. Yeterli olduğunu bilmeme rağmen Python'da düzenli olarak yaptığım şeyler var.
Mark Ransom

28
Chris Smith mükemmel makalesinde yazdığı gibi : Tip sistemlerle tartışmadan önce bilinmesi gerekenler : "Bu durumda sorun, çoğu programcının sınırlı deneyime sahip olması ve çok fazla dil denememesidir. Bağlam için, altı ya da yedi "çok fazla" sayılmaz ... Bunun iki ilginç sonucu: (1) Birçok programcı statik olarak çok az yazılan dilleri kullandı. (2) Birçok programcı dinamik olarak yazılan dilleri çok az kullandı. "
Daniel Pryden

3
@suslik: Dil ilkellerinin saçma sapan türleri varsa, elbette türlerle saçma sapan şeyler yapabilirsiniz. Bunun statik ve dinamik yazma arasındaki farkla ilgisi yok.
Jon Purdy

10
@CzarekTomczak: Bu, dinamik olarak yazılmış bazı dillerin bir özelliğidir, evet. Ancak statik olarak yazılmış bir dilin çalışma zamanında değiştirilebilir olması mümkündür. Örneğin, Visual Studio, hata ayıklayıcıda kesme noktasındayken C # kodunu yeniden yazmanıza ve hatta kodunuzu yeni değişikliklerle yeniden çalıştırmak için komut işaretçisini geri sarmanıza olanak tanır. Diğer yorumumda Chris Smith'den alıntı yaptığım gibi: "Birçok programcı çok zayıf statik yazılmış diller kullandı" - statik olarak yazılmış tüm dilleri bildiklerinizle yargılamayın.
Daniel Pryden

11
@WarrenP: "Dinamik tip sistemleri, yazmak zorunda olduğum fazladan kırılganlığın miktarını azalttığını" iddia ediyorsun - ama sonra Python'u C ++ ile karşılaştırıyorsun. Bu adil bir kıyaslama değil: elbette C ++ Python'dan daha ayrıntılı, ama bu onların tip sistemlerindeki farklılıktan değil, gramerlerindeki farktan kaynaklanıyor. Program kaynağınızdaki karakter sayısını azaltmak istiyorsanız, J veya APL'yi öğrenin: Daha kısa olacaklarını garanti ederim. Python'u Haskell ile karşılaştırmak daha adil bir karşılaştırma olacaktır. (Kayıt için: Python'u seviyorum ve C ++ 'ı tercih ediyorum ama Haskell'i daha çok seviyorum.)
Daniel Pryden

Yanıtlar:


50

Belirli bir örnek istediğinden beri, sana bir tane vereceğim.

Rob Conery'nin Masif ORM'i 400 kod satırıdır. Bu kadar küçük çünkü Rob, SQL tablolarını eşleştirebilir ve SQL tablolarını yansıtmak için çok fazla statik tür gerektirmeden nesne sonuçları sağlayabilir. Bu, dynamicC # veri tipini kullanarak gerçekleştirilir . Rob'ın web sayfası bu süreci ayrıntılı olarak açıklamaktadır, ancak bu özel kullanım durumunda, dinamik yazmanın büyük ölçüde kodun kısaltmasından sorumlu olduğu açıkça görülmektedir.

Statik türleri kullanan Sam Saffron'un Dapper'ı ile karşılaştırın ; SQLMapperSınıf tek başına kod 3000 satırdır.

Genel feragatnamelerin geçerli olduğunu ve kilometrenizin değişebileceğini unutmayın; Dapper'ın Massive'den farklı hedefleri var. Bunu sadece 400 satırlık kodda yapabileceğiniz ve dinamik yazmadan mümkün olamayacak bir şeyin örneği olarak gösteriyorum.


Dinamik yazma, kararlarınızı çalışma zamanına ertelemenizi sağlar . Bu kadar.

Dinamik olarak yazılmış bir dil ya da statik olarak yazılmış bir dil kullanıyorsanız, tür seçenekleriniz hala mantıklı olmalıdır. İki dizgiyi bir araya getirmeyeceksiniz ve dizgiler sayısal veriler içermedikçe sayısal bir yanıt beklemeyeceksiniz ve eğer yoksa, beklenmedik sonuçlar elde edeceksiniz. Statik olarak yazılmış bir dil, bunu en başta yapmanıza izin vermez.

Statik olarak yazılmış dillerin savunucuları, derleyicinin, tek bir satır çalıştırılmadan önce derleme zamanında kodunuzu önemli miktarda "akıl denetimi" yapabileceğini belirtir. Bu iyi bir şey ™.

C #, dynamickodunuzun geri kalan kısmında statik tip güvenliğin yararlarını kaybetmeden, çalışma kararını çalışma zamanına ertelemenizi sağlayan bir anahtar kelimeye sahiptir . Tür çıkarımı ( var), statik olarak yazılmış bir dilde yazma sıkıntısını ortadan kaldırarak türleri her zaman açıkça beyan etme ihtiyacını ortadan kaldırır.


Dinamik diller, programlama için daha etkileşimli, anında bir yaklaşım lehine görünmektedir. Hiç kimse sizden bir miktar Lisp kodu yazmak ve yürütmeyi izlemek için bir sınıf yazıp bir derleme döngüsünden geçmenizi beklemiyor. Yine de tam olarak C # ile yapmam beklendiği gibi.


22
İki sayısal diziyi birlikte ekleseydim, yine de sayısal bir sonuç beklemiyordum.
pdr

22
@Robert Cevabınızın çoğuna katılıyorum. Ancak, Scala ve Haskell gibi etkileşimli okuma-değerlendirme-baskı döngülerine sahip statik olarak yazılmış diller olduğunu unutmayın. Bu C #, özellikle etkileşimli bir dil olmayabilir.
Andres F.

14
Bana bir Haskell öğrenmelisin.
Robert Harvey,

7
@RobertHarvey: Daha önce denemediyseniz, F # ile şaşırmış / etkilenmiş olabilirsiniz. Normalde .NET dilinde aldığınız tüm (derleme zamanı) tür güvenliğini elde edersiniz, ancak nadiren herhangi bir tür bildirmeniz gerekmez. F # 'daki tür çıkarımı C #' da bulunanların / çalışanların ötesine geçer. Ayrıca: Andres ve Daniel'ın işaret ettiği gibi, F # interaktif Visual Studio'nun bir parçası ...
Steven Evers

8
"Birlikte iki dizeyi ekleyin ve dizeleri sayısal veriler içeren sürece sayısal bir yanıt bekliyoruz etmeyeceğiz ve onlar yoksa, beklenmeyen sonuçlar alacağız" Üzgünüm, bu ile ilgisi yoktur statik vs dinamik yazarak , bu güçlü vs zayıf yazarak.
vartec

26

"Statik yazma" ve "dinamik yazma" gibi ifadeler çok fazla etrafa fırlar ve insanlar çok farklı tanımlar kullanmaya meyillidir, bu yüzden ne demek istediğimizi açıklığa kavuşturalım.

Derleme zamanında denetlenen statik türleri olan bir dil düşünün. Ancak, bir tür hatasının yalnızca ölümcül olmayan bir uyarı oluşturduğunu ve çalışma zamanında her şeyin ördek tipinde olduğunu söyleyin. Bu statik türler yalnızca programcının rahatlığı içindir ve kodgenleri etkilemez. Bu, statik yazmanın kendi başına herhangi bir sınırlama getirmediğini ve dinamik yazarak karşılıklı olarak dışlanmadığını göstermektedir. (Amaç-C buna benzer bir şeydir.)

Ancak çoğu statik tip sistem bu şekilde davranmaz. Statik tip sistemlerin sınırlamalar getirebilecek iki ortak özelliği vardır:

Derleyici, statik tür hatası içeren bir programı reddedebilir.

Bu bir sınırlamadır, çünkü çoğu güvenli program mutlaka statik bir tür hata içerir.

Örneğin, hem Python 2 hem de Python 3 olarak çalıştırılması gereken bir Python betiğim var. Bazı işlevler parametre türlerini Python 2 ve 3 arasında değiştirdi, bu yüzden şöyle kod var:

if sys.version_info[0] == 2:
    wfile.write(txt)
else:
    wfile.write(bytes(txt, 'utf-8'))

Bir Python 2 statik tipi denetleyicisi, hiçbir zaman çalıştırılmasa bile Python 3 kodunu (ve tersi) reddeder. Güvenli yazım programım statik bir yazım hatası içeriyor.

Başka bir örnek olarak, OS X 10.6'da çalıştırmak isteyen, ancak 10.7'deki yeni özelliklerden faydalanan bir Mac programını düşünün. 10.7 yöntemleri çalışma zamanında bulunabilir veya bulunmayabilir ve bunları algılamak için benim üzerimde programcıdır. Statik bir tür denetleyicisi, tür güvenliğini sağlamak için programımı reddetmek veya çalışma zamanında bir tür hatası (işlev eksik) üretme olasılığı ile birlikte programı kabul etmek zorunda kalır.

Statik tip kontrolü çalışma zamanı ortamının derleme zamanı bilgisi tarafından yeterince tanımlandığını varsayar. Ancak geleceği tahmin etmek tehlikeli!

İşte bir tane daha sınırlama:

Derleyici, çalışma zamanı türünün statik tür olduğunu varsayan kod oluşturabilir.

Statik türlerin "doğru" olduğunu varsaymak, optimizasyon için birçok fırsat sağlar, ancak bu optimizasyonlar sınırlayıcı olabilir. İyi bir örnek, proxy nesneleri, örneğin uzaklaştırmadır. Diyelim ki yöntem çağrılarını başka bir işlemde gerçek bir nesneye ileten bir yerel proxy nesnesi olsun. Proxy'nin genel (herhangi bir nesne olarak maskelenebilir) ve saydam olması (mevcut bir kodun bir proxy ile konuştuğunu bilmesine gerek kalmaması için) iyi olurdu. Ancak bunu yapmak için, derleyici statik türlerin doğru olduğunu varsayan, örneğin statik çağrılar yöntem çağrıları yaparak, nesne gerçekten bir proxy ise başarısız olacağı için kod üretemez.

Bu tür bir uzaktan çalıştırmaya örnek olarak ObjC’nin NSXPCConnection veya C # ’s ŞeffafProxy (uygulamalarında çalışma zamanında birkaç önleme yapılması gerekebilir - tartışma için buraya bakınız ).

Kodgen statik türlere bağlı olmadığında ve mesaj iletme gibi olanaklara sahipseniz, proxy nesneleri, hata ayıklama, vb. İle birçok harika şey yapabilirsiniz.

Bu yüzden, bir tür kontrolcüyü tatmin etmeniz gerekmiyorsa, yapabileceğiniz bazı şeylerin bir örneği budur. Sınırlamalar statik tipler tarafından değil, zorunlu statik tip kontrolü tarafından uygulanmaktadır.


2
"Bir Python 2 statik tip denetleyicisi, hiç çalıştırılmamasına rağmen Python 3 kodunu reddeder (ve tersi de geçerlidir). Tip güvenli programım statik bir tür hatası içeriyor." Gerçekte neye ihtiyacınız varsa bir tür "statik eğer" var gibi gözüküyor, burada derleyici / yorumlayıcı koşul yanlışsa bile kodu görmüyor.
David Stone

c ++ 'da var olan @davidstone
Milind R

A Python 2 static type checker would reject the Python 3 code (and vice versa), even though it would never be executed. My type safe program contains a static type error. Herhangi bir makul statik dilde, bunu IFDEFher iki durumda da tür güvenliğini korurken, bir tür ön işlemci ifadesiyle yapabilirsiniz.
Mason Wheeler,

1
@MasonWheeler, davidstone Hayır, önişlemci numaralar ve static_if ikisi de çok statik. Örneğimde Python2 ve Python3 kullandım, ancak sürümler arasında bazı arabirimlerin değiştiği, AmazingModule2.0 ve AmazingModule3.0 gibi kolayca olabilirdi. Arabirimi en erken bildiğiniz, çalışma zamanında (en azından dinamik bağlantıyı destekleme isteğiniz varsa) zorunlu olan modül alma zamanındadır.
ridiculous_fish

18

Ördek tipi değişkenler, herkesin düşündüğü ilk şeydir, ancak çoğu durumda statik faydaları kullanarak aynı faydaları elde edebilirsiniz.

Ancak dinamik olarak oluşturulan koleksiyonlarda ördek yazmanın başka bir yolla elde edilmesi zor:

>>> d = JSON.parse(foo)
>>> d['bar'][3]
12
>>> d['baz']['qux']
'quux'

Peki, ne tür JSON.parsegeri döner? Bir tamsayı dizisi sözlüğü veya dizelerin sözlükleri? Hayır, bu bile yeterince genel değil.

JSON.parsenull, bool, float, string, ardışık olarak bu türlerden herhangi birinin dizisi ya da string'den ardışık olarak bu türlerden herhangi birine sözlük şeklinde bir çeşit "varyant değeri" döndürmelidir. Dinamik yazmanın temel güçlü yönleri, bu tür değişkenlere sahip olmaktan gelir.

Şimdiye kadar bu, dinamik olarak yazılmış dillerin değil, dinamik türlerin bir yararıdır . İyi bir statik dil, bu tür bir türü mükemmel şekilde simüle edebilir. (Ve "kötü" diller bile kaputun altındaki tip güvenliğini kırarak ve / veya sakarca erişim sözdizimi gerektirerek onları sık sık taklit edebilir.)

Dinamik olarak yazılmış dillerin avantajı, bu tiplerin statik tip çıkarım sistemleriyle çıkarılamamasıdır. Türü açıkça yazmanız gerekir. Ancak bu gibi birçok durumda - bir kez de dahil olmak üzere - türü tanımlayan kod, türü tanımlamaksızın nesneleri ayrıştırma / oluşturma kodu kadar karmaşıktır, bu nedenle hala mutlaka bir avantaj değildir.


21
JSON ayrıştırma örneğiniz Cebirsel Veri Türü tarafından kolayca statik olarak kullanılabilir.

2
Tamam, cevabım yeterince açık değildi; Teşekkürler. JSValue, tam olarak bahsettiğim dinamik tipin açık bir tanımıdır. Dinamik yazma gerektiren diller değil, faydalı olan dinamik tiplerdir. Bununla birlikte, dinamik türlerin herhangi bir gerçek tür çıkarım sistemi tarafından otomatik olarak oluşturulamayacağı, bununla birlikte yaygın örneklerin çoğu önemsiz bir şekilde çıkarılamayacağı ile ilgilidir. Umarım yeni sürüm daha iyi açıklar.
abarnert

4
@ MattFenwick Cebirsel Veri Tipleri (pratikte) fonksiyonel dillerle sınırlıdır. Peki ya Java ve c # gibi diller?
spirc

4
ADT'ler, C / C ++ dilinde etiketli sendikalar olarak bulunur. Bu işlevsel dillere özgü değildir.
Clark Gaebel

2
@ spirc, hepsi ortak bir arabirimden türetilen çoklu sınıfları, getClass () veya GetType () için çalışma zamanı çağrıları ve eşitlik kontrollerini kullanarak, ADT'leri klasik bir OO dilinde taklit edebilirsiniz. Veya çift gönderim kullanabilirsiniz, ancak bunun C ++ 'da daha iyi olacağını düşünüyorum. Böylece bir JSObject arayüzüne ve JSString, JSNumber, JSHash ve JSArray sınıflarına sahip olabilirsiniz. Daha sonra bu "yazılmamış" veri yapısını "yazılan uygulama" veri yapısına dönüştürmek için bazı kodlara ihtiyacınız olacaktır. Ama muhtemelen bunu dinamik olarak yazılmış bir dilde de yapmak istersiniz.
Daniel Yankowsky

12

Her uzaktan pratik statik tip sistem, ilgilendiği programlama diline göre oldukça sınırlı olduğundan, çalışma zamanında kodun kontrol edebileceği tüm değişkenleri ifade edemez. Bir tip sistemin vermeye çalıştığı garantileri aşmamak için, muhafazakar olmayı ve bu çekleri geçebilecek, ancak (tip sistemde) kanıtlanamayan davaları kullanmamayı tercih eder.

Bir örnek yapacağım. Varsayalım ki, model xFoo türündeki nesnenin niteliği bir tamsayıya sahipse, her zaman bir tamsayı tutması gerektiğini söyleyen statik olarak yazılmış veri nesnelerini, bunların koleksiyonlarını vb. Tanımlamak için basit bir veri modeli uyguladığınızı varsayalım . Bu bir çalışma zamanı yapısı olduğu için statik olarak yazamazsınız. YAML dosyalarında açıklanan verileri sakladığınızı varsayalım. Bir karma haritası oluşturursunuz (daha sonra bir YAML kütüphanesine verilecek), xniteliği alın, haritada saklayın, dize gibi olan başka bir niteliği alın, bir saniye bekleyin. Şimdi neyin türü the_map[some_key]? Eh bunu biliyoruz, ateş some_keyolduğunu 'x've sonuç dolayısıyla bir tamsayı olmalıdır, ancak tür sistemi bile bu konuda ikna etmeye başlayamaz.

Bazı aktif olarak araştırılan bazı tip sistemler bu özel örnek için işe yarayabilir, ancak bunlar son derece karmaşıktır (hem derleyici yazarlar için hem de programcının akla yatması için), özellikle bu "basit" bir şey için (yani, sadece bir konuda açıkladım) paragraf).

Tabii ki, bugünün çözümü herşeyi kutlamak ve sonra atmaktır (ya da çoğu "uygulanmayan" istisnaları ortaya çıkaran bir dizi geçersiz kılma yöntemine sahip olmaktır). Ancak bu statik olarak yazılmış değildir , çalışma zamanında tür denetimlerini yapmak için tür sisteminin çevresinde bir kesmek vardır .


Genel tiplerde boks şartı yoktur.
Robert Harvey,

@RobertHarvey Evet. Ben konuşmuyordum Java C # boks, ben "Tek amacı U bir alt tipi içinde T'nin bir değerini temsil eder bazı sarıcı sınıfta kesmek" söz ediyordu. Bununla birlikte, parametrik polimorfizm (genel yazım dediğiniz şey) benim örneğim için geçerli değildir. Somut türler üzerinde derleme zamanı soyutlama, ancak bir çalışma zamanı yazma mekanizmasına ihtiyacımız var.

Scala'nın tip sisteminin Turing'in eksiksiz olduğunu belirtmek faydalı olabilir. Bu yüzden tip sistemleri, sizin düşündüğünüzden daha az önemsiz olabilir.
Andrea

@Andrea kasıtlı olarak açıklamamı turing tamlığına indirgemedi. Hiç bir turing tarpitinde programlanmış mı? Veya bu tür şeyleri kodlamak için çalıştı? Bir noktada, mümkün olamayacak kadar karmaşık hale geliyor.

@delnan Katılıyorum. Sadece tip sistemlerinin oldukça karmaşık şeyler yapabileceğini işaret ediyordum. Cevabınızın bu tip sistemin sadece önemsiz bir doğrulama yapabileceği anlamına geldiğini ancak ikinci bir okumada böyle bir şey yazmadığınızı düşündüm!
Andrea

7

Dinamik yazarak statik yazarak yapamayacağınız hiçbir şey yoktur, çünkü statik yazılan bir dilin üzerine dinamik yazmayı uygulayabilirsiniz.

Haskell'de kısa bir örnek:

data Data = DString String | DInt Int | DDouble Double

-- defining a '+' operator here, with explicit promotion behavior
DString a + DString b = DString (a ++ b)
DString a + DInt b = DString (a ++ show b)
DString a + DDouble b = DString (a ++ show b)
DInt a + DString b = DString (show a ++ b)
DInt a + DInt b = DInt (a + b)
DInt a + DDouble b = DDouble (fromIntegral a + b)
DDouble a + DString b = DString (show a ++ b)
DDouble a + DInt b = DDouble (a + fromIntegral b)
DDouble a + DDouble b = DDouble (a + b)

Yeterli durumda herhangi bir dinamik tip sistemi uygulayabilirsiniz.

Buna karşılık, statik olarak yazılmış herhangi bir programı da eşdeğer bir dinamik programa çevirebilirsiniz. Tabii ki, statik olarak yazılan dilin sağladığı tüm derleme zamanı doğruluk güvencelerini kaybedersiniz.

Düzenleme: Bu basit tutmak istedim, ancak burada bir nesne modeli hakkında daha fazla ayrıntı

Bir işlev, Veri listesini bir argüman olarak alır ve ImplMonad'da yan etkileri olan hesaplamaları yapar ve bir Veri döndürür.

type Function = [Data] -> ImplMonad Data

DMember ya bir üye değeri ya da bir işlevdir.

data DMember = DMemValue Data | DMemFunction Function

DataNesneleri ve İşlevleri içerecek şekilde genişletin . Nesneler, adlandırılmış üyelerin listesidir.

data Data = .... | DObject [(String, DMember)] | DFunction Function

Bu statik türler, aşina olduğum her dinamik olarak yazılmış nesne sistemini uygulamak için yeterlidir.


Bu kesinlikle aynı değil çünkü tanımını gözden geçirmeden yeni tür ekleyemezsiniz Data.
Jed

5
Örneğinizde dinamik yazma kavramlarını zayıf yazma ile karıştırıyorsunuz. Dinamik yazarak, izin verilen türlerin listesini tanımlamak değil, aralarındaki aşırı yükleme işlemlerini tanımlamak değil, bilinmeyen türlerde çalışmakla ilgilidir.
hcalves

2
@Jed Nesne modelini, temel türleri ve ilkel işlemleri uyguladıktan sonra, başka hiçbir temel çalışmaya gerek yoktur. Orijinal dinamik dildeki programları kolayca ve otomatik olarak bu lehçeye çevirebilirsiniz.
NovaDenizen

2
@hcalves Haskell kodumda aşırı yüklemeye başvurduğunuzdan beri anlambilim hakkında doğru bir fikre sahip olmadığınızdan şüpheleniyorum. Orada +iki Datadeğeri başka bir Datadeğerde birleştiren yeni bir operatör tanımladım . DataDinamik tip sistemindeki standart değerleri temsil eder.
NovaDenizen

1
@Jed: Çoğu dinamik dil, küçük bir "ilkel" tür kümesine ve yeni değerler (bazı listeler gibi veri yapıları) tanıtmak için bazı endüktif yollara sahiptir. Örneğin, şema, atomlardan, çiftlerden ve vektörlerden biraz daha fazlasıyla oldukça uzar. Bunları, verilen dinamik tipin geri kalanıyla aynı şekilde uygulayabilmelisiniz.
Tikhon Jelvis,

3

Zarlar :

Bir zar, sadece tek bir nesne için bir sargıya karşılık olarak, bütün bir nesne grafiğinin etrafındaki bir sarıcıdır. Tipik olarak, bir zarın yaratıcısı bir zardaki sadece tek bir nesneyi sarmaya başlar. Temel fikir, zarı geçen herhangi bir nesne referansının kendisinin aynı zar içine geçişli olarak sarılmış olmasıdır.

görüntü tanımını buraya girin

Her tür, aynı arabirime sahip, ancak iletileri kesen ve membranı geçtikçe değerleri sarar ve çözen bir tür tarafından sarılır. Sarma işlevinin favori statik olarak yazılmış dilindeki türü nedir? Belki Haskell'in bu işlevler için bir türü vardır, ancak statik olarak yazılan dillerin çoğu Nesne → Nesne'yi kullanmaz veya yazı denetleyicisi olarak sorumluluklarını etkin bir şekilde ortadan kaldırabilir.


4
Evet, Haskell aslında varoluşsal türleri kullanarak bunu yapabilir. Bazı Foo sınıf sınıfınız varsa, bu arayüzü örnekleyen herhangi bir tür etrafında bir sarıcı yapabilirsiniz. class Foo a where ... data Wrapper = forall a. Foo a => Wrapper a
Jake McArthur

@JakeMcArthur, Açıkladığınız için teşekkür ederiz. Bu da benim oturup Haskell'i öğrenmem için başka bir neden.
Mike Samuel,

2
Membranınız bir 'arayüzdür' ve nesnelerin türleri "varoluşsal olarak yazılmıştır" - yani arayüzün altında olduklarını biliyoruz, ama tek bildiğimiz bu. Veri soyutlama için varolan türler 80'li yıllardan beri bilinmektedir. İyi bir referans cs.cmu.edu/~rwh/plbook/book.pdf bölüm 21.1
Don Stewart

@DonStewart. Java proxy sınıfları varoluşsal bir tür mekanizma mıdır? Membranların zorlaştığı yerlerden biri, bu tip tanımının dışında görünen somut tipler için isimleri olan nominal tip sistemler bulunan dillerdir. Örneğin, biri StringJava’da somut bir tür olduğundan sarılmıyor. Smalltalk bu soruna sahip değildir, çünkü yazmaya çalışmaz #doesNotUnderstand.
Mike Samuel,

1

Birinin belirttiği gibi, teoride, belirli mekanizmaları kendi başınıza uygularsanız, statik tipleme ile yapamayacağınız dinamik tipleme ile yapabileceğiniz pek bir şey yoktur. Dillerin çoğu, boşluklu işaretçiler ve kök Nesne türü veya boş arabirim gibi tür esnekliğini desteklemek için tür rahatlama mekanizmaları sağlar.

Daha iyi soru, dinamik yazmanın neden bazı durumlarda ve problemlerde daha uygun ve daha uygun olduğudur.

İlk önce tanımlayalım

Varlık - Koddaki bazı varlıklar hakkında genel bir fikre ihtiyacım var. İlkel sayılardan karmaşık verilere kadar her şey olabilir.

Davranış - varlığımızın bazı durumlara sahip olduğunu ve dış dünyanın varlığa belirli tepkiler vermesini sağlayan bir dizi yöntem olduğunu söyleyelim. Bu varlığın durum + arabirimini davranışını arayalım. Bir varlık, dilin sağladığı araçlarla belirli bir biçimde birleştirilmiş birden fazla davranışa sahip olabilir .

Varlıkların tanımları ve davranışları - her dil, programdaki belirli varlıkların davranışlarını (yöntem kümesi + iç durum) tanımlamanıza yardımcı olacak bazı soyutlamalar sağlar. Bu davranışlara bir ad atayabilir ve bu davranışa sahip tüm örneklerin belirli türde olduğunu söyleyebilirsiniz .

Bu muhtemelen yabancı bir şey değil. Ve dediğin gibi, farkı anladın, ama yine de. Muhtemelen tam değil ve en doğru açıklama ama biraz değer getirecek kadar eğlenceli olmasını umuyorum :)

Statik yazım - programınızdaki tüm varlıkların davranışı, kod çalıştırılmaya başlamadan önce derleme zamanında incelenir. Bunun anlamı, örneğin Person türünün varlığınızın davranış yapmasını (böyle davranması) Magician'ı istiyorsanız, MagicianPerson varlığını tanımlamanız ve bunu throwMagic () gibi bir sihirbazın davranışları vermesi gerektiği anlamına gelir. Kodunuzda, yanlışlıkla sıradan Person.throwMagic () derleyicisine söyleyin."Error >>> hell, this Person has no this behavior, dunno throwing magics, no run!".

Dinamik yazma - Dinamik yazma ortamlarında, belirli bir varlıkla gerçekten bir şeyler yapmayı deneyene kadar varlıkların kullanılabilir davranışları kontrol edilmez. Bir Person.throwMagic () soran Ruby kodunu çalıştırmak, kodunuz gerçekten gelene kadar yakalanmayacaktır. Bu sinir bozucu, değil mi? Ama aynı zamanda vahiy gibi görünüyor. Bu özelliğe göre ilginç şeyler yapabilirsiniz. Mesela, herhangi bir şeyin Büyücü'ye dönebileceği bir oyun tasarladığınızı ve kodun belirli bir noktasına gelinceye kadar bunun kim olacağını gerçekten bilmediğinizi söyleyelim. Ve sonra Kurbağa gelir ve sen söylersinHeyYouConcreteInstanceOfFrog.include Magicve ondan sonra bu Kurbağa, Büyü gücüne sahip özel bir Kurbağa haline gelir. Diğer kurbağalar, hala değil. Statik yazım dillerinde, bu ilişkiyi, davranışların standart bir kombinasyon ortalamaları (arayüz uygulaması gibi) ile tanımlamanız gerekir. Dinamik yazarak, bunu çalışma zamanında yapabilirsiniz ve kimse umursamaz.

Dinamik yazma dillerinin çoğu, arayüzlerine iletilen herhangi bir mesajı yakalayacak genel bir davranış sağlama mekanizmalarına sahiptir. Mesela iyi hatırlıyorsam Ruby method_missingve PHP __call. Bu, programın çalışma zamanında her türlü ilginç şeyi yapabileceğiniz ve mevcut program durumuna göre tür kararlar verebileceğiniz anlamına gelir. Bu, Java gibi muhafazakar statik programlama diline nazaran daha esnek bir problemin modellenmesi için araçlar getirir.

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.