Adlandırılmış Parametreler Kodu Okumayı Kolaylaştırır, Yazması Daha Zorlaştırır
Bir kod parçası okurken, adlandırılmış parametreler kodu daha kolay anlaşılır kılan bağlam tanıtabilir. Örneğin bu kurucu düşünün: Color(1, 102, 205, 170)
. O da ne demek? Gerçekten de, Color(alpha: 1, red: 102, green: 205, blue: 170)
okumak çok daha kolay olurdu. Ama ne yazık ki, Derleyici “hayır” diyor - istiyor Color(a: 1, r: 102, g: 205, b: 170)
. Adlandırılmış parametreleri kullanarak kod yazarken, tam adları aramak için gereksiz bir zaman harcarsınız - bazı parametrelerin tam adlarını unutmak, sıralarını unutmaktan daha kolaydır.
DateTime
Neredeyse aynı arayüzlere sahip noktalar ve süreler için iki kardeş sınıfı olan bir API kullanırken bu bir kez beni ısırdı . İken DateTime->new(...)
kabul edilen bir second => 30
argüman, DateTime::Duration->new(...)
istediği seconds => 30
ve diğer birimler için benzer. Evet, kesinlikle mantıklı, ama bu bana adlandırılan parametrelerin kullanım kolaylığı olduğunu gösterdi.
Kötü İsimler Okumayı Kolaylaştırmaz
İsimlendirilmiş parametrelerin nasıl kötü olabileceğinin bir başka örneği muhtemelen R dilidir. Bu kod parçası bir veri grafiği oluşturur:
plot(plotdata$n, plotdata$mu, type="p", pch=17, lty=1, bty="n", ann=FALSE, axes=FALSE)
X ve y veri satırları için iki konum bağımsız değişkeni ve sonra adlandırılmış parametrelerin bir listesini görürsünüz . Varsayılanları olan daha birçok seçenek vardır ve yalnızca varsayılanlarını değiştirmek veya açıkça belirtmek istediğim listede listelenir. Bu kodun sihirli sayılar kullandığını görmezden geldiğimizde ve enum (R varsa!) Kullanmaktan fayda sağlayabildiğimizde, sorun bu parametre adlarının çoğunun çözülemez olmasıdır.
pch
aslında çizim karakteri, her veri noktası için çizilecek glif. 17
boş bir çember ya da bunun gibi bir şeydir.
lty
çizgi türüdür. İşte 1
sağlam bir çizgi.
bty
kutu tipidir. Bunu ayarlamak "n"
, çizimin etrafına bir kutu çizilmesini önler.
ann
eksen detaylandırmalarının görünümünü kontrol eder.
Her kısaltmanın ne anlama geldiğini bilmeyen biri için bu seçenekler oldukça kafa karıştırıcıdır. Bu ayrıca R'nin neden şu etiketleri kullandığını da gösterir: Kendini belgeleyen kod olarak değil, (dinamik olarak yazılan bir dil olarak) değerleri doğru değişkenleriyle eşleştirmek için anahtarlar olarak.
Parametrelerin ve İmzaların Özellikleri
İşlev imzaları aşağıdaki özelliklere sahip olabilir:
- Bağımsız değişkenler sipariş edilebilir veya sırasız olabilir,
- adlandırılmış veya adlandırılmamış,
- gerekli veya isteğe bağlı.
- İmzalar ayrıca boyut veya türüne göre aşırı yüklenebilir,
- ve varargs ile belirtilmemiş bir boyuta sahip olabilir.
Farklı diller bu sistemin farklı koordinatlarına girer. C'de argümanlar sıralanır, isimlendirilmez, her zaman gereklidir ve varargs olabilir. Java'da durum benzerdir, ancak imzalar aşırı yüklenebilir. Amaç C'de imzalar sipariş edilir, adlandırılır, istenir ve aşırı yüklenemez çünkü C'nin sadece sözdizimsel şekeri.
Varargs (komut satırı arabirimleri, Perl,…) ile dinamik olarak yazılan diller isteğe bağlı adlandırılmış parametreleri taklit edebilir. İmza boyutu aşırı yüklemesi olan dillerde, isteğe bağlı konumsal parametreler gibi bir şey bulunur.
Adlandırılmış Parametreler Nasıl Uygulanmaz?
Adlandırılmış parametreleri düşünürken genellikle adlandırılmış, isteğe bağlı, sırasız parametreler olduğunu varsayıyoruz. Bunları uygulamak zordur.
İsteğe bağlı parametrelerin varsayılan değerleri olabilir. Bunlar çağrılan işlev tarafından belirtilmeli ve çağrı kodunda derlenmemelidir. Aksi takdirde, tüm bağımlı kodlar yeniden derlenmeden varsayılanlar güncellenemez.
Şimdi önemli bir soru, argümanların aslında işleve nasıl aktarıldığıdır. Sıralı parametrelerle, argümanlar bir kayıtta veya yığın üzerindeki doğal sırayla geçirilebilir. Kayıtları bir anlığına hariç tuttuğumuzda sorun, yığına sıralanmamış isteğe bağlı bağımsız değişkenlerin nasıl yerleştirileceğidir.
Bunun için isteğe bağlı argümanlar üzerinde bir düzene ihtiyacımız var. Beyanname kodu değiştirilirse ne olur? Sıra önemsiz olduğundan, işlev bildirimindeki yeniden sıralama yığın üzerindeki değerlerin konumunu değiştirmemelidir. Ayrıca yeni bir isteğe bağlı parametre eklemenin mümkün olup olmadığını da dikkate almalıyız. Bu perspektifi daha önce kullanmayan kodun yeni parametre ile çalışmaya devam etmesi gerektiğinden, kullanıcı açısından bu böyle görünmektedir. Bu, beyanda siparişi kullanmak veya alfabetik sırayı kullanmak gibi sıralamaları hariç tutar.
Bunu alt tipleme ve Liskov İkame Prensibi ışığında da düşünün - derlenmiş çıktıda, aynı talimatlar yöntemi muhtemelen yeni adlandırılmış parametreleri olan bir alt tipte ve bir süper tipte çağırabilmelidir.
Olası Uygulamalar
Eğer kesin bir düzen elde edemezsek, bu yüzden bazı düzensiz veri yapısına ihtiyacımız var.
En basit uygulama, parametrelerin adını değerlerle birlikte iletmektir. Adlandırılmış parametreler Perl'de veya komut satırı araçlarıyla bu şekilde taklit edilir. Bu, yukarıda belirtilen tüm genişletme sorunlarını çözer, ancak performans açısından kritik kodda bir seçenek değil, büyük bir alan kaybı olabilir. Ayrıca, bu adlandırılmış parametrelerin işlenmesi artık değerleri bir yığından atmaktan çok daha karmaşıktır.
Aslında, alan gereksinimleri, daha sonraki dize karşılaştırmalarını işaretçi karşılaştırmalarına indirgeyebilen dize havuzlaması kullanılarak azaltılabilir (statik dizelerin gerçekten bir araya getirildiği garanti edilemediği sürece, bu durumda iki dizenin karşılaştırılması gerekir detay).
Bunun yerine, adlandırılmış argümanların sözlüğü olarak çalışan akıllı bir veri yapısı da iletebiliriz. Bu, arayan tarafında ucuzdur, çünkü anahtar kümesi çağrı konumunda statik olarak bilinir. Bu, mükemmel bir karma işlevi oluşturmaya veya bir üçgeni önceden hesaplamaya izin verir. Callee, yine de biraz pahalı olan tüm olası parametre adlarının varlığını test etmek zorunda kalacaktır. Böyle bir şey Python tarafından kullanılır.
Bu yüzden çoğu durumda çok pahalı
İsimlendirilmiş parametrelere sahip bir fonksiyon düzgün bir şekilde genişletilebilirse, kesin bir sıralama yapılamaz. Yani sadece iki çözüm var:
- Adlandırılmış parametrelerin sırasını imzanın bir parçası haline getirin ve daha sonra değişikliklere izin vermeyin. Bu, kendi kendini belgeleyen kodlar için kullanışlıdır, ancak isteğe bağlı bağımsız değişkenlere yardımcı olmaz.
- Callee'ye daha sonra yararlı bilgiler elde etmek zorunda olan bir anahtar / değer veri yapısı iletin. Bu, karşılaştırma açısından çok pahalıdır ve genellikle yalnızca performansa vurgu yapılmadan kodlama dillerinde görülür.
Diğer Tuzaklar
İşlev bildirimindeki değişken adları genellikle bazı dahili anlamlara sahiptir ve arabirimin bir parçası değildir - birçok belge aracı hala gösterse bile. Çoğu durumda, dahili bir değişken ve buna karşılık gelen adlandırılmış argüman için farklı adlar istersiniz. Değişken adı çağıran bağlam göz önünde bulundurularak kullanılmazsa, adlandırılmış bir parametrenin harici olarak görünür adlarının seçilmesine izin vermeyen diller bunların çoğunu kazanmaz.
İsimlendirilmiş argümanların emülasyonlarıyla ilgili bir sorun, arayan tarafında statik kontrol eksikliğidir. Bir argüman sözlüğü geçerken bunu unutmak özellikle kolaydır. Bir sözlük geçirerek JavaScript ortak bir çözüm, örneğin, çünkü bu önemlidir: foo({bar: "baz", qux: 42})
. Burada ne değer türleri ne de belirli isimlerin varlığı ya da yokluğu statik olarak kontrol edilemez.
Adlandırılmış Parametrelerin Taklit Edilmesi (Statik Yazılmış Diller)
Dizeleri anahtar olarak ve herhangi bir nesneyi değer olarak kullanmak, statik tip denetleyicinin varlığında çok yararlı değildir. Ancak, adlandırılmış argümanlar yapılarla veya nesne değişmezleriyle taklit edilebilir:
// Java
static abstract class Arguments {
public String bar = "default";
public int qux = 0;
}
void foo(Arguments args) {
...
}
/* using an initializer block */
foo(new Arguments(){{ bar = "baz"; qux = 42; }});