Ruby'de açıkça geri dönmek iyi bir stil mi?


155

Stil söz konusu olduğunda her zaman "bunu yapmanın doğru yolu" ("Pythonic" yolu) olan bir Python arka planından geliyorum, Ruby için de bunun olup olmadığını merak ediyorum. Kendi stil yönergelerimi kullanıyorum, ancak kaynak kodumu serbest bırakmayı düşünüyorum ve var olabilecek yazılı olmayan kurallara uymasını istiyorum.

Açıkça returnyöntemlerle yazmak "Ruby Way" mi? Yaptım ve yapmadım gördüm, ama bunu yapmanın doğru bir yolu var mı? Bunu yapmak için belki doğru zaman var mı? Örneğin:

def some_func(arg1, arg2, etc)
  # Do some stuff...
  return value # <-- Is the 'return' needed here?
end

3
Bu çok eski bir soru, ancak benzer soruları olanlar için Eloquent Ruby kitabı şiddetle tavsiye edilir. Deyimsel Ruby yazmaya giriş kadar bir stil rehberi değildir. Keşke daha fazla kişi onu okuyabilseydi!
Brian Sevgili

Ruby'de geliştirilen büyük bir eski uygulamayı devralan biri olarak, bu soruyu sorduğunuz için çok minnettarım. Bu bir oylamayı hak ediyor. Bu bizim eski uygulaması boyunca çöp. Bu ekipteki işlerimden biri kod tabanını (Ruby'de yeniyken zor) geliştirmek.
Stevers

Yanıtlar:


226

Eski (ve "cevaplandı") sorusu, ama cevap olarak iki sentime atılacağım.

TL; DR - Zorunda değilsiniz, ancak bazı durumlarda kodunuzu çok daha net hale getirebilir.

Açık bir dönüş kullanmamak "Ruby yolu" olsa da, tanıdık kodla çalışan veya Ruby'nin bu özelliğine aşina olmayan programcılar için kafa karıştırıcıdır.

Biraz çelişkili bir örnek, ancak geçen sayıya bir ekleyen ve bir örnek değişkenine atayan böyle küçük bir işleve sahip olduğunuzu düşünün.

def plus_one_to_y(x)
    @y = x + 1
end

Bu bir değer döndüren bir işlev miydi, değil miydi? Her ikisi de örnek değişkenini atadığı için VE geliştiricinin ne anlama geldiğini söylemek gerçekten zor VE atanan değeri de döndürüyor.

Çok daha sonra, başka bir programcı (belki de Ruby'nin yürütülen son kod satırına göre nasıl döndüğüne aşina olmadığı) varsayalım ve günlüğe kaydetmek için bazı yazdırma ifadeleri koymak istiyor ve işlev bu hale geliyor ...

def plus_one_to_y(x)
    @y = x + 1
    puts "In plus_one_to_y"
end

Şimdi bir şey döndürülen bir değer bekliyorsa işlev bozulur . Hiçbir şey döndürülen bir değer beklemiyorsa, sorun olmaz. Kod zincirinin aşağısında bir yerde, bunu çağıran bir şey döndürülen bir değer bekliyorsa, beklediği şeyi geri almadığı için başarısız olacaktır.

Şimdi asıl soru şudur: bir şey gerçekten döndürülen bir değer bekliyor muydu? Bu bir şey mi kırdı yoksa değil mi? Gelecekte bir şey kıracak mı? Kim bilir! Tüm aramaların yalnızca tam kod incelemesi size bildirir.

Bu yüzden en azından benim için en iyi uygulama yaklaşımı ya bir şeyi önemliyse iade ettiğinizin çok açık olması ya da hiç olmadığı zaman hiçbir şey döndürmemenizdir.

Bu yüzden küçük demo fonksiyonumuzda, bir değer döndürmesini istediğimizi varsayarsak, bu şekilde yazılır ...

def plus_one_to_y(x)
    @y = x + 1
    puts "In plus_one_to_y"
    return @y
end

Ve herhangi bir programcı için bir değer döndürdüğü çok açıktır ve farkında olmadan onu kırmaları çok daha zordur.

Alternatif olarak, bu şekilde yazılabilir ve dönüş ifadesini bırakabilir ...

def plus_one_to_y(x)
    @y = x + 1
    puts "In plus_one_to_y"
    @y
end

Ama neden kelime dönüşünü bırakarak zahmet ediyorsunuz? Neden sadece oraya koyup neler olduğunu% 100 netleştirmiyorsunuz? Kodunuzun gerçekleştirme yeteneği üzerinde hiçbir etkisi olmayacaktır.


6
İlginç bir nokta. Orijinal geliştiricinin kodlarında örtük dönüş değerini kullandığı bu soruyu sorduğumda aslında benzer bir duruma girdim ve neler olduğunu anlamak çok zordu. Cevabınız için teşekkürler!
Sasha Chedygov

6
Bu soruyu yaktığım için örtük getirilerle Google'da çalışırken soruyu buldum. Örtük olarak bir şey döndüren bir işlevin sonuna biraz mantık ekledim. Çoğu çağrı döndürülen değeri umursamadı (veya kontrol etmedi), ama biri yaptı - ve başarısız oldu. Neyse ki en azından bazı fonksiyonel testlerde ortaya çıktı.
Tim Holt

16
Doğru olsa da, kodun okunabilmesi önemlidir, bir programlama dilinin iyi bilinen bir özelliğinin ayrıntılara dayanarak lehine dönmesi, bence kötü bir uygulamadır. Bir geliştirici Ruby'ye aşina değilse, belki de koda dokunmadan önce aşina olması gerekir. Ben sadece Ruby olmayan bazı geliştirici daha sonra bir şey yapmak zorunda gelecek olay için kod dağınıklığı artırmak zorunda biraz aptalca buluyorum. Bir dili en düşük ortak paydaya indirmemeliyiz. Ruby'nin güzelliğinin bir parçası, sadece 3 alması gereken bir şey söylemek için 5 satır kod kullanmamız gerekmemesidir.
Brian Sevgili

25
Sözcük returnkoda anlamsal anlam eklerse, neden olmasın? Çok ayrıntılı değil - 3 satır vs 3 konuşmuyoruz, sadece bir kelime daha. returnKod aslında ne yaptığını ifade etmek için en azından fonksiyonları (belki bloklar halinde) görmeyi tercih ederim . Bazen orta fonksiyona geri dönmeniz gerekir - returnsadece yapabildiğiniz için son satırdaki son anahtar kelimeyi dışarıda bırakmayın . Ben ayrıntı düzeyini hiç sevmiyorum ama tutarlılığı destekliyorum.
mindplay.dk

6
Bu harika bir cevap. Ancak yine de bir prosedür (örneğin işlev geri dönen birim) olmak üzere bir Ruby yöntemi yazmanız riskini ortadan kaldırır side_effect()ve başka bir geliştirici (ab) prosedürünüzün örtük dönüş değerini kullanmaya karar verir. Bunu düzeltmek için prosedürlerinizi açıkça yapabilirsiniz return nil.
Alex Dean

66

Hayır. İyi Yakut stili genellikle erken dönüş için yalnızca açık bir dönüş kullanır . Ruby kod minimalizminde / örtük büyüde büyüktür.

Bununla birlikte, açık bir geri dönüş işleri daha net veya daha kolay hale getirirse, hiçbir şeye zarar vermez.


116
Karmaşık maksimalizm ile sonuçlanırsa kod minimalizminin anlamı nedir?
jononomo

@JonCrowell Bunun yerine dokümantasyon maksimalizmi ile sonuçlanmalıdır.
jazzpi

29
@jazzpi bunu iyi olmak size alıştırma yapıyoruz, minimalizm antreman yapmıyoruz anlaşılan için ağır kodunuzu belgelemek varsa kod golf .
Schwern

2
Son dönüşü hariç tutmak kafa karıştırıcı değil, onu DAHİL ETMEK kafa karıştırıcı - Ruby geliştiricisi olarak returnzaten fonksiyona ERKEN ÇIKIŞ olarak önemli bir anlamsal anlamı var.
Devon Parsons

14
@DevonParsons Yeryüzünde nasıl birisi returnson satırda bir ERKEN ÇIKIŞ olarak karıştırılabilir ?
DarthPaghius

31

Ben şahsen fonksiyonel yöntemlerreturn dediğim , yani esas olarak dönüş değeri için yürütülen yöntemler ve birincil olarak yan etkileri için yürütülen prosedür yöntemleri arasında ayrım yapmak için anahtar kelimeyi kullanın . Dolayısıyla, dönüş değerinin önemli olduğu yöntemler, dönüş değerine dikkat çekmek için fazladan bir anahtar kelime edinin .return

Yöntemleri çağırırken aynı ayrımı kullanıyorum : fonksiyonel yöntemler parantez alır, yordamsal yöntemler kullanmaz.

Ve son fakat aynı derecede önemli olarak, bu ayrımı bloklarla da kullanıyorum: fonksiyonel bloklar kıvırcık parantezler, prosedür blokları (yani "bir şey yapan" bloklar) olsun do/ end.

Ancak, bu konuda dini olmaya çalışmıyorum: bloklarla, kıvırcık parantezlerle ve do/ endfarklı önceliğe sahip ve bir ifadeyi belirsizleştirmek için açık parantez eklemek yerine, sadece diğer stile geçiyorum. Aynı yöntem çağırma için de geçerlidir: parametre listesi etrafında parantez eklemek kodu daha okunabilir hale getirirse, söz konusu yöntem doğada prosedürel olsa bile bunu yaparım.


1
Şu anda yaptığınız şeye benzeyen herhangi bir "tek gömlekte" geri dönüşü atlıyorum ve diğer her şeyi aynı şekilde yapıyorum. Tarzımda tamamen kapalı olmadığımı bilmek güzel. :)
Sasha Chedygov

@Jorg: Kodunuzda erken iadeler kullanıyor musunuz? Bu, prosedür / fonksiyonel planınızla ilgili bir karışıklığa neden oluyor mu?
Andrew Grimm

1
@Ardrew Grimm: Evet ve Evet. Ben bunu tersine çevirmeyi düşünüyorum. Metodlarımın büyük çoğunluğu referans olarak şeffaf / saf / fonksiyonel / neyse onu aramak istediğiniz şeydir, bu yüzden orada daha kısa formu kullanmak mantıklıdır. Ve fonksiyonel tarzda yazılmış yöntemler erken dönüşlere sahip değildir, çünkü bu çok işlevsel olmayan "adım" kavramını ima eder. Yine de, ortadaki geri dönüşleri sevmiyorum. Onları başlangıçta koruma olarak veya sonunda kontrol akışını basitleştirmek için kullanıyorum.
Jörg W Mittag

Harika bir cevap, ancak prosedürel yöntemleri () ve fonksiyonel yöntemler olmadan çağırmak daha iyi bir uygulamadır - neden için aşağıdaki cevabımı görün
Alex Dean

13

Aslında önemli olan aşağıdakileri ayırt etmektir:

  1. İşlevler - dönüş değerleri için yürütülen yöntemler
  2. Prosedürler - yan etkileri için uygulanan yöntemler

Ruby'nin bunları ayırt etmenin yerel bir yolu yoktur - bu sizi bir prosedür yazmaya karşı savunmasız bırakır side_effect()ve başka bir geliştirici prosedürünüzün örtük dönüş değerini kötüye kullanmaya karar verir (temel olarak onu saf olmayan bir işlev olarak ele alır).

Bunu çözmek için Scala ve Haskell'in kitabından bir yaprak alın ve prosedürlerinizin açıkça nil( diğer dillerde Unitveya ()diğer dillerde) geri alınmasını sağlayın .

Bunu izlerseniz, açık returnsözdizimini kullanmak veya kullanmak kişisel bir stil meselesi haline gelir.

İşlevler ve prosedürler arasında daha fazla ayrım yapmak için:

  1. Jörg W Mittag'in işlevsel blokları kıvırcık parantezlerle ve prosedür bloklarını do/end
  2. Yordamları ()çağırırken işlevlerini çağırırken,

Kaçınarak - Jörg W Mittag aslında tersi savunduğu o Not ()ler prosedürler için - ama yan etkileyen yöntem invocations Arity 0. Bkz olduğu zaman, değişkenler açıkça ayırt olmak istiyorum çünkü tavsiye edilmez yöntem çağırma üzerinde Scala stil kılavuzu için detaylar.


Ben dönen değeri gerekiyorsa function_ave function_aaramaya yazılmıştır (ve arayarak işletmek yalnızca olabilir) procedure_b, daha sonra function_agerçekten bir fonksiyon? İşlevler için gereksiniminizi karşılayan bir değer döndürür, ancak prosedürlerin gereksinimlerini karşılayan bir yan etkisi vardır.
Devon Parsons

2
Haklısın Devon - function_abir procedure_...arama ağacı içerebilir , çünkü procedure_abir function_...arama ağacı içerebilir . Scala gibi ama Haskell'den farklı olarak Ruby'de bir işlevin yan etki yaratmadığının garantisi olamaz.
Alex Dean

8

Stil rehberi , returnson ifadenizde kullanmamanız gerektiğini belirtir . Sonuncusu değilse yine de kullanabilirsiniz . Bu, topluluğun sıkı bir şekilde takip ettiği sözleşmelerden biridir ve bu yüzden Ruby kullanan herhangi biriyle işbirliği yapmayı planlıyorsanız.


Bununla birlikte, açık returns kullanmanın ana argümanı , diğer dillerden gelen insanlar için kafa karıştırıcı olmasıdır.

  • İlk olarak, bu tamamen Ruby'ye özel değildir. Örneğin, Perl'in örtülü dönüşleri de vardır.
  • İkincisi, bunun geçerli olduğu insanların çoğunluğu Algol dillerinden geliyor. Bunların çoğu Ruby'den "düşük seviye" dir , bu nedenle bir şeyler yapmak için daha fazla kod yazmanız gerekir.

Java'da yöntem uzunluğu (alıcılar / ayarlayıcılar hariç) için ortak bir sezgisel tarama bir ekrandır . Bu durumda, yöntem tanımını görmüyor olabilirsiniz ve / veya nereden döndüğünüzü unutmuş olabilirsiniz.

Öte yandan, Ruby'de 10 satırdan daha kısa yöntemlere bağlı kalmak en iyisidir . Bunu göz önüne alındığında, açıkça ima edildiğinde neden ~% 10 daha fazla ifade yazması gerektiği merak edilebilir.


Ruby geçersiz yöntemlere sahip olmadığından ve her şey çok daha özlü olduğu için, açık returns ile giderseniz hiçbir fayda için ek yük eklersiniz .


1
"Bu, topluluğun sıkı bir şekilde takip ettiği sözleşmelerden biri" Deneyimlerim hayır, çok deneyimli Ruby geliştiricileri olmadıkça insanlar bunu kesinlikle takip etmiyor.
Tim Holt

1
@TimHolt O zaman çok şanslı olmalıydım. (:
ndnenkov

1
@ndn tamamen katılıyorum. Önemli olan, bir yöntem (veya sınıf) 5/100 çizgiyi aşmaya başladığında, neyi başarmaya çalıştığınızı yeniden düşünmek iyi bir fikirdir. Gerçekten Sandi'nin Kuralları, keyfi bir dogmanın aksine kodu düşünmek için bilişsel bir çerçevedir. Karşılaştığım kodun çoğunluğu sorunlu değil çünkü yapay olarak kısıtlanmış - genellikle tam tersi - birden fazla sorumluluğu olan sınıflar, birçok sınıftan daha uzun yöntemler. Esasen çok fazla insan "köpekbalığı atlamak" - sorumlulukları karıştırma.
Brian Sevgili

1
Bazen kongre hala kötü bir fikirdir. Büyüye dayanan, dönüş türlerini tahmin etmeyi zorlaştıran üslupsal bir kongre. 7 tuş vuruşunu kaydetmekten başka bir avantaj sunmaz ve hemen hemen tüm diğer dillerle uyumsuzdur. Ruby hiç bir Python 3 tarzı konsolidasyon ve basitleştirme geçişi yaparsa , kesme bloğunda ilk olan her şeyin örtülü olduğunu umarım .
Shayne

2
Açıkça görülmesi dışında, işleri daha kolay okumaz! Büyü ve anlaşılabilirlik, ame şey değildir.
Shayne

4

Ben Hughes ile aynı fikirdeyim ve Tim Holt ile aynı fikirde değilim, çünkü soru Python'un yaptığı gibi kesin bir şekilde bahsediyor ve Ruby'nin benzer bir standarda sahip olup olmadığını soruyor.

Öyle.

Bu, dilin çok iyi bilinen bir özelliğidir, yakutta bir sorunu ayıklaması beklenen herkesin bu konuda makul bir şekilde bilmesi beklenir.


3
Teoride sana katılıyorum, ama pratikte, programcılar hata yapar ve dağıtır. Durumda, hepimiz biliyoruz ki "==" koşullu değil "==" kullanıyorsunuz, ama TÜM bu hatayı daha önce yaptık ve sonraya kadar fark etmedik.
Tim Holt

1
@TimHolt Belirli bir kullanım durumunu ele almıyorum, sadece soruyu cevaplıyorum. Topluluk tarafından seçildiği gibi, returngereksiz olduğunda anahtar kelimeyi kullanmak açıkça kötü bir stildir .
Devon Parsons

3
Yeterince adil. Dikkatli olmazsan, bahsettiğin tarzın hatalara yol açabileceğini söylüyorum. Deneyimlerime dayanarak, kişisel olarak farklı bir tarzı savunuyorum.
Tim Holt

1
@TimHolt Bu arada, bu soru stil rehberi yazılmadan önce soruldu, bu yüzden katılmıyorum cevaplar mutlaka yanlış değil, sadece modası geçmiş. Burada bir şekilde olsa tökezledi ve sağladığım bağlantı görmedim, bu yüzden başka birinin de burada olabilir düşündüm.
Devon Parsons

1
Resmi bir "standart" değildir. Rubocop tarafından kullanılan ve yukarıda Devon Parsons tarafından var olduğu iddiasıyla bağlantılı olan yakut tarzı kılavuz, çekirdek olmayan bir yakut korsanı tarafından yaratılmıştır. Bu yüzden Devon'un yorumu aslında yanlış. Tabii ki STILL kullanabilirsiniz ama bu bir standart değildir.
shevy

1

Çoğunlukla hangi stili tercih edeceğiniz meselesi. Bir yöntemin ortasında bir yerden dönmek istiyorsanız return anahtar sözcüğünü kullanmanız gerekir.


0

Ben'in dediği gibi. 'Yakut yöntemin dönüş değerinin işlev gövdesindeki son ifadenin dönüş değeri olması' dönüş anahtar kelimesinin çoğu yakut yöntemde nadiren kullanılmasına neden olur.

def some_func_which_returns_a_list( x, y, z)
  return nil if failed_some_early_check


  # function code 

  @list     # returns the list
end

4
niyetiniz hala açıksa, "fail_some_early_check durumunda return nil" yazabilirsiniz
Mike Woodhouse

@Gishu Aslında yöntem adı değil, if ifadesinden şikayet ediyordum.
Andrew Grimm

@Andrew .. oh kayıp son :). Anladım. Mike'ın diğer yorumunu da yatıştırmak için düzeltildi.
Gishu

Neden olmasın if failed_check then nil else @list end? Bu gerçekten işlevsel .
cdunn2001

@ cdunn2001 O zaman neden başka bir işlevin işlevsel olduğu konusunda net değil .. bu stilin nedeni erken çıkışlarla yuvalamayı azaltmasıdır. IMHO da daha okunabilir.
Gishu
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.