SORU
14 Ocak 2009, ÇARŞAMBA


Aşırı dönüş türü işlev?

Neden daha mainstream statik olarak yazılan diller fonksiyon, metot dönüş tipi aşırı yükleme desteği yok? Bunu herhangi düşünemiyorum. Az parametre Türüne göre aşırı destekleyen daha yararlı ya da makul görünüyor. Nasıl bu kadar az popüler oluyor?

CEVAP
14 Ocak 2009, ÇARŞAMBA


Diğerleri, dönüş türü tarafından aşırı söylediğinin aksinemümkünbazı modern diller tarafından yapılır. Her zamanki itiraz kodu gibi

int func();
string func();
int main() { func(); }

func() * deniyor ki söyleyemezsin. Bu birkaç yolla çözülebilir:

  1. Böyle bir durumda denir belirlemek için tahmin edilebilir bir yöntem var.
  2. Böyle bir durum olduğunda, bir derleme zamanı hatası. Ancak, programcı belirsizliği ortadan kaldırmak için izin veren bir sözdizimi vardır, örneğin int main() { (string)func(); }.
  3. Yan etkileri yoktur. Yan etkileri yok ve hiç bir işlevin dönüş değeri kullanın, sonra derleyici böyle bir işlevi çağırmadan önleyebilirsiniz.

Ben düzenli olarak (ab)tekrar dönüş türü: dil ikiPerlveHaskell. Bana yaptıklarını tarif edeyim.

Perlarasında temel bir fark vardırskalervelistebağlam (ve diğerleri, ama iki tane var sayalım). Her yerleşik perl'de fonksiyon farklı şeyler bağlı olarak yapabilirbağlamhangi denir. Örneğin, join operatör scalar operatör bağlam, yani karşılaştırmak: skaler güçleri ise liste bağlam şey katılmış olmak () zorlar

print join " ", localtime(); # printed "58 11 2 14 0 109 3 13 0" for me right now
print scalar localtime(); # printed "Wed Jan 14 02:12:44 2009" for me right now.

Perl her operatör skaler bağlamda bir şey ve liste bağlamda bir şey yok, ve resimli olarak farklı olabilirler. (Bu sadece localtime gibi rasgele operatörler için değil. Eğer liste bağlamda bir dizi @a kullanırsanız, skaler bağlamda, öğe sayısını döndürür süre diziyi verir. Örneğin print @a print 0 @a boyutu baskı sırasında öğeleri yazdırır.) Ayrıca, her operatörzorlaörneğin içerik bir ek skaler bağlamda zorlar. man perlfunc Her Giriş Bu belge. Örneğin, burada glob EXPR giriş parçası

Bağlam, bir (muhtemelen listesini verir boş) dosya adı uzantılarına listesi standart olarak EXPR değeri /bin/csh shell Unıx yapardı. İçinde üzerinden skaler bağlamda tulumu dolaşır bu dosya adı uzantılarına, dönen liste kaldığında undef.

Şimdi, skaler ve liste bağlamı arasındaki ilişki nedir? İyi, man perlfunc diyor

Unutmayın aşağıdaki önemli kural: Eğer ilgili kural yok listedeki bir ifade davranış skaler kendi davranış bağlam bağlam, ya da tam tersi. Yapabilir tamamen farklı iki şey. Her operatör ve fonksiyon kesinleşir en olurdu değeri sıralama uygun skaler dönmek bağlam. Bazı operatörler dönüş ki listenin uzunluğu liste içerik. iade edilmiş Bazı operatörler ilk değeri döndürür liste. Bazı operatörler dönüş listedeki son değer. Bazı operatörler başarılı bir geri sayım işlemleri. Genel olarak, ne yapıyorlar tutarlılık istemiyorsan.

tek bir işlevi olan basit bir mesele değil, ve sonra basit bir dönüşüm sonunda. Aslında, bu nedenle localtime örnek seçtim.

Sadece bu davranış-ins inşa değil. Herhangi bir kullanıcı böyle bir fonksiyon listesi, skaler ve boşluk içeriği arasında ayırt etmek için izin verir wantarray kullanarak tanımlayabilirsiniz. Bu yüzden, örneğin, eğer boşluk bağlamda sizi çağırıyorlar eğer bir şey yapmaya karar verebilirsiniz.

Şimdi, bu değil şikayet edebilirsinizdoğrudönüş aşırı yüklenme sadece deniyor bağlamında söyledim ve sonra da bu bilgilere dayanarak hareket eden bir fonksiyon, çünkü değer. Ancak, bu (ve Perl her zamanki kelimenin tam anlamıyla aşırı yükleme izin vermez, ama bir işlev bağımsız değişkenleri incelemek nasıl benzer) açıkça eşdeğerdir. Ayrıca, güzelce belirsiz durum bu yanıtın başında da belirtildiği giderir. Perl aramak için hangi bilmiyor şikayetçi değildir, sadece çağırır. Gerisi ona kalmış. her zaman mümkün olan fonksiyonu içinde ne olduğunu anlamaya

sub func {
    if( not defined wantarray ) {
        print "void\n";
    } elsif( wantarray ) {
        print "list\n";
    } else {
        print "scalar\n";
    }
}

func(); # prints "void"
() = func(); # prints "list"
0 func(); # prints "scalar"

(Not: bazen işlevi yani ne zaman Perl operatör diyebilirim. Bu tartışma için çok önemli değildir.)

Haskelldiğer yaklaşım, yani yan etkisi olmayan alır. Aynı zamanda güçlü bir tip sistemine sahiptir, ve bu yüzden aşağıdaki gibi bir kod yazabilirsiniz:

main = do n <- readLn
          print (sqrt n) -- note that this is aligned below the n, if you care to run this

Bu kod standart girdiden bir kayan nokta sayısı okur ve kare kökü yazdırır. Ama bu konuda şaşırtıcı bir şey var mı? İyi, readLn tipi readLn :: Read a => IO a. Bunun anlamı, herhangi bir türü için Read (resmi olarak, Read yazın sınıfın bir örneği her türü), readLn olabilir ne okuyabilir. Nasıl Haskell kayan noktalı bir sayı görmek istedim biliyor muydunuz? İyi, sqrt türü aslında sqrt sadece kayan nokta sayıları girdi olarak kabul edebilir anlamına gelir sqrt :: Floating a => a -> a, ve ne istediğimi çok Haskell anlaşılmaktadır.

Ne istediğimi anlaması Haskell o zaman ne yapacağız? Birkaç olasılık var. Eğer dönüş değeri hiç kullanmıyorum bile, Haskell, sadece ilk etapta bir işlev çağrısı olmayacak. Ancak, eğer benyapındönüş değeri kullanın, sonra Haskell türü gerçekleştirip olabilir mi şikayet edecektir:

main = do n <- readLn
          print n
-- this program results in a compile-time error "Unresolved top-level overloading"

İstiyorum türünü belirterek belirsizlik çözebileceğime:

main = do n <- readLn
          print (n::Int)
-- this compiles (and does what I want)

Dönüş değeri aşırı yükleme mümkün ve yapılır, soru cevaplar parçası olan bütün bu tartışma ne demek zaten.

Sorunuzun diğer kısmı daha fazla dil yapma nedeni budur. Diğerleri de buna cevap veririm. Ancak, bir kaç yorum: akıl karışıklığı için gerçekten büyük bir fırsat burada aşırı daha büyük olasılıkla bağımsız değişken Türüne göre ilkedir. Ayrıca tek tek diller: gerekçeleri bakabilirsiniz

Ada: "en basit aşırı çözümleme kuralı her şeyi mümkün olduğunca geniş bir bağlamdan tüm bilgi - aşırı başvuru gidermek için kullanmak gibi görünebilir. Bu kural basit olabilir, ama yararlı değildir. İnsan okuyucu keyfi metin büyük parçaları taramak için, ve keyfi karmaşık çıkarımlar (yukarıda (g) gibi) yapmak gerekir. İyi bir kural, açık bir insan bir okur ya da derleyici gerçekleştirmelisiniz görev yapan biri olduğuna inanıyoruz ve bu görevi mümkün olduğunca insan okuyucu için doğal olarak yapar."

(Bjarne Stroustrup ... ... alt bölüm 7.4.1"") C Programlama Dili: "Dönüş türleri aşırı çözümleme dikkate alınmaz. C Sebebi tek operatör veya bir işlev çağrısı kapsamında bağımsız çözünürlük tutmaktır. Düşünün:

float sqrt(float);
double sqrt(double);

void f(double da, float fla)
{
    float fl = sqrt(da);     // call sqrt(double)
    double d = sqrt(da); // call sqrt(double)
    fl = sqrt(fla);            // call sqrt(float)
    d = sqrt(fla);             // call sqrt(float)
}

Eğer dönüş türü hesaba katıldığında, artık yalıtım sqrt() bir ara bakıp işlevi çağrıldı belirlemek mümkün olacaktır." (Haskell yok olduğunu, karşılaştırma için, unutmayınörtülüdönüşüm.)

Java (Java Language Specification 9.4.1): "miras yöntemlerden Biri olmalı başka bir yöntemi miras için değiştirilebilir tip iadesi gerekir; aksi halde, bir derleme zamanı hatası oluşur." (Evet, bu bir gerekçe vermez biliyorum. Gerekçe Gosling tarafından verilir eminim"". Java Programlama Dili Belki birisi bir kopyası var mı? Eminim bunu "prensip en az" özü.) sürpriz. Ancak, Java hakkında ilginç bir bilgi: JVMsağlardönüş tarafından aşırı değer! Bu, örneğin, Scala kullanılır directly through Java iç uğraşırken de erişilebilir.

PS. Son bir not olarak, aslında C dönüş değeri tarafından aşırı olası bir hile ile. Tanık:

struct func {
    operator string() { return "1";}
    operator int() { return 2; }
};

int main( ) {
    int x    = func(); // calls int version
    string y = func(); // calls string version
    double d = func(); // calls int version
    cout << func() << endl; // calls int version
    func(); // calls neither
}

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • David Tedeyev

    David Tedeye

    20 AĞUSTOS 2011
  • Dylan Brenan

    Dylan Brenan

    22 Aralık 2009
  • TheDroidDemos

    TheDroidDemo

    15 ŞUBAT 2011