Pertanyaan Haruskah fungsi hanya memiliki satu pernyataan pengembalian?


Apakah ada alasan bagus mengapa itu adalah praktik yang lebih baik untuk hanya memiliki satu pernyataan pengembalian dalam suatu fungsi?

Atau tidak apa-apa untuk kembali dari fungsi segera setelah logis secara logis untuk melakukannya, yang berarti mungkin ada banyak pernyataan kembali dalam fungsi?


781


asal


Jawaban:


Saya sering memiliki beberapa pernyataan di awal suatu metode untuk kembali untuk situasi "mudah". Misalnya, ini:

public void DoStuff(Foo foo)
{
    if (foo != null)
    {
        ...
    }
}

... dapat dibuat lebih mudah dibaca (IMHO) seperti ini:

public void DoStuff(Foo foo)
{
    if (foo == null) return;

    ...
}

Jadi ya, saya pikir tidak apa-apa memiliki beberapa "titik keluar" dari fungsi / metode.


743



Tidak ada yang menyebutkan atau mengutip Kode Lengkap jadi saya akan melakukannya.

17,1 kembali

Minimalkan jumlah pengembalian di setiap rutin. Lebih sulit untuk memahami rutinitas jika, membacanya di bagian bawah, Anda tidak menyadari kemungkinan bahwa itu kembali ke suatu tempat di atas.

Gunakan kembali saat ini meningkatkan keterbacaan. Dalam rutinitas tertentu, begitu Anda tahu jawabannya, Anda ingin mengembalikannya ke rutin pemanggilan. Jika rutinitas didefinisikan sedemikian rupa sehingga tidak memerlukan pembersihan, tidak segera kembali berarti Anda harus menulis lebih banyak kode.


355



Saya akan mengatakan itu akan sangat tidak bijaksana untuk memutuskan secara sewenang-wenang melawan beberapa titik keluar karena saya telah menemukan teknik untuk menjadi berguna dalam praktek lagi dan lagi, sebenarnya saya sudah sering refactored kode yang ada ke beberapa titik keluar untuk kejelasan. Kita dapat membandingkan kedua pendekatan itu: -

string fooBar(string s, int? i) {
  string ret = "";
  if(!string.IsNullOrEmpty(s) && i != null) {
    var res = someFunction(s, i);

    bool passed = true;
    foreach(var r in res) {
      if(!r.Passed) {
        passed = false;
        break;
      }
    }

    if(passed) {
      // Rest of code...
    }
  }

  return ret;
}

Bandingkan ini dengan kode tempat beberapa titik keluar adalah diizinkan: -

string fooBar(string s, int? i) {
  var ret = "";
  if(string.IsNullOrEmpty(s) || i == null) return null;

  var res = someFunction(s, i);

  foreach(var r in res) {
      if(!r.Passed) return null;
  }

  // Rest of code...

  return ret;
}

Saya pikir yang terakhir jauh lebih jelas. Sejauh yang saya tahu, kritikan tentang beberapa titik keluar adalah pandangan yang agak kuno akhir-akhir ini.


229



Saat ini saya sedang mengerjakan basis kode di mana dua orang yang mengerjakannya secara membabi buta menganut teori "satu titik keluar" dan saya dapat memberi tahu Anda bahwa dari pengalaman, ini adalah praktik mengerikan yang mengerikan. Itu membuat kode sangat sulit dipertahankan dan saya akan menunjukkan alasannya.

Dengan teori "titik keluar tunggal", Anda pasti berakhir dengan kode yang terlihat seperti ini:

function()
{
    HRESULT error = S_OK;

    if(SUCCEEDED(Operation1()))
    {
        if(SUCCEEDED(Operation2()))
        {
            if(SUCCEEDED(Operation3()))
            {
                if(SUCCEEDED(Operation4()))
                {
                }
                else
                {
                    error = OPERATION4FAILED;
                }
            }
            else
            {
                error = OPERATION3FAILED;
            }
        }
        else
        {
            error = OPERATION2FAILED;
        }
    }
    else
    {
        error = OPERATION1FAILED;
    }

    return error;
}

Tidak hanya ini membuat kode sangat sulit untuk diikuti, tetapi sekarang katakan nanti Anda harus kembali dan menambahkan operasi di antara 1 dan 2. Anda harus indent saja tentang seluruh fungsi freaking, dan semoga berhasil memastikan semua Anda jika / ketentuan lain dan kawat gigi dicocokkan dengan benar.

Metode ini membuat pemeliharaan kode sangat sulit dan rawan kesalahan.


191



Pemrograman terstruktur mengatakan Anda seharusnya hanya memiliki satu pernyataan pengembalian per fungsi. Ini untuk membatasi kerumitan. Banyak orang seperti Martin Fowler berpendapat bahwa lebih mudah untuk menulis fungsi dengan beberapa pernyataan kembali. Dia menyajikan argumen ini dalam klasik refactoring buku yang ditulisnya. Ini berfungsi dengan baik jika Anda mengikuti sarannya yang lain dan menulis fungsi-fungsi kecil. Saya setuju dengan sudut pandang ini dan hanya puritan pemrograman terstruktur yang ketat yang mematuhi pernyataan pengembalian tunggal per fungsi.


72



Seperti dicatat Kent Beck ketika membahas klausa penjaga di Pola Implementasi membuat rutinitas memiliki satu titik masuk dan keluar ...

"adalah untuk mencegah kebingungan itu   ketika melompat masuk dan keluar dari banyak   lokasi dalam rutinitas yang sama. Itu dibuat   akal sehat saat diterapkan pada FORTRAN atau   program bahasa assembly ditulis   dengan banyak data global bahkan   memahami pernyataan yang mana   dieksekusi adalah kerja keras ... dengan metode kecil dan kebanyakan data lokal, itu tidak perlu konservatif. "

Saya menemukan fungsi yang ditulis dengan klausa penjaga yang lebih mudah diikuti daripada sekelompok bertumpuk panjang if then else pernyataan.


62



Dalam fungsi yang tidak memiliki efek samping, tidak ada alasan yang baik untuk memiliki lebih dari satu kali pengembalian dan Anda harus menulisnya dalam gaya fungsional. Dalam metode dengan efek samping, hal-hal lebih berurutan (time-indexed), jadi Anda menulis dalam gaya imperatif, menggunakan pernyataan kembali sebagai perintah untuk berhenti mengeksekusi.

Dengan kata lain, bila mungkin, nikmatilah gaya ini

return a > 0 ?
  positively(a):
  negatively(a);

lebih dari ini

if (a > 0)
  return positively(a);
else
  return negatively(a);

Jika Anda menemukan diri Anda menulis beberapa lapis kondisi yang disarangkan, mungkin ada cara Anda dapat mem-refactor itu, menggunakan daftar predikat misalnya. Jika Anda menemukan bahwa ifs dan elses Anda terpisah secara sintaksis, Anda mungkin ingin memecahnya menjadi fungsi yang lebih kecil. Blok bersyarat yang membentang lebih dari satu layar penuh teks sulit dibaca.

Tidak ada aturan keras dan cepat yang berlaku untuk setiap bahasa. Sesuatu seperti memiliki pernyataan balasan tunggal tidak akan membuat kode Anda bagus. Tetapi kode yang baik akan cenderung memungkinkan Anda untuk menulis fungsi Anda seperti itu.


61



Saya pernah melihatnya dalam standar pengkodean untuk C ++ yang merupakan hang-over dari C, seolah-olah Anda tidak memiliki RAII atau manajemen memori otomatis lainnya maka Anda harus membersihkan untuk setiap pengembalian, yang berarti cut-and-paste dari pembersihan atau goto (secara logis sama dengan 'akhirnya' dalam bahasa yang dikelola), keduanya dianggap sebagai bentuk buruk. Jika praktik Anda menggunakan pointer cerdas dan koleksi di C ++ atau sistem memori otomatis lainnya, maka tidak ada alasan kuat untuk itu, dan itu menjadi semua tentang keterbacaan, dan lebih dari panggilan penilaian.


43