İçeriğe geç
academia.sh

Ders 08 / 12

Bağımlılık ve Özellik Bayrakları

Koşullu derlemeyle dışarıda bırakılan bir kaynak parçasının derleyici tarafından hiç görülmediğinin, bu gözlemin iki ayrı özellik bayrağıyla tekrarlanarak sınıfının (denetlenmiyor) doğrulanması.

Yayın Güncelleme

Bu derste

  • Koşullu derlemeyle dışarıda kalan bir gövdenin derleyici tarafından hiç görülmediğini koşturarak gösterir
  • Aynı gözlemi iki ayrı özellik bayrağıyla tekrarlayarak sınıfın (denetlenmiyor) rastlantı olmadığını doğrular
  • Bu ölçümün bayrak açıldığında ne olacağını göstermediğini, yalnızca bugünkü durumu kanıtladığını açıklar
İçindekiler

Alt Düzey konusu dört dersle kapandı ve dördünde de derleyici en azından bir şeyi görüyordu: bir unsafe bloğun içindeki birkaç işlem denetimsiz kalıyordu ama aynı bloktaki başka bir işlem hâlâ denetleniyordu; yabancı bir işlevin gövdesi hiç görülmüyordu ama en azından imzası derlemeye giriyordu; bir hedefin verdiği sınır kaynaktan okunuyordu, standart kütüphaneye dayanan ve dayanmayan iki yazım yerel hedefte yan yana koşturulmuştu. Dördünde de derleyici kaynağın bir kısmını derliyor, güvence oradan başlıyordu — denetim daraldı, ama tümüyle durmadı. Proje Yaşam Döngüsü konusu bambaşka bir soru soruyor: kaynakta duran ama derleyicinin hiç görmediği bir parça var mı ve varsa bu parça bozulsa bile kimse fark eder mi?

Bu derste yanıt koşullu derlemede aranıyor. Bir kaynak dosyasının bir bölümü, bir özellik bayrağının açık olup olmamasına göre derlemeye girer ya da hiç girmez; girmeyen bölüm, sözdiziminin bile geçerli olması dışında hiçbir denetimden geçmez. Rust Ekosistemi ve İleri Konular kursunun ortak sorusu — derleyicinin güvencesi burada nerede bitiyor — bu derste en keskin yanıtını buluyor: bazı gövdeler için güvence hiç başlamıyor.

Kursun dört yanıtı — güvencenin sürdüğü, yazana devredildiği, dilin dışında kaldığı ve hiç kimse tarafından denetlenmediği durumlar — Proje Yaşam Döngüsü konusunun dört dersinde de tek tek karşılığını buluyor: bu ders bir gövdenin hiç denetlenmediğini, sıradaki iki ders bir sınamanın ya da bir sayının hangi güvenceyi koşarak kurduğunu, son ders ise aynı kaynakta hem hiç denetlenmeyen hem de gerçekten denetlenen iki iddianın yan yana durabileceğini gösteriyor.

Kapsam Dışı Kalan Gövde

Bir bildirim dosyası, normal koşullarda bir kasanın hangi bölümlerinin isteğe bağlı olduğunu özellik bayraklarıyla tanımlar; paket yöneticisi bu bayrakları derleyiciye --cfg seçeneğiyle iletir. Bu kursta paket yöneticisi kullanılmadığından bayrak durumu doğrudan derleyiciye verilir, ama düzenek aynıdır: #[cfg(feature = "ad")] niteliğiyle işaretlenmiş bir öğe, yalnız o bayrak açıkken derlemeye girer. Bayrak kapalıyken derleyici o öğeyi hiç görmez — ne tip denetiminden geçirir ne de adları çözer.

Bağımlılıklarla özellik bayrakları çoğunlukla birlikte anılır çünkü bir bayrak sıklıkla bir bağımlılığa duyulan ihtiyacı sınırlamak için kullanılır: bir bölüm belirli bir dış işlevselliğe dayanıyorsa ve bu işlevselliğe çoğu kullanıcı ihtiyaç duymuyorsa, o bölüm bir bayrağın arkasına konur ve bayrak kapalıyken hem o bölüm hem de dayandığı bağımlılık derlemeye hiç girmez. Bu derste kasa dışı bir bağımlılık kullanılmıyor — kurs boyunca bağımlılıklar standart kütüphaneyle sınırlı — ama mekanizma birebir aynı: #[cfg(...)] bir öğeyi neye dayandığına bakmaksızın derlemenin dışında bırakır.

Özellik bayrakları çoğunlukla bir kasanın isteğe bağlı bölümlerini ayırmak için kullanılır: bir bölüm çoğu kullanıcıya gerekmiyorsa bir bayrağın arkasına konur ve yalnız isteyen taraf o bayrağı açar. Bir bildirim dosyası bu bayrakların hangisinin varsayılan olarak açık geleceğini de belirtir; açıkça kapatılmadıkça varsayılan bayraklar her derlemeye girer, geri kalanı yalnız isteyen tarafın elini uzatmasıyla açılır. Bunun getirisi, kullanılmayan bölümün hiç derlenmemesidir — ama bu derste ölçülen getiri değil, bu getirinin bedeli: kapalı kalan bölüm, açık kalan bölümden farklı bir denetim düzeyinde yaşıyor.

Aşağıdaki kesit iki bayrakla işaretlenmiş iki gövde taşıyor. İlki, acilmayan bayrağı altında duruyor ve iki farklı hata taşıyor: var olmayan bir işlevi çağırıyor ve bir dizgeyi doğrudan bir tam sayıya atıyor. İkincisi, denenmemis bayrağı altında duruyor ve o da benzer biçimde var olmayan bir yöntemi çağırıp sonucunu yanlış bir tipe atıyor. İki gövde de bilerek iki farklı statik denetim türünü ihlal edecek biçimde kuruldu: biri ad çözümlemesini (var olmayan bir çağrı), öbürü tip denetimini (yanlış bir atama) ihlal ediyor. İkisinin de aynı sonuca — sessizce dışarıda kalmaya — vardığını göstermek için ikisi de gerekliydi; yalnız bir tür hata seçilseydi gözlem yalnız o hata sınıfına özgü olabilirdi. Üçüncü gövde hiçbir bayrağa bağlı değil ve her koşulda derlemeye giriyor.

// bayrak_govdeleri.rs — iki ayri, hep kapali kalan bayrak, hep acik kalan bir govde
#[cfg(feature = "acilmayan")]
pub fn hic_denetlenmeyen() {
    bu_islev_hic_tanimlanmadi();
    let _x: i32 = "metin";
}

#[cfg(feature = "denenmemis")]
pub fn baska_denetlenmeyen(liste: &[i32]) -> i32 {
    let toplam: i32 = liste.paralel_topla();
    let _s: &str = toplam;
    toplam
}

pub fn calisan_govde() -> i32 {
    41
}

Bu dosya hiç fn main taşımıyor; bir kaynak kesiti olarak duruyor ve aşağıdaki gövde onu mod bildirimiyle çekiyor. PY1. Buradaki iddia şu: hiçbir bayrak açık olmadığında, bayrak_govdeleri.rs içindeki iki hatalı gövde kaynakta dursa bile derleme uyarısız tamamlanır — çünkü ikisi de derlemeye hiç girmiyor.

// bayrak_olcumu.rs — iki bayrak da kapali; disarida kalan iki govde hic denetlenmiyor
mod bayrak_govdeleri;
use bayrak_govdeleri::calisan_govde;

fn main() {
    println!("calisan govde sonucu: {}", calisan_govde());
    println!("acilmayan bayrak acik mi: {}", cfg!(feature = "acilmayan"));
    println!("denenmemis bayrak acik mi: {}", cfg!(feature = "denenmemis"));
}
calisan govde sonucu: 41
acilmayan bayrak acik mi: false
denenmemis bayrak acik mi: false

Derleme hiçbir uyarı basmadı ve program üç satır yazdı. hic_denetlenmeyen ile baska_denetlenmeyenin ikisi de kaynakta duruyor, ikisinin de içinde tanımsız bir çağrı ve bir tip hatası var ve ikisi de bu koşumda hiç derlenmedi. Derleyici onları görmediği için ne çağrıyı ne de hatalı atamayı fark edebildi. Kod içindeki bir çalışma-zamanı bayrak sorgusu bu durumu program içinden doğruluyor: her iki bayrak da koşum sırasında kapalı okunuyor — ikisi de kapalı, ikisi de gövdesiz.

Bu, bir bayrağı sıradan bir çalışma zamanı koşuluyla karıştırmamak için önemli bir ayrım taşıyor. Aynı iki hatalı gövde #[cfg(...)] yerine sıradan bir çalışma zamanı dallanmasının (örneğin hiçbir zaman doğru olmayan bir koşulun) içine yazılsaydı sonuç aynı olmazdı: böyle bir dallanmanın gövdesi çalışma zamanında hiç işletilmese bile, kaynak ağacında hâlâ bulunduğu için derleme zamanında tip denetiminden geçer. Tanımsız bir çağrı orada yazılı olsaydı derleme başarısız olurdu — çalışma zamanında hiç ulaşılamayan bir dal, tanımsız bir adı gizlemez. #[cfg(...)] bunun tam tersini yapar: gövdeyi kaynak ağacından, dolayısıyla adları çözme ve tip denetleme aşamalarından tamamen çıkarır. PY2. Bu fark, “hiç çalışmayan kod” ile “hiç derlenmeyen kod”un aynı şey olmadığını gösteriyor; yalnız ikincisi bu dersin sınıfına, denetlenmiyor sınıfına giriyor.

Ayrım cümlesi: M09/K05 kursu derleme etiketlerini bir programın araç bilgisi olarak ölçtü — bir derleme etiketi hangi dosyanın hangi işletim sistemine ya da mimariye derlendiğini belirliyordu ve bunu söyleyen bir araçtı. Bu derste ölçülen bambaşka: dışarıda kalan gövdenin hiç denetlenmediği. Orada bir bilgi kaynaktan mı, araçtan mı, koşumdan mı geliyordu diye soruluyordu; burada sorulan, kaynağın bir kısmının derleyicinin ilgi alanına hiç girip girmediği. İki kavram da #[cfg(...)] niteliğini kullanıyor — Rust’ta hedef seçimi de özellik seçimi de aynı mekanizmadan geçiyor — ama sordukları soru farklı: biri “hangi dosya nereye derlenir”, öbürü “derlenmeyen bir gövdeyi kim denetler”.

Aynı gözlem ikinci bir bayrakla (denenmemis) tekrarlandı çünkü tek bir bayrağın kapalı kalması bir rastlantı olabilirdi — belki o bayrak zaten hiç kullanılmayacak biçimde tasarlanmıştı. PY3. İki farklı bayrak, iki farklı hata türü (tanımsız çağrı ile yanlış tip ataması, sonra tanımsız yöntem ile yanlış tip ataması) taşıyarak aynı sonuca ulaştı: kapalı bir bayrağın gövdesi, içeriği ne olursa olsun, derleme sürecine hiç girmiyor. Bu, tek bir örneğin özel bir durumu değil, koşullu derlemenin genel davranışı.

Bir proje bu riski, her bayrak bileşimini ayrı ayrı derleyen bir sürece devrederek azaltabilir: her bileşim en az bir kez derlenirse, o an için hiçbir bayrak kapalı kalmaz ve denetim geçici olarak tam kapsama ulaşır. Bu, ölçülen sınıfı denetlenmiyordan çıkarmaz — yalnızca denetlenme anını, bayrağın açıldığı ana öteler. Böyle bir süreç çalıştırılmadığı her an, kaynak ağacındaki kapalı bayrakların gövdeleri yine denetimsiz kalmaya devam eder; bu dersin ölçtüğü durum, o sürecin yokluğunda neyin olduğudur, varlığında neyin garanti edildiği değil.

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

Yukarıdaki koşum, kapalı bir bayrağın gövdesinin derlemeye girmediğini gösterdi. Ama bu, o gövdenin görünmez olduğu anlamına gelmiyor — kaynakta duruyor, okunabiliyor, sürüm denetim sisteminde izlenebiliyor. Görünmeyen olan, derleyicinin ona bakıp bakmadığı. Aşağıdaki koşum bu ayrımı çalışan bir programın içinden gösteriyor: kapalı bayrağın gövdesine ayrılmış bir blok, programın kendisi tarafından da hiç işletilmiyor.

// govde_gorunurlugu.rs — kapali bir bayragin govdesi kosumdan da gorunmez
mod bayrak_govdeleri;
use bayrak_govdeleri::calisan_govde;

fn main() {
    let sonuc = calisan_govde();
    #[cfg(feature = "acilmayan")]
    {
        println!("bu satir hicbir zaman derlenmiyor");
    }
    #[cfg(not(feature = "acilmayan"))]
    {
        println!("acilmayan bayrak kapali: govdesi kaynakta duruyor, kosuma hic girmedi");
    }
    println!("calisan govde yine {} dondurdu", sonuc);
}
acilmayan bayrak kapali: govdesi kaynakta duruyor, kosuma hic girmedi
calisan govde yine 41 dondurdu

PY4. İki blok da aynı main işlevinin içinde yazılı, ama yalnız biri koşuma giriyor — hangisinin gireceğine derleme anında, cfg niteliğine bakılarak karar veriliyor. Kaynakta iki blok da var; koşumda yalnız biri var. Bu, koşullu derlemenin okuyucuya verdiği bir söz değil, kaynağın kendisinden çıkarılabilecek bir gerçek — ama bu ölçümün kendisi bir sınır taşıyor.

Bu koşumda #[cfg(...)] bir öğenin (bir işlevin) üzerinde değil, main içindeki bir ifade bloğunun üzerinde duruyor; niteliğin kendisi hem işlevlere hem yapılara hem de tek bir ifade bloğuna uygulanabilir. Gerçek bir projede bu, bir işlevin çoğu paylaşılan kalırken yalnız küçük bir bölümünün — örneğin bir günlükleme çağrısının ya da bir ek denetimin — bir bayrağın arkasına konabileceği anlamına gelir; işlevin tamamını bayrağa bağlamak zorunlu değildir. Ölçülen sınıf değişmez: hangi düzeyde uygulanırsa uygulansın, kapalı kalan blok yine derlemeye hiç girmez.

Yukarıdaki koşumda #[cfg(feature = "acilmayan")] ile #[cfg(not(feature = "acilmayan"))] aynı yerde, birbirini dışlayan iki blok olarak yazıldı. Bu, bayrakların sık kullanılan bir başka biçimi: bir bayrak açıkken bir davranış, kapalıyken onun karşıtı bir davranış çalışır ve kaynakta ikisi de görünür durur. Derleyici bunlardan yalnız bayrak durumuna uyanı derlemeye alır, öbürünü tıpkı yukarıdaki hic_denetlenmeyen gibi tamamen dışarıda bırakır — kapalı kalan taraf burada hatalı değil, yalnızca kapalı; ama derleyicinin ona bakmaması gerçeği değişmiyor.

Bu ölçüm, kapalı bir bayrağın gövdesinin bugün derlenmediğini gösteriyor; gövdenin bayrak açıldığında derlenip derlenmeyeceğini göstermiyor. Bunu göstermenin tek yolu bayrağı gerçekten açıp derlemeyi denemek, ama hic_denetlenmeyen ile baska_denetlenmeyen açıldığında derlenmeyecek biçimde kurulmuş durumda — derlenmeyen bir kaynağı bu derste koşturmak mümkün değil. Bu yüzden ölçüm yalnızca şunu kanıtlıyor: kapalı bir bayrağın gövdesi bugün kimse tarafından denetlenmiyor.

Bunu sıradan kullanılmayan bir öğeyle karşılaştırmak ayrımı netleştiriyor. Bir işlev hiçbir bayrağa bağlı olmadan yazılır ama hiç çağrılmazsa, derleyici bunu fark eder ve bir kullanılmama uyarısı basar — çünkü o işlev derleme sürecine girmiştir, adı çözülmüş ve tipi denetlenmiştir, yalnız çağrılmamıştır. Kapalı bir bayrağın gövdesi bu uyarıyı hiç almaz, çünkü derleme sürecine hiç girmemiştir; sessizliğin nedeni “kullanılmadığı bilinip görmezden gelinmesi” değil, “hiç var olmamış gibi davranılmasıdır”. Bu derste teslim edilen her kod bloğu uyarısız derlendiği için bu karşılaştırma koşulmuyor, ama derleyicinin kullanılmayan koda verdiği tepkiyle kapalı bir bayrağın gövdesine verdiği (vermediği) tepki arasındaki fark, sınıfın (denetlenmiyor) neden yalnızca kapalı bayraklara özgü olduğunu açıklıyor.

Açıldığında ne olacağı, açılana kadar bilinmiyor — ve bu bilinmezlik, kapalı bir bayrağın gövdesinin zamanla kaynaktaki geri kalanla uyumunu yitirmesinin (çürümesinin) doğrudan nedeni. Kaynak ağacı büyüdükçe, etrafındaki tipler ve işlev imzaları değiştikçe, kapalı bir bayrağın gövdesi bu değişikliklerin hiçbirine ayak uydurmak zorunda kalmıyor; derleyici onu kontrol etmediği için uyumsuzluk yalnızca bayrak açıldığı gün ortaya çıkıyor.

Bu sınır tek bir bayrakla da bitmiyor. Bir kaynak ağacı yalnız iki bağımsız bayrak taşısa bile açık/kapalı ikilisi dört olası derleme durumu üretir; bayrak sayısı arttıkça olası durum sayısı katlanarak büyür. Alışılmış bir derleme akışı bu durumların yalnızca birkaçını — çoğunlukla hepsi kapalı ya da hepsi açık olan uç durumları — gerçekten derler; aradaki bileşimlerin çoğu hiç denenmez. Yukarıdaki koşum tek bir kaynak dosyasında iki bayrağı da kapalı bırakarak bu uç durumlardan birini gösterdi; acilmayan ile denenmemisin birlikte açıldığı bir durum bu derste hiç kurulmadı, çünkü böyle bir durum bu iki gövdenin ikisini de derlemeye sokar ve ikisi de derlenmeyecek biçimde kurulmuştur. Denenmeyen bileşimlerin sayısı arttıkça, kapalı kalan bir bayrağın ne zaman açılacağını ve o an ne olacağını kestirmek de zorlaşır. Bu derste yalnızca iki bayrak, dört olası bileşimin en uç olanı (ikisi de kapalı) gösterildi; kalan üç bileşim — yalnız acilmayan açık, yalnız denenmemis açık, ikisi birden açık — bu ölçümün kapsamı dışında kaldı ve bu kapsam dışılığın kendisi de, ölçülen sınıfın (denetlenmiyor) bir başka örneği.

Özet

  • #[cfg(feature = "ad")] ile işaretlenmiş bir öğe, o bayrak kapalıyken derleyiciye hiç girmez; tanımsız çağrı ve tip hatası taşısa bile derleme uyarısız tamamlanır.
  • Bu gözlem iki farklı bayrakla (acilmayan, denenmemis) ve iki farklı hata türüyle tekrarlandı; sonuç ikisinde de aynı kaldı.
  • Güvencenin sınıfı denetlenmiyor: kapalı bir bayrağın gövdesini ne derleyici, ne bir araç, ne de koşan program denetliyor.
  • Sıradan bir çalışma zamanı dallanması (if gibi) gövdeyi yalnız çalışma yolundan çıkarır ve gövde yine de tip denetiminden geçer; #[cfg(...)] gövdeyi kaynak ağacından çıkarır ve tip denetimi hiç başlamaz — iki dışlama biçimi aynı şey değildir.
  • Bu ölçümün sınırı: kapalı bir bayrağın gövdesinin bugün derlenmediğini gösterir, ama açıldığında derlenip derlenmeyeceğini göstermez — bu yalnızca bayrak gerçekten açıldığında bilinir.
  • Kapalı kalan bir bayrağın gövdesi zamanla kaynaktaki değişikliklere ayak uyduramaz; bunun fark edilmesi bayrağın açıldığı ana kalır.

Sonraki Adım

Bu ders, kimsenin bakmadığı bir gövdenin nasıl sessizce durabildiğini gösterdi; bu sessizliğin nedeni bir hatanın gizlenmesi değil, o gövdenin derleme sürecine hiç girmemesiydi. Sıradaki ders aynı sorunun tersini soruyor: bir gövde derlemeye giriyor, tip denetiminden geçiyor ve yine de yanlış çalışabiliyor — bir gövdenin doğru çalıştığını söylemek için derleyicinin denetimi neden yetmiyor ve bu yetersizliği kapatmak için koşan bir sınamaya ne kadar güvenilebilir? Test ve Özellik Tabanlı Sınama dersi, derleyicinin hiç sormadığı bu soruyu bu kez kapalı bir bayrakla değil, koşarak sınanan bir özellikle yanıtlıyor.

İlerlemeni kaydetmek ve not almak için Giriş yap

Notlarım

Not almak için giriş yapmalısın.

Aramak için yazmaya başlayın.

↑↓ ↵ Esc gezin · aç · kapat