Neden bu kadar çok dil değer olarak geçiyor?


36

Eğer her zaman değeriyle geçirilen C gibi açık işaretçi manipülasyon olsa bile diller (siz yapabilirsiniz referans olarak onları geçmek ama bu varsayılan davranış değil).

Bunun faydası nedir, neden bu kadar çok dil değerler tarafından iletiliyor ve diğerleri neden referans olarak geçiyor ? (Anladığım kadarıyla Haskell referans tarafından geçti ancak emin değilim).


5
void acceptEntireProgrammingLanguageByValue(C++);
Thomas Eding

4
Daha kötü olabilirdi. Bazı eski diller aynı zamanda ada göre arama
hugomg

25
Aslında, C de referans olarak geçemezsiniz. Bu olabilir değerine göre bir işaretçi geçmek pass referans ile çok benzer, ancak aynı şey. C ++ 'ta olsa referans olarak geçebilirsiniz.
Mason Wheeler

@Mason Wheeler biraz daha detaylandırabilir veya bir link ekleyebilir, C / C ++ gurusu olmadığım için
ifadenizin

1
@Betlista: Referans ile başarılı, şuna benzer bir takas rutini yazabilirsiniz: temp := a; a := b; b := temp;Ve döndüğünde, değerleri ave bdeğiştirilecektir. Bunu C de yapmanın bir yolu yok; Eğer işaretçileri geçmek zorunda ave bve swaprutin işaret ettikleri değerler üzerinde hareket etmek zorundadır.
Mason Wheeler

Yanıtlar:


58

Değere göre geçiş genellikle referansa göre geçmek için daha güvenlidir, çünkü parametrelerinizi yanlışlıkla yöntem / işlevinize göre değiştiremezsiniz. Bu, dili bir işleve verdiğiniz değişkenler hakkında endişelenmenize gerek olmadığı için kullanımını kolaylaştırır. Onların değişmeyeceğini biliyorsunuz ve bu genellikle beklediğiniz şey .

Bununla birlikte, parametreleri değiştirmek istiyorsanız , bunu netleştirmek için açık bir işlem yapmanız gerekir (bir işaretçiye geçin). Bu, tüm arayanları aramayı biraz farklı şekilde ( &variableC cinsinden) yapmaya zorlar ve bu, değişken parametresinin değişebileceğini açıkça belirtir.

Böylece, bir işlevin, değişken işaretini yapmak için açıkça işaretlenmediği sürece, değişken göstergesini değiştirmeyeceğini varsayabilirsiniz (bir işaretçi girmenizi gerektirerek). Bu, alternatiften daha güvenli ve temiz bir çözümdür: Özel olarak yapamadıklarını söylemedikçe, her şeyin parametrelerinizi değiştirebileceğini varsayalım.


4
+1 İşaretçilere çürüyen diziler önemli bir istisna sunar, ancak genel açıklama iyidir.
dasblinkenlight

6
@dasblinkenlight: diziler, C :('de boğuşma noktasıdır
Matthieu M.

55

Değere göre arama ve başvuruya göre arama, uzun zaman önce parametre geçiş modları ile hatalı olan uygulama teknikleridir.

Başlangıçta, FORTRAN vardı. FORTRAN sadece referans çağrısına sahipti, çünkü alt rutinler parametrelerini değiştirebiliyordu ve hesaplama döngüleri birden fazla parametre geçme moduna izin veremeyecek kadar pahalıydı, artı FORTRAN ilk tanımlandığında programlama hakkında yeterince bilgi sahibi değildi.

ALGOL isim-by-isim ve by-value ile geldi. Değeri arama, değiştirilmemesi gereken şeyler içindi (giriş parametreleri). Ada göre yapılan çağrı, çıktı parametreleri içindi. Adına göre çağrı büyük bir güveç olduğu ortaya çıktı ve ALGOL 68 bunu bıraktı.

PASCAL, değerine göre arama ve referansa göre arama sağladı. Programcıya, parametre yığınını üflemekten kaçınmak için derleyiciye referans olarak büyük bir nesneyi (genellikle bir dizi) geçirdiğini, ancak nesnenin değiştirilmemesi gerektiğini söyleme yolu yoktur.

PASCAL, dil tasarım sözlüğüne işaretçiler ekledi.

C, bir değer göstergesini ve bellekteki herhangi bir nesneye bir gösterici döndürmek için bir kludge operatörü tanımlayarak referans-referans çağrısını sağladı.

Daha sonra diller C'yi kopyaladı, çünkü tasarımcılar daha önce başka hiçbir şey görmediler. Bu muhtemelen, aramaya göre arama değerinin bu kadar popüler olmasının nedenidir.

C ++ referans çağrısı sağlamak için C çamurunun üstüne bir çamur ekledi.

Şimdi, bir değere göre çağrıya karşı-referansa göre çağrıya karşı-çağrı-by-pointer-kludge'in doğrudan bir sonucu olarak, C ve C ++ (programlayıcılar) const işaretçileri ve işaretçilerine yapışacak korkunç baş ağrıları vardır (salt okunur). itiraz ediyor.

Ada bütün bu kabustan uzak durmayı başardı.

Ada açık bir değer-by-by-referans çağrısına sahip değildir. Daha ziyade, Ada'nın parametreleri (okunabilir ancak yazılmayabilir), parametreleri (okunmadan önce yazılması zorunludur) ve parametreleri, herhangi bir sırada okunup yazılabilen parametreleri vardır. Derleyici, belirli bir parametrenin değere mi yoksa referansa göre mi geçileceğine karar verir: programlayıcı için şeffaftır.


1
+1. Bu, şu ana kadar burada gördüğüm tek cevap, aslında soruya cevap veriyor ve mantıklı geliyor ve bunu FP yanlısı bir rant için şeffaf bir bahane olarak kullanmıyor.
Mason Wheeler

11
"Daha sonra diller C'yi kopyaladı, çünkü çoğunlukla tasarımcılar başka bir şey görmediler." Her ne zaman 0-ön eklenmiş sekizlik sabitleri ile yeni bir dil görsem biraz içeride ölürüm.
librik

4
Bu programlama İncil'in ilk cümlesi olabilir: In the beginning, there was FORTRAN.

1
ADA ile ilgili olarak, genel bir değişken bir giriş / çıkış parametresine iletilirse, dil, iç içe bir aramanın onu incelemesini veya değiştirmesini engeller mi? Olmazsa, giriş / çıkış ve ref parametreleri arasında net bir fark olacağını düşünüyorum. Şahsen, dilleri açıkça "giriş / çıkış / giriş + çıkış" ve "değere göre / ref / umursamayan" tüm kombinasyonlarını desteklediğini görmek istiyorum; Uygulamada [programcının niyetine göre ayarlandığı sürece] maksimum esnekliğe sahip olacaktır.
supercat

2
@Neikos Ayrıca 0ön ekin , on temel olmayan diğer ön eklerle tutarsız olduğu da bir gerçek . Bu, C (ve çoğunlukla kaynağa uyumlu diller, örneğin C ++, Objective C) 'de mazeret olabilir, eğer oktal tanıtıldığında tek alternatif üstüyse , ama daha modern diller her ikisini birden kullandığında 0xve 0en baştan, kötü görünmesini sağlar düşünülmüş.
8bittree

13

Referansa göre geçmek, istenmeyen davranışa neden olduklarında izlerinin sürülmesinin imkansız olması yanında çok zor olan istenmeyen istenmeyen yan etkilere izin verir.

Özellikle, değeriyle geçirin final, staticya da constgiriş parametreleri böcek yok bu tüm sınıf yapar.

Değiştirilemeyen diller, neyin girdiğini ve bir işlevden neyin gelmesi beklendiğini anlamak ve mantıklı olmak için daha belirleyicidir.


7
Her şeyin varsayılan olarak referans aldığı 'eski' VB kodunu hata ayıklamaya çalıştıktan sonra anladığınız şeylerden biri.
jfrankcarr

Belki de sadece arkaplanım farklıdır, ama ne hakkında "izini sürmek imkansız olanın yanında çok zor olan çok ince istenmeyen istenmeyen yan etkiler" hakkında hiçbir fikrim yok. Pascal'a alışkınım, burada by-value varsayılandır ancak by-reference parametresi açıkça işaretlenerek kullanılabilir (temelde C # ile aynı model) ve benim için sorunlara neden olmadı. By-ref'in varsayılan olduğu "antik VB" de sorunlu olacağını görebiliyorum, ancak by-ref tercih edildiğinde, yazarken bunu düşünmenizi sağlıyor.
Mason Wheeler

4
@MasonWheeler arkanızda gelen yenilikler hakkında ne düşünüyorsunuz ve ne yaptığınızı kopyalamadan kopyalayın ve bu durumu her yerde dolaylı olarak manipüle etmeye başlayın, gerçek dünya her zaman olur. Daha az dolaylı olmak iyi bir şey. İnanılmaz en iyisidir.

1
@MasonWheeler Basit bir takma ad örnekleri, Swapgeçici değişken kullanmayan bilgisayar korsanları gibi , ancak kendileri için bir problem olmayacak olsa da, daha karmaşık bir örneğin hata ayıklamak için ne kadar zor olabileceğini gösteriyor.
Mark Hurd

1
@MasonWheeler: FORTRAN'daki "Değişkenler olmaz; sabitler değil" diyen klasik örnek, 3.0 parametresini değiştiren bir işleve kayan nokta sabitinden geçiyordu. Bir fonksiyona geçirilen herhangi bir kayan nokta sabiti için, sistem uygun değerde başlatılan ve fonksiyonlara geçirilebilecek bir "gizli" değişken yaratacaktır. Eğer fonksiyon parametresine 1.0 eklerse, programdaki keyfi bir 3.0 'lık alt küme aniden 4.0' olur.
supercat

8

Neden bu kadar çok dil değer olarak geçiyor?

Büyük programları küçük alt programlara bölmenin amacı, alt programlara bağımsız olarak sebep olabileceğinizdir. Referansa göre bu özelliği keser. (Paylaşılabilir değişken durumu olduğu gibi.)

Eğer her zaman değeriyle geçirilen C gibi açık işaretçi manipülasyon olsa bile diller (siz yapabilirsiniz referans olarak onları geçmek ama bu varsayılan davranış değil).

Aslında, C her zaman değer by-pass, asla by-by-referans. Bir şeyin adresini alabilir ve bu adresi iletebilirsiniz, ancak adres yine de değere göre iletilir.

Bunun faydası nedir, neden bu kadar çok dil değerler tarafından iletiliyor ve diğerleri neden referans olarak geçiyor ?

Referansa göre kullanmanın iki ana nedeni vardır:

  1. çoklu dönüş değerlerini simüle etme
  2. verim

Şahsen, # 1’in sahte olduğunu düşünüyorum: Neredeyse her zaman kötü API ve / veya dil tasarımı için bir bahane:

  1. Birden fazla dönüş değerine ihtiyacınız varsa, bunları simüle etmeyin, sadece onları destekleyen bir dil kullanın.
  2. Çoklu dönüş değerlerini, parantez gibi bazı hafif veri yapılarına paketleyerek de simüle edebilirsiniz. Bu, özellikle dil örüntü eşleştirme veya yok etme bağını destekliyorsa işe yarar. Örneğin Ruby:

    def foo
      # This is actually just a single return value, an array: [1, 2, 3]
      return 1, 2, 3
    end
    
    # Ruby supports destructuring bind for arrays: a, b, c = [1, 2, 3]
    one, two, three = foo
    
  3. Çoğu zaman, çoklu geri dönüş değerlerine bile ihtiyacınız yoktur. Örneğin, popüler bir model, alt rutinin bir hata kodu döndürmesi ve gerçek sonucun referans ile geri yazılmasıdır. Bunun yerine, hata beklenmeyen bir durumsa, bir istisna atmanız veya bir Either<Exception, T>hata olması durumunda döndürmeniz gerekir . Bir başka model, işlemin başarılı olup olmadığını belirten bir boole döndürmek ve gerçek sonucu referans olarak döndürmektir. Yine, başarısızlık beklenmiyorsa, bunun yerine bir istisna atmalısınız, başarısızlık bekleniyorsa, örneğin bir sözlükte bir değer ararken, Maybe<T>bunun yerine bir geri dönmelisiniz.

Referansa göre by-pass değerine göre daha verimli olabilir, çünkü değeri kopyalamanız gerekmez.

(Anladığım kadarıyla Haskell referans tarafından geçti ancak emin değilim).

Hayır, Haskell referans yoluyla değil. Aynı zamanda değer geçişi de değildir. Referansa göre geçiş ve değere göre geçiş değeri hem katı değerlendirme stratejileridir, hem de Haskell katı değildir.

Aslında, Haskell Spesifikasyonu herhangi bir özel değerlendirme stratejisi belirtmemektedir . Hakell uygulamalarının çoğu, isim-arama ve ihtiyaç-arama (not ile bir arama-arama varyantı) karışımını kullanır, ancak standart bunu zorunlu kılmaz.

Sıkı diller için bile, referans dilleri veya referans by pass değerleri arasında ayrım yapmanın bir anlamı yoktur, çünkü aralarındaki fark ancak referansı değiştirirseniz görülebilir. Bu nedenle, uygulayıcı dil anlamını bozmadan, ikisi arasında seçim yapmakta serbesttir.


9
"Birden fazla dönüş değerine ihtiyacınız varsa, bunları simüle etmeyin, sadece onları destekleyen bir dil kullanın." Bu söylemesi biraz garip bir şey. Temel olarak "diliniz ihtiyaç duyduğunuz her şeyi yapabilirse, ancak muhtemelen kodunuzun% 1'inden daha azına ihtiyaç duyacağınız bir özellik - ancak yine de % 1'ine ihtiyacınız olacak - söylenemez özellikle temiz bir yol, o zaman diliniz projeniz için yeterince iyi değil ve her şeyi başka bir dilde yeniden yazmalısınız. " Üzgünüm, ama bu sadece saçma.
Mason Wheeler

+1 Bu noktaya tamamen katılıyorum Büyük programları küçük alt programlara bölmenin amacı, alt programlara bağımsız olarak sebep olabileceğinizdir. Referansa göre bu özelliği keser. (Paylaşılabilir durumu paylaşır.)
Rémi

3

Dilin çağıran modeline, argüman türüne ve dilin bellek modellerine bağlı olarak farklı davranışlar vardır.

Basit yerel türlerde, değere göre geçirmek, değeri kayıtlara göre iletmenizi sağlar. Bu değer çok hızlı olabilir çünkü değerin bellekten yüklenmesi gerekmemektedir. Benzer bir optimizasyon, yalnızca, callee onunla yapıldığında, argüman tarafından kullanılan hafızayı yeniden kullanarak, nesnenin arayan kopyasını karıştırmama riski olmadan da mümkündür. Eğer argüman geçici bir nesne olsaydı, muhtemelen tam bir kopyasını kaydetmiş olacaktınız (C ++ 11 bu tür bir optimizasyonu yeni sağ referans ve onun taşıma anlamında daha da belirginleştiriyor).

Birçok OO dilinde (C ++ bu bağlamda bir istisnadır), bir nesneyi değerden geçiremezsiniz. Referans olarak geçmek için zorlanıyorsunuz. Bu, kodu varsayılan olarak polimorfik hale getirir ve OO'ya uygun örnekler kavramıyla satır içidir. Ayrıca, değere göre geçmek istiyorsanız, bu tür bir işlemi yapan performansın maliyetini kabul ederek kendiniz bir kopyasını almalısınız. Bu durumda, dil sizin için en iyi performansı vermesi daha muhtemel olan yaklaşımı seçer.

İşlevsel dillerde, değer veya referansa göre geçen sadece bir optimizasyon meselesidir. Bu gibi bir dilde işlevler saf ve yan etkilerden arındırılmış olduğundan, hız dışında değeri kopyalamak için hiçbir neden yoktur. Bu dilin genellikle aynı değerlere sahip nesnelerin aynı kopyasını paylaştığından bile eminim, ancak bir geçiş (const) referans semantik kullandıysanız kullanılabilecek bir olasılık. Python ayrıca, bu numarayı Python'da neden tamsayı ve dizgelerin sabit nesneler olduğunu açıklayan tamsayı ve ortak dizgiler (yöntemler ve sınıf isimleri gibi) için de kullandı. Bu ayrıca, örneğin içerik karşılaştırması yerine işaretçi karşılaştırmasına izin vererek ve bazı dahili verilerin tembel değerlendirmesini yaparak kodu tekrar en iyi duruma getirmeye yardımcı olur.


2

Bir ifadeyi değerine göre iletebilirsiniz, bu doğaldır. İfade (geçici) referansla iletiliyor ... garip.


1
Ayrıca, ifadeyi geçici referansa göre iletmek, kötü bir hataya (durumsal dilde), mutlulukla değiştirdiğiniz zaman (yalnızca geçici olduğundan) yol açabilir, ancak daha sonra bir değişkeni geçirdiğinizde geri tepir ve foo'yu geçmek gibi çirkin bir geçici çözüm geliştirmelisiniz Foo yerine +0.
herby,

2

Eğer referans ile geçerseniz, global kürelerin tüm sorunlarıyla (kapsam ve istenmeyen yan etkiler gibi) her zaman etkin bir şekilde çalışıyorsunuzdur.

Referanslar, tıpkı globaller gibi, bazen yararlı olabilir, ancak ilk tercihiniz olmamalıdır.


3
İlk cümlede referans olarak geçmek demek istediğinizi varsayıyorum?
jk.
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.