Programlama Dilleri


Programlama dillerini sözdizimi ve semantikten tür sistemlerine, çalışma zamanı ve bellek modellerinden eşzamanlılık, fonksiyonel/nesne yönelimli paradigmalara ve güncel C, C++, Java 27, C# 14, Python 3.14, Rust, Go, Kotlin, ECMAScript ve WebAssembly çizgisine kadar karşılaştırmalı ele alan ders notu.
Programlama dilleri dersi, çok sayıda dilin sözdizimini art arda ezberleme dersi değildir. Amaç; bir dilin hangi soyutlamaları sunduğunu, bu soyutlamaların hangi çalışma zamanı ve güvenlik maliyetlerini doğurduğunu, farklı paradigmalardaki tasarım kararlarının programın doğrulanabilirliğini ve bakımını nasıl etkilediğini anlayabilmektir.
Bir dil seçimi yalnız popülerlik kararı değildir. Çalışma zamanı modeli, tür sistemi, bellek güvenliği, eşzamanlılık, FFI/ABI gereksinimi, gerçek zaman kısıtları, geliştirme araçları ve uzun vadeli standartlaşma projenin risk profilini değiştirir. Klasik dil kuramı, güncel dil ve çalışma zamanı örnekleriyle birlikte değerlendirildiğinde tasarım tercihleri daha görünür hâle gelir.
Ünite 1: Dil Tasarımı, Sözdizimi ve Semantik Temelleri
Bir dilin sözdizimini değerlendirirken önce hangi dizgilerin geçerli kabul edileceği, ardından bu dizgilerin hangi yapıya dönüştürüleceği belirlenir. Ayrıştırma ağacı tek başına programın anlamını açıklamaz; isim çözümleme, tür denetimi ve değerlendirme sırası ayrı aşamalarda incelenir. Aynı örnek program üzerinde sözcüksel çözümleme, ayrıştırma ve statik kontroller yürütülürse hatanın hangi katmanda ortaya çıktığı ayırt edilebilir. Belirsiz bir dilbilgisinde ise alternatif ayrıştırma ağaçları karşılaştırılmadan tek bir anlam varsayılmamalıdır.
1.1. Programlama Dillerinin İncelenme Gerekçeleri
Birden çok dili kavramsal düzeyde bilmek üç önemli kazanım sağlar:
- aynı problemi farklı soyutlama maliyetleriyle modelleyebilmek,
- yeni dili yalnız sözdizimi değil mevcut kavramların yeni kombinasyonu olarak öğrenmek,
- proje gereksinimine göre dil/çalışma zamanı ödünleşimlerini daha bilinçli değerlendirmek.
Örneğin async/await, pattern matching veya generics farklı dillerde farklı sözdizimine sahip olabilir; asıl önemli olan bunların tür sistemi, allocation ve control-flow üzerinde hangi semantiği kurduğudur.
1.2. Dil Değerlendirme Ölçütleri
Klasik değerlendirme eksenleri okunabilirlik, yazılabilirlik, güvenilirlik ve toplam maliyettir. Güncel kritik sistemlerde bunlara şu boyutları eklemek gerekir:
- type ve bellek güvenliği,
- deterministik davranış ve worst-case latency,
- concurrency modeli,
- FFI/ABI ve platform erişimi,
- build/reproducibility,
- toolchain ve static analysis olgunluğu,
- standardizasyon ve backward compatibility,
- dağıtım footprint ve startup,
- library/supply-chain yüzeyi.
Bir kriter diğerini otomatik olarak üstün kılmaz. Daha güçlü safety kontrolleri derleme süresini artırabilir; daha dinamik yapı geliştirme hızını artırırken bazı hataları çalışma zamanına bırakabilir.
1.3. Dil Tasarımı bir Ödünleşim Problemidir
Programlama dili, "en fazla özellik" yarışması değildir. Tasarım kararları birbirini etkiler:
implicit conversion <-> convenience / ambiguity
manual memory <-> control / safety burden
dynamic typing <-> flexibility / earlier error detection
GC <-> simpler ownership / pause + throughput cost
reflection <-> dynamism / analyzability + AOT costİyi bir dil tasarımı hedef domain'in önceliklerini görünür hale getirir. Sistem programlama, veri analizi ve UI scripting aynı optimum noktaya sahip değildir.
1.4. Sözdizimi, Statik Semantik ve Dinamik Semantik
Sözdizimi bir programın biçimsel olarak hangi token ve yapılardan oluşabileceğini tanımlar. Statik semantik, parse edilmiş program üzerinde çalışma öncesi uygulanabilen kurallardır: type checking, isim çözümleme veya kesin atama buna örnektir. Dinamik semantik ise program yürütülürken yapıların ne anlama geldiğini tanımlar.
Şu kod sözdizimsel olarak geçerli olabilir fakat type sistemi tarafından reddedilebilir:
int count = "forty-two"Buna karşılık sıfıra bölme veya null dereference gibi bazı problemler dil ve analiz düzeyine göre ancak çalışırken ortaya çıkabilir.
1.5. Grammar: BNF ve EBNF
Bir dilin context-free sözdizimi BNF/EBNF üretimleriyle açıklanabilir:
expression = term { ("+" | "-") term } ;
term = factor { ("*" | "/") factor } ;
factor = number | "(" expression ")" ;Bu grammar çarpma/bölmenin toplama/çıkarmadan daha sıkı bağlanmasını doğrudan yapı üzerinden ifade eder. Grammar, type kuralları veya çalışma zamanı davranışı açıklamaz; onlar ayrı semantik katmanlardır.
1.6. Sözcüksel Çözümleyici ve Ayrıştırıcı Ayrımı
Sözcüksel çözümleyici kaynak metni identifier, literal, keyword ve operator gibi token'lara ayırır. Ayrıştırıcı bu token dizisini grammar'a göre syntax tree'ye dönüştürür.
source -> characters -> tokens -> AST -> semantic analysis -> IR/codeModern ayrıştırıcı pipeline'larında hata recovery, source span ve incremental parsing IDE deneyimi açısından en az "geçerli programı parse etmek" kadar önemlidir.
1.7. Ayrıştırıcı Yaklaşımları
Recursive-descent, LL/LR ailesi ve ayrıştırıcı generator yaklaşımları farklı grammar sınıfları ve geliştirme araçları maliyetleri sunar. Küçük DSL için elle yazılan recursive-descent ayrıştırıcı okunabilir olabilir; büyük dilde generated ayrıştırıcı veya PEG gibi başka modeller tercih edilebilir.
Ayrıştırıcı seçimi yalnız hız kararı değildir. Hata mesajının kalitesi, incremental parse, ambiguity ve grammar bakım maliyeti de değerlendirilir.
Ünite 2: İsimler, Türler ve Veri Semantiği
2.1. İsim, Bağlama ve Yaşam Süresi
Bir name'in neye bağlandığı ve bu bağlamanın ne zaman oluşturulduğu dilin temel semantiğidir.
name -> entity
entity -> storage/value/function/type/moduleStatic bağlama compile/link zamanında belirlenebilir. Dynamic dispatch gibi bazı bağlamalar çalışma zamanında seçilir.
Kapsam, ismin kaynak kodda görünür olduğu alanı; yaşam süresi ise bağlı nesnenin çalışma zamanında var olduğu süreyi ifade eder. Bunlar aynı kavram değildir. Closure dış kapsamdaki değişkenin yaşam süresini lexical bloktan daha uzun hale getirebilir.
2.2. Lexical ve Dynamic Kapsam
Çoğu modern genel amaçlı dil lexical kapsam kullanır: isim çözümleme kaynak kodun statik iç içe yapısına göre yapılır.
Dynamic kapsam ise çağrı zincirine göre isim arar ve local reasoning'i zorlaştırır. Bazı özel DSL veya configuration sistemlerinde benzer dinamik bağlam davranışları görülebilir.
Lexical kapsam derleyici optimizasyonu, refactoring ve static analysis için daha öngörülebilir bir temel sunar.
2.3. Değer, Referans ve Kimlik
Bir dilde x = y ifadesi "değeri kopyala", "referansı kopyala", "move et" veya başka bir semantic olabilir.
C'de struct assignment değer kopyalayabilir. Java'da object variable'ı referans değerini taşır. Rust'ta bazı değerlerin assignment'ı ownership move eder. C++'ta copy/move constructor ve overload'lar devreye girebilir.
Bu nedenle "pass by value" ifadesi, taşınan değerin pointer/reference olması halinde nesnenin de kopyalandığı anlamına gelmez.
2.4. Tür Sisteminin Amacı
Tür sistemi, mümkün olmayan durumların bir kısmını program yürütülmeden veya kontrollü çalışma zamanı check ile engellemeye çalışır.
Type özellikleri farklı eksenlerde incelenebilir:
- static / dinamik türleme,
- nominal / structural typing,
- explicit / inferred types,
- strong / permissive conversions,
- nullable / non-null types,
- algebraic types,
- ownership/yaşam süresi types.
"Strongly typed" tek ve evrensel kesinlikte bir sınıflandırma değildir; hangi dönüşümlerin ve hangi hataların engellendiği açıkça belirtilmelidir.
2.5. Nominal ve Structural Typing
Nominal sistemde type uyumluluğu declaration identity ve açık ilişkilerle belirlenir. Java class/interface ve C# type ilişkileri büyük ölçüde nominaldir.
Structural sistemde bir değerin gereken üyeleri sağlaması yeterli olabilir. TypeScript bu yaklaşımı yaygın biçimde kullanır. Go interface satisfaction da açık implements declaration gerektirmeyen structural bir model sunar.
Structural typing adapter ihtiyacını azaltabilir; nominal typing domain sınırını ve intent'i daha belirgin hale getirebilir.
2.6. Primitive, Product, Sum ve Optional Types
Record/struct/tuple, birden çok alanın birlikte bulunduğu product type olarak düşünülebilir. Variant/discriminated union/enum-with-payload ise alternatiflerden yalnız birinin aktif olduğu sum type modelidir.
Result<T, E> = Ok(T) | Error(E)
Option<T> = Some(T) | NoneBu model hata ve eksik değeri null veya sentinel sayı yerine tür sistemine taşır. Rust Result/Option, Swift Optional ve fonksiyonel dillerdeki algebraic data type'lar bu fikrin pratik örnekleridir.
2.7. Null Tasarım Kararıdır
Null kolay bir "değer yok" işareti sunar fakat her reference'a sessizce eklenirse hata alanını büyütür. Modern diller bu sorunu farklı yollarla ele alır:
- Kotlin
TileT?'yi ayırır, - Swift optional kullanır,
- Rust
Option<T>kullanır, - C# nullable reference analysis sunar,
- Java
Optional<T>'ı belirli API senaryolarında library type olarak sunar.
Amaç null'u yasaklamak değil, absence durumunu sözleşmede görünür yapmaktır.
2.8. Unicode ve String Semantiği
"Bir karakter bir byte'tır" varsayımı modern metin işlemede geçerli değildir. Unicode code point, UTF-8/UTF-16 code unit ve kullanıcı tarafından algılanan grapheme cluster farklı kavramlardır.
Bir dilde length fonksiyonunun byte, code unit, scalar value veya grapheme sayması API tasarımını etkiler. C/C++ byte-oriented string, Java/C# UTF-16 kökenli string ve Rust UTF-8 String farklı indexing kararları gösterir.
Metin algoritmaları storage encoding ile insan dilindeki karakter kavramını karıştırmamalıdır.
2.9. Conversion ve Coercion
Explicit conversion programcı tercihidir; implicit coercion dilin otomatik dönüşümüdür. Otomatik dönüşüm kolaylık sağlarken precision kaybı veya overload ambiguity yaratabilir.
Kritik hesapta narrowing conversion açık olmalı ve range kontrolü düşünülmelidir. Para hesabında binary floating point ile decimal arithmetic seçimi tür sisteminin domain doğruluğuna etkisine örnektir.
2.10. Generics ve Parametric Polymorphism
Generic yapı, algoritmayı belirli bir concrete type'a bağlamadan type-safe yeniden kullanımı sağlar.
function max<T: Ordered>(a: T, b: T) -> TImplementation stratejileri farklı olabilir: C++ template instantiation/monomorphization, Java type erasure, .NET reified generic üst veri/çalışma zamanı specialization ve Rust monomorphization farklı binary-size/çalışma zamanı ödünleşimleri üretir.
Generic abstraction "sıfır maliyet" varsayımıyla değil dilin gerçek implementation modeliyle değerlendirilmelidir.
2.11. Ad-hoc, Subtype ve Parametric Polymorphism
Polymorphism tek bir mekanizma değildir:
- ad-hoc: overload/operator overloading,
- subtype: interface/base type üzerinden dynamic dispatch,
- parametric: generic type parameter,
- coercion: değerin başka tipe dönüştürülmesi.
Bu ayrım API tasarımında önemlidir. Overload set büyüdükçe resolution karmaşıklaşabilir; dynamic dispatch çalışma zamanı indirection getirir; generic specialization binary büyütebilir.
Ünite 3: Altprogramlar, Kontrol, Kaynak ve Soyutlama Modelleri
3.1. Fonksiyonlar, Closure ve higher-order Yapı
Fonksiyon birinci sınıf değer olduğunda parameter olarak taşınabilir veya döndürülebilir. Closure, executable code ile lexical environment'ı birlikte tutar.
function counter() {
let value = 0;
return () => ++value;
}
const next = counter();
console.log(next());
console.log(next());value, outer call tamamlandıktan sonra da closure tarafından erişilebilir. Bu durum yaşam süresi ve allocation üzerinde etki oluşturabilir.
3.2. Parameter Passing Semantiği
Klasik modeller value, reference, result, value-result ve name gibi yöntemleri inceler. Modern dillerde pratik olarak value semantics, reference/pointer values, ref/out, borrow ve inout benzeri mekanizmalar görülür.
Aliasing, iki farklı erişim yolunun aynı mutable nesneye ulaşmasıdır. Aliasing arttıkça derleyici optimizasyonu ve local reasoning zorlaşır. Rust borrow checker bu sınıf problemi type/yaşam süresi kurallarıyla kısıtlamaya çalışır.
3.3. Evaluation Order ve Side Effect
Şu ifadenin güvenilir olması için dilin operand evaluation order kuralı bilinmelidir:
f(i++, i++)Evaluation order tanımsız, unspecified veya kesin olabilir. Side effect taşıyan expression'lar sıralama kuralına duyarlıdır.
Kritik kodda karmaşık expression yerine adımları açık statement'lara ayırmak dil farklarından ve refactoring sürprizlerinden korunmaya yardımcı olur.
3.4. Control Flow ve Pattern Matching
Selection ve iteration temel yapılardır; modern diller pattern matching ile veri biçimi ve control-flow'u birleştirir.
match result {
Ok(value) => use(value),
Error(cause) => recover(cause)
}Exhaustiveness checking, tüm variant'ların ele alınmasını derleyici seviyesinde doğrulayabilir. Bu, yeni variant eklendiğinde sessiz default davranıştan daha güvenli olabilir.
3.5. Exception, Result ve Effect Yaklaşımı
Exception normal return yolundan ayrı stack unwinding mekanizması sunar. Bazı diller checked istisna, bazıları unchecked model kullanır; Rust gibi diller recoverable hata için Result tipini tercih eder.
Hata modelinin seçiminde şu sorular önemlidir:
- caller hatayı görmeye zorlanıyor mu?
- stack unwinding maliyeti nedir?
- resource cleanup garanti altında mı?
- hata type-safe mi yoksa string/code mu?
- API composition nasıl davranıyor?
Exception'ı rutin branch mekanizması yapmak hem maliyet hem okunabilirlik problemi oluşturabilir.
3.6. Resource Management: GC, RAII ve Ownership
Bellek yönetiminde üç yaygın yaklaşım birbirini tamamen dışlamaz:
- manual allocation/free,
- tracing çöp toplama,
- deterministic ownership/RAII.
C manual yaşam süresi kontrolü verir fakat use-after-free/double-free riskini programcıya bırakır. Java/C# tracing GC ile object heap'i yönetir fakat file/socket gibi dış kaynaklar için yine explicit close/dispose gerekir. C++ RAII destructor ömrünü lexical/object yaşam süresi ile bağlar. Rust ownership ve borrow kurallarıyla GC olmadan bellek güvenliği hedefler.
GC "bellek sızıntısı imkânsız" anlamına gelmez; erişilebilir fakat artık gereksiz nesne tutulabilir.
3.7. Stack, Heap ve Escape
Stack/heap ayrımı source-level type kategorisinden çok çalışma zamanı implementation konusudur. Escape analysis bir nesnenin local kapsam dışına çıkmadığını kanıtlayıp allocation'ı optimize edebilir.
Closure capture, interface boxing, async state machine veya reflection allocation davranışını değiştirebilir. Performans analizi dil sloganıyla değil derleyici/çalışma zamanı çıktısıyla yapılmalıdır.
3.8. Object-oriented Model
OOP'nin temel mekanizmaları encapsulation, abstraction, inheritance ve dynamic dispatch çevresinde gelişmiştir. Ancak inheritance kod tekrarını azaltmak için otomatik ilk tercih değildir.
Composition, interface/protocol ve immutable value object çoğu domain'de daha gevşek coupling sağlar. Modern Java/C#/Kotlin/Swift gibi diller inheritance ile birlikte sealed type, record/data class ve pattern matching gibi başka modeling araçları da sunar.
3.9. Interface, Trait ve Protocol
Benzer amaç farklı dillerde farklı adlarla görünür:
- Java/C#: interface,
- Rust: trait,
- Swift: protocol,
- Go: interface.
Semantic fark önemlidir. Go interface structural olarak satisfaction görür; Rust trait generic constraint ve static/dynamic dispatch için kullanılabilir; Swift protocol associated type ve extension mekanizmalarıyla farklı abstraction imkânları sunar.
"Hepsi interface" demek bu çalışma zamanı farklarını gizler.
3.10. Modül, Package ve Namespace
Büyük sistemde type kadar compilation/dağıtım birimi de önemlidir. Module sistemi visibility, dependency graph ve initialization order'ı etkiler.
C/C++ header/module modeli, Java module/package, C# assembly/namespace, Go package/module, Rust crate/module ve JavaScript ES module aynı probleme farklı seviyelerde çözüm getirir.
Package manager, dil module sistemi ve OS shared library aynı kavram değildir.
Ünite 4: Eşzamanlılık, Paradigmalar ve Metaprogramlama
Eşzamanlı bir programın davranışı, yalnızca komutların tek tek doğruluğundan çıkarılamaz. Önce paylaşılan durum ve erişen yürütme bağlamları belirlenir; sonra erişimlerin olası sıraları ve görünürlük koşulları incelenir. Karşılıklı dışlama veya mesajlaşma kararı, korunması gereken değişmezler üzerinden verilir. Doğrulamada yalnız başarılı yürütmeler değil, yarış durumu, kilitlenme ve ilerleme kaybı üretebilen sıralamalar da aranır. Güvenilirlik için hedef, belirli bir zamanlamanın tesadüfen çalışması değil, izin verilen zamanlamalarda sözleşmenin korunmasıdır.
4.1. Concurrency ile Paralellik Ayrımı
Concurrency birden çok işin ilerlemesini organize eder; paralellik bunların aynı anda farklı execution resource üzerinde çalışmasıdır.
Dil/çalışma zamanı modelleri:
- OS iş parçacığı + shared memory,
- user-mode task/fiber/virtual iş parçacığı,
- async event loop,
- actor/message passing,
- CSP/channel,
- data parallel primitives.
Model değişse de race, deadkilit, starvation, cancellation ve geri basınç problemleri kaybolmaz.
4.2. Memory Model ve happens-before
Shared-memory dilde "iki iş parçacığı aynı değişkeni okur/yazar" problemi yalnız CPU önbellek meselesi değildir. Dil memory model'i hangi read/write yeniden sıralamalarının mümkün olduğunu ve synchronization'ın görünürlük garantisini tanımlar.
Atomic, volatile, kilit/mutex ve channel gibi primitive'ler birbirinin doğrudan eş anlamlısı değildir. Lock mutual exclusion sağlar; atomic belirli işlemin indivisible olmasını sağlayabilir; visibility/order garantisi dile göre değişir.
4.3. Async/Await Mekanizmasının İşlevi
async/await çoğu dilde continuation/state-machine modelini daha okunabilir yazmayı sağlar. Otomatik paralellik veya yeni iş parçacığı garantisi değildir.
I/O-bound yüksek concurrency için değerli olabilir. CPU-bound iş için scheduler/iş parçacığı pool/parallel primitive ayrıca seçilmelidir.
Cancellation ve timeout structured concurrency modelinin parçası yapılmadığında orphan task ve resource leak ortaya çıkabilir.
4.4. Fonksiyonel Programlama
Functional yaklaşım first-class function, immutable data ve expression composition'ı öne çıkarır. Pure function aynı input için aynı output'u üretir ve gözlemlenebilir dış yan etki oluşturmaz.
Bu özellikler test ve concurrency reasoning'i kolaylaştırabilir. Gerçek uygulama I/O yaptığı için amaç "hiç side effect olmasın" değil, effect boundary'lerini görünür ve sınırlı tutmaktır.
Java Stream, C# LINQ, Kotlin collection operators veya JavaScript array higher-order metodları functional fikirleri imperative/OOP dillere taşır.
4.5. Logic ve Declarative Programming
Logic programming'de programcı işlem sırasından çok relation ve kuralları belirtir. Prolog klasik örnektir.
SQL de imperative kontrol akışından ziyade istenen sonucu tarif eden declarative bir dil örneğidir; query optimizer fiziksel execution planını seçer.
Declarative dil "performans düşünmeye gerek yok" anlamına gelmez. Abstraction altında optimizer ve evaluation modeli vardır.
4.6. Metaprogramming, Macro ve Reflection
Metaprogramming kodun kod veya program yapısı üzerinde çalışmasıdır. Preprocessor macro, hygienic macro, annotation processor, source generator, compile-time evaluation ve çalışma zamanı reflection farklı mekanizmalardır.
Çalışma zamanı reflection esneklik sağlarken startup, trimming/AOT ve static analysis maliyeti oluşturabilir. Compile-time generation daha fazla build karmaşıklığı karşılığında çalışma zamanı üst veri taramasını azaltabilir.
Textual macro ile AST/token-aware macro aynı güvenlik ve hygiene özelliklerine sahip değildir.
Ünite 5: Derleme, Çalışma Zamanı ve Dil Sınırları
5.1. Derleyici, İnterpreter, JIT ve AOT
"Derlenen dil" ve "yorumlanan dil" ikili sınıflandırması modern çalışma zamanları açıklamakta yetersizdir.
Java source -> bytecode -> JVM interpreter/JIT -> native code
C# source -> IL -> CLR JIT/AOT -> native code
C/C++ -> object -> linker -> native image
JavaScript -> parser/IR/interpreter/JIT -> native executionAOT startup ve dağıtım karakteristiğini değiştirir; JIT çalışma zamanı profile üzerinden adaptif optimizasyon yapabilir. Ödünleşim workload'a bağlıdır.
5.2. Intermediate Representation ve Optimizer
Derleyici genellikle source'tan doğrudan machine code üretmez. AST sonrası bir veya daha çok IR üzerinden type lowering, SSA, inlining, dead-code elimination, vectorization ve register allocation gibi aşamalar uygulanabilir.
IR, birden çok source dilinin ortak optimizer/backend kullanmasını mümkün kılar. LLVM IR bunun tanınmış örneklerinden biridir; JVM bytecode ve .NET IL ise aynı zamanda dağıtım/çalışma zamanı formatı rolü oynar.
5.3. ABI, FFI ve Dil Sınırı
İki dilin birbirini çağırabilmesi yalnız function adını bilmek değildir. Calling convention, symbol mangling, layout/alignment, ownership, istisna ve string representation uyumlu olmalıdır.
C ABI birçok ekosistemde ortak düşük seviye sınır olarak kullanılır. FFI sınırında safety garantileri zayıflayabilir; Rust unsafe, Java JNI/FFM veya .NET P/Invoke gibi mekanizmalar explicit boundary oluşturur.
Serialization kullanarak process boundary kurmak, aynı-process FFI'dan farklı latency ve failure semantics üretir.
5.4. WebAssembly bir Hedef Platformdur
W3C'nin 12 Ağustos 2026 tarihli WebAssembly Core Specification belgesi sürüm 3.0'ı tanımlar ve Candidate Recommendation Draft durumundadır. WebAssembly güvenli, taşınabilir ve düşük seviyeli bir kod biçimidir; C/C++, Rust ve başka diller için tarayıcı veya WASI hedefi olabilir.
Wasm bir kaynak dil değildir; derleyici hedefi ve çalışma zamanı modelidir. Çöp toplayıcılı diller, bileşen modeli veya konak API'leriyle kullanımda ek ABI ve birlikte çalışabilirlik kararları gerekir.
Ünite 6: Modern Diller, Ekosistemler ve Uygulama Alanları
6.1. C ve C++: Güncel Standart Çizgisi
2026 itibarıyla yayımlanmış ISO standartları C için ISO/IEC 9899:2024 ve C++ için ISO/IEC 14882:2024'tür.
C; açık memory layout, pointer ve düşük çalışma zamanı abstraction ile sistem/embedded alanında güçlüdür. Bu kontrol undefined behavior ve manual yaşam süresi sorumluluğunu da beraberinde getirir.
C++ RAII, templates, constexpr, concepts ve standard library ile zero-overhead abstraction hedefler; dilin büyük özellik alanı coding standard ve toolchain discipline gerektirir.
İlgili uygulama notları: C Programlama ve C++ Programlama.
6.2. Java: JVM ve Managed Çalışma Zamanı
Java 27 güncel özellik sürümü, Java 25 ise uzun süreli destek (LTS) çizgisidir. Java source JVM bytecode'a derlenir; çalışma zamanı JIT/AOT ve çöp toplama tekniklerini kullanabilir.
Java'nın nominal static type sistemi, generics, records/sealed classes, pattern matching, virtual iş parçacığıs ve geniş library/çalışma zamanı ekosistemi modern dil tasarımının birçok konusunu aynı platformda gösterir.
Ayrıntılar için Java Programlama.
6.3. C# ve .NET
C# 14, .NET 10 üzerinde güncel dil sürümüdür. C#; nominal statik türleme, generics, delegates, LINQ, records, pattern matching, async/await, spans ve unsafe escape hatch'lerini aynı dilde birleştirir.
CLR IL, üst veri, JIT ve AOT seçenekleri type/çalışma zamanı tasarımını doğrudan görünür kılar.
Ayrıntılar için C# Programlama.
6.4. Python 3.14
Python 3.14.7, 3.14 serisinin güncel bakım sürümüdür. Python 3.14 serisi dinamik türleme, duck typing, first-class function, generator/coroutine ve geniş çalışma zamanı introspection modelini sürdürür. Python 3.14'te free-iş parçacığıed Python resmi destek kazanmıştır; bu gelişme "GIL her Python build'inin değişmez özelliğidir" gibi genellemeleri geçersiz kılar.
Dynamic typing ile type annotations farklı katmanlardır: annotation, interpreter'ın bütün type hatalarını otomatik engellemesi anlamına gelmez; static checker/geliştirme araçları ek bir analysis katmanıdır.
6.5. Rust 2024 Edition
Rust 1.98.1 güncel kararlı sürümdür; Rust 2024 Edition ise dilin sürümden bağımsız edition çizgisini belirtir. Rust'ın ayırt edici tasarımı ownership, borrowing ve yaşam süresi kurallarıyla tracing GC olmadan bellek güvenliği sağlamayı hedeflemesidir.
unsafe Rust, derleyicinin bazı safety kanıtlarını programcıya devrettiği explicit boundary'dir; unsafe kullanılması tüm programın denetimsiz olduğu anlamına gelmez.
Rust'ın enum + pattern matching + Result modeli sum type ve explicit error handling için öğretici örnektir.
6.6. Go 1.27
Go 1.27 specification; strongly typed, garbage-collected ve explicit concurrency desteği olan genel amaçlı bir dil tanımlar. Go 1.27 generic methods desteğini de eklemiştir.
Goroutine ve channel, CSP-benzeri concurrency yaklaşımını pratikleştirir; bununla birlikte shared memory, mutex ve atomic primitive'ler de mevcuttur.
Go'nun küçük dil yüzeyi ve backward compatibility politikası dil karmaşıklığı ile ecosystem stability arasındaki farklı tasarım tercihine örnektir.
6.7. Kotlin 2.4 ve Swift
Kotlin 2.4.20 güncel 2.4 release line'ındadır ve JVM yanında JavaScript, WebAssembly ve Native hedeflerini destekler. Null safety, extension function, coroutine ve multiplatform modeli; kaynak dil ile target çalışma zamanı ayrımını görmek için güçlü örnektir.
Swift'in resmi Language Reference'ı protocol, value semantics, generics, optionals ve structured concurrency gibi özellikleri tanımlar. Swift yalnız iOS UI dili olarak değil, modern type-system ve ownership yönelimli tasarım kararları açısından incelenmelidir.
6.8. JavaScript / ECMAScript 2026
ECMAScript 2026, ECMA-262'nin 17. baskısıdır. JavaScript dinamik türleme, prototype-based object model, closure, event-loop ile bütünleşen promise/async model ve module sistemini bir arada gösterir.
JavaScript çalışma zamanı ile Web API aynı şey değildir. fetch, DOM ve localStorage tarayıcı platform API'leridir; ECMAScript dil standardının kendisi değildir. Node.js başka host API'leri sağlar.
6.9. Dil Seçimi için Pratik Matris
Tek bir "en iyi dil" yerine gereksinimleri görünür yapın:
Kriter Sorulacak soru
--------------------- ---------------------------------------------
Latency p99/p999 ve worst-case sınırı var mı?
Memory safety unsafe/native sınır ne kadar geniş?
Runtime GC/JIT kabul edilebilir mi?
Startup/footprint kısa ömürlü process veya edge hedefi mi?
Concurrency thread, actor, async, channel hangisi doğal?
Interop mevcut C ABI/JVM/.NET/native koda bağlanacak mı?
Tooling static analysis, profiler, debugger yeterli mi?
Portability hangi OS/CPU/runtime hedefleniyor?
Team mevcut uzmanlık ve bakım süresi nedir?
Standardization dil/toolchain sürüm politikası ne kadar kararlı?Bu matris winner üretmez; ödünleşimlerin projeye göre açıkça belgelenmesini sağlar.
6.10. Kritik ve Gerçek Zamanlı Sistemlerde Dil Semantiği
Kritik sistemde average throughput yeterli ölçüt değildir. Allocation, GC pause, hidden synchronization, istisna path, scheduler ve JIT warm-up tail latency'yi etkileyebilir.
Determinism gerekiyorsa:
- allocation stratejisini sınırla,
- bkiliting noktalarını görünür yap,
- concurrency primitive'lerini ölç,
- istisna/error path'i benchmark et,
- derleyici flags/çalışma zamanı sürümünü sabitle,
- undefined behavior ve data race'i static/dynamic analysis ile denetle,
- production benzeri workload kullan.
Dil seçimi bu operasyonel disiplinin yerine geçmez.
6.11. Güvenlik Açısından Dil Seçimi
Memory-safe dil bütün güvenlik açıklarını çözmez; authorization, injection ve business logic hataları devam eder. Bununla birlikte bounds check, ownership, safe reference ve type-safe serialization belirli exploit sınıflarını azaltabilir.
Native FFI, unsafe, reflection, deserialization ve code generation safety sınırını tekrar açabilir. Threat model bu escape hatch'leri ayrıca işaretlemelidir.
Supply-chain riski çoğu zaman dilin kendisinden çok package ecosystem ve build pipeline'dan gelir.
Ünite 7: Dil Seçimi ve Teknik Kanıt
7.1. İlgili Dersler
Dil kuramını somut platformlarda görmek için C Programlama, C++ Programlama, Java Programlama ve C# Programlama birlikte okunabilir. Syntax/grammar tarafı için Otomatlar Kuramı ve Biçimsel Diller, çalışma zamanı/memory için İşletim Sistemleri, web host modeli için Web Programlama tamamlayıcıdır.
7.2. Dil Seçimini Çalışma Modeliyle İlişkilendirmek
Bir programlama dilini yalnız sözdizimi üzerinden karşılaştırmak yanıltıcıdır. Aynı algoritma; bellek yönetimi, çağrı modeli, hata sözleşmesi, eşzamanlılık ilkelleri ve çalışma zamanı nedeniyle farklı dillerde farklı operasyonel özellikler gösterir. Dil seçimi bu nedenle "hangi dil daha hızlı?" sorusundan çok, hangi maliyetlerin görünür ve denetlenebilir olduğuyla ilgilidir.
Örneğin GC kullanan bir çalışma zamanı kısa ömürlü nesneler için geliştirici yükünü azaltabilir; fakat gecikme bütçesi çok sıkı bir sistemde allocation hızı ve duraklama dağılımı ayrıca ölçülmelidir. Sahiplik tabanlı bir model ise bazı yaşam süresi hatalarını derleme zamanına taşıyabilir; bunun karşılığında API tasarımı daha açık sahiplik kuralları ister.
Dil değerlendirmesinde yararlı bir matris şunları birlikte ele alır:
- tür güvenliği ve ifade gücü,
- hata ve iptal sözleşmesi,
- bellek sahipliği ve yaşam süresi,
- eşzamanlılık ve paralellik modeli,
- ABI/FFI ve ekosistem sınırı,
- derleme, JIT/AOT ve dağıtım modeli,
- tanılama, profil çıkarma ve test araçları.
Bu yaklaşım, dili "özellik listesi" olarak değil, yazılımın çalışma davranışını belirleyen bir mühendislik sistemi olarak okumayı sağlar.
7.3. Bir Dil İddiasını Teknik Kanıta Bağlamak
Bir dil özelliği değerlendirilirken üç kaynak birbirinden ayrılmalıdır: dil standardı veya resmi belirtim, gerçek çalışma zamanı/derleyici davranışı ve belirli bir iş yükünde yapılan ölçüm. “Dil bunu garanti eder” ifadesi ancak belirtim düzeyinde destekleniyorsa genellenebilir; tek bir derleyicide gözlenen davranış dil sözleşmesi yerine geçmez.
Performans karşılaştırmasında aynı algoritma, aynı veri kümesi, benzer optimizasyon düzeyi ve tekrar edilebilir ölçüm düzeni gerekir. Başlangıç süresi, ısınma, bellek ayırma ve G/Ç maliyeti ayrı raporlanır. Sonuçlar kullanılan sürüm, donanım ve çalışma zamanı ile birlikte anlam kazanır.
Bir dil seçimi değerlendirilirken teknik sınırlar da yazılmalıdır: gerçek zaman gereksinimi, ABI/FFI ihtiyacı, dağıtım modeli, hata toleransı, ekip yetkinliği ve bakım ömrü. Bu çerçeve, sözdizimi tercihini mühendislik kararından ayırır.
Ünite 8: İleri Semantik ve Programlama Modelleri
8.1. Bağlama Zamanları: Dil Tasarımından Çalışma Zamanına
Bağlama (binding), bir ad, sembol veya program varlığı ile onun bir özelliği arasında ilişki kurulmasıdır. Statik ve dinamik bağlama ayrımının ötesinde daha güçlü bir zihinsel model, hangi kararın ne zaman kesinleştiğini izlemektir.
Dil tasarım zamanı
|
v
Dil gerçekleştirim zamanı
|
v
Derleme zamanı
|
v
Bağlama / yükleme zamanı
|
v
Çalışma zamanıÖrneğin + sembolünün toplama anlamını taşıması dil tasarımının parçasıdır. double türünün bellekte hangi bit düzeniyle temsil edildiği dil standardı ile gerçekleştirim arasında paylaşılmış bir sözleşmedir. Bir yerel değişkenin türü derleme sırasında belirlenebilirken, sanal metot çağrısında hangi gövdenin çalışacağı çalışma zamanında seçilebilir.
Erken bağlanan bilgi derleyiciye daha fazla doğrulama ve optimizasyon fırsatı verebilir. Geç bağlama ise çalışma zamanı çeşitliliğine izin verir. Fakat gerçek maliyet, hangi bilginin geç bağlandığına ve gerçekleştirim stratejisine bağlıdır.
8.1.1. Bağlama Zamanı bir Performans Etiketi Değildir
Aynı dinamik çağrı iki çalışma zamanında farklı maliyetle gerçeklenebilir:
Çalışma zamanı A:
her çağrıda tam arama
Çalışma zamanı B:
ilk çağrıda çöz
-> önbelleğe al
-> sonraki çağrılarda hızlı yolJIT derleyicileri, inline cache yapıları ve çalışma zamanı profili, dil düzeyindeki dinamik davranışın her zaman aynı çalışma zamanı maliyetini taşımasını engeller.
8.1.2. Bağlama ve Dağıtım
Bir değer derleme sırasında programa gömülmüşse değişiklik yeniden derleme gerektirebilir. Aynı değer yapılandırmadan okunuyorsa çalışma zamanında değişebilir.
erken bağlama
-> daha fazla ön bilgi
-> daha az çalışma zamanı esnekliği
geç bağlama
-> daha fazla esneklik
-> daha fazla çalışma zamanı çözümlemeBağlama zamanı bu nedenle yalnız dil kuramı değil, dağıtım ve değişiklik yönetimi kararıdır.
8.2. Değişkeni Yalnız "İsim + Değer" Olarak Düşünmemek
Bir değişkeni anlamak için en az şu kavramları ayırmak gerekir:
isim
adres / saklama yeri
değer
tür
kapsam
yaşam süresi
değiştirilebilirlik
sahiplikKlasik terminolojide l-değeri (l-value) erişilebilir bir saklama yerini, r-değeri (r-value) ise ifadede kullanılan değeri anlatmak için kullanılır. Modern diller bu kategorileri daha ayrıntılı biçimde tanımlayabilir; fakat temel ayrım hâlâ değerlidir: hangi değerin okunduğu ile hangi saklama yerinin değiştirildiği aynı soru değildir.
8.2.1. Kapsam ile Yaşam Süresi
Kapsam bir adın kaynak kodun hangi bölümünde görünür olduğunu; yaşam süresi ise bağlı nesnenin çalışma sırasında ne kadar var olduğunu ifade eder.
kaynak kod görünürlüğü -> kapsam
çalışma zamanı varlığı -> yaşam süresiBir closure, dış fonksiyondaki yerel değişkene erişmeye devam ettiğinde değişkenin saklama süresi lexical bloktan daha uzun olabilir.
8.2.2. Saklama Süresi Kategorileri
Dillere göre adlandırma değişse de yaygın sınıflar şunlardır:
- program boyunca yaşayan statik saklama,
- çağrı çerçevesiyle yaşayan otomatik/yığın saklama,
- açık veya örtük dinamik heap nesneleri,
- thread veya görev kapsamına bağlı saklama.
GC, RAII ve ownership bu sorunun farklı çözümleridir: nesne ne zaman doğar, kim erişebilir, temizleme sorumluluğu kimdedir ve erişim ne zaman geçersiz olur?
8.2.3. Takma Adlandırma (Aliasing)
İki farklı erişim yolu aynı değiştirilebilir nesneye ulaşıyorsa aliasing vardır.
A ----\
>---- aynı mutable nesne
B ----/Bu durum yerel akıl yürütmeyi zorlaştırır. C/C++ optimizasyonlarında alias analizi önemlidir. Rust benzeri sahiplik/ödünç alma modelleri ise belirli alias + mutation kombinasyonlarını statik kurallarla sınırlandırmaya çalışır.
8.3. Tür Eşdeğerliği, Tür Uyumluluğu, Çıkarım ve Varyans
"Statik türleme" tek başına tür sistemini açıklamaz. En az dört soru ayırmak gerekir:
- Tür ne zaman belirleniyor?
- İki tür hangi kuralla aynı veya uyumlu sayılıyor?
- Uyumlu olmayan değer hangi dönüşümlerle kabul ediliyor?
- Alt tür ilişkisi bileşik türlerde nasıl yayılıyor?
8.3.1. Ada Dayalı ve Yapısal Eşdeğerlik
Ada dayalı (nominal) sistemde tür ilişkisi açık bildirim veya ada dayanır. Yapısal sistemde üyelerin biçimi önemlidir.
A = {x: int, y: int}
B = {x: int, y: int}Nominal sistem A ve B'yi ayrı tutabilir. Yapısal sistem kullanıldığı bağlama göre uyumlu sayabilir. Nominal model alan sınırını belirginleştirirken, yapısal model daha esnek bileşim sağlayabilir.
8.3.2. Tür Çıkarımı Dinamik Türleme Değildir
statik tür sistemi
+
derleyici çıkarımı
=
türü yazmadan statik doğrulamaDerleyicinin x = 42 bağlamından tür çıkarması, x'in çalışma sırasında keyfî biçimde başka türe dönüşeceği anlamına gelmez.
8.3.3. "Güçlü Türleme" Yerine Somut Sorular
"Güçlü türleme" için tek evrensel ölçüt yoktur. Şunları sormak daha yararlıdır:
- örtük dönüşüm ne kadar geniş,
- bellek temsilleri güvenli biçimde ayrılıyor mu,
- tür hatası ne zaman yakalanıyor,
unsafekaçış noktaları var mı,null/opsiyonel değer nasıl temsil ediliyor?
8.3.4. Varyans
Kedi, Hayvanın alt türü olsa bile:
Kedi <: Hayvanşu ilişki otomatik değildir:
Kutu<Kedi> <: Kutu<Hayvan>Okuma ağırlıklı üretici yapılarda kovaryans, tüketici yapılarda kontravaryans güvenli olabilir. Değiştirilebilir koleksiyonlar daha sıkı kurallar gerektirir. Varyans, jenerik API'lerde tür güvenliğinin doğrudan sonucudur.
8.4. Dizi, Dilim, Kayıt, Birlik ve Cebirsel Veri Türleri
Klasik derslerde diziler, kayıtlar ve birlikler ayrı tür aileleri olarak incelenir. Modern dillerde aynı semantik ayrımlar farklı adlarla yaşamaktadır.
8.4.1. Dizi ile Dilim Aynı Şey Değildir
Dizi çoğu zaman bir saklama alanına sahipken, dilim (slice/view) mevcut veri üzerindeki başlangıç ve uzunluğu temsil edebilir.
buffer: [a b c d e f g h]
|-------|
dilimAlt dizi işlemi kopya oluşturabilir veya yalnız görünüm döndürebilir. Bu fark performans ve yaşam süresini etkiler.
8.4.2. Satır-major ve sütun-major Yerleşim
row-major:
[a00 a01 a02 a10 a11 a12]
column-major:
[a00 a10 a01 a11 a02 a12]Bu ayrım önbellek davranışında, yabancı fonksiyon arabirimlerinde ve sayısal kütüphanelerde görünür hâle gelir.
8.4.3. Kayıt / Struct
Kayıt farklı alanları tek mantıksal nesnede toplar. Dil; alan sırası, hizalama ve padding için hangi garantiyi veriyor? Normal iş kodunda görünmeyen bu ayrıntılar ABI, ikili dosya ve protokol sınırlarında kritiktir.
8.4.4. Etiketsiz ve Etiketli Birlik
Etiketsiz union hangi üyenin geçerli olduğunu programcı sözleşmesine bırakabilir.
Etiketli birlik / ayrık birleşim (discriminated union, sum type) ise varyant bilgisini veri modeline taşır:
Sonuç
+-- Başarılı(değer)
+-- Hata(neden)Bu yaklaşım null veya sihirli hata kodu yerine durum uzayını açık biçimde ifade edebilir.
8.5. İfade Semantiği: Sıra, Kısa Devre, Taşma ve Tanımsız Davranış
Benzer sözdizimi aynı semantik demek değildir.
8.5.1. Değerlendirme Sırası
f(g(), h())çağrısında g() ile h() hangi sırada çalışır? Dil bunu tanımlayabilir veya bazı bağlamlarda gerçekleştirim seçimine bırakabilir. Yan etkiler bu seçimi gözlenebilir hâle getirir.
8.5.2. Kısa Devre
x != 0 && 10 / x > 2ikinci ifadenin yalnız ilk koşul doğruysa çalışması durumunda güvenlidir. Kısa devre yalnız hızlandırma değil, kontrol akışı sözleşmesidir.
8.5.3. Taşma
Tamsayı taşması:
- modüler sarma,
- hata/exception,
- çalışma moduna bağlı davranış,
- tanımsız davranış
gibi farklı sözleşmeler taşıyabilir. Bit genişliği, taşma semantiğini tek başına açıklamaz.
8.5.4. Tanımsız Davranış
Bazı sistem dillerinde standart belirli işlemler için sonuç tanımlamaz. Bu, "rastgele bir değer döner" demek değildir; program dil sözleşmesinin dışına çıkmıştır ve optimizer geçersiz durumun oluşmadığını varsayabilir.
Somut örnekler C Programlama Temelleri ve C++ ile Nesne Yönelimli Programlama dersleriyle birlikte okunmalıdır.
8.6. Altprogramların Çalışma Zamanı: Çağrı Çerçevesi, Özyineleme ve Closure
Fonksiyon veya prosedür çağrısı yalnız başka bir kod bloğuna geçiş değildir. Çalışma zamanı çoğu durumda bir etkinleştirme kaydı (activation record / stack frame) yönetir.
çağrı çerçevesi
+-- dönüş adresi
+-- parametreler
+-- yerel değişkenler
+-- geçici değerler
+-- kaydedilmiş register'lar
+-- gerekirse exception / GC bilgisiGerçek yerleşim ABI ve derleyiciye bağlıdır; her değer fiziksel olarak stack üzerinde olmak zorunda değildir.
8.6.1. Özyineleme
f(3)
-> f(2)
-> f(1)
-> f(0)Her etkin çağrı kendi yerel durumunu taşımalıdır.
8.6.2. Parametre Geçirme Biçimleri
Klasik modeller değer, referans, sonuç, değer-sonuç ve ad ile geçirme gibi yöntemleri inceler. Modern diller farklı sözdizimi kullansa da şu sorular değişmez:
değer kopyalanıyor mu?
nesne kimliği paylaşılıyor mu?
çağrılan taraf çağıranın saklama yerini yeniden bağlayabilir mi?
mutation çağıranı etkiler mi?
yaşam süresi nasıl sınırlandırılıyor?"Python pass-by-reference" veya "Java her şeyi pass-by-value" gibi sloganlar nesne kimliği ile yerel referans değişkenini ayırmadan eksik kalır.
8.6.3. Closure
Closure:
fonksiyon kodu
+
yakalanan lexical çevrebirlikte taşındığında oluşur. Bu nedenle closure yalnız callback kolaylığı değil, değişken yaşam süresi ve allocation davranışıdır.
8.6.4. Coroutine ve Generator
başla
-> üret / askıya al
-> devam et
-> üret
-> bitirCoroutine çalışma akışını askıya alıp sürdürebilir. Generator bunun daha sınırlı bir biçimi olabilir. async/await benzeri yapılar da durum makinesine dönüştürülebilir; coroutine doğrudan işletim sistemi thread'i değildir.
8.7. Soyut Veri Türü, Modül ve Kapsülleme Sınırı
Soyut veri türü (Abstract Data Type, ADT), iç temsilden çok izin verilen işlemleri ve davranış sözleşmesini tanımlar.
Dışarıdan görünen:
push(x)
pop()
isEmpty()
Gizli temsil:
array olabilir
linked list olabilir
başka yapı olabilirMüşteri kodu temsile değil sözleşmeye bağlıysa iç yapı daha güvenli değiştirilebilir.
8.7.1. Modül ile Sınıf Aynı Şey Değildir
Modül; isim alanı, görünürlük, bağımlılık ve derleme birimi sınırı sağlayabilir. Sınıf ise nesne kimliği, durum, kalıtım veya dinamik gönderim gibi ek semantik taşır.
C translation unit, Rust crate/modül, Java package/module ve ML ailesindeki module sistemleri farklı tasarım noktalarıdır.
8.7.2. Temsil Sızıntısı
public API
|
+--> iç mutable veriye doğrudan referansverildiğinde private anahtar sözcüğü tek başına invariants'ı koruyamaz.
8.7.3. Soyutlama Maliyeti
Sanal çağrı, allocation veya kontrol gibi maliyetler oluşabilir; optimizer bazılarını kaldırabilir. "Yüksek seviye yavaştır" ve "zero-cost her yerde bedelsizdir" ifadelerinin ikisi de ölçüm olmadan fazla geneldir.
8.8. Yerel Olmayan Kontrol Akışı: Exception, Cleanup, İptal ve Effect
Exception normal çağrı zincirini aşabilen bir kontrol aktarımıdır.
A()
-> B()
-> C()
-> throw
|
+----> uygun handlerBu nedenle kaynak temizliği dil güvenilirliğinin parçasıdır.
RAII, try/finally, defer, using ve context manager aynı temel soruya yaklaşır: kontrol hangi yoldan çıkarsa çıksın dosya, kilit, socket veya transaction nasıl güvenle bırakılacak?
8.8.1. Exception ile Result Aynı Değildir
exception -> yerel olmayan control transfer
Result -> açık değer akışıHangi modelin uygun olduğu hata sınıfı ve API sınırına bağlıdır.
8.8.2. İptal
Asenkron işlem yarıda kesildiğinde:
- lock tutuluyor mu,
- transaction açık mı,
- kısmi çıktı oluştu mu,
- child task yaşamaya devam ediyor mu
soruları yanıtlanmalıdır.
Yapılandırılmış eşzamanlılık (structured concurrency), child task yaşam süresini görünür bir görev kapsamına bağlamayı hedefler.
8.9. Eşzamanlılık Modelleri: Paylaşılan Bellekten Mesajlaşmaya
"Eşzamanlılığı destekliyor" tek başına yeterli bir dil özelliği değildir. Asıl soru, hangi durum paylaşım modelinin doğal olduğudur.
8.9.1. Paylaşılan Bellek + Kilit
Thread A ----\
>---- shared mutable state
Thread B ----/
lock / atomic / conditionBu model güçlüdür fakat data race, deadlock ve görünürlük sorunları üretir.
8.9.2. Monitor
Monitor, paylaşılan durumu ve senkronizasyon kurallarını aynı soyutlamada toplamaya çalışır.
8.9.3. Kanal / CSP Benzeri Model
Task A --message--> Channel --message--> Task BDoğrudan ortak mutation yerine veri aktarımı öne çıkar.
8.9.4. Actor
Actor özel durum, mailbox ve mesaj işleme döngüsünü birleştirir. Başka actor'ın belleğine doğrudan erişmek yerine mesaj gönderilir.
8.9.5. Yapılandırılmış Eşzamanlılık
parent task
+-- child A
+-- child Bparent kapsamı tamamlanmadan child görevlerin yaşam döngüsü çözülür. Bu, izsiz "başlat ve unut" görevlerini azaltır.
8.9.6. Bellek Modeli
Dil/runtime hangi yeniden sıralamalara izin verildiğini ve hangi senkronizasyon işlemlerinin happens-before ilişkisi kurduğunu tanımlar. Ayrıntılar İşletim Sistemleri ve Bilgisayar Mimarisi dersleriyle ilişkilidir.
8.10. Fonksiyonel Programlamayı "Fonksiyon Kullanmak"Tan Ayırmak
Fonksiyonel programlama yalnız lambda veya map/filter değildir. Temel soru durum ve etkilerin nasıl modellenmesidir.
8.10.1. Değişmezlik
eski durum
|
fonksiyon
|
v
yeni durumPersistent veri yapıları değişmeyen bölümleri fiziksel olarak paylaşabilir. Bu, bütün yapının her değişiklikte tam kopyalanması gerektiği anlamına gelmez.
8.10.2. Katı ve Tembel Değerlendirme
Katı değerlendirme argümanları genellikle çağrıdan önce hesaplar. Tembel değerlendirme değeri ihtiyaç oluşana kadar erteleyebilir.
ifade
-> ertelenmiş hesap
-> ihtiyaçta değerlendirTembellik sonsuz akışları ifade etmeyi kolaylaştırabilir; bellek tutulumu ve performans davranışını daha az sezgisel hâle de getirebilir.
8.10.3. Saf Çekirdek + Effect Sınırı
Gerçek program I/O yapar. Amaç etkileri yok etmek değil, sınırlarını görünür kılmaktır.
pure core
|
+--> I/O
+--> database
+--> network8.10.4. Tail Call
Tail recursion döngü gibi ifade edilebilir; fakat runtime tail-call optimizasyonu garanti etmiyorsa derin özyineleme stack büyütür. Paradigma ile gerçekleştirim yine ayrı değerlendirilmelidir.
8.11. Mantıksal ve Kısıt Tabanlı Programlamayı Daha Derin Okumak
Mantıksal Programlama ve Prolog bu alanı ayrıntılı ele alır. Programlama dilleri açısından önemli olan, Prolog'un yalnız farklı sözdizimli tarihsel bir dil olmamasıdır.
8.11.1. Birleştirme (Unification)
Terimler tutarlı değişken bağlamalarıyla eşleştirilebilir.
8.11.2. Geri İzleme (Backtracking)
sorgu
-> kural 1
-> başarısız
-> kural 2
-> alt hedefler
-> başarıKural ve hedef sırası performansı ve bazı durumlarda sonlanmayı etkileyebilir. Deklaratif anlam ile yürütme stratejisi aynı şey değildir.
8.11.3. Tabling
Hesaplanmış alt hedef sonuçlarının saklanması tekrar hesaplamayı azaltabilir ve bazı döngüsel ilişkilerde sonlanmayı iyileştirebilir.
8.11.4. Kısıt Programlama
değişkenler
+
alanlar
+
kısıtlar
+
aramabiçiminde ifade edilen problemde programcı çözümün tüm adımlarını yazmak yerine çözüm uzayını sınırlar.
8.12. Biçimsel Semantik: Programın Anlamını Matematiksel Olarak Tanımlamak
Sözdizimi biçimsel geçerliliği, semantik ise geçerli yapının ne anlama geldiğini belirler. Doğal dil açıklaması öğreticidir; biçimsel doğrulama için daha kesin modellere ihtiyaç vardır.
8.12.1. İşlemsel Semantik
Programı soyut makine durum geçişleriyle açıklar:
<ifade, durum>
|
v
<ifade', durum'>
|
v
...8.12.2. Aksiyomatik Semantik
Program parçalarını önkoşul ve sonkoşulla ilişkilendirir:
{ P } program { Q }Invariant ve program doğrulama düşüncesiyle doğrudan bağlantılıdır.
8.12.3. Denotasyonel Semantik
Dil yapısını matematiksel nesne veya fonksiyona eşler:
syntax construct
|
semantic mapping
|
v
mathematical meaningGerçek bir dilin tüm ayrıntılarını bu düzeyde tanımlamak güç olabilir; buna rağmen semantiği gerçekleştirimden bağımsız düşünmek için güçlü bir çerçevedir.
Bu bölüm Otomatlar Kuramı ve Biçimsel Diller, statik analiz ve doğrulama konularına doğal geçiş sağlar.
8.13. Dil Semantiğinden Bellek Modeline
Çok çekirdekli programlamada doğruluk yalnız veri yarışının bulunmaması değildir. Programlama dili düzeyinde eşzamanlılık semantiği üç ayrı soruyu ayırmayı gerektirir: gözlenen sonuçlar hangi sıralı yürütmeyle açıklanabilir, bir iş parçacığının ilerlemesi hangi koşullarda garanti edilir ve dilin bellek modeli yazma-okuma görünürlüğünü hangi senkronizasyon olaylarıyla kurar; kilit rekabeti ise bunlardan ayrı bir performans olgusudur. Linearizability doğruluk için güçlü bir model sunarken lock-free ve wait-free gibi ilerleme sınıfları, sistemin gecikme davranışının yalnız mutex sayısıyla açıklanamayacağını gösterir.
- Derleyici optimizasyonlarının gözlenebilir program davranışı sınırlarında değerlendirilmesi.
- Eşzamanlı programlarda dil belleği modeli ile donanım yeniden sıralamasının ayrıştırılması.
- Bir dilin soyut makinesi ile çalışma zamanı maliyet modelinin aynı şey olmadığının korunması.
Ünite 9: Çalışma Zamanı, Evrim, Güvenlik ve Uygunluk
9.1. "Derlenen" ve "Yorumlanan" İkiliğinin Ötesinde Çalışma Zamanı
Modern gerçekleştirimler bir spektrum oluşturur:
Kaynak
|
+--> Native AOT -----------------------> Makine kodu
|
+--> Bytecode / IR --> Interpreter ----> Yürütme
| |
| +--> JIT ---------> Makine kodu
|
+--> Adaptive interpreter
| |
| +--> sıcak işlemleri özelleştir
|
+--> JIT + AOT karma modellerPerformans kıyaslamasında dil adından önce gerçekleştirim yolu belirtilmelidir.
9.1.1. Profil Güdümlü Runtime
JIT; sıcak metot, baskın çağrı hedefi ve gözlenen türler üzerinden specialization ve inline yapabilir. Varsayım bozulursa deoptimization ile daha genel yola dönebilir.
9.1.2. Uyarlanan Yorumlayıcı
Yorumlayıcı çalışma zamanı gözlemlerine göre bytecode işlemlerini özelleştirebilir. Böylece klasik "interpreter = her zaman aynı yavaş yol" varsayımı geçersiz olur.
9.1.3. AOT
Önden derleme başlangıç ve dağıtım özelliklerini iyileştirebilir; buna karşılık çalışma zamanı profili fırsatlarını azaltabilir veya ek profil güdümlü derleme aşaması gerektirebilir.
dil adı != tek bir çalışma modeli9.2. Çok Dilli Sistemler: Kontrol Düzlemi ve Yerel Çekirdekler
Gerçek sistemlerde tek dil zorunlu değildir.
Yapay zekâ ve bilimsel hesaplamada yaygın desen:
Python
|
| orchestration / API
v
C / C++ native library
|
+--> SIMD
+--> GPU kernel
+--> vendor libraryBu nedenle Python programının toplam performansı yalnız Python bytecode maliyeti değildir. Python kontrol düzlemi rolü üstlenirken ağır hesap native çekirdekte gerçekleşebilir.
Benzer sınırlar JNI, P/Invoke, Rust-C ABI ve C++-GPU runtime arasında görülür.
9.2.1. FFI Gerçek bir Mimari Sınırdır
- sahiplik kimde,
- bellek kim tarafından serbest bırakılır,
- hata nasıl çevrilir,
- string kodlaması nedir,
- struct hizalaması uyumlu mu,
- callback yaşam süresi nedir,
- thread hangi runtime'a bağlıdır
soruları tanımlanmadan FFI güvenli bir sözleşme değildir.
9.2.2. Sıfır Kopya da Ödünleşimdir
copy cost
vs
ownership complexityKopyalamamak gecikmeyi azaltırken iki runtime arasında yaşam süresi ve eşzamanlılık karmaşıklığını artırabilir.
9.3. Dil Yeteneği ile Ekosistem Yeteneğini Ayırmak
Bir dilin pratik değeri yalnız sözdizimi veya tip sistemi değildir:
Dil
+ runtime
+ standart kütüphane
+ paket ekosistemi
+ framework'ler
+ debugger / profiler
+ deployment araçları
+ insan kaynağı
+ bakım ufku9.3.1. Framework Dili Yeniden Konumlandırabilir
Framework; dependency injection, ORM, queue, cache, test, deployment ve gözlemlenebilirlik gibi kararları ortaklaştırarak dilin belirli uygulama sınıfındaki üretkenliğini ciddi biçimde değiştirebilir.
9.3.2. İnsan Kaynağı
Teknik olarak güçlü bir dil; ekip bilgisi düşük, işe alım havuzu dar, kritik kütüphaneleri bakımsız veya hedef platformu sınırlıysa uzun ömürlü ürün için riskli olabilir.
9.3.3. Kurulu Taban
Eski dilde çalışan sistemi yeniden yazmak otomatik olarak modernizasyon değildir. İş kuralı, veri göçü, test, entegrasyon ve kullanıcı alışkanlığı geçiş maliyetidir.
Bu, Yazılım Mühendisliği ile programlama dili seçiminin kesişimidir.
9.4. Heterojen Donanım ve Çok Seviyeli Ara Gösterimler
Klasik derleyici modeli:
Kaynak
-> AST
-> IR
-> Makine koduşeklindedir. Heterojen donanımda birden fazla ara soyutlama düzeyi yararlı olabilir:
yüksek seviye tensör işlemi
|
v
döngü / bellek dönüşümü
|
v
vektör / SIMD işlemi
|
v
GPU / CPU hedef işlemi
|
v
makine koduLLVM ve MLIR benzeri altyapılar, ara gösterimi optimizer iç ayrıntısından çıkarıp derleyici mimarisinin birinci sınıf parçası hâline getirir.
9.4.1. Donanıma Specialization
Aynı algoritma x86 SIMD, Arm SIMD, GPU veya başka hızlandırıcı için farklı düşük seviye koda dönüşebilir.
yüksek seviye niyet
+
hedef bilgisi
|
v
specialized kernelMojo gibi yeni dil/derleyici deneyleri Python benzeri yüksek seviye kullanım ile statik specialization, sahiplik ve heterojen kod üretimini aynı altyapıda birleştirmeyi araştırmaktadır. Genç dillerde kavramsal yön ile üretim olgunluğu ayrı değerlendirilmelidir.
9.5. Dil Evrimi ve Uyumluluk Bütçesi
Uzun yaşayan diller iki zıt baskıyı dengeler:
yenilik
vs
geriye dönük uyumluluk9.5.1. Kaynak Uyumluluğu
Eski kaynak yeni derleyiciyle derleniyor mu?
9.5.2. Binary Uyumluluğu
Eski derlenmiş kütüphane yeniden derlenmeden çalışıyor mu?
9.5.3. Davranış Uyumluluğu
Kod derlenmeye devam ederken köşe durum semantiği değişmiş olabilir mi?
Bunlar ayrı garantilerdir.
9.5.4. Edition / Dil Modu
Bazı diller büyük değişiklikleri edition veya açık dil modu üzerinden aşamalı sunar. Yeni kod yeni kuralları kullanırken eski kaynak aynı anda kırılmak zorunda kalmaz.
9.5.5. Deprecation
Sağlıklı geçiş:
uyarı
-> alternatif
-> migration aracı
-> geçiş süresi
-> kaldırmabiçiminde ilerler.
Dil tasarımı yalnız yeni özelliğin zarafeti değil, mevcut kod tabanının yaşam döngüsüdür.
9.6. Güvenlik, Dil Semantiğinin bir Parçasıdır
Dil semantiği hangi hata sınıflarının yazılabilir olduğunu etkiler.
9.6.1. Bellek Güvenliği
Unsafe bellek işlemleri:
- sınır dışı erişim,
- use-after-free,
- double free,
- dangling reference,
- veri yarışı
gibi hata sınıflarına yol açabilir.
Bellek güvenli dil güvenli uygulama garantisi değildir; yetki veya injection hataları yine mümkündür. Fakat belirli düşük seviye bug sınıflarını azaltabilir.
9.6.2. Güvenli Çoğunluk + Açık Unsafe Sınır
safe çoğunluk
|
+--> explicit unsafe bölgeyaklaşımı düşük seviyeli işi yasaklamak yerine inceleme yüzeyini küçültür.
9.6.3. Capability Yaklaşımı
Global ve ortamdan gelen yetki yerine nesne/referans üzerinden sınırlı yetki taşımak, "kim hangi kaynağa erişebilir?" sorusunu API ve dil tasarımına yaklaştırır.
9.6.4. FFI Güvenlik Zarfını Kırabilir
memory-safe dil
|
v
FFI sınırı
|
v
unsafe native kodDil garantileri native sınırın ötesine otomatik taşınmaz.
9.7. "En İyi Dil" Yerine Uygunluk Modeli
Tek bir programlama dili sıralaması mühendislik kararını gereğinden fazla basitleştirir.
Daha yararlı zihinsel model:
Dil uygunluğu
=
problem uyumu
x runtime uyumu
x ekosistem uyumu
x donanım uyumu
x takım uyumu
x yaşam döngüsü uyumuBu matematiksel skor değildir. Bir eksendeki ciddi uyumsuzluğun diğer güçlü yönleri baskılayabileceğini anlatır.
9.7.1. Katmana Göre Dil Seçimi
servis katmanı -> Java / C#
AI orchestration -> Python
native sıcak yol -> C / C++ / Rust
mantıksal çıkarım -> Prolog / kural motoru
web istemcisi -> JavaScript / TypeScriptSınırlar iyi tasarlanmışsa çok dilli sistem mimari başarısızlık değil, problem başına uygun soyutlama seçimidir.
9.7.2. Son Kontrol Listesi
- Dilin semantiği probleme doğal uyuyor mu?
- Tür sistemi hangi hata sınıflarını erken yakalıyor?
- Bellek ve kaynak yaşam süresi nasıl yönetiliyor?
- Eşzamanlılık modeli iş yüküne uygun mu?
- Runtime gecikme ve başlangıç gereksinimlerine uyuyor mu?
- FFI/ABI sınırları yönetilebilir mi?
- Hedef işletim sistemi ve işlemci mimarileri destekleniyor mu?
- Debugger, profiler ve gözlemlenebilirlik yeterli mi?
- Paket/framework ekosistemi bakımlı mı?
- Ekip sistemi yıllarca sürdürebilir mi?
Programlama dilleri bilgisinin amacı bir kazanan ilan etmek değil, soyutlama ile maliyet arasındaki sözleşmeyi görünür hâle getirmektir.
9.8. Çok Boyutlu Sınıflandırma ve Standart Dil Profili
Bir programlama dilini tek bir etikete indirgemek yerine, aynı dili birden çok tasarım ekseninde incelemek gerekir. Bu ünite, dersin önceki bölümlerindeki kavramları karşılaştırma yöntemi hâline getirir.
9.8.1. Programlama Dillerini Çok Boyutlu Sınıflandırmak
Bir programlama dilini yalnız “derlenen”, “yorumlanan”, “nesne yönelimli” veya “fonksiyonel” diye tanımlamak, dilin yalnız bir yönünü gösterir. Daha doğru yaklaşım, dili bağımsız ya da kısmen bağımsız tasarım eksenlerinin birleşimi olarak incelemektir.
Programlama Dili
|
+--> çeviri ve çalıştırma modeli
+--> programlama paradigmaları
+--> tür sistemi
+--> değerlendirme stratejisi
+--> durum ve değiştirilebilirlik
+--> bellek ve kaynak yönetimi
+--> kapsam ve bağlama
+--> kontrol akışı
+--> hata ve etki modeli
+--> eşzamanlılık ve paralellik
+--> nesne / veri modeli
+--> metaprogramlama
+--> çalışma zamanı mimarisi
+--> hedef platform
+--> güvenlik
+--> biçimsel doğrulama
+--> kullanım alanı
+--> soyutlama düzeyiBu eksenler birbirinin alternatifi değildir. Örneğin bir dil aynı anda statik türlemeli, fonksiyonel özellikli, çöp toplamalı, JIT destekli ve aktör tabanlı eşzamanlılığa uygun olabilir.
Dolayısıyla:
“Bu dil hangi türdür?”yerine:
“Bu dil farklı tasarım eksenlerinde nasıl konumlanır?”sorusu daha açıklayıcıdır.
Bu bakış, dil ile gerçekleştirim ayrımını da korur. Programlama dili; derleyici, yorumlayıcı, sanal makine, standart kütüphane ve uygulama çatısı (framework) ile aynı şey değildir. Aynı dil birden fazla çalışma zamanı veya derleyiciyle farklı performans karakteristikleri gösterebilir.
9.8.2. Yeni bir Dili Analiz Etmek için Standart Profil
Yeni bir programlama dili incelenirken aynı soru setini kullanmak karşılaştırmayı güçlendirir:
- Hangi problem alanı için tasarlanmıştır?
- Genel amaçlı mı, alan özel mi?
- Temel paradigmaları nelerdir?
- Tür sistemi statik/dinamik, nominal/yapısal mı?
- Tür çıkarımı, jenerikler ve boş değer (null) modeli nasıl?
- Bellek ve kaynak yaşam süresi nasıl yönetiliyor?
- Değerlendirme katı mı, tembel mi?
- Hata modeli istisna (exception), Result, panic veya başka bir yapı mı?
- Eşzamanlılık iş parçacığı (thread), aktör, kanal veya async üzerinden mi?
- Yerel kod, sanal makine, bytecode, JIT ve AOT ilişkisi nedir?
- Metaprogramlama ve yansıtma ne kadar güçlü?
- Bellek güvenliği ve
unsafesınırı nasıl? - FFI/ABI yeteneği ne?
- Gerçek zaman ve deterministik davranış gereksinimlerine ne kadar uygun?
- Hedef platform ve ekosistem ne kadar olgun?
- Takım bu dili ve araç zincirini uzun süre sürdürebilir mi?
Son kontrol olarak şu kavram çiftleri birbirine karıştırılmamalıdır:
dil != derleyici
statik türleme != türleri açık yazmak
dinamik türleme != zayıf türleme
tür çıkarımı != dinamik türleme
derleme != yalnız AOT
yorumlama != hiç derleme yapılmaması
eşzamanlılık != paralellik
async != çoklu thread
fonksiyonel != saf fonksiyonel
değişmez != durumsuz
çöp toplama != bellek güvenliği
nesne yönelimli != sınıf tabanlı
gerçek zamanlı != hızlı
düşük seviye != otomatik olarak hızlı
yüksek seviye != otomatik olarak yavaşProgramlama dili bilgisinin amacı tek bir “en iyi dil” seçmek değildir. Amaç, hangi soyutlamanın hangi maliyeti ve hangi garanti düzeyini beraberinde getirdiğini görünür kılmaktır.
9.9. Java ve C#: Aynı Sözdizimi Ailesinde Farklı Dil Tasarımları
Java ile C# ilk bakışta birbirine çok benzer. İkisi de C/C++ ailesinden gelen süslü parantezli sözdizimini kullanır; sınıf, arayüz, istisna, çöp toplama, jenerik tür ve sanal makine kavramlarını merkeze alır. Buna rağmen iki dilin tür sistemi, çalışma zamanı, üye modeli, jenerikler, işlevsel programlama, hata modeli ve birlikte çalışabilirlik konularındaki tercihleri önemli ölçüde farklıdır.
Bu bölümde amaç "hangisi daha iyi?" sorusuna cevap vermek değildir. Aynı problem ailesine hitap eden iki olgun dilin farklı tasarım kararlarının sonuçlarını görmek amaçlanır.
Sürüm bağlamı: Eylül 2026 itibarıyla Java SE 27 en güncel Java SE sürümüdür; Java 25 güncel LTS hattıdır. C# 14, .NET 10 ile desteklenen güncel C# sürümüdür. Eski Java–C# karşılaştırmalarındaki platform, dil özelliği ve ekosistem iddiaları bu nedenle güncel sürümlere göre okunmalıdır.
9.9.1. Ortak Zemin ve Temel Ayrım
Her iki dil:
- statik tür denetimi kullanır,
- sınıf tabanlı nesne yönelimli programlamayı destekler,
- arayüzleri (interface) soyutlama sınırı olarak kullanır,
- otomatik bellek yönetimini yaygın çalışma modeli hâline getirir,
- jenerik programlamayı destekler,
- istisna tabanlı hata aktarımı sunar,
- çalışma zamanı üst verisi ve yansıtma (reflection) yeteneklerine sahiptir,
- sanal makine ve JIT derleme ekosistemiyle güçlü biçimde ilişkilidir.
Fakat aynı kavramın yüzeyde bulunması, semantiğinin aynı olduğu anlamına gelmez.
benzer sözdizimi
|
v
benzer kavram adları
|
X
aynı dil semantiği9.9.2. İlkel Türler, Değer Türleri ve Birleşik Tür Sistemi
Java'da int, long, double, boolean gibi ilkel türler (primitive types), sınıf başvurularından ayrıdır. Integer, Long ve benzeri sarmalayıcı sınıflar ayrı başvuru türleridir.
Java
|
+-- int -> ilkel tür
+-- Integer -> sınıf / başvuru türüC# ise değer türlerini (value types) .NET tür sistemi içinde daha bütünleşik biçimde modeller:
C#
|
+-- int -> System.Int32
+-- struct -> kullanıcı tanımlı değer türü
+-- class -> başvuru türüC# int anahtar sözcüğü System.Int32 için dil düzeyi bir addır. Değer türleri gerektiğinde object veya arayüz türüne kutulanabilir (boxing).
Bu fark yalnız sözdizimi değildir. Kullanıcı tanımlı küçük veri yapılarını nesne davranışıyla birlikte fakat başvuru kimliği olmadan modellemek C#'ta struct ile doğrudan dilin parçasıdır. Java record türleri veri taşıyıcıları için güçlü bir özellik sunar; ancak normal Java record ve class nesneleri hâlâ başvuru türüdür.
9.9.3. Kutulama ve Kutudan Çıkarma
İki dil de değer benzeri türlerle nesne dünyası arasında dönüşüm yapar; fakat tür modelleri farklıdır.
Java:
int
-> Integer
-> ObjectC#:
int / System.Int32
-> kutulama
-> objectKutulama görünmez bellek ayırma, kimlik ve performans maliyeti oluşturabilir. Bu nedenle jenerik koleksiyon, yansıtma veya arayüz sınırında "küçük değer" kullanımının çalışma zamanı temsili önemlidir.
9.9.4. Sayısal Türler
C# dilinde işaretsiz tamsayı türleri (uint, ulong vb.) ve decimal değer türü doğrudan bulunur. Java'nın yerleşik tamsayı türleri esas olarak işaretlidir; char işaretsiz 16 bit kod birimidir. Keyfî hassasiyetli ondalık hesap için Java BigDecimal gibi kitaplık türlerine dayanır.
Bu, "hangi dil daha sayısal?" sonucunu doğurmaz. Önemli fark şudur:
dil düzeyi yerleşik sayı modeli
!=
kitaplık üzerinden genişletilen sayı modeliAritmetik taşma davranışı da ayrıca incelenmelidir. C# checked / unchecked bağlamlarıyla belirli tamsayı işlemlerinde taşma denetimini açıkça kontrol edebilir.
9.9.5. Enum Tasarımı
Java enum, sınıf benzeri zengin bir başvuru türüdür. Alan, yöntem ve arayüz uygulaması taşıyabilir.
C# enum ise temelde belirli bir tamsayı türü üzerine kurulu değer türüdür.
Java enum
-> sınıf davranışına yakın
C# enum
-> sayısal temsile yakın değer türüBu fark seri hâle getirme, yansıtma, davranış ekleme ve bit bayrağı tasarımında görünür olur.
9.9.6. Null Modeli
Java'da başvuru türleri doğal olarak null taşıyabilir. İlkel türler null taşıyamaz; sarmalayıcı sınıflar taşıyabilir.
C# iki ayrı mekanizma sunar:
T? -> Nullable<T> üzerinden boş değer alabilen değer türü
string? / MyClass?
-> boş değer alabilen başvuru türü çözümlemesiBoş değer alabilen başvuru türleri (nullable reference types) esas olarak derleyici akış çözümlemesi ve uyarı sistemiyle çalışır; çalışma zamanında string ile string? iki farklı CLR sınıfı değildir.
Java ekosisteminde Optional<T> belirli API'lerde "değer olmayabilir" durumunu açık ifade etmek için kullanılabilir; fakat Optional<T>, C# boş değer alabilen başvuru türü mekanizmasının doğrudan eşdeğeri değildir.
9.9.7. Jenerikler: Java'da Tür Silme, C#'ta Çalışma Zamanı Tür Bilgisi
İki dil arasındaki en öğretici farklardan biri jeneriklerin gerçekleştirimidir.
Java genel olarak tür silme (type erasure) yaklaşımını kullanır. Derleyici tür parametrelerini denetler; ardından bytecode düzeyinde birçok jenerik ayrıntı sınır veya Object üzerinden temsil edilir. Sınıf dosyasında jenerik imzalar üst veri olarak bulunabilir, fakat çalışma zamanında örneğin List<String> ile List<Integer> ayrı JVM sınıfları değildir.
Java kaynak
List<String>
List<Integer>
|
v
tür denetimi
|
v
silinmiş çalışma zamanı temsiliC# jenerikleri ise CLR tür sistemiyle bütünleşiktir. Çalışma zamanı oluşturulmuş jenerik türün tür bağımsız değişkenlerini bilir.
C#
List<string>
List<int>
|
v
CLR jenerik tür bilgisi korunurBu fark şunları etkiler:
- çalışma zamanı tür sorguları,
- yansıtma,
- jenerik kısıtlar,
- değer türleri için kod üretimi,
- jenerik diziler ve belirli çalışma zamanı işlemleri.
"Java jenerikleri yalnız derleyici numarasıdır" demek de fazla basittir; jenerik imzalar ve köprü yöntemleri class dosyasında görülebilir. Doğru ifade, Java jenerik tür bağımsız değişkenlerinin büyük bölümünün çalışma zamanı nesne kimliğine C#/.NET'teki biçimde taşınmamasıdır.
9.9.8. Varyans: Kullanım Yerinde ve Bildirim Yerinde Yaklaşım
Java jenerik varyansı çoğunlukla joker tür belirteçleriyle kullanım yerinde ifade eder:
? extends T
? super TC# belirli jenerik arayüz ve temsilci (delegate) tanımlarında bildirim yerinde:
out T
in Tkullanır.
İki yaklaşım aynı tür güvenliği problemine farklı API tasarım ergonomisi sunar.
9.9.9. Temsilci (Delegate), Lambda ve Yöntem Başvurusu
C# temsilcisi (delegate), imzası belirlenmiş çağrılabilir hedefi temsil eden özel bir türdür.
temsilci
-> statik yöntem
-> örnek yöntemi
-> lambda
-> birden fazla hedef (multicast çağrı listesi)C# olay (event) modeli de temsilci altyapısına dayanır.
Java'da lambda ve yöntem başvuruları (method reference), tek soyut yöntemi bulunan işlevsel arayüzlere (functional interface) hedeflenir:
Predicate<T>
Function<T,R>
Runnable
kullanıcı tanımlı SAM arayüzüModern Java bu nedenle eski "Java'da temsilci benzeri hiçbir yapı yok" karşılaştırmasını büyük ölçüde geçersiz kılmıştır. Fakat tasarım hâlâ farklıdır:
C# -> temsilci, dil düzeyi bir çağrılabilir tür kategorisi
Java -> lambda, hedef işlevsel arayüz türüne uyarlanır9.9.10. Olaylar: C# event Ve Java Dinleyici Kalıpları
C# event, yayınlayanın abonelik yüzeyini dil düzeyinde sınırlandırır. Dış kod genellikle += / -= ile abone olabilir; olayı doğrudan tetikleme yetkisi yayınlayıcıda kalır.
Java'da dil düzeyinde event üyesi yoktur. Yaygın desenler:
- dinleyici arayüzleri,
- geri çağırım (callback),
Flow/ tepkisel akışlar,- uygulama çatısı (framework) olay altyapılarıdır.
Bu fark, olay kavramının bir dil özelliği mi yoksa API/kitaplık kalıbı mı olduğuna iyi bir örnektir.
9.9.11. Özellik (Property) ve Erişimci Yöntemler
C# özelliği (property), alan benzeri kullanım sözdizimi ile yöntem benzeri denetimi birleştirir:
nesne.Adarka planda get / set erişimcileri çalışabilir.
Java'da genel amaçlı dil düzeyi özellik sözdizimi bulunmaz. Klasik JavaBeans geleneğinde:
getAd()
setAd(...)kullanılır. Java record bileşenleri kısa erişimci yöntemleri üretir; fakat bu, C# özellik modelinin genel eşdeğeri değildir.
C# 14 ayrıca genişletme üyesi (extension member) ve field destekli özellik yeteneklerini genişletmiştir.
9.9.12. İndeksleyici (İndexer)
C# bir nesnenin:
nesne[index]biçiminde kullanılmasını sağlayan indeksleyici tanımlayabilir.
Java'da kullanıcı tanımlı sınıf için [] operatörünü genel biçimde aşırı yüklemek mümkün değildir. Koleksiyonlar get, set veya alan özel yöntemler kullanır.
Bu, iki dilin "özel sözdizimini kitaplık tasarımına ne kadar açtığı" konusunda net bir farktır.
9.9.13. İşleç Aşırı Yükleme
C# seçili işleçlerin kullanıcı tanımlı türler için aşırı yüklenmesine izin verir.
Java genel kullanıcı tanımlı işleç aşırı yükleme mekanizması sunmaz. String için + gibi bazı davranışlar dilin kendisi tarafından özel tanımlanmıştır.
İşleç aşırı yükleme:
alan modelini doğal ifade etme
vs
gizli / şaşırtıcı semantiködünleşimi yaratır.
Vektör, karmaşık sayı veya ölçü birimi gibi alanlarda yararlı olabilir; iş kurallarında aşırı kullanıldığında okunabilirliği düşürebilir.
9.9.14. Genişletme Üyeleri ve Yardımcı API Tasarımı
C# uzun süredir genişletme yöntemi (extension method) sunar. C# 14 ile genişletme üyesi sözdizimi; genişletme özelliği ve türü genişleten statik üyeler gibi olanaklarla genişlemiştir.
Java'nın doğrudan aynı dil özelliği yoktur. Alternatifler:
- statik yardımcı yöntem,
- varsayılan arayüz yöntemi,
- dekoratör (decorator) / uyarlayıcı (adapter),
- uygulama çatısı üretimi
olabilir.
Genişletme yöntemi gerçek sınıf üyesi değildir; çağrı sözdizimi üye çağrısına benzetilir. Bu ayrım yansıtma, erişim, sanal gönderim ve sürümleme sırasında önemlidir.
9.9.15. Kısmi (partial) Tür ve Üyeler
C# kaynak üretimi ve büyük sınıf tanımlarını ayırmak için kısmi (partial) türler sunar. Zaman içinde kısmi yöntem/özellik gibi kavramlar genişlemiş, C# 14 kısmi kurucu ve kısmi olay desteği de eklemiştir.
Java sınıf tanımını birden fazla kaynak parçasında birleştiren genel bir kısmi sınıf (partial class) özelliği sunmaz.
Bu fark özellikle kod üreticilerinde görünürdür:
üretilen dosya
+
elle yazılan dosya
|
v
aynı C# kısmi türüJava tarafında benzer ayrım genellikle kalıtım, bileşim, anotasyon işlemcisi çıktısı veya ayrı üretilen türlerle çözülür.
9.9.16. Arayüz Uygulaması
Her iki dil de bir sınıfın birden fazla arayüz uygulamasına izin verir.
C# ayrıca açık arayüz uygulaması (explicit interface implementation) ile aynı adlı üyelerin yalnız ilgili arayüz görünümünden erişilebilir olmasını sağlayabilir.
Java varsayılan arayüz yöntemi çakışmalarında sınıfın hangi davranışı kullanacağını açıkça çözmesini isteyebilir; ancak C#'taki gibi üyenin normal sınıf yüzeyinden gizlenip yalnız belirli arayüz dönüşümü üzerinden görünmesi aynı mekanizma değildir.
9.9.17. Parametre Geçirme: İkisi de Yalnız "Referans ile" Değildir
Java bütün parametreleri değer ile geçirir. Nesne söz konusu olduğunda geçirilen değer, nesneye başvurudur.
Java:
nesne başvurusunun değeri kopyalanırBu yüzden fonksiyon nesneyi değiştirebilir; fakat çağıranın yerel değişkenini doğrudan başka nesneye yeniden bağlayamaz.
C# varsayılan olarak yine değer ile geçirme kullanır; buna ek olarak ref, out, in gibi açık parametre kipleri vardır.
C#:
normal parametre -> değer ile
ref -> çağıranın saklama konumuna başvuru
out -> çıktı için başvuru
in -> salt okunur başvuru semantiğiBu nedenle "Java referans ile geçirir, C# değer ile geçirir" gibi tek satırlık karşılaştırmalar yanlıştır.
9.9.18. İstisna Modeli: Denetlenen İstisna Farkı
Java, RuntimeException ve Error dışındaki belirli istisna aileleri için yakala veya bildir (catch or specify) kuralı uygular.
Java denetlenen istisnası
-> catch
veya
-> throws ile bildirC# derleyicisi yöntem imzasında benzer bir denetlenen istisna sözleşmesi zorunlu tutmaz.
Bu fark API tasarımında önemli bir felsefe ayrımıdır:
Java
-> bazı hata yollarını tür/imza yüzeyinde zorunlu kıl
C#
-> istisna sözleşmesini dokümantasyon ve API tasarımına bırakHer iki yaklaşımın da maliyeti vardır. Denetlenen istisna görünürlük sağlar; fakat geniş çağrı zinciri boyunca mekanik throws yayılımı oluşturabilir. Zorunluluk olmaması API'yi sadeleştirir; fakat çağıranın hangi hataları beklemesi gerektiğini daha az görünür kılabilir.
9.9.19. Kaynak Temizleme
Java:
try-with-resources
AutoCloseableC#:
using
IDisposable / IAsyncDisposableyaklaşımlarıyla kapsam sonu kaynak temizliğini yapılandırır.
İki mekanizma da "çöp toplayıcı varsa dosya/soket kendiliğinden zamanında kapanır" yanlışını engellemek açısından önemlidir.
9.9.20. Üst Veri: Anotasyon ve Öznitelik
Java anotasyonu (annotation) ile C# özniteliği (attribute) aynı genel ihtiyaca cevap verir: programa ek üst veri bağlamak.
Java anotasyonu:
@Target,@Retention,- anotasyon işlemcisi,
- yansıtma
gibi mekanizmalarla kullanılır.
C# özniteliği:
Attributetabanlı türler,- hedefler,
- yansıtma,
- kaynak üreticileri ve uygulama çatısı üst verisi
ile kullanılır.
Benzerlik yüksek olsa da sözdizimi ve derleme/çalışma zamanı iş akışları aynı değildir.
9.9.21. Yansıtma ve Dinamik Bağlama
Her iki platform güçlü yansıtma (reflection) desteği sunar.
C# ayrıca dynamic anahtar sözcüğüyle belirli işlemlerin bağlanmasını çalışma zamanına erteleyebilir.
Java'da doğrudan aynı dil anahtar sözcüğü yoktur. Yansıtma, MethodHandle, dinamik çağrı altyapısı ve uygulama çatısı teknikleri benzer problem alanlarına hizmet edebilir.
Burada:
dinamik bağlama özelliği
!=
dinamik türlemeli dilayrımı korunmalıdır. C# temel olarak statik türlemeli kalır.
9.9.22. LINQ ve Java Stream API Aynı Şey Değildir
C# Language Integrated Query (LINQ):
kaynak
-> filtre
-> dönüştür
-> grupla
-> sırala
-> sonuçişlemlerini dil ve standart kitaplıkla güçlü biçimde bütünleştirir.
IEnumerable<T> üzerinde çalışma zamanında yürütülen sorgular yanında IQueryable<T> ve ifade ağacı (expression tree) kullanılarak sorgu başka bir sağlayıcıya çevrilebilir.
Java Stream API de güçlü bir fonksiyonel veri işleme hattı sunar:
stream()
-> filter
-> map
-> collectAncak standart Java Stream, genel olarak C# IQueryable + expression tree modelinin doğrudan eşdeğeri değildir. ORM sorgu çevirisi için Java ekosisteminde JPA Criteria, JPQL veya uygulama çatısı DSL'leri gibi ayrı mekanizmalar kullanılır.
9.9.23. Lambda ve İfade Ağacı
C# lambda ifadesi bağlama göre delegate'e veya ifade ağacına (expression tree) dönüştürülebilir.
lambda
|
+--> çalıştırılabilir temsilci
|
+--> incelenebilir ifade ağacıBu, LINQ sağlayıcılarının sorguyu SQL gibi başka dile çevirmesinde temel rol oynar.
Java lambda, hedef işlevsel arayüzün davranışına uyarlanır. Java standart dil modeli C# ifade ağacı modelinin genel eşdeğerini sunmaz.
9.9.24. Asenkron Programlama
C# async / await, görev tabanlı asenkron kalıbı (Task-based Asynchronous Pattern) dil düzeyinde okunabilir duruma dönüştürür.
async yöntem
|
await
|
+--> iş parçacığını zorunlu olarak bloke etmeden askıya alınabilirJava'da aynı anahtar sözcük modeli yoktur. Modern Java farklı araçlar sunar:
CompletableFuture,- sanal iş parçacıkları,
- yürütücü (executor) altyapısı,
- Java 27'de hâlâ önizleme olan yapılandırılmış eşzamanlılık.
Bu nedenle karşılaştırma:
C# async/await
vs
Java iş parçacıklarışeklinde basitleştirilmemelidir.
C# async/await bir asenkron kontrol akışı soyutlamasıdır. Java sanal iş parçacıklarıi ise çok sayıda bloklayan görevin klasik sıralı kod görünümüyle verimli çalışmasını hedefler. Problemin farklı katmanlarını çözerler.
9.9.25. Yerel Kod ve Güvenli Olmayan Alan
C#:
unsafe,- pointer,
Span<T>/ReadOnlySpan<T>,- P/Invoke,
- .NET yerel birlikte çalışabilirlik araçları
sunabilir.
Java normal dil sözdiziminde ham işaretçi sunmaz. Yerel sınır için tarihsel olarak JNI; modern Java'da Foreign Function & Memory API gibi mekanizmalar kullanılabilir.
İki ekosistemde de yerel sınır:
bellek yaşam süresi
ABI
metin kodlaması
iş parçacığı bağlamı
istisna / hata dönüşümükonularını açık sözleşmeye dönüştürmelidir.
9.9.26. Çalışma Zamanı: JVM ve CLR
Java kaynak kodu yaygın olarak JVM sınıf dosyasına, C# kaynak kodu Common Intermediate Language/CLI dünyasına derlenir. Her iki ekosistem de yorumlama, JIT ve farklı önden derleme tekniklerini kullanabilir.
Güncel .NET 10, JIT yanında NativeAOT dağıtımını da destekler. Java ekosisteminde HotSpot JIT merkezîdir; farklı JVM ve yerel imaj çözümleri de bulunur.
Dolayısıyla:
Java = yorumlanan
C# = derlenengibi bir ayrım teknik olarak anlamsızdır.
9.9.27. Platform Bağımsızlığı
Eski kaynaklarda C#'ın Windows'a bağımlı veya Mono üzerinden sınırlı, Java'nın ise tek başına platform bağımsız olduğu yönünde karşılaştırmalar görülebilir. Bu, 2026 için güncel değildir.
Modern .NET Linux, macOS ve Windows üzerinde resmî olarak desteklenen çok platformlu çalışma zamanıdır. Java da uzun süredir çok platformlu sanal makine ekosistemine sahiptir.
Bugünkü soru:
"çalışır mı?"yerine:
hangi hedefte
hangi çalışma zamanı sürümüyle
hangi yerel bağımlılıklar ve dağıtım modeliyle
hangi performans / bakım maliyetiyle çalışır?olmalıdır.
9.9.28. Dil Evrimi ve Geriye Dönük Uyumluluk
Java ve C# yeni dil özellikleri eklerken mevcut kaynak kodu kırmamak için farklı teknikler kullanmıştır.
Java zaman içinde:
- yeni sözdizimsel biçimler,
- kısıtlı / bağlama duyarlı tanımlayıcılar,
- önizleme özellikleri,
- kaynak sürümü seçenekleri
kullanmıştır.
C# da çok sayıda bağlama duyarlı anahtar sözcük ve dil sürümü özelliği kullanır.
2026 itibarıyla iki dil de ilk sürümlerinden çok daha zengin durumdadır. Eski "C# özellik ekler, Java sade kalır" genellemesi artık öğretici değildir. Daha doğru soru, yeni özelliğin:
kaynak uyumluluğu
ikili uyumluluğu
çalışma zamanı gereksinimi
araç zinciri
öğrenme maliyetiüzerindeki etkisidir.
9.9.29. Güncel Örnek: Java 27 ve C# 14
Java 27, Eylül 2026 itibarıyla en güncel Java SE sürümüdür. Java'nın son yıllardaki dili:
- record türleri,
- mühürlü sınıflar (sealed classes),
- örüntü eşleme,
switchifadeleri,- daha sade başlangıç kaynakları,
- modül içe aktarma
gibi özelliklerle genişlemiştir. Java 27'de ilkel türlerin örüntü eşleme içinde kullanımı hâlâ önizleme özelliğidir.
C# 14 ise .NET 10 ile:
- genişletme üyeleri,
fielddestekli özellikler,- null koşullu atama,
- kısmi kurucu ve olay,
- kullanıcı tanımlı bileşik atama,
Span<T>dönüşümleri
gibi özellikleri genişletmiştir.
Bu karşılaştırmanın sonucu "C# daha fazla özellik taşır" veya "Java daha sade ve iyidir" olmamalıdır.
Asıl ders şudur:
Dil evrimi, aynı problem alanına hizmet eden platformların geriye uyumluluk, çalışma zamanı yeteneği, sözdizimsel ifade gücü ve ekosistem maliyeti arasında farklı denge noktaları seçmesidir.
9.9.30. Java ve C# Farklarını Ezberlemek Yerine Tasarım Eksenini Bulmak
Her farkı bir tasarım sorusuna dönüştürmek daha kalıcıdır:
ilkel tür / değer türü
-> veri modeli nasıl birleşiyor?
tür silme / çalışma zamanında korunan jenerikler
-> tür bilgisi çalışma zamanına ne kadar taşınıyor?
temsilci / işlevsel arayüz
-> çağrılabilir davranış hangi tür modeliyle temsil ediliyor?
özellik / erişimci yöntem
-> API yüzeyi alan gibi mi yöntem gibi mi ifade ediliyor?
denetlenen istisna / zorunlu olmayan bildirim
-> hata sözleşmesi derleyici tarafından mı zorlanıyor?
async/await / sanal iş parçacığı
-> asenkronluk hangi soyutlama düzeyinde çözülüyor?
unsafe / PInvoke vs FFM/JNI
-> yerel sınır ve bellek yetkisi nasıl ifade ediliyor?Böyle okunduğunda Java–C# karşılaştırması iki dilin sözdizimi yarışması olmaktan çıkar; programlama dili tasarımının somut laboratuvarına dönüşür.
9.10. Genişletilmiş Paradigma, Değerlendirme ve Durum Modelleri
Temel buyruksal, nesne yönelimli, fonksiyonel ve mantıksal ayrım modern dilleri tek başına açıklamaz. Veri akışı, olay, akış, sembolik hesap ve durum yönetimi de ayrı programlama modelleridir.
9.10.1. Temel Paradigmaların Ötesindeki Programlama Modelleri
Buyruksal, nesne yönelimli, fonksiyonel ve mantıksal programlama ana eksenlerdir; fakat modern yazılım sistemlerinde başka programlama modelleri de önemlidir.
9.10.2. Veri Akışlı Programlama
Veri akışlı programlamada (dataflow programming) yürütme sırası, kaynak kod satırlarının sırasından çok veri bağımlılıklarıyla belirlenir.
A ----\\
+--> C --> D
B ----/C işlemi A ve B hazır olduğunda çalışabilir. Bu model sinyal işleme, veri işleme hatları, görsel programlama ve paralel hesaplamada güçlüdür.
9.10.3. Tepkisel ve Olay Güdümlü Programlama
Tepkisel programlama (reactive programming), zaman içinde değişen veri ve olay akışlarını birinci sınıf kavram olarak ele alır. Olay güdümlü programlama (event-driven programming) ise kontrol akışını olay kuyruğu ve olay işleyicileri üzerinden düzenler.
olay
|
v
kuyruk
|
v
işleyici
|
v
durum değişikliğiTepkisel sistemlerde geri basınç (backpressure), iptal, hata yayılımı ve abonelik ömrü önemlidir. “Asenkron” olmak tek başına tepkisel programlama anlamına gelmez.
9.10.4. Dizi, Vektör ve Veri Paralelliği Odaklı Yaklaşım
Dizi odaklı (array-oriented) dillerde temel işlem birimi tek skaler yerine bütün dizi olabilir. Bu yaklaşım sayısal hesaplamada yoğun ve okunabilir ifadeler oluşturabilir.
C = A + Bifadesi tüm elemanlar üzerinde işlem anlamına gelebilir. Derleyici veya çalışma zamanı bunu SIMD, GPU ya da başka veri paralelliği biçimlerine dönüştürebilir.
9.10.5. Yığıt Tabanlı ve Birleştirmeli Diller
Yığıt tabanlı (stack-oriented) diller operandları açık veya örtük yığın üzerinde işler.
2 3 +Birleştirmeli (concatenative) programlama ise fonksiyonları art arda birleştirerek program kurar. Forth ailesi bu yaklaşımın klasik örneklerindendir.
9.10.6. Olasılıksal ve Türevlenebilir Programlama
Olasılıksal programlama (probabilistic programming), dağılım, gözlem ve çıkarımı doğrudan program modeline taşır.
önsel dağılım
+
gözlem
|
v
çıkarım
|
v
sonsal dağılımTürevlenebilir programlama (differentiable programming), programın belirli bölümlerinin türevini otomatik türevleme yoluyla elde ederek optimizasyonu dil/çalışma zamanı modelinin parçası hâline getirir. Bu alan İstatistiksel Öğrenme ve Makine Öğrenmesi ile doğrudan ilişkilidir.
9.10.7. Görünüş Yönelimli Programlama
Görünüş yönelimli programlama (Aspect-Oriented Programming, AOP), günlükleme, yetkilendirme ve işlem (transaction) gibi birçok modülü kesen davranışları ayrı yapılarda tanımlamaya çalışır. Tekrarı azaltabilir; fakat gerçek kontrol akışını izlemeyi zorlaştırabilir.
9.10.8. Değerlendirme ve Durum Modelleri
Fonksiyon çağrısında argümanın ne zaman hesaplandığı ayrı bir dil tasarım kararıdır.
9.10.9. Değer, Ad, Gereksinim ve Paylaşım ile Çağrı
Değer ile çağrı (call-by-value), argümanı önce hesaplar.
Ad ile çağrı (call-by-name), ifadeyi kullanıldığı yerde yeniden değerlendirebilir.
Gereksinim ile çağrı (call-by-need), ilk sonucu saklar ve daha sonra yeniden kullanır; tembel değerlendirmenin yaygın gerçekleştirimlerinden biridir.
Paylaşım ile çağrı (call-by-sharing), nesne başvurusunun değerini paylaşır. Çağrılan fonksiyon aynı nesneyi değiştirebilir; fakat çağıranın yerel bağlamasını doğrudan başka nesneye bağlayamaz.
9.10.10. Katı ve Katı Olmayan Değerlendirme
Katı (strict) değerlendirme ile katı olmayan (non-strict) değerlendirme, “tembel” kavramıyla yakın olsa da bire bir aynı değildir. Katı olmayan semantik, sonucu gerekmeyen bir argümanın hiç hesaplanmamasına izin verebilir.
9.10.11. Kalıcı Veri Yapıları
Kalıcı (persistent) veri yapısı, yeni sürüm oluşturulurken eski sürümü de erişilebilir bırakır. Yapısal paylaşım sayesinde her sürümün bütün veriyi kopyalaması gerekmez.
eski ağaç yeni ağaç
A A <- paylaşılır
B B <- paylaşılır
C D <- yeni9.10.12. Yazılımsal İşlemsel Bellek
Yazılımsal işlemsel bellek (Software Transactional Memory, STM), ortak durum değişikliklerini transaction benzeri atomik bloklar olarak ifade eder. Kilit kullanımını soyutlayabilir; fakat çatışma, geri alma ve performans maliyetini ortadan kaldırmaz.
9.11. Tür Sistemi Derinliği: Çıkarımdan Etki Sistemlerine
Tür sistemi yalnız statik/dinamik ikiliği değildir. Tür bilgisinin ne zaman üretildiği, çalışma zamanına ne kadar taşındığı, alt tür ilişkilerinin nasıl ifade edildiği ve hangi program özelliklerinin tür düzeyinde kanıtlanabildiği ayrı eksenlerdir.
9.11.1. İleri Tür Sistemi Eksenleri
Statik/dinamik türleme yalnız ilk ayrımdır. Daha ayrıntılı incelemede şu sorular sorulur:
tür ne zaman denetleniyor?
tür kimliği ada mı yapıya mı bağlı?
tür ne kadar çıkarılabiliyor?
tür bilgisi çalışma zamanında kalıyor mu?
boş değer (null) nasıl modelleniyor?
jenerikler nasıl gerçekleştiriliyor?
alt tür ilişkisi nasıl yayılıyor?
kontrol akışı tür bilgisini daraltıyor mu?9.11.2. Kademeli ve İsteğe Bağlı Türleme
Kademeli türleme (gradual typing), aynı programda statik olarak denetlenen bölgeler ile daha dinamik bölgelerin birlikte bulunmasına izin verir.
İsteğe bağlı tür açıklaması (optional typing), programcıya tür bilgisi ekleme olanağı verir. Her isteğe bağlı türleme sistemi tam anlamıyla kademeli türleme değildir.
9.11.3. Tür Sağlamlığı
Tür sağlamlığı (type soundness), iyi türlenmiş programların belirli tür hatalarını çalışma zamanında üretmemesine ilişkin biçimsel özelliktir. Üretim dilleri pratik nedenlerle bazı kaçış noktaları veya bilinçli ödünleşimler sunabilir.
9.11.4. Tür Silme, Tür Bilgisini Koruma ve Monomorfizasyon
Jenerik türler farklı biçimde gerçekleştirilebilir:
derleme sırasında kullan, sonra tür bilgisini sil
veya
çalışma zamanında tür bilgisini koru
veya
her somut tür için uzmanlaşmış kod üretSon yaklaşım monomorfizasyon (monomorphization) olarak bilinir ve optimizasyon karşılığında kod boyutunu artırabilir.
9.11.5. Akışa Duyarlı Tür Daraltma
Tür denetleyicisi kontrol akışındaki denetimleri kullanarak değişkenin olası türünü daraltabilir. Birleşim (union) ve opsiyonel (optional) türlerin pratik kullanımında bu mekanizma önemlidir.
9.11.6. İyileştirilmiş ve Bağımlı Türler
İyileştirilmiş tür (refinement type), temel türe mantıksal koşul ekler:
x : Integer
koşul: x > 0Bağımlı tür (dependent type) ise türün değerlerden etkilenmesine izin verebilir:
Vector<T, N>Bu yaklaşım bazı invariantları tür sistemine taşıyabilir; karşılığında programlama ve tür denetimi daha karmaşık hâle gelir.
9.11.7. Doğrusal, Afin ve Tekillik Türleri
Doğrusal türler (linear types) kaynağın belirli biçimde bir kez kullanılmasını, afin türler (affine types) en fazla bir kez kullanılmasını modelleyebilir. Tekillik türleri (uniqueness types) ise tekil erişim garantileri kurmaya çalışır.
Bu fikirler kaynak yaşam süresi, sahiplik ve güvenli yerinde güncelleme ile ilişkilidir.
9.11.8. Etki Sistemleri
Etki sistemi (effect system), fonksiyonun yalnız dönüş türünü değil yaptığı etkileri de görünür kılar.
dosyaOku : Yol -> IO<String>I/O, istisna, durum değişikliği, asenkron çalışma veya ağ erişimi tür benzeri biçimde izlenebilir.
9.12. Bellek, Kaynak Yaşam Süresi ve Güvenlik Modelleri
Bellek yönetimini yalnız "elle yönetim veya çöp toplama" biçiminde sınıflandırmak yetersizdir. Kaynağın edinilmesi, paylaşılması, sahipliği, yaşam süresi ve bırakılması birlikte ele alınmalıdır.
9.12.1. Bellek ve Kaynak Yönetimi Aileleri
Bellek yönetimini yalnız “elle yönetim” ve “çöp toplama” ikiliğine indirgememek gerekir.
9.12.2. Referans Sayımı ve ARC
Referans sayımı (reference counting), nesneye kaç başvuru bulunduğunu izler. Sayı sıfıra düştüğünde nesne bırakılabilir. Döngüsel başvurular ek çözüm gerektirir.
Otomatik Referans Sayımı (Automatic Reference Counting, ARC), gerekli sayım işlemlerini derleyicinin eklemesine dayanır.
9.12.3. İzlemeli Çöp Toplama Çeşitleri
İzlemeli çöp toplama (tracing GC) içinde:
- işaretle ve süpür,
- işaretle ve sıkıştır,
- kopyalayan toplayıcı,
- nesil tabanlı toplama,
- eşzamanlı toplama,
- paralel toplama,
- artımlı toplama
gibi farklı gerçekleştirimler bulunur.
Eşzamanlı toplama ile paralel toplama aynı şey değildir. Birincisi uygulama çalışırken toplayıcının da ilerlemesiyle, ikincisi toplama işinin birden fazla işlemci tarafından yapılmasıyla ilgilidir.
9.12.4. Bölge ve Arena Tabanlı Ayırma
Bölge (region) veya arena yaklaşımında ortak yaşam süresine sahip nesneler birlikte ayrılır ve topluca bırakılabilir.
arena
+-- A
+-- B
+-- C
arena bitti
-> A, B, C birlikte bırakılırDerleyiciler, oyun motorları, ayrıştırıcılar ve kısa ömürlü yüksek hacimli veri yapılarında bu yaklaşım etkili olabilir.
9.12.5. Kaynak Yönetimi Bellekten Geniştir
Dosya, kilit, socket, veri tabanı bağlantısı ve GPU tamponu da kaynaktır. Bellek güvenli bir dil, bu kaynakların otomatik olarak doğru zamanda bırakılmasını tek başına garanti etmez.
9.12.6. Biçimsel Doğrulama, Güvenlik ve Standart Davranış
9.12.7. Sözleşmeyle Tasarım
Sözleşmeyle tasarım (Design by Contract), önkoşul, sonkoşul ve invariant gibi özellikleri program sözleşmesine taşır.
9.12.8. Doğrulama Odaklı Diller
Bazı diller veya araç zincirleri tür sistemi, ispat yükümlülüğü ve otomatik çözücüleri geliştirme sürecine dahil eder.
test -> seçilmiş yürütmeler
ispat -> tanımlı model altında genel özellikBiçimsel ispat, yanlış şartnameyi doğru hâle getirmez; yalnız verilen modeli doğrular.
9.12.9. Güvenliği Alt Eksenlere Ayırmak
“Dil güvenli mi?” yerine şu sorular ayrılmalıdır:
tür güvenliği
bellek güvenliği
null güvenliği
aritmetik güvenliği
kaynak güvenliği
eşzamanlılık güvenliği
kontrol akışı güvenliği
yalıtılmış çalışma alanı (sandbox)Bellek güvenli bir program yine yanlış yetkilendirme yapabilir. Null güvenliği SQL injection'ı önlemez. Güvenlik özellikleri birbirinin yerine geçmez.
9.12.10. Tanımsız, Gerçekleştirim Tanımlı ve Belirtilmemiş Davranış
Tanımsız davranışta (undefined behavior) standart geçerli sonuç tanımlamaz.
Gerçekleştirim tanımlı (implementation-defined) davranışta gerçekleştirim izin verilen seçeneklerden birini seçer ve belgelemek zorundadır.
Belirtilmemiş (unspecified) davranışta birden fazla sonuca izin verilir; her seçim ayrıca belgelenmek zorunda olmayabilir.
tanımsız
!=
gerçekleştirim tanımlı
!=
belirtilmemiş“Benim derleyicimde böyle oldu” dil garantisi değildir.
9.13. Sözdizimi, Kontrol Akışı, Metaprogramlama ve Modül Sınırları
Dil yüzeyi yalnız estetik değildir. Sözdizimi; makro tasarımını, statik çözümlemeyi, araç desteğini ve modül sınırlarını etkiler. Kontrol akışının birinci sınıf değer hâline gelmesi de dilin ifade gücünü değiştirir.
9.13.1. Sözdizimi, Kontrol Akışı ve Metaprogramlama Modelleri
9.13.2. Sözdizimi Aileleri
Programlama dilleri C benzeri sözdizimi, S-ifade (S-expression), önek, araek, sonek gösterim veya anlamlı boşluk gibi farklı yüzey biçimleri kullanabilir.
önek: + 2 3
araek: 2 + 3
sonek: 2 3 +Sözdizimi yalnız estetik değildir; ayrıştırma, kod üretimi, araç desteği ve öğrenilebilirliği etkiler.
9.13.3. Homoikoniklik
Homoikoniklik (homoiconicity), programın temel temsiliyle programın işlediği veri yapısı arasındaki yakınlığı ifade eder. Lisp ailesinde kodun liste yapısına yakın olması makro sistemlerini kolaylaştıran önemli bir özelliktir.
9.13.4. Continuation ve Generator
Continuation, “hesabın bundan sonra ne yapacağını” bir değer gibi temsil eder. İstisna (exception), coroutine, geri izleme ve asenkron kontrol akışını anlamak için kuramsal olarak güçlüdür.
Generator ise değer ürettikten sonra askıya alınıp daha sonra aynı yerden devam edebilir.
9.13.5. Makro Türleri
Metaprogramlama mekanizmaları birbirinden ayrılmalıdır:
- metinsel ön işlemci,
- token/sözdizim ağacı makrosu,
- hijyenik makro,
- şablon metaprogramlama,
- derleme zamanı değerlendirme,
- kaynak üretimi,
- yansıtma (reflection),
- içgözlem (introspection),
- çalışma zamanında
eval.
Hijyenik makro, makronun ürettiği isimlerle kullanıcı isimlerinin kazara çakışmasını azaltmayı amaçlar.
Yansıtma, çalışma zamanı tür/üye bilgisine erişim sağlar. eval ise dinamik kod yürütmeye kadar gidebilir; bu nedenle statik analiz, güvenlik ve AOT açısından daha ağır maliyet taşır.
9.13.6. Açık Sınıflar ve Çalışma Zamanında Yama
Bazı dinamik sistemlerde mevcut sınıf veya modül davranışı çalışma sırasında değiştirilebilir. “Monkey patching” olarak bilinen bu yaklaşım hızlı uyarlama sağlar; fakat davranışın gerçek kaynağını bulmayı ve sürüm uyumluluğunu zorlaştırabilir.
9.13.7. Modül, Taşınabilirlik ve Soyutlama Düzeyi
9.13.8. Derleme Birimi ve Modül
Fiziksel kaynak dosyası ile dil modülü aynı sınır olmak zorunda değildir. C/C++ translation unit, Java package/module, C# assembly ve Rust crate/modül farklı örneklerdir.
Modül sistemi isim alanı, dışa aktarma, içe aktarma, görünürlük ve bağımlılık sınırlarını düzenler.
Herkese açık API yüzeyini küçültmek yalnız kapsülleme değil, bağımlılık ve bakım maliyetini azaltma stratejisidir.
9.13.9. Taşınabilirlik
Taşınabilirlik (portability) farklı biçimlerde olabilir:
- aynı kaynağı başka hedefte yeniden derlemek,
- aynı ara kodu (bytecode) farklı sanal makinelerde çalıştırmak,
- WebAssembly gibi taşınabilir düşük seviye hedef kullanmak,
- başka mimari için çapraz derlemek.
Taşınabilir kaynak, her hedefte bire bir aynı davranış garantisi değildir.
9.13.10. Soyutlama Düzeyi
Makine dili, assembly, düşük seviye, yüksek seviye ve çok yüksek seviye ifadeleri donanım veya problem alanına göre göreli uzaklığı anlatır.
Tarihsel 1GL–5GL sınıflandırması öğretici olabilir:
1GL -> makine dili
2GL -> assembly
3GL -> genel yüksek seviye diller
4GL -> alana yakın / bildirimsel sistemler
5GL -> mantık / kısıt / AI odaklı sistemlerAncak modern dilleri kesin teknik sınıflara ayırmak için bu şema fazla kabadır.
9.14. Çalışma Zamanı, Sanal Makine, Hedef Platform ve Taşınabilirlik
Bir dilin çalışma modeli, kaynak koddan makine koduna giden tek bir yol değildir. Aynı dil farklı sanal makine, yorumlayıcı, JIT, AOT ve hedef platform düzenleriyle gerçekleştirilebilir.
9.14.1. Sanal Makine, Hedef Platform ve Dil Alanı
9.14.2. Sanal Makine Türleri
Yığıt tabanlı (stack-based) sanal makinede komutlar operandları sanal yığından alır.
Yazmaç tabanlı (register-based) sanal makinede sanal yazmaçlar açıkça adlandırılır.
Bazı basit gerçekleştiriciler ayrı ara kod (bytecode) yerine soyut sözdizim ağacını doğrudan yorumlayabilir.
9.14.3. Yönetilen ve Yerel Çalışma Zamanı
Yönetilen çalışma zamanı çöp toplama, üst veri, istisna altyapısı ve JIT gibi hizmetleri merkezileştirebilir. Yerel kod ise çalışma zamanı hizmetlerinin hiç olmadığı anlamına gelmez.
yönetilen != yavaş
yerel != güvensiz9.14.4. Hedef Platformlar
Dil hedefi şunlardan biri olabilir:
yerel işlemci
sanal makine
WebAssembly
GPU
gölgelendirici işlem hattı (shader pipeline)
donanım tanımlama ortamıBir dilin WebAssembly'e derlenebilmesi onu otomatik olarak “web dili” yapmaz.
GPU programlamada kernel, iş parçacığı grubu, özel bellek alanları ve veri aktarımı görünür olabilir.
Verilog/VHDL gibi donanım tanımlama dilleri (Hardware Description Languages, HDL), klasik yazılım yürütmekten çok devre yapısını ve davranışını tanımlar.
9.14.5. Genel Amaçlı ve Alan Özel Diller
Genel amaçlı dil (General-Purpose Language, GPL) geniş problem alanına hitap eder.
Alan özel dil (Domain-Specific Language, DSL) daha dar problemi doğrudan ifade eder. İç DSL ev sahibi dilin içinde, dış DSL ise kendi sözdizimi ve ayrıştırıcısıyla çalışabilir.
Bir DSL'in bazı genel amaçlı özellikleri bilinçli olarak kaldırması güvenlik ve analiz edilebilirlik açısından avantaj olabilir.
9.15. Uygulama Alanı, Gerçek Zamanlılık ve Hesaplama Gücü
Programlama dili seçimi problem alanından bağımsız değildir. Gerçek zamanlılık, alan özel kısıtlar ve genel hesaplanabilirlik aynı dil özelliğini farklı biçimlerde değerli veya riskli hâle getirebilir.
9.15.1. Uygulama Alanı, Gerçek Zamanlılık ve Hesaplama Gücü
Programlama dilleri kullanım alanına göre de sınıflandırılabilir:
- sistem programlama,
- iş ve uygulama geliştirme,
- bilimsel/sayısal hesaplama,
- istatistik,
- veritabanı,
- kabuk ve betik,
- yapılandırma,
- akıllı sözleşme,
- teorem kanıtlama,
- biçimsel belirtim.
Bu sınıflandırma dilin semantiği değil, hangi gereksinimleri önceliklendirdiğini anlatır.
9.15.2. Gerçek Zamanlılık
Gerçek zamanlı (real-time) sistem “çok hızlı sistem” değildir. Temel konu son tarihin öngörülebilir biçimde karşılanmasıdır.
Sert gerçek zamanlı sistemde son tarihin kaçırılması hata olabilir; yumuşak gerçek zamanlı sistemde kalite kaybı yaratabilir.
Deterministik davranış da tek boyutlu değildir:
işlevsel sonuç
zamanlama sırası
gecikme
bellek ayırma
I/O davranışıAynı girdi aynı çıktıyı üretse bile çalışma süresi aynı olmayabilir.
9.15.3. Turing Tamamlığı ve Bilinçli Sınırlama
Genel amaçlı dillerin büyük bölümü Turing-tamdır (Turing-complete). Fakat her alanın sınırsız ifade gücüne ihtiyacı yoktur.
Bir yapılandırma veya DSL, sonsuz döngü ve keyfî yan etkiyi yasaklayarak:
- sonlanma analizi,
- kaynak sınırı,
- güvenlik,
- statik doğrulama
açısından daha güçlü özellikler sağlayabilir.
Bu nedenle “daha güçlü dil” her zaman “daha iyi mühendislik aracı” değildir.
9.16. Performans Bağlamı ve Mühendislik Kararı
Bir programlama dilinin performansı tek bir benchmark sayısı değildir. Derleyici, çalışma zamanı, veri yapısı, ısınma, bellek ayırma, gecikme dağılımı ve yerel kitaplıklar sonucu birlikte belirler.
9.16.1. Performans Sınıflandırmasında Dikkat Edilmesi Gerekenler
“X dili daha hızlı” ifadesi ölçüt verilmeden teknik olarak eksiktir.
Ayrı metrikler:
başlangıç süresi
ısınma süresi
ortalama gecikme
p95 / p99 gecikme
işlem hacmi
bellek kullanımı
bellek ayırma oranı
enerji tüketimi
ikili dosya boyutu
derleme süresiJIT uzun süreli işlem hacminde güçlü olabilirken kısa ömürlü komut satırı aracında ısınma maliyeti taşıyabilir. AOT hızlı başlayabilir fakat bazı çalışma zamanı uzmanlaşmalarından yararlanmayabilir.
9.16.2. Derleyici Optimizasyonu
Derleyici semantiği koruyarak:
- sabit katlama,
- ölü kod kaldırma,
- inline,
- sanal çağrıyı doğrudanlaştırma,
- döngü dönüşümü,
- vektörleştirme,
- kaçış analizi,
- profil güdümlü optimizasyon
yapabilir.
Kuyruk çağrı (tail call) bazı dil/çalışma zamanı kombinasyonlarında yeni çağrı çerçevesi oluşturmadan gerçekleştirilebilir. Fakat kaynakta kuyruk özyineleme bulunması tek başına sabit yığın garantisi değildir.
Karşılaştırmada algoritma, veri, donanım, işletim sistemi, derleyici/çalışma zamanı sürümü, optimizasyon ayarı, ısınma yöntemi ve ölçülen metrik birlikte verilmelidir.
Kaynakça
- Alfred V. Aho; Monica S. Lam; Ravi Sethi; Jeffrey D. Ullman. Compilers: Principles, Techniques, and Tools. Pearson.
- Benjamin C. Pierce. Types and Programming Languages. MIT Press, 2002.
- Brendan Gregg. Systems Performance: Enterprise and the Cloud. Pearson Education, 2014.
- C. A. R. Hoare. “Communicating Sequential Processes.” Communications of the ACM, 21(8), 1978.
- Ecma International, ECMA-262 — ECMAScript 2026. https://ecma-international.org/publications-and-standards/standards/ecma-262/
- Ecma International. ECMA-335 — Common Language Infrastructure (CLI).
- Harold Abelson; Gerald Jay Sussman; Julie Sussman. Structure and Interpretation of Computer Programs. MIT Press.
- ISO, ISO/IEC 14882:2024 — Programming languages — C++. https://www.iso.org/standard/83626.html
- ISO, ISO/IEC 9899:2024 — Programming languages — C. https://www.iso.org/standard/82075.html
- JetBrains, Kotlin 2.4 release documentation. https://kotlinlang.org/docs/releases.html
- LLVM Project. LLVM and MLIR documentation.
- Luca Cardelli; Peter Wegner. “On Understanding Types, Data Abstraction, and Polymorphism.” ACM Computing Surveys, 17(4), 1985.
- Maurice Herlihy; Nir Shavit. The Art of Multiprocessor Programming. Morgan Kaufmann, 2008.
- Microsoft. .NET 10 Runtime and Native AOT Documentation. https://learn.microsoft.com/dotnet/
- Microsoft. C# 14 Language Reference and What's New in C# 14. https://learn.microsoft.com/dotnet/csharp/
- OpenJDK. HotSpot, Virtual Threads and Java runtime documentation.
- Oracle, Java SE Downloads and Release Information. https://www.oracle.com/java/technologies/downloads/
- Oracle. Java Language and Virtual Machine Specifications, Java SE 27 Edition. https://docs.oracle.com/javase/specs/
- Oracle. JDK 27 Release Notes. https://www.oracle.com/java/technologies/javase/27all-relnotes.html
- Peter Van Roy; Seif Haridi. Concepts, Techniques, and Models of Computer Programming. MIT Press.
- Python Software Foundation. Python 3.14 Documentation; Adaptive Interpreter, Extension/Embedding, and Free-Threaded CPython. https://docs.python.org/3.14/
- Robert Harper. Practical Foundations for Programming Languages, 2nd ed. Cambridge University Press, 2016.
- Robert W. Sebesta, Concepts of Programming Languages, 12th Global Edition, Pearson, 2023.
- Robin Milner. “A Theory of Type Polymorphism in Programming.” Journal of Computer and System Sciences, 17(3), 1978.
- SWI-Prolog. Reference Manual; tabling, constraints and multi-threading documentation.
- Swift.org, The Swift Programming Language — Language Reference. https://www.swift.org/documentation/tspl/
- The Go Project, The Go Programming Language Specification. https://go.dev/ref/spec
- The Rust Project, The Rust Programming Language. https://doc.rust-lang.org/book/
- W3C WebAssembly Working Group, WebAssembly Core Specification 3.0. https://www.w3.org/TR/wasm-core/