EDA Playground'da Dene

Method Argüman Yönleri - input, output, inout ve ref Farkı

Gün 2: Method Argüman Yönleri | Yönlerin farkları

Bu derste bir task veya function'a argüman geçerken kullanılan dört yönü (input, output, inout, ref) ve özellikle sınıf handle'ları söz konusu olduğunda aralarındaki davranış farklarını öğreneceğiz. Bu farkları kavramak, doğrulama ortamında nesnelerin beklenmedik şekilde değişmesini (veya değişmemesini) anlamak için kritiktir.

Argüman Yönleri ve Kopyalama Mantığı

Bir handle (sınıf değişkeni) aslında bir nesneye işaret eden adrestir. Bir metoda handle geçtiğinizde, yönün ne olduğu adresin mi yoksa nesnenin mi etkileneceğini belirler. Burada iki ayrı kavramı birbirinden ayırmak gerekir: handle'ın işaret ettiği nesnenin içeriğini değiştirmek (d.value = 10) ile handle'ı başka bir nesneye yönlendirmek (d = new(...)).

  • input: Dışarıdaki my_obj adresini içeriye kopyalar. İçerideki d.value = 10 dediğinde asıl nesneyi değiştirirsin (çünkü aynı adrese bakıyorlar). Ama içeride d = new(99) dediğinde, sadece içerideki kopya etiketin yönünü değiştirmiş olursun. Task bitince o kopya etiket silinir, dışarıdaki my_obj eski nesneye bakmaya devam eder.

  • output: İçeriye hiçbir bilgi almaz. İçeride sıfırdan bir adres yaratır (new). Task bittiği saniye, bu yeni adresi dışarıdaki my_obj'ye zorla yazar.

  • inout: input ve output'un birleşimidir. Dışarıdaki adresi alır, içeride kullanmana izin verir. Eğer içeride handle'ı başka bir yere yönlendirirsen (new(30)), task bittiği an bu yeni adresi dışarıya kopyalar.

  • ref: Kopya yoktur. İçerideki d ile dışarıdaki my_obj kelimenin tam anlamıyla aynı değişkendir. İçeride handle'a new() atadığın an, dışarıdaki değişken de anında o yeni nesneye bakmaya başlar (task'ın bitmesini bile beklemez). Performans açısından en hızlısıdır çünkü adres kopyalama işlemi bile yapılmaz.

Kaynak Kod

// =============================================================================
// GUN 2 Konu 2.1 - ARGÜMAN YÖNLERİ: input vs output vs inout vs ref
// =============================================================================

class Dummy;
  int value;
  
  // Kurucu Metot (Constructor)
  function new(int v = 0);
    value = v;
  endfunction
endclass

module arg_directions_demo;

  // 1. INPUT: İçeri giren handle'ı (işaretçiyi) kopyalar. 
  // Çağrıldığı yerdeki asıl handle'ın işaret ettiği yeri değiştiremez, 
  // ancak nesnenin İÇERİĞİNİ değiştirebilir.
  task automatic test_input(input Dummy d);
    // Nesnenin içeriğini değiştirmek dışarıdan görünür
    d.value = 10; 
    
    // Handle'ın kendisini değiştirmek dışarıdan GÖRÜNMEZ
    d = new(99); 
  endtask

  // 2. OUTPUT: Başlangıçta null'dır. Task bittiğinde handle'ı DIŞARI kopyalar.
  task automatic test_output(output Dummy d);
    // Task bittikten sonra dışarıdaki handle bu yeni nesneyi işaret edecektir
    d = new(20); 
  endtask

  // 3. INOUT: Handle'ı İÇERİ kopyalar ve task bittiğinde DIŞARI kopyalar.
  task automatic test_inout(inout Dummy d);
    // Gelen nesneyi değiştirir
    d.value = 35; 
    
    // Yeni bir nesneye işaret eder, task bittikten sonra dışarısı bu yeni adresi görecektir
    d = new(30); 
  endtask

  // 4. REF: Handle'ın GERÇEK hafıza referansını iletir (kopyalama yapılmaz).
  // Handle üzerindeki herhangi bir değişiklik anında dışarıdan görünür.
  task automatic test_ref(ref Dummy d);
    // Dışarıdaki handle anında bu yeni nesneyi işaret etmeye başlar
    d = new(40); 
  endtask

  initial begin
    Dummy my_obj;

    $display("=== Argüman Yönleri Demosu ===\n");

    // --- INPUT ---
    my_obj = new(1);
    test_input(my_obj);
    // my_obj.value 99 DEĞİL, 10 olacaktır. 'new(99)' task bittiğinde silindi.
    $display("[INPUT]  test_input sonrasi : my_obj.value = %0d", my_obj.value); 

    // --- OUTPUT ---
    // my_obj adresi tamamen üzerine yazılır.
    test_output(my_obj);
    $display("[OUTPUT] test_output sonrasi: my_obj.value = %0d", my_obj.value); 

    // --- INOUT ---
    test_inout(my_obj);
    // my_obj artık test_inout içinde oluşturulan yeni nesneyi işaret ediyor.
    $display("[INOUT]  test_inout sonrasi : my_obj.value = %0d", my_obj.value); 

    // --- REF ---
    test_ref(my_obj);
    // my_obj anında doğrudan değiştirildi.
    $display("[REF]    test_ref sonrasi   : my_obj.value = %0d", my_obj.value); 

    $finish;
  end
endmodule

Kodun Açıklaması

  • Dummy sınıfı: Tek bir value özelliği ve onu başlatan new(int v = 0) constructor'ı içerir. Yön farklarını gözlemlemek için sade bir taşıyıcı olarak kullanılır.
  • test_input: d.value = 10 satırı gelen nesnenin içeriğini değiştirir ve bu dışarıdan görünür. Ancak d = new(99) yalnızca içerideki yerel handle'ı yeni bir nesneye yönlendirir; task bitince bu kopya kaybolur. Bu yüzden çıktıda my_obj.value 99 değil 10'dur.
  • test_output: Argüman task'a girerken null kabul edilir; içeride hiçbir giriş bilgisi kullanılmaz. d = new(20) ile oluşturulan yeni nesne, task bittiğinde dışarıdaki my_obj'ye kopyalanır. Sonuç my_obj.value = 20 olur.
  • test_inout: Hem girişte hem çıkışta kopyalama yapar. d.value = 35 gelen nesneyi değiştirir, ama sonra d = new(30) ile yeni bir nesneye geçilir. Task bittiğinde dışarı kopyalanan bu son handle olduğundan my_obj.value = 30 olur.
  • test_ref: ref ile kopya yapılmaz; içerideki d ile dışarıdaki my_obj aynı değişkendir. d = new(40) çağrıldığı anda my_obj da yeni nesneyi işaret etmeye başlar; task'ın bitmesini beklemez. Sonuç my_obj.value = 40 olur.
  • automatic anahtar kelimesi: Tüm task'lar automatic olarak tanımlanmıştır; bu, her çağrıda argümanların ve yerel değişkenlerin kendi kopyasının oluşturulmasını sağlar (özyineleme ve yeniden giriş güvenliği için gereklidir).

Önemli Noktalar

  • input ile gelen bir handle üzerinden nesnenin içeriğini değiştirebilirsiniz, fakat handle'ı yeni bir nesneye yönlendirmeniz dışarıyı etkilemez.
  • output argümanına metoda girerken güvenmeyin; başlangıçta null kabul edilir ve yalnızca metot bitiminde dışarı yazılır.
  • inout ve output, değeri metot bittiğinde dışarı kopyalar; bu nedenle değişiklik metot sırasında değil, dönüşte görünür.
  • ref en hızlısıdır (adres kopyalama bile yapılmaz) ve değişiklikler anında dışarıya yansır; ancak bu güç, istenmeyen yan etkilere de yol açabileceği için dikkatli kullanılmalıdır.
  • Yalnızca okumak için bir nesneyi geçiyorsanız ve onu değiştirmeyeceğseniz const ref tercih edilebilir; bu hem performans sağlar hem de kazara değişikliği önler.