İngilizce Kaynaklar


Diğer




const ve immutable Kavramları

Çeviren: Ali Çehreli
Tarih: 13 Temmuz 2009
İngilizcesi: Const and Immutable

[Çevirenin notu: "constant" ve "immutable" sözcüklerinin hem İngilizce hem Türkçe karşılıkları temelde aynıdır: sabit, değişmez. Türkçe'de const başka programlama dillerinde zaten "sabit" olarak geçtiği için ben burada da aynı karşılığı kullanıyorum. Böylece immutable'a "değişmez" kalıyor.]

Bir veri yapısını veya bir arayüz fonksiyonunu incelerken hangi verilerin değişmeyeceklerini, hangilerinin değişebileceklerini, ve değişimlerin kimin tarafından yapılabileceğini bilmek çok önemlidir. Bunu sağlayan düzeneklerden birisi, dilin tür sistemidir. D'de her veri const veya immutable olarak belirtilebilir. Özellikle belirtilmemişse veri değişebilir demektir.

immutable, verinin değişemez olduğunu bildirir. Bu tür veriler, ilk değerlerini aldıktan programın sonuna kadar aynı değerde kalırlar. Bunlar ROM'a veya donanımın değiştirilemez olarak işaretlediği bellek bölgelerine yerleştirilmiş olabilirler. Verinin değişemez olduğunun baştan biliniyor olması; derleyici için eniyileme olanaklarının artmasının yanında, fonksiyonel programlama açısından da yararlıdır.

const, verinin const olarak belirlenen referans yoluyla değiştirilemeyeceğini bildirir. Aynı veri, başka bir referans aracılığıyla değiştirilebilir durumda olabilir. const, fonksiyonların verileri değiştirmeyecekleri sözü vermeleri için kullanılır.

const ve immutable geçişlidirler; onlar aracılığıyla erişilen başka veriler de yine const veya immutable'dırlar.

immutable depolama türü

immutable'ın en basit kullanımı sabit değerler oluşturmaktır.

immutable int x = 3;     // x 3'tür
x = 4;                   // hata: x değiştirilemez
char[x] s;               // s, uzunluğu 3 olan bir char dizisidir

Verinin türü, ilkleme için kullanılan değerden çıkarsanabilir:

immutable y = 4;        // y'nin türü int'tir
y = 5;                  // hata: y değiştirilemez

Eğer ilkleme değeri henüz mevcut değilse, değişmez veri daha sonraki bir noktada kendisiyle ilgili kurucuda ilklenebilir.

immutable int z;
void deneme()
{
    z = 3;              // hata: z değiştirilemez
}
static this()
{
    z = 3;    // olur: ilkleme değeri z'nin tanımlandığı
              // noktada bilinmiyorsa burada ilklenir
}

Yerel olmayan bir immutable verinin ilk değerinin derleme zamanında hesaplanabilen bir türden olması gerekir.

int foo(int f) { return f * 3; }
int i = 5;
immutable x = 3 * 4;      // olur: 12
immutable y = i + 1;      // hata: derleme zamanında işletilmez
immutable z = foo(2) + 1; // olur: foo(2) derleme zamanında 7
                          // olarak hesaplanır

static olmayan yerel immutable veriler çalışma zamanında ilklenirler.

int foo(int f)
{
  immutable x = f + 1;  // çalışma zamanında işletilir
  x = 3;                // hata: x değiştirilemez
}

Değişmezlik geçişli olduğu için immutable yoluyla erişilen veri de değişmezdir.

immutable char[] s = "foo";
s[0] = 'a';  // hata: s bir immutable veri referansıdır
s = "bar";   // hata: s değiştirilemez

immutable veriler soldeğerlerdir [lvalue]. Yani adresleri alınabilir ve bellekte yer tutarlar.

const depolama türü

const bildirimi ile immutable bildirimi arasında şunlardan başka fark yoktur:

immutable türler

Değeri değişmeyecek olan verilerin türleri immutable olarak bildirilebilir. immutable anahtar sözcüğü bir tür kurucusu olarak düşünülebilir:

immutable(char)[] s = "merhaba";

immutable anahtar sözcüğü, o kullanımda parantez içindeki türü etkiler. Orada s'ye yeni değerler atanabiliyor olsa da, s'nin içindeki değerler değiştirilemez:

s[0] = 'b';  // hata: s[] değiştirilemez
s = null;    // olur: s'nin kendisi immutable değil

immutable geçişlidir; kendisi yoluyla erişilen veri de değiştirilemez:

immutable(char*)** p = ...;
p = ...;        // olur: p immutable değil
*p = ...;       // olur: *p immutable değil
**p = ...;      // hata: **p değiştirilemez
***p = ...;     // hata: ***p değiştirilemez

Depolama türü olarak kullanılan immutable, bütün bildirimin türü için kullanılan tür kurucusu immutable'ın eşdeğeridir:

immutable int x = 3;   // x'in türü immutable(int) olur
immutable(int) y = 3;  // y değiştirilemez
Değiştirilemeyen veri oluşturmak

Bunun bir yolu, değiştirilemeyen değerler kullanmaktır. Örneğin dizgi sabitleri değiştirilemezler:

auto s = "merhaba";   // s'nin türü immutable(char)[] olur
char[] p = "dünya";   // hata: immutable, değiştirilebilen bir
                      //       türe otomatik olarak dönüşemez

Diğer yol, tür değişiminde immutable kullanmaktır. Ama böyle yapıldığında, veriyi değiştirebilecek başka referansların bulunmadığını sağlamak programcının sorumluluğundadır.

char[] s = ...;
immutable(char)[] p = cast(immutable)s;    // tanımsız davranış

immutable(char)[] p = cast(immutable)s.dup;
 // olur: p, .dup ile kopyalanan yeni kopyanın tek referansıdır

Dizilerin immutable kopyalarını almanın kolay yolu, .idup dizi niteliğini kullanmaktır:

auto p = s.idup;
p[0] = ...;          // hata: p[] değiştirilemez
immutable'ın tür değişimi ile kaldırılması

Değişmezlik tür dönüşümü ile kaldırılabilir:

immutable int* p = ...;
int* q = cast(int*)p;

Ama bu, verinin artık değiştirilebileceği anlamına gelmez:

*q = 3; // derleyici izin verir ama tanımsız davranıştır

Bazı durumlarda immutable'ın kaldırılabilmesi gerekebilir. Örneğin kaynak kodlarına sahip olmadığımız bir kütüphane, immutable olması gereken fonksiyon parametrelerini immutable olarak bildirmemiş olabilir. O kütüphane fonksiyonlarını çağırabilmek için immutable'ı tür dönüşümü yoluyla kaldırmak zorunda kalırız; ancak bu durumda sorumluluk tamamen programcıya aittir; derleyici o veri için artık denetim sağlayamaz.

immutable üye fonksiyonlar

Üye fonksiyonları immutable olarak bildirmek, o nesnenin o üye fonksiyon içindeyken değiştirilemeyeceği anlamına gelir. Bu, nesne içinde tanımlı bütün verileri ve onların this yoluyla erişildiği durumları kapsar:

struct S
{   int x;

    immutable void foo()
    {
        x = 4;            // hata: x değiştirilemez
        this.x = 4;       // hata: x değiştirilemez
    }
}

const ve immutable belirteçleri üye fonksiyonların parametre listesinden sonra da yazılabilirler:

struct S
{
    void bar() immutable
    {
    }
}
const türler

const türler de immutable türler gibidirler; ama bu türden olan veriler const olmayan referanslar yoluyla değiştirilebilirler.

const üye fonksiyonlar

const üye fonksiyonlar içindeyken nesnenin this yoluyla erişilen üyeleri değiştirilemez.

Otomatik dönüşümler

Değişken (normal) türler ve immutable türler otomatik olarak const'a dönüşürler. Değişken türler immutable türlere, immutable türler de değişken türlere otomatik olarak dönüşmezler.

D'deki const ve immutable'ın C++'daki const ile karşılaştırılması
const ve immutable Karşılaştırması
Olanak D C++98
const anahtar sözcüğü var var
immutable anahtar sözcüğü var yok
const yazımı Fonksiyon bildirimi gibi:
// const int
// const işaretçisi
// işaretçisi:
const(int*)* p;
Sonda:
// const int
// const işaretçisi
// işaretçisi:
const int *const *p;
const geçişliliği var:
// const int
// const işaretçisi
// const işaretçisi:
const int** p;
**p = 3; // hata
yok:
// int
// işaretçisi
// const işaretçisi:
int** const p;
**p = 3;  // olur
const'ı kaldırmak var:
// const int işaretçisi:
const(int)* p;

int* q = cast(int*)p; //olur
var:
// const int işaretçisi:
const int* p;
int* q = const_cast<int*>p;
                     // olur
const'ı kaldırdıktan sonra değişiklik yok:
// const int işaretçisi:
const(int)* p;
int* q = cast(int*)p;
*q = 3; // tanımsız davranış
var:
// const int işaretçisi:
const int* p;
int* q = const_cast<int*>p;
*q = 3;   // olur
fonksiyon yüklemede üst düzey const'ın etkisi var:
void foo(int x);
void foo(const int x);//olur
yok:
void foo(int x);
void foo(const int x);//hata
aynı const'a değişken olarak da erişebilmek var:
void foo(const int* x,
         int* y)
{
   bar(*x); // bar(3)
   *y = 4;
   bar(*x); // bar(4)
}
...
int i = 3;
foo(&i, &i);
var:
void foo(const int* x,
         int* y)
{
   bar(*x); // bar(3)
   *y = 4;
   bar(*x); // bar(4)
}
...
int i = 3;
foo(&i, &i);
aynı immutable'a değişken olarak da erişebilmek yok:
void foo(immutable int* x,
         int* y)
{
  bar(*x);// bar(3)

  *y = 4; // tanımsız
          // davranış

  bar(*x);// bar(??)
}
...
int i = 3;
foo(cast(immutable)&i, &i);
immutable desteklenmez
dizgi sabitlerinin türü
immutable(char)[]
const char[N]
dizgi sabitinin değişken dizgiye otomatik dönüşümü izin verilmez izin verilir ama emekliye ayrılmış [deprecated] bir olanaktır