Lingkup dan Masa Hidup

Variabel lokal, field kelas, dan perilaku shadowing.

Daftar isi

Lingkup (scope) adalah wilayah kode di mana sebuah nama variabel dapat dipakai, sedangkan masa hidup (lifetime) adalah lamanya nilai variabel itu bertahan. Topik ini membahas lingkup variabel lokal, peran field pada kelas, serta perilaku shadowing ketika dua nama sama bertemu. Setelah topik ini, letak deklarasi variabel dapat ditentukan secara sadar, bukan sekadar mengikuti kebiasaan menulis.

Lingkup variabel lokal#

Variabel yang dideklarasikan di dalam blok hanya sah di blok itu dan di blok yang lebih dalam, dan namanya lenyap begitu blok berakhir. Blok adalah kode di antara sepasang kurung kurawal, termasuk badan metode, badan if, dan badan perulangan. Lingkup yang sempit adalah pilihan yang baik, karena masa hidup variabel yang pendek mempersempit wilayah kode yang dapat mengubah nilainya. Kebiasaan mendeklarasikan seluruh variabel sekaligus di awal metode justru memperlebar lingkupnya tanpa keperluan, sehingga deklarasi diletakkan sedekat mungkin dengan pemakaiannya.

csharp Contoh: lingkup blok if
int luar = 10;

if (luar > 5)
{
    int dalam = luar * 2;
    Console.WriteLine($"dalam = {dalam}");
}

Console.WriteLine($"luar = {luar}");
text Keluaran
dalam = 20
luar = 10

Variabel dalam lahir di dalam blok if dan habis begitu blok tersebut selesai, sehingga pemakaiannya setelah blok ditolak kompilator dengan error CS0103. Sebaliknya, variabel luar dideklarasikan di tingkat teratas sehingga terlihat oleh seluruh blok di dalamnya. Aturan yang sama berlaku pada perulangan, karena variabel yang dideklarasikan pada kepala perulangan for hanya sah di dalam perulangan itu. C# juga menolak deklarasi ulang nama yang sudah dipakai lingkup luarnya dengan error CS0136, sebuah penjagaan yang mencegah kebingungan soal nilai mana yang sedang dirujuk.

Field kelas dan masa hidupnya#

Field adalah variabel yang dideklarasikan langsung di dalam kelas, dan nilainya bertahan selama objek yang memuatnya masih dirujuk program. Perbedaannya dengan variabel lokal terlihat jelas pada metode yang dipanggil berulang, karena setiap pemanggilan memulai masa hidup baru untuk variabel lokalnya, sedangkan field tetap menyimpan nilai dari pemanggilan sebelumnya. Program utuh berikut membandingkan keduanya. Salin programnya ke berkas Program.cs, lalu jalankan dengan dotnet run --file Program.cs.

csharp Program.cs
// Lingkup menentukan wilayah di mana sebuah nama dapat dipakai.
// Masa hidup menentukan berapa lama nilai sebuah variabel bertahan.

var rekap = new RekapNilai();
Console.WriteLine(rekap.Baca());
Console.WriteLine(rekap.Baca());
Console.WriteLine(rekap.Baca());

// Variabel lokal hidup hanya selama pemanggilan metode ini berlangsung.
int sementara = 99;
Console.WriteLine($"Nilai lokal: {sementara}");

class RekapNilai
{
    // Field jumlah bertahan selama objek RekapNilai masih dirujuk.
    private int jumlah;

    // Setiap pemanggilan memulai masa hidup baru untuk variabel lokal urutan.
    public string Baca()
    {
        int urutan = jumlah + 1;
        jumlah = urutan;
        return $"Pembacaan ke-{urutan}, total {jumlah}";
    }
}
text Keluaran
Pembacaan ke-1, total 1
Pembacaan ke-2, total 2
Pembacaan ke-3, total 3
Nilai lokal: 99

Setiap pemanggilan Baca menciptakan variabel lokal urutan yang baru, sehingga nilainya selalu dihitung ulang dari field jumlah. Field jumlah tidak ikut lenyap di antara pemanggilan karena bertahan bersama objek rekap. Tanda private membatasi akses field ke dalam kelasnya, sedangkan kata kunci static pada field menyatakan nilainya bersifat tunggal untuk seluruh kelas dan bertahan sepanjang program berjalan.

Field yang tidak diinisialisasi tetap memiliki nilai awal yang teratur, yaitu 0 untuk field bertipe angka dan false untuk field bool, sehingga pembacaan pertamanya tidak pernah gagal. Masa hidup objek itu sendiri berakhir apabila tidak ada lagi rujukan yang menunjuknya, dan pembersihannya diserahkan kepada garbage collector, yaitu bagian runtime yang mendaur ulang memori objek yang tidak terpakai. Aturan sederhananya, data yang seharusnya hilang di akhir metode cukup menjadi variabel lokal, sedangkan data yang harus diingat antar pemanggilan menjadi field.

Shadowing antara parameter dan field#

Shadowing (shadowing) terjadi apabila parameter atau variabel lokal memakai nama yang sama dengan field, sehingga nama field tertutup selama metode itu berjalan.

csharp Contoh: parameter menutupi field
var catatan = new Catatan();
Console.WriteLine(catatan.Simpan("suhu 30 derajat"));
Console.WriteLine($"Isi field: {catatan.Isi}");

// Parameter isi menutupi field Isi selama metode Simpan berjalan.
class Catatan
{
    public string Isi = "(kosong)";

    public string Simpan(string isi)
    {
        Isi = isi;
        return "Catatan disimpan";
    }
}
text Keluaran
Catatan disimpan
Isi field: suhu 30 derajat

Di dalam metode Simpan, nama isi merujuk pada parameter, sedangkan Isi merujuk pada field karena keduanya dibedakan huruf kapitalnya. Apabila nama keduanya persis sama, pembedaan dilakukan dengan kata kunci this, misalnya this.Isi = isi, karena this menunjuk objek tempat metode itu berjalan.

Shadowing tidak dilarang, tetapi pemakaiannya menuntut kewaspadaan tambahan dari setiap pembaca kode. Konvensi yang lazim adalah memberi field nama dengan awalan garis bawah seperti _isi, sehingga field dan parameter tampak berbeda tanpa perlu memeriksa deklarasinya. Penamaan yang menjaga perbedaan itu tetap menjadi pilihan paling sederhana agar pembacaan kode tidak perlu berhenti untuk memastikan rujukannya.

Kesalahan umum#

Perhatikan kesalahan yang sering muncul pada pengelolaan lingkup dan masa hidup.

  • Memakai variabel di luar bloknya ditolak dengan error CS0103, dan perbaikannya adalah mendeklarasikan variabel pada lingkup yang lebih luas atau memindahkan pemakaiannya ke blok yang sama.
  • Mendeklarasikan ulang nama yang sudah dipakai lingkup luarnya ditolak dengan error CS0136, dan perbaikannya adalah mengganti nama variabel yang baru.
  • Mengandalkan variabel lokal untuk menyimpan nilai antar pemanggilan menghasilkan nilai yang selalu kembali ke keadaan awalnya, karena variabel lokal lahir baru pada setiap pemanggilan. Perbaikannya adalah memindahkan data tersebut ke field.
  • Penugasan isi = isi pada parameter yang menutupi field hanya memicu peringatan CS1717, sehingga nilai field tidak pernah berubah. Tulis Isi = isi atau this.Isi = isi agar penugasan tepat sasaran.

Ringkasan#

  • Lingkup menentukan wilayah sahnya sebuah nama, dan variabel lokal hanya sah di blok deklarasinya beserta blok di dalamnya.
  • Masa hidup variabel lokal adalah sepanjang satu pemanggilan, sedangkan field bertahan selama objeknya masih dirujuk.
  • Shadowing terjadi bila parameter atau variabel lokal menutupi nama field, dan kata kunci this membedakan keduanya.

Referensi#