Neden birçok dil adlandırılmış parametreleri desteklemiyor? [kapalı]


14

Sadece bir işlevi çağırırken, yazabilirseniz, kodu okumak ne kadar kolay olacağını düşünüyordum:

doFunction(param1=something, param2=somethingElse);

Herhangi bir dezavantaj düşünemiyorum ve kodu çok daha okunaklı yapacak. Sadece argüman olarak bir dizi geçmek ve parametre adları olarak dizi anahtarları var biliyorum, ancak yine de okunabilir olmaz biliyorum.

Bunun eksik olduğum bir dezavantajı var mı? Değilse, neden birçok dil buna izin vermiyor?


1
adlandırılmış parametreleri olması gereken (ve olabilecek) bir dil verebilir misiniz?
Bryan Chen

1
Bence birçok durumda çok ayrıntılı. Gördüğüm kadarıyla, bir dilin bunu kullanıp kullanmadığı, dili olumlu veya olumsuz etkileyip etkilemeyeceğine bağlıdır. Çoğu C tarzı dil onsuz iyi sonuç verir. Onların durumunda, ne olup bittiğine dair oldukça açıktır ve yokluğu, genel olarak dağınıklığı azaltmaya gerçekten yardımcı olur.
Panzercrisis

2
@SteveFallows: "Adlandırılmış Parametre Deyimi", bir oluşturucu sınıfında akıcı bir API'nin (Martin Fowler tarafından adlandırıldığı gibi) tanımlanması için garip bir ad gibi görünüyor. Aynı modelin örneklerini Joshua Bloch'un Etkili Java'sının ilk öğelerinden birinde bulabilirsiniz .
jhominal

3
Bu mutlaka fikir tabanlı bir soru değildir
Catskul

2
Kabul. "Neden birçok dil adlandırılmış parametreleri desteklemiyor?" dilden ziyade dillerin tarihi meselesidir. Birisi "Parametrelere daha iyi adlandırılmamış mı?"
Andy Fleming

Yanıtlar:


14

Parametre adları belirtme değil , her zaman kod daha okunabilir hale: örnek olarak, okumayı tercih ediyorum min(first=0, second=1)ya min(0, 1)?

Önceki paragrafın bağımsız değişkenini kabul ederseniz, parametre adlarını belirtmenin zorunlu olmaması gerektiği açıktır. Neden tüm diller parametre adlarını belirtmeyi geçerli bir seçenek haline getirmiyor?

En az iki sebep düşünebilirim:

  • Genel olarak, zaten kapsanan bir ihtiyaç için ikinci bir sözdizimi getirmek (burada parametreler geçmek), getirilen dil karmaşıklığının içsel maliyetiyle (hem dil uygulamasında hem de programcının dilin zihin modelinde) faydaları dengelenmesi gereken bir şeydir. ;
  • Parametre adlarının değiştirilmesinin, geliştiricinin parametre adını değiştirmenin önemsiz ve kırılmaz bir değişiklik olduğu beklentisine uymayabilecek bir API kırılma değişikliği olmasını sağlar;

Ayrıca, isteğe bağlı parametreler (adlandırılmış parametreler gerektiren) uygulamadan adlandırılmış parametreleri uygulayan herhangi bir dil bilmediğimi unutmayın - bu nedenle, Akıcı Arayüzlerin tanımıyla daha tutarlı bir şekilde elde edilebilen okunabilirlik faydalarını fazla tahmin etmekten kaçınmalısınız .


6
Düzenli olarak birkaç farklı dilde kod yazıyorum, neredeyse her zaman belirli bir dilde basit bir alt dize için parametreleri aramak zorundayım. Alt dize (başlangıç, uzunluk) veya alt dize (başlangıç, bitiş) mi ve son dizeye dahil mi?
James Anderson

1
@JamesAnderson - Adlandırılmış parametreli bir alt dize sorunu nasıl çözer? İkinci parametrenin adının ne olduğunu bilmek için parametreleri aramak zorunda kalacaksınız (her iki işlev de mevcut değilse ve dilin polimorfizm özelliği farklı adlarla aynı tür parametrelere izin vermedikçe).
mouviciel

6
@mouviciel: Adlandırılmış parametreler yazar için hiç kullanılmaz , ancak okuyucu için harika . Değişken adlarının okunabilir kod yapmak için ne kadar önemli olduğunu hepimiz biliyoruz ve adlandırılmış parametreler, bir arabirimin yaratıcısının iyi parametre adları ve iyi işlev adları vermesine izin vererek, bu arabirimi kullanan kişilerin okunabilir kod yazmasını kolaylaştırır.
Phoshi

@Phoshi - Haklısın. Önceki yorumumu yazarken kodun okunmasının önemini unuttum.
mouviciel

14

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.

DateTimeNeredeyse 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 => 30argüman, DateTime::Duration->new(...)istediği seconds => 30ve 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.

  • pchaslında çizim karakteri, her veri noktası için çizilecek glif. 17boş bir çember ya da bunun gibi bir şeydir.
  • ltyçizgi türüdür. İşte 1sağlam bir çizgi.
  • btykutu 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; }});

3
it is easier to forget the exact names of some parameters than it is to forget their order” ... bu ilginç bir iddia.
Catskul

1
İlk karşı örnek, adlandırılmış parametrelerle ilgili bir sorun değil ve daha çok İngilizce çoğulların arabirimlerdeki alan adlarıyla nasıl eşleştiği ile ilgili bir kusur. İkinci karşı örnek de benzer şekilde kötü adlandırma seçimleri yapan geliştiricilerle ilgili bir sorundur. (Parametre geçiş arabiriminin hiçbir seçeneği kendi başına okunabilirlik için yeterli bir koşul olmayacaktır - soru, bazı durumlarda bunun için gerekli bir koşul veya yardım olup olmadığıdır ).
mtraceur

1
Uygulama maliyetleri ve adlandırılmış parametreler yapmaya ilişkin genel puanlar için +1. Sadece başlangıçların insanları kaybedeceğini düşünüyorum.
mtraceur

@mtraceur Bir noktan var. Şimdi, 5 yıl sonra, muhtemelen cevabı oldukça farklı yazardım. İsterseniz daha az yararlı olan şeyleri kaldırmak için cevabımı düzenleyebilirsiniz. (Genellikle bu tür düzenlemeler yazarın niyetiyle çeliştikleri için reddedilir, ancak burada iyiyim). Örneğin, birçok parametre parametresinin sadece dinamik dillerin kısıtlamaları olduğuna inanıyorum ve sadece bir tür sistem almaları gerekiyor. Örneğin JavaScript'in Flow ve TypeScript, Python'da MyPy vardır. Çoğu kullanılabilirlik sorununu ortadan kaldıran uygun IDE entegrasyonu ile. Hala Perl'de bir şey bekliyorum.
amon

7

Aynı nedenden dolayı Macarca Gösterim artık yaygın olarak kullanılmamaktadır; Intellisense (veya Microsoft dışı IDE'lerde ahlaki eşdeğeri). Çoğu modern IDE, sadece parametre referansının üzerine gelip bir parametre hakkında bilmeniz gereken her şeyi size söyleyecektir.

Bununla birlikte, bazı diller C # ve Delphi dahil adlandırılmış parametreleri destekliyor. C # 'da isteğe bağlıdır, bu yüzden istemiyorsanız kullanmanıza gerek yoktur ve özellikle nesne başlatma gibi üyeleri bildirmenin başka yolları da vardır.

Adlandırılmış Parametreler çoğunlukla, yalnızca isteğe bağlı parametrelerin bir alt kümesini belirtmek istediğinizde yararlıdır, bunların tümünü değil. C # 'da bu çok kullanışlıdır, çünkü programcıya bu esnekliği sağlamak için bir sürü aşırı yüklenmiş yönteme artık ihtiyacınız yoktur.


4
Python adlandırılmış parametreleri kullanır ve dilin harika bir özelliğidir. Keşke daha fazla dil kullanılmışsa. Artık C ++ 'da olduğu gibi varsayılan değerleri "önce" açıkça belirtmeye zorlamadığınız için varsayılan bağımsız değişkenleri kolaylaştırır. (Son paragrafınızda olduğu gibi, python'un aşırı yüklemeye sahip olmamasıyla bu şekilde kaçar ... varsayılan bağımsız değişkenler ve ad bağımsız değişkenleri aynı şeyleri yapmanızı sağlar.) Adlandırılmış bağımsız değişkenler de daha okunabilir kodlar sağlar. Gibi bir şey olduğunda sin(radians=2), "Intellisense" gerekmez.
Robotu Gort

2

Bash kesinlikle bu programlama tarzını destekler ve hem Perl hem de Ruby ad / değer parametre listelerini (yerel karma / harita desteğine sahip herhangi bir dil gibi) geçirmeyi destekler. Hiçbir şey, parametrelere adlar ekleyen bir yapı / kayıt veya karma / harita tanımlamayı seçmenizi engellemez.

Yerel olarak hash / map / keyvalue depolarını içeren diller için, yalnızca işlev / yöntemlerinize anahtar / değer karmalarını geçirme deyimini benimseyerek istediğiniz işlevselliği elde edebilirsiniz. Bir projede denedikten sonra, kullanım kolaylığından elde edilen artan üretkenlikten veya azaltılmış hatalar yoluyla iyileştirilmiş kaliteden herhangi bir şey kazanıp kazanmadığınızı daha iyi anlayacaksınız.

Deneyimli programcıların parametreleri sipariş / yuvaya göre iletme konusunda rahat olduklarını unutmayın. Bu deyimin yalnızca birkaç argümandan fazlasına sahip olduğunuzda da değerli olduğunu görebilirsiniz (örneğin,> 5/6). Ve çok sayıda argüman genellikle (aşırı) karmaşık yöntemleri gösterdiği için, bu deyimin sadece en karmaşık yöntemler için yararlı olduğunu görebilirsiniz.


2

Sanırım c # VB.net daha popüler neden aynı olduğunu düşünüyorum. VB.NET daha "okunabilir" olsa da, örneğin bir kapanış köşeli ayraç yerine "end if" yazarsanız, kodun dolmasına neden olur ve sonunda anlaşılmasını zorlaştırır.

Kodun anlaşılmasını kolaylaştıran şeyin kısalık olduğu ortaya çıkıyor. Ne kadar az o kadar iyi. İşlev parametresi adları normalde zaten oldukça açıktır ve kodu anlamanıza yardımcı olmak için bu kadar ileri gitmeyin.


1
Ben şiddetle "daha az daha iyi" olduğunu katılmıyorum. Mantıksal aşırılıkları göz önüne alındığında, kod golf kazananları "en iyi" programlar olacaktır.
Riley Major

2

Adlandırılmış parametreler, kaynak kodun yeniden düzenlenmesi ile ilgili bir soruna bir çözümdür ve kaynak kodunu daha okunabilir hale getirmeye yönelik değildir . Adlandırılmış parametreler, derleyici / ayrıştırıcının işlev çağrıları için varsayılan değerlerin çözümlenmesine yardımcı olmak için kullanılır. Kodu daha okunaklı yapmak istiyorsanız, anlamlı yorumlar ekleyin.

Yeniden düzenleme zor olan diller genellikle adlandırılmış parametreleri destekler, çünkü değişikliklerin foo(1)imzası olduğunda kırılacak foo(), ancak foo(name:1)programcıdan değişiklik yapmak için daha az çaba gerektirecek şekilde kırılma olasılığı daha düşüktür foo.

Aşağıdaki işleve yeni bir parametre eklemeniz gerektiğinde ne yaparsınız ve bu işlevi çağıran yüzlerce veya binlerce kod satırı vardır?

foo(int weight, int height, int age = 0);

Çoğu programcı aşağıdakileri yapacaktır.

foo(int weight, int height, int age = 0, string gender = null);

Artık yeniden düzenleme gerekli değildir ve işlev gendernull olduğunda eski modda çalışabilir .

Belirli genderbir değere artık çağrı için HARDCODEDage . Bu örnek olarak:

 foo(10,10,0,"female");

Programcı fonksiyon tanımına baktı, agevarsayılan değere sahip olduğunu gördü 0ve bu değeri kullandı.

Şimdi ageişlev tanımındaki varsayılan değer tamamen işe yaramaz.

Adlandırılmış parametreler bu sorunu önlemenizi sağlar.

foo(weight: 10, height: 10, gender: "female");

Yeni parametreler eklenebilir foove eklendikleri sıra hakkında endişelenmenize gerek yoktur ve ayarladığınız varsayılanın gerçekten gerçek varsayılan değer olduğunu bilerek varsayılan değerleri değiştirebilirsiniz.

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.