---
title: 'Alan Özel Diller'
source: 'https://academia.sh/tr/kurslar/rust-ileri/alan-ozel-diller'
course: 'Rust Ekosistemi ve İleri Konular'
language: tr
updated: '2026-10-21T05:03:45+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Aynı yönlendirme yapısını bir makro yazımıyla ve elle kurulan yazımla oluşturup aynı sonucu verdiğini koşturarak gösterir'
    - 'Makro yazımının aynı işi kaç satır kısalttığını, kaynağın kendi metnini sayarak ölçer'
    - 'Okunaklı bir makro yazımının doğruluk garantisi getirmediğini, mantıksal olarak yanlış bir yol-işlev bağının da tip denetiminden geçtiğini örnekle gösterir'
---

# Alan Özel Diller

Aynı yönlendirme yapısı bir makro yazımıyla ve elle kurulan yazımla ayrı ayrı oluşturulur, aynı sonucu verdiği koşturularak gösterilir ve makro yazımının kaynağı kaç satır kısalttığı sayılır; ama makro çıktısının okunaklı olması doğruluk getirmez — mantıksal olarak yanlış bir yol-işlev bağı da aynı kolaylıkla tip denetiminden geçer.

Önceki iki ders, üretilen bir gövdenin nasıl denetlendiğini iki farklı kurguda gösterdi: bir
kez aynı okumada metinsel yer değiştirmeyle, bir kez ayrı bir derleme adımında çalıştırılan
bir programla. İkisinde de ortak bir soru henüz sorulmadı: üretim neden tercih ediliyor, elle
yazmak yerine? Bu konunun son dersi bu soruyu ele alıyor. Bir makro, çağıranın gözünden bir
küçük dil gibi görünen bir arayüz kurabilir — kendi sözdizimiyle, kendi kısayollarıyla; buna
alan özel dil deniyor. Bu ders aynı yapıyı iki yazımla kuruyor, ikisinin aynı sonucu
verdiğini koşturarak doğruluyor, makro yazımının kaç satır kısalttığını sayıyor ve sonunda bu
kısalmanın bir doğruluk garantisi taşımadığını gösteriyor.

Alan özel dil terimi burada geniş bir çerçeveyi değil, dar ve somut bir kullanımı işaret
ediyor: kaynağı okuyan tarafın, altında yatan `match` bloğunu, işlev tanımını ya da başka bir
mekaniği hiç görmeden, doğrudan problem alanının kelimeleriyle (bir yol, bir işleyici) yazı
yazabilmesi. Bu arayüz derleyicinin yeni bir kural öğrenmesini gerektirmiyor — makro
genişledikten sonra ortaya çıkan kaynak, önceki iki derste görüldüğü gibi, sıradan Rust
kaynağından ayırt edilemiyor. Kazanılan şey yalnız kaynağı **yazma** biçimi; kaynağı
**denetleme** biçimi hiç değişmiyor.

Bu tanım, alan özel dil terimini programlama dilleri kuramındaki geniş kullanımından
ayırıyor: orada terim çoğunlukla kendi ayrıştırıcısı, kendi çalışma zamanı olan bağımsız bir
dili işaret ediyor. Burada ise ortada ikinci bir dil yok — tek bir dil var, Rust'ın kendisi
ve makro yalnız o dilin sözdizimini belirli bir problem için daha kısa bir kalıba
sığdırıyor. Bu yüzden derste kurulan arayüz, kendi başına bir ayrıştırıcı taşımıyor;
ayrıştırma zaten derleyicinin kendi ayrıştırıcısı tarafından, makro genişlemesinin bir
parçası olarak yapılıyor.

## Aynı Yapı, İki Yazım

Bir yönlendirme tablosu — bir yol dizgisini bir işleve bağlayan bir tablo — hem bir makro
yazımıyla hem elle kurulabilir. Makro yazımı, yol ve işleyici çiftlerini bir liste gibi
sıralar; elle yazım aynı tabloyu bir `match` bloğunun dallarına döker. İkisi de aynı işi
yapıyor: bir yol dizgisini bir sonuca çeviriyor.

Elle yazılan biçim her yeni yol için üç şeyi tekrar etmeyi gerektiriyor: `match` bloğunun
kendisini, bir dalın sözdizimini ve yakalayıcı dalın varlığını. Bu tekrar bir hata
değil — Desen Eşleme dersinde (M10/K01) görüldüğü gibi, `match`'in bütünlük istemesi kaynağın
güvenli kalmasını sağlıyor. Ama tekrar eden kısım, yol ile işleyici çiftinden başka hiçbir
yeni bilgi taşımıyor: `match`, `yol {`, `_ => -1` satırları her yönlendirme tablosunda
birebir aynı. Makro bu sabit kalıbı bir kez, kendi tanımının içinde yazıyor ve her çağrıda
yeniden üretiyor; çağıran taraf yalnız değişen kısmı — çiftlerin kendisini — yazıyor.

```rust
// yonlendirici.rs — ayni yonlendirme tablosu bir makro yazimiyla ve elle kurulan esdegeriyle olusturuluyor.
macro_rules! yonlendirici_olustur {
    ($ad:ident { $($yol:literal => $isleyici:expr),+ $(,)? }) => {
        fn $ad(yol: &str) -> i32 {
            match yol {
                $($yol => $isleyici,)+
                _ => -1,
            }
        }
    };
}

fn ana_sayfa() -> i32 { 200 }
fn hakkinda_sayfa() -> i32 { 200 }

yonlendirici_olustur!(makro_ile_yonlendir {
    "/ana" => ana_sayfa(),
    "/hakkinda" => hakkinda_sayfa(),
});

fn elle_yonlendir(yol: &str) -> i32 {
    match yol {
        "/ana" => ana_sayfa(),
        "/hakkinda" => hakkinda_sayfa(),
        _ => -1,
    }
}

fn main() {
    for yol in ["/ana", "/hakkinda", "/bilinmeyen"] {
        let m = makro_ile_yonlendir(yol);
        let e = elle_yonlendir(yol);
        println!("{:<12}makro={} elle={} ayni_mi={}", yol, m, e, m == e);
    }
}
```

```
/ana        makro=200 elle=200 ayni_mi=true
/hakkinda   makro=200 elle=200 ayni_mi=true
/bilinmeyen makro=-1 elle=-1 ayni_mi=true
```

**MK7.** Makro tanımının deseni üç parçadan kuruluyor: `$ad:ident` üretilecek işlevin adını
yakalıyor, `$yol:literal => $isleyici:expr` çiftini bir ya da daha çok kez (`+`) tekrarlıyor,
`$(,)?` de son çiftten sonra isteğe bağlı bir virgülü kabul ediyor. Bu üç parça birlikte, dilin
kendi sözdizimini bir liste-benzeri yazıma dönüştürüyor: çağıran taraf `match` yazmıyor, süslü
parantez içine yol-işlev çiftlerini art arda diziyor. Üç yoldan (`/ana`, `/hakkinda`,
`/bilinmeyen`) üçü de iki yazımda birebir aynı sonucu veriyor; `ayni_mi` sütunu bunu tek tek
doğruluyor.

Bu ifade edici arayüz bildirimsel bir makroyla kuruldu, prosedürel bir makroyla değil — bu
seçim rastgele değil. Önceki dersin gösterdiği gibi, prosedürel bir makro ayrı bir kasada
derlenmek zorunda ve onu kullanmak iki aşamalı bir derleme gerektiriyor. Burada kurulan
yönlendirme tablosu, tekrar eden bir sözdizim kalıbından ibaret; bu tür bir tekrarı sarmak
için andaç akışını elle işlemeye, ayrı bir kasaya ya da iki aşamalı bir derlemeye gerek yok —
bildirimsel makronun desen eşleme düzeneği zaten yeterli. Prosedürel makro, girdi
üzerinde gerçek bir hesaplama yapmak gerektiğinde tercih ediliyor; yalnız bir kalıbı
tekrarlamak için değil.

Üretilen `makro_ile_yonlendir` işlevi ile elle yazılan `elle_yonlendir` işlevi, derleyicinin
gözünde aynı statüde: ikisi de birer `fn`, ikisi de aynı imzayı taşıyor, ikisi de aynı `match`
mantığını çalıştırıyor. Bu, önceki iki dersin bulgusunu bir kez daha doğruluyor —
üretilen gövde "sürdürüyor" sınıfına düşüyor — ama bu derste asıl soru gövdenin denetlenip
denetlenmediği değil, gövdeyi **yazmanın** ne kadar kısaldığı.

Bu eşitliğin bir sonucu var: iki yazım arasında seçim yaparken, çalışma zamanı davranışı
hiçbir zaman bir ölçüt olamaz — ikisi de birebir aynı şeyi üretiyor. Seçimi belirleyen tek
eksen kaynağın nasıl **okunduğu** ve nasıl **yazıldığı**. Yol sayısı arttıkça bu fark daha
belirgin hale geliyor: üç yol yerine otuz yol eklemek gerekseydi, elle yazım otuz kez `match`
dalının sözdizimini tekrar ederdi, makro yazımı yalnız otuz çift eklerdi. Bu ders bu farkı
sezgisel bırakmıyor, sayıyla ölçüyor.

## Kaynağın Kendi Uzunluğu

Makronun gerçekte kaç satır ürettiğini çalışma zamanında ölçmenin doğrudan bir yolu yok —
genişleme derleme sırasında olur ve çalışan programın eline yalnız sonuç geçer. Ölçülebilir
olan, iki yazımın **kaynaktaki** uzunluğu: makro çağrısının kendisi kaç satır, aynı işi yapan
elle yazılmış `match` bloğu kaç satır. Bu iki kaynak metni birer dize sabiti olarak tutulup
satır sayıları karşılaştırılabilir.

Bu, bir önceki bölümdeki koşumdan bağımsız, ayrı bir ölçüm. Önceki bölüm iki yazımın **aynı
sonucu** verdiğini gösterdi; bu bölüm ikisinin **aynı işi ne kadar kaynakla** yaptığını
gösteriyor. İkisi birbirini tamamlıyor: birincisi olmadan ikincisi anlamsız kalırdı — kısa
ama yanlış bir yazımı kısa olduğu için övmenin bir anlamı yok. Bu yüzden bu ders satır
sayımına geçmeden önce eşitliği koşturarak doğruladı; sıra bilinçli seçildi, tersi olsaydı
kısalığın doğruluğun yerine geçtiği izlenimi doğardı.

```rust
// satir_sayimi.rs — ayni yonlendirme tanimi iki yazimda tutuluyor, satir sayisi karsilastiriliyor.
fn main() {
    let makro_yazimi = "yonlendirici_olustur!(makro_ile_yonlendir {\n    \"/ana\" => ana_sayfa(),\n    \"/hakkinda\" => hakkinda_sayfa(),\n});";
    let elle_yazim = "fn elle_yonlendir(yol: &str) -> i32 {\n    match yol {\n        \"/ana\" => ana_sayfa(),\n        \"/hakkinda\" => hakkinda_sayfa(),\n        _ => -1,\n    }\n}";

    let makro_satir = makro_yazimi.lines().count();
    let elle_satir = elle_yazim.lines().count();
    println!("makro yazimi: {} satir", makro_satir);
    println!("elle yazim: {} satir", elle_satir);
    println!("kisalan satir: {}", elle_satir - makro_satir);
}
```

```
makro yazimi: 4 satir
elle yazim: 7 satir
kisalan satir: 3
```

**MK8.** Bu ölçüm, önceki derste `--extern` yolunun neden ekrana basılmadığını hatırlatan
aynı gerekçeyle kuruldu: makronun genişlemesini çalışma zamanında okumanın bir yolu yok, o
yüzden ölçüm çalışma zamanına taşınabilecek tek şeyi — kaynağın kendi metnini — ölçüyor. Rust'ın
Tasarım Hedefleri dersinde (M10/K01) örtük bir tür dönüşümünün reddi de aynı yöntemle, iki
kaynak satırının karakter sayısı karşılaştırılarak ölçülmüştü; burada birim karakter değil
satır, ama yöntem aynı: kaynağı çalıştırmak yerine kaynağın kendisini bir veri olarak ele
almak.

Elle yazılan yönlendirme yedi satır: işlev imzası, `match` başlığı, iki dal, yakalayıcı dal,
iki kapanış parantezi. Makro çağrısı dört satır: çağrının kendisi, iki yol-işlev çifti,
kapanış. Aradaki üç satırlık fark, `fn`, `match` ve kapanış parantezlerinin makro tarafında hiç
yazılmasına gerek kalmamasından geliyor — bu üç satır, makro tanımının içinde **bir kez**
yazılı ve her çağrıda yeniden üretiliyor. Yol sayısı arttıkça bu oran değişmiyor: her yeni
yol-işlev çifti, iki yazımda da birer satır ekliyor, ama iki yazım arasındaki sabit üç satırlık
fark hep aynı kalıyor.

Bu sabit maliyet, ölçümün neden "kısalan satır" diye mutlak bir sayı bastığını, "kaç kat kısa"
diye bir oran basmadığını da açıklıyor. İki yol için fark üç satır, otuz yol için de fark yine
üç satır olurdu — oran küçülür, mutlak fark değişmez. Ölçüm bu yüzden oranı değil farkı
basıyor: kursun sayı kuralı gereği bir iddia yalnız gerçekten ölçülen büyüklüğü taşımalı ve
burada belirlenimci olarak ölçülebilen şey iki sabit kaynağın satır farkı, bir genelleme
değil.

## Sınırlayıcı Ölçüm

Okunaklı bir yazım doğruluk getirmiyor. Makro, çağıranın yazdığı yol-işlev çiftlerinin
**anlamlı** olup olmadığını hiç sormuyor — yalnız her çiftin bir dizgi sabiti ve `i32`
döndüren bir ifade olup olmadığına bakıyor. Bu sınır önceki iki bölümdeki ölçümlerin
üzerine ekleniyor, onları geçersiz kılmıyor: makro yazımının aynı sonucu verdiği ve kaynağı
kısalttığı doğru kalıyor; ama bu iki kazanç, üçüncü bir soruya — kurulan tablonun doğru
olup olmadığına — hiçbir yanıt taşımıyor. Aşağıdaki örnek, bir yolun yanlışlıkla olması
gerekenden başka bir işleve bağlandığı bir tabloyu aynı makroyla kuruyor.

```rust
// yanlis_ama_dogru_tip.rs — mantiksal olarak yanlis bir esleme de tip denetiminden geciyor.
macro_rules! yonlendirici_olustur {
    ($ad:ident { $($yol:literal => $isleyici:expr),+ $(,)? }) => {
        fn $ad(yol: &str) -> i32 {
            match yol {
                $($yol => $isleyici,)+
                _ => -1,
            }
        }
    };
}

fn basarili() -> i32 { 200 }

yonlendirici_olustur!(hatali_yonlendir {
    "/ana" => basarili(),
    "/hata" => basarili(),
});

fn main() {
    println!("/hata -> {}", hatali_yonlendir("/hata"));
}
```

```
/hata -> 200
```

**MK9.** `/hata` yolu, adından da anlaşılacağı gibi bir başarısızlık durumunu temsil etmesi
beklenen bir yol; ama tabloyu kuran satır yanlışlıkla `basarili()` işlevine bağlanmış ve
sonuç `200`. Makro bunu reddetmiyor, çünkü reddedecek bir bilgisi yok: `$isleyici:expr`
deseni yalnız "burada `i32` döndüren bir ifade olacak" diyor, o ifadenin çağrıldığı yolun
anlamıyla tutarlı olup olmadığını sormuyor. Derleyici de aynı nedenle sessiz kalıyor —
`basarili()` gerçekten `i32` döndürüyor, imza tutuyor, tür denetimi geçiyor. Üretilen gövde
yine "sürdürüyor" sınıfına düşüyor, çünkü tür denetimi gerçekten çalışıyor; ama tür denetimi
burada "bu doğru mu" sorusuna hiç yanıt vermiyor, yalnız "bu türden mi" sorusuna yanıt
veriyor.

Bu örnekte hata elle de aynı kolaylıkla yazılabilirdi — `elle_yonlendir` içindeki bir
dalı yanlış işleve bağlamak da aynı şekilde derlenirdi. Makro burada hatayı **kolaylaştırmıyor**;
yalnız hatayı **gizlemiyor** da. Fark, iki yazımın da aynı zayıflığı taşıdığı ama makro
yazımının bu zayıflığı daha az satırda ve daha az yazımla ulaşılır kıldığı: yanlış bir çift
eklemek, otuz satırlık bir `match` bloğunda bir dalı değiştirmekten daha az dikkat gerektiren
bir işlem. Kaynağın kısalması, kaynağın gözden geçirilmesini kolaylaştırıyor ama gözden
geçirmenin yerini almıyor.

Bu gözlem, kursun dört sınıfından hiçbirine yeni bir beşinciyi eklemiyor — "yanlış ama tür
uyumlu" ayrı bir sınıf değil, "sürdürüyor" sınıfının kendi içindeki bir ayrıntı. Derleyici
burada da gerçekten denetliyor, hiçbir adımı atlamıyor; yalnız denetlediği şey, kaynağı
okuyan bir insanın sorduğu sorudan daha dar: "bu ifade beklenen türde mi", "bu bağ doğru
mu" değil.

Bu, önceki iki dersteki gözlemlerle aynı sınıfta duran ama farklı bir köşeden gösterilen bir
sınır. Bildirimsel Makrolar dersi, aynı makronun `i32` ve `bool` gibi iki anlamca uzak türle
çağrılabildiğini, ikisinin de derlenip makronun hangisinin anlamlı olduğunu söyleyemediğini
göstermişti. Burada tür sabit (`i32`), değişen şey bir dizginin **hangi ifadeyle**
bağlandığı — ama sonuç aynı: makro sözdizimi düzeyinde çalışıyor, iki farklı bağın
birbirinden **anlamca** ayrıldığını göremiyor, yalnız ikisinin de biçimce doğru olduğunu
görüyor. Okunaklı bir yazım, yalnız yazan tarafın niyetini daha kısa ifade etmesini
sağlıyor; o niyetin doğru kurulup kurulmadığını hâlâ okuyan tarafın kontrol etmesi
gerekiyor.

Prosedürel Makrolar dersinde görülen ayrım da burada geçerliliğini koruyor: bir prosedürel
makro, girdi andacını okuyup üzerinde daha karmaşık bir işlem yapabilseydi bile, yine yalnız
**tür uygunluğuna** bakardı — çünkü Rust'ta tür denetimi her zaman genişlemeden sonra,
üretilen kaynak üzerinde çalışıyor, hangi makro biçimi kullanılırsa kullanılsın. İki makro
biçiminin (bildirimsel, prosedürel) üretim mekanizması farklı olsa da, ikisinin de vardığı
kaynak aynı denetim sürecinden geçiyor ve o denetim sürecinin sınırı da ikisinde aynı: tür
doğru mu, anlam doğru mu sorularının yalnız ilkine yanıt veriyor.

## Özet

- Aynı yönlendirme yapısı bir makro yazımıyla ve elle kurulan yazımla oluşturuldu; üç yol için
  ikisi de birebir aynı sonucu verdi ve bu eşitlik koşturularak, tek tek karşılaştırılarak
  doğrulandı.
- Üretilen gövde bu derste de sürdürüyor sınıfına düşüyor: makro çağrısının ürettiği işlev,
  elle yazılmış işlevle aynı kurallarla denetleniyor.
- Makro yazımı aynı işi üç satır kısalttı; bu kısalma makronun sabit başlık-kapanış
  maliyetini bir kez yazıp her çağrıda yeniden kullanmasından geliyor ve yol sayısı arttıkça
  mutlak farkın kendisi değişmiyor.
- Okunaklı bir makro yazımı doğruluk garantisi getirmiyor: mantıksal olarak yanlış bir
  yol-işlev bağı da, türü tuttuğu için aynı kolaylıkla derleniyor.
- Makronun denetleyebildiği tek şey biçim — bir ifadenin beklenen türden olup olmadığı; o
  ifadenin çağıranın niyetiyle örtüşüp örtüşmediğini denetleyen bir mekanizma yok.
- İfade edici bir arayüz kurmak için bildirimsel makro seçildi; prosedürel makro yalnız girdi
  üzerinde gerçek bir hesaplama gerektiğinde tercih ediliyor, sabit bir kalıbı sarmak için
  değil.

## Sonraki Adım

Bu konunun üç dersi, üretilen kaynağın üç ayrı kurguda — aynı dosyada, ayrı bir derleme
adımında, ifade edici bir arayüzün içinde — hep aynı sınıfa, sürdürüyor sınıfına düştüğünü
gösterdi. Üçünde de ortak kalan sınır aynıydı: derleyici üretilen kaynağın **türünü**
denetliyor, **anlamını** denetlemiyor. Sıradaki konu, Düşük Seviye ve Birlikte Çalışma, bu
sınırı derinleştiriyor: derleyicinin denetimi hiç durmadığı bu üç dersin ardından, sıradaki
ders denetimin **gerçekten** durduğu bir bloğa giriyor — orada da denetim toptan kapanmıyor,
yalnız birkaç işlem "devredildi" sınıfına açılıyor ve geri kalan her şey, tıpkı burada olduğu
gibi, sürmeye devam ediyor.
