Concepts of Programming Languages Sıfırdan Çalışma Rehberi
Dersin Künyesi
Hocanın ilk derste anlattığı organizasyon bilgileri — ne, ne zaman, kaç puan. (⭐ = hocanın vurguladığı, sınavda çıkması muhtemel konu; ⭐⭐ = en güçlü adaylar.)
Bu ders tek bir dili öğretmez; dillerin kendisini inceler. Amaç, önüne bir problem geldiğinde "bunu hangi dille, hangi yaklaşımla çözmek en mantıklı?" sorusuna cevap verebilmen. Hoca ilk derste bunu defalarca tekrarladı: herkes bildiği dille yazmaya çalışıyor, ama doğru araç çoğu zaman başka bir paradigm oluyor.
| Bileşen | Adet | Ağırlık | Not |
|---|---|---|---|
| Vize (midterm) | 1 | %40 | Yaz okulunun ~3. haftası, muhtemelen Salı; önceden duyurulacak |
| Quiz | 4 | %20 | Panopto üzerinden, 5–10 soru, 5–15 dk; Blackboard'dan duyurulur |
| Final | 1 | %40 | Dönem sonu |
- Önkoşul: SE 116 (Introduction to Programming II) — hoca OOP bildiğinizi varsayıyor.
- Devam zorunlu: dersler kaydediliyor ama hoca açıkça söyledi: "There is no watching later" — kayıttan izlemek devam yerine geçmiyor.
- Lab yok: kod örnekleri dersin içinde çözülüyor; aynı problem farklı dillerde tekrar tekrar yazılıyor.
- Gerçekleşen konu akışı: Ch.1–2 (giriş + tarih) → Ch.3–4 (syntax/semantics + parsing) → Ch.5 (names/bindings/scopes) → Ch.6 (data types) → Ch.7–8 (expressions/assignment) → vize → Ch.9 (subprograms) → Ch.10 (implementing subprograms) → Ch.11 (ADT) → Ch.12 (OOP desteği — 10 Ağustos, son ders). İlk derste planlanan Ch.14 (exception/event handling) işlenmedi — dönem 10 Ağustos'ta Ch.12 ile kapandı, hoca o oturumda açıkça "this is the last session… we now finally closed this course" dedi. Dolayısıyla Ch.14 final kapsamı dışıdır.
Lecture 1–4 · 6, 7, 13, 14 Temmuz dersleri. Vize 20 Temmuz 2026'da yapıldı, ağırlığı %40. Bu bölüm arşiv olarak duruyor: finalde bu konular doğrudan sorulmasa da readability/writability/reliability, binding ve static/dynamic kavramları final bölümlerinin tamamına yayılıyor — temel olarak hâlâ gerekli.
Vize Sınav Radarı
Hocanın kendi ağzından, sınav hakkında söylediği her şey tek yerde.
- Sorular kavramsal olacak: "questions will be more conceptual... not coding so much because it won't be fair to ask you some codes when we didn't exercise that." Yani tanımlar, karşılaştırmalar, "neden/hangisi" soruları öne çıkacak.
- Kod sorusu gelirse dil serbest: "write a program in your preferred language... I will not force any languages." Verdiği örnek konu: 10 sayının ortalamasını hesaplamak.
- Assembly muhtemelen yok: "I don't think that assembly will be included in the exam." von Neumann anlatımındaki hex/opcode simülasyonunu kavramsal düzeyde bilmek yeterli.
- Grammar/BNF kesin radarda: "I guess they will be included... Maybe I can give you a grammar and say, okay, what does this language do?" — karmaşık parse tree çizdirmekten çok, verilen bir grammar'ı yorumlatması bekleniyor.
- Quizler hafif: "not something that will make you feel bad" — kısa, sunumdan takip edilebilir sorular.
- Tarih: 20 Temmuz Pazartesi, yüz yüze (hoca derste iki kez teyit etti; gözetmen olabilir, section duyurusu gelecek).
- Format: 10–15 çoktan seçmeli + 3–5 açık uçlu. Seçmeliler kısmen tanım; açık uçlular kavrayış: "What is the difference between this concept and this?"
- Hocanın kendi ağzından örnek sorular: (1) "A grammar is given... what does this grammar produce?"; (2) COBOL'un en büyük avantajı nedir, açıklayın; (3) PL/I'ın katkıları (ilk exception handling vb.); (4) "Why did Lisp start functional but then become imperative?" — cevap: verimlilik; saf fonksiyonel dili von Neumann mimarisine taşımak çok zor. Hoca bunun için "this is an important thing... a question I can answer in one line" dedi.
- Sorulmayacak: yıl/tarih ezberi ("there is no need to know that"), COBOL'un 300 reserved word'ü gibi detaylar, delikli kart trivia'sı. İlke: "Our book is on concepts... Is there an advantage? Is there a disadvantage?"
- Quiz 1 14 Temmuz 17:00'de Blackboard'da yapıldı — gerçek soruları aşağıda, ayrı kutuda.
- Format: 10 soru × 10 puan, 15 dakika, 4 şıklı çoktan seçmeli, tek oturum, otomatik gönderim. Süre yeterli (10 soru ~14 dakikada rahat bitiyor).
- Kapsam dağılımı sözünü tuttu: soruların ağırlığı Lecture 1 kavramları (orthogonality, writability,
von Neumann, okuma gerekçeleri, AI→LISP, Prolog→logic) + Lecture 3 temelleri (BNF
::=, syntactic error, lexical analyzer, recursive descent→top-down). Lecture 2'nin tarih/yıl/"ilk" detaylarından TEK soru bile yok — "conceptual olacak, tarih sormam" sözü birebir doğrulandı. - Soru kalıbı: kalın yazılmış tek bir anahtar terim + "hangisi doğru tanımlar/hangisiyle ilişkilidir?" Şıklar makul çeldiricili ama slayt cümlesini bilen için net. Bu rehberdeki Soru Havuzu kalıbıyla aynı.
- Tuzak dersi (tek kaybedilen soru): "Which is NOT a reason for studying PL?" sorusunda cevap anahtarı, "Facilitation of compiler design"ı gerekçe SAYDI (0 puan verdi); anahtara göre doğru cevap "Better understanding of program efficiency" idi. Ders: 6 gerekçeyi slayttaki birebir ifadeleriyle ezbere bil ve NOT-sorularında önce birebir eşleşen şıkları ele; anahtar tartışmalıysa hocaya itiraz edilebilir.
Bu rehberdeki fosforlu kutular hocanın derste üzerinde durduğu, tekrarladığı veya "bunu bilmelisiniz" dediği yerler; konu anlatımındaki ⭐ işaretli başlıklar da sınavda çıkması en muhtemel konuları gösterir. Sınava az vaktin varsa önce yıldızlı başlıkları, fosforlu kutuları ve Deneme Sınavı + Soru Havuzu bölümlerini çalış.
1 · Giriş & Motivasyon
Sebesta Ch.1 — 6 Temmuz oturumunun tamamı. Hoca bu bölümü "dersin neden var olduğunun cevabı" olarak anlattı.
⭐⭐ Bu dersi neden okuyorsun?
Hocanın ilk derste en çok zaman ayırdığı soru buydu. Cevabın özü bir dil felsefesi gözlemine dayanıyor: düşünebildiğin şey, anlatabildiğin şeyle sınırlı. Hoca bunu şöyle aktardı: "the depth at which people can think is influenced by the expressive power of the language" — yani bildiğin diller/yapılar arttıkça, kurabildiğin çözümler de artıyor. Türkçe gramerini bilen birinin ikinci bir dili çok daha kolay öğrenmesi gibi: buradaki kavramları öğrenince yeni bir programlama dili öğrenmek günler meselesine iniyor.
Sebesta'nın (ve hocanın tek tek üzerinden geçtiği) 6 gerekçesi:
- Fikirleri ifade etme gücü artar — daha çok yapı bilirsen daha çok çözüm düşünebilirsin.
- Doğru dili seçebilirsin — probleme göre dil/paradigma seçimi bu dersin ana hedefi.
- Yeni dilleri kolay öğrenirsin — kavramlar ortak; sözdizimi detay.
- Implementation'ın önemini anlarsın — dilin arka planda nasıl çalıştığını bilmek, verimli kod yazdırır ve hataları anlamayı kolaylaştırır.
- Bildiğin dilleri daha iyi kullanırsın — dilinin az bilinen köşelerini keşfedersin.
- Bilişimin genel ilerlemesine katkı — popüler dilin her zaman en iyi dil olmadığını görebilen bir nesil.
Quiz 1'in tek "kaybettiren" sorusu buradan geldi: "Which is NOT a reason?". Altı gerekçeyi slayttaki birebir İngilizce ifadeleriyle bil: increased ability to express ideas · improved background for choosing appropriate languages · increased ability to learn new languages · better understanding of the significance of implementation · better use of languages that are already known · overall advancement of computing. NOT-sorularında önce bu ifadelerle birebir eşleşen şıkları ele; kalan çeldiriciler arasında anahtar tartışmalı olabilir (Quiz 1'de anahtar "facilitation of compiler design"ı gerekçe saydı) — gerekirse hocaya itiraz et.
⭐ Programlama alanları (programming domains)
Farklı problem alanları, farklı ihtiyaçlar doğurur; farklı diller de tam olarak bu yüzden var. Hoca her alanı "neye ihtiyaç duyar → hangi dil" kalıbıyla anlattı; bu eşlemeyi ezbere bilmen gerekiyor:
| Alan | İhtiyaç | Tipik dil |
|---|---|---|
| Scientific | Yoğun floating-point hesap, diziler/matrisler, sayaçlı döngüler | Fortran |
| Business | Rapor üretimi, ondalık (decimal) aritmetik, karakter verisi | COBOL |
| Artificial intelligence | Sayı değil sembol işleme; dizi değil linked list | LISP, Prolog, Scheme |
| Systems | Sürekli çalışan yazılımda verimlilik (OS, sürücüler) | C |
| Web | Karma ihtiyaçlar: markup + script + genel amaçlı | HTML, PHP, Java(Script) |
⭐ Bir dili nasıl değerlendiririz?
Sebesta'nın meşhur dört kriteri. Hoca 1970'i dönüm noktası olarak anlattı: öncesinde tek dert "çalışan kod"du; sonrasında yazılımın bakımı pahalılaşınca kodun okunabilirliği kalite ölçütü oldu.
1 · Readability (okunabilirlik)
Programın okunup anlaşılma kolaylığı. Dört faktörü var:
- Overall simplicity: dilin yönetilebilir sayıda yapısı olmalı. Üç düşmanı var:
(a) feature subset — dil o kadar büyük ki herkes farklı bir alt kümesini öğreniyor;
(b) feature multiplicity — aynı işin birden çok yolu. Hocanın örneği Java'da sayıyı artırmanın
dört yolu:
count=count+1,cnt+=1,cnt++,++cnt(bu örneği kendisi verdi ve "that's why I don't like Java so much" diye espri yaptı); (c) operator overloading'in aşırı kullanımı. - Orthogonality: az sayıda temel yapı + az sayıda birleştirme kuralı, ve her kombinasyon geçerli. Ne kadar ortogonal, o kadar az istisna; az istisna = kolay öğrenme. Hocanın karşı örneği İngilizce imla kuralları: istisna üstüne istisna.
- Data types: yeterli hazır veri tipi olmalı (ör.
booleanyoksaint'le bayrak tutmak okunabilirliği düşürür). - Syntax considerations: anlamlı keyword'ler, esnek tanımlayıcı isimleri, kendini anlatan yapılar.
Hocanın kötü tasarım örneği C'deki
static: fonksiyon içinde "compile time'da yarat" demek, dosya düzeyinde "sadece bu dosyadan görünsün" demek — aynı kelime iki farklı anlam, okunabilirlik zehri.
2 · Writability (yazılabilirlik)
- Simplicity + orthogonality burada da geçerli — ama hocanın uyarısı: aşırı ortogonallik de tehlikeli; neredeyse her kombinasyon geçerliyse, hatalar derleyiciye takılmadan geçer.
- Expressivity: işlemleri ifade etmenin pratik yolları (zengin operatörler, hazır fonksiyonlar).
- Abstraction: karmaşık yapıları detaylarını görmeden tanımlayıp kullanabilmek.
3 · Reliability (güvenilirlik)
- Type checking: tip hatalarını yakalamak.
- Exception handling: çalışma zamanı hatasını yakalayıp toparlanabilmek.
- Aliasing: aynı bellek konumuna iki farklı isimle erişim — kısıtlı olması güvenilirliği artırır.
- Readability ve writability da güvenilirliği besler: algoritmayı "doğal" ifade edemediğin dilde dolambaçlı çözümler yazarsın, dolambaçlı kod daha çok hata barındırır.
4 · Cost (maliyet)
Eğitim + kod yazma + derleme + çalıştırma + derleyici/araç maliyeti + düşük güvenilirliğin faturası + bakım. Hoca bakım maliyetinin çoğu zaman geliştirme maliyetini aştığını vurguladı. Bonus kriterler: portability (başka ortama taşınabilirlik), generality (geniş uygulama alanı), well-definedness (resmi tanımın eksiksizliği).
Hoca slayttaki tabloyu satır satır okudu ve şu ayrımın altını çizdi: simplicity, orthogonality, data types, syntax design → üç kriteri de (R+W+G) etkiler; abstraction ve expressivity → yalnızca writability + reliability; type checking, exception handling, restricted aliasing → yalnızca reliability. "...not important for readability or writability. It is important for the reliability." Bu tablo klasik bir "hangisi hangisini etkiler?" sorusudur.
⭐ von Neumann mimarisi — dillerin şekillendiği kalıp
Hoca burada resmen mini bir mimari dersi yaptı; gerekçesi de netti: "you don't have any architecture courses. So we will make a crash course." Çünkü bugünün baskın dil ailesi (imperative), doğrudan bu mimarinin ürünü.
von Neumann architecture'ın özü iki cümle: veri ve program aynı bellekte durur; bellek CPU'dan ayrıdır ve komutlar/veri ikisi arasında "borularla" (pipe) taşınır. Dillerle bağlantısı birebir:
- Variable = bellek hücresinin soyutlaması,
- Assignment (atama) = bellek–CPU arası taşımanın (piping) soyutlaması,
- Iteration (döngü) = komutların bellekte yan yana durmasından dolayı verimli.
CPU'nun ritmi fetch-execute cycle: program counter'ın gösterdiği komutu bellekten getir → sayacı artır → komutu çöz (decode) → çalıştır → sonsuza kadar tekrarla. Getirilen komut instruction register'a yüklenir; aritmetik ALU'da yapılır (hocanın benzetmesiyle ALU "katır" gibi işi yapan, control unit ise "beyin").
1940 → 5941 → 2941 komut dizisini adım adım, registerların içeriğini hex yazarak yürüttü ve şöyle bitirdi:
"That is how the system works in the background. That's what you should know there."
Sınav için detaylı assembly değil, akışın mantığı isteniyor (kendisi assembly'nin sınava girmeyeceğini söyledi).
"load the content of memory address 940 into the accumulator; add 941; store back"
Bir de darboğaz var: komutların işlenme hızı, bellek–CPU bağlantısının hızından çok daha yüksek. Bu bağlantı hızı bilgisayarın hızını sınırlar; buna von Neumann bottleneck denir. Hoca sayı da verdi: 7200 rpm bir disk ile modern bir i5/i7 arasında tek veri erişiminde "15–20 milyon cycle" boşa gidebilir.
⭐ Metodolojilerin etkisi — kısa tarih
Dil tasarımını mimari kadar, yazılım geliştirme alışkanlıkları da şekillendirdi. Kronoloji sınav dostu:
- 1950'ler–60 başı: donanım pahalı → tek dert machine efficiency.
- 60'ların sonu: maliyet donanımdan yazılıma kaydı → people efficiency, readability, structured programming, top-down design, stepwise refinement.
- 70'lerin sonu: süreç odaklıdan veri odaklıya → data abstraction (ADT).
- 80'lerin ortası: OOP doğdu. Hocanın tahtaya yazdığı formül: OOP = data abstraction + inheritance + polymorphism.
⭐ Dil kategorileri
| Kategori | Karakteri | Örnekler |
|---|---|---|
| Imperative | Merkezde variable + assignment + iteration; von Neumann'ın çocuğu | C, Java, Python, Perl, JavaScript, C++ |
| Functional | Hesaplama = fonksiyonları parametrelere uygulamak | LISP, Scheme, ML, F# |
| Logic | Kural tabanlı; kurallar sırasız yazılır, çıkarım motoru çalışır | Prolog |
| Markup/programming hybrid | Markup dillerine programlama eklentileri | XSLT, JSTL |
⭐ Tasarım ödünleşimleri (trade-offs)
Her kriter aynı anda maksimize edilemez; üç ezber örnek:
- Reliability ↔ cost of execution: Java her dizi erişiminde sınır kontrolü yapar → güvenli ama yavaş.
- Readability ↔ writability: APL — bir satırda müthiş işler, ama "traded readability for writability"; yazması hızlı, okuması işkence.
- Writability/flexibility ↔ reliability: C++ pointer'ları — güçlü ve esnek, ama güvenilmez. Hocanın tabiriyle "pointers in C are a nightmare for all students."
⭐ Implementation: dil nasıl hayata geçer?
Yazdığın kaynak kod üç yoldan biriyle makineye ulaşır.
1 · Compilation
Program bir bütün olarak makine diline çevrilir: çeviri yavaş, çalıştırma çok hızlı. Fazlar:
- Lexical analysis: karakter dizisini lexeme'lere ayırır (identifier'lar, keyword'ler, operatörler, noktalama).
- Syntax analysis: lexeme'lerden programın hiyerarşik yapısını gösteren parse tree'leri kurar.
- Semantic analysis: ara kod üretir; syntax'ın yakalayamadığı anlam hatalarını bulur. Hocanın örneği: eksik noktalı virgülü syntax analyzer görür ama iç içe if'lerdeki uyumsuz dallanmayı semantic analyzer yakalar.
- Code generation: makine kodu üretilir.
Süreç boyunca symbol table kullanılır — hocanın tanımıyla "a database for the compilation process". Sonra linking ile sistem kütüphaneleri eklenir; ortaya çıkan bütüne load module (executable image) denir.
2 · Pure interpretation
Hiç çeviri yok; bir interpreter kodu doğrudan yürütür — "software simulation of a machine". Hata ayıklama kolay (hata anında, satırıyla görünür) ama çalıştırma 10–100 kat yavaş. Web scripting dilleriyle (JavaScript, PHP) geri dönüş yaptı.
3 · Hybrid + JIT
Orta yol: kaynak kod önce bir ara dile çevrilir, ara dil yorumlanır. Java'nın klasik hikâyesi: kod → byte code → JVM her platformda çalıştırır → taşınabilirlik. JIT ise bunun hızlandırılmışı: ara dildeki alt programlar çağrıldıkları anda makine koduna derlenir ve sonraki çağrılar için saklanır. Hocanın tek cümlelik tanımı: "JIT systems are essentially delayed compilers." .NET dilleri de böyle çalışır.
Bir de preprocessor var:
derlemeden hemen önce çalışan "macro expander" — C'deki #include, #define satırlarını genişletir.
Hoca güncel dil popülerliğine de girdi: PYPL endeksi Google'da dil tutorial'ı aramalarını sayar; TIOBE ise programculara "ne kullanıyorsun?" diye sorar — metodoloji farkını bilerek vurguladı. Temmuz 2026 tablosunda Python hâlâ 1 numara ama düşüşte; C yükselişte. Hocanın yorumu: donanıma yakın programlama ("hardware close programming") yeniden önem kazanıyor; Rust da bu dalganın dili ve "one of the languages which we will examine here."
2 · Büyük Dillerin Evrimi
Sebesta Ch.2 — 7 Temmuz oturumunun tamamı. Bölüm baştan sona bitirildi; ders "aynı problemin 12 dilde çözümü" örnekleriyle kapandı.
⭐ Ana tema: her dil, ortamının ürünüdür
Hoca bu üç saatlik dersi tek bir fikrin etrafında anlattı: hiçbir dil boşlukta doğmaz. Her dili tanıtırken önce "environment of development"i kurdu, sonra tasarım kararlarını o ortamla açıkladı. Kapanışta öğrenme hedefini de aynen böyle tarif etti: "you should be able to know the development environments and evolution of important programming languages."
"X dilinin tasarımını, geliştirildiği ortam nasıl etkiledi?" Hocanın en uzun anlattığı örnek Fortran'ın 4 ortam maddesi: (1) makineler küçük ve güvenilmezdi, (2) uygulamalar bilimseldi, (3) programlama metodolojisi ve araç yoktu, (4) "machine efficiency was the most important concern" — çünkü bilgisayar, insan emeğinden pahalıydı. Aynı kalıbı COBOL↔iş dünyası/DoD, BASIC↔timesharing/öğrenciler, Ada↔embedded/DoD için de kurabilmelisin.
Kronoloji — kim, neden, ne getirdi?
Tarih öncesi: Plankalkül ve pseudocode'lar
İlk programlama dili bir Alman mühendisten: Konrad Zuse (hocanın deyişiyle "the father of computer" — savaş yıllarında binary çalışan makineler yaptı, Z4'le Bavyera'ya kaçtı, tarih onu uzun süre görmezden geldi). Plankalkül 1945'te tasarlandı ama 1972'ye kadar yayımlanmadı ve hiç implement edilmedi. Buna rağmen çağının ötesindeydi: floating point, arrays ve records (hiyerarşik veri) içeren ilk dildi.
Makine kodunun dertleri (okunmaz, değiştirilmez, ifade yazmak işkence, donanımda indexing/floating point yok) pseudocode'ları doğurdu — "koda benzeyen ama gerçek kod olmayan" ara diller:
- Short Code (Mauchly, 1949, BINAC/UNIVAC I): ifadeler soldan sağa kodlanıyor; saf yorumlamayla çalışıyordu ve makine kodundan ~50 kat yavaştı — o dönem buna "automatic programming" deniyordu.
- Speedcoding (Backus, IBM 701): aritmetik/matematik pseudo-op'ları, otomatik artan register'lar; ama yavaş ve kullanıcı programına yalnızca 700 kelime bellek kalıyordu. Backus'un iddiası: makine kodunda iki haftalık iş, speedcoding'le birkaç saat.
- Grace Hopper'ın ekibi pseudocode'u makine koduna genişleten "compiling system"i geliştirdi; Wheeler relocatable address bloklarıyla mutlak adresleme derdini çözdü.
⭐ Fortran (1957): her şeyi değiştiren dil
IBM 704, floating point'i donanımda yapan ilk makineydi. O güne kadar yorumlamanın maliyeti, zaten yazılımla yapılan floating point'in gölgesinde kalıyordu; donanım gelince bahane bitti — "there was no place to hide the cost of interpretation" — ve derlenen dil fikri doğdu. Hoca iki kez tekrarladı: "one single computer can change everything"; IBM 704 + Fortran olmasaydı bugün burada olmazdık.
Sürüm zinciri (sınavda "hangi sürüm neyi getirdi?" eşleştirmesi olarak düşün):
| Sürüm | Yıl | Getirdiği |
|---|---|---|
| Fortran 0 | 1954 | Tasarlandı, hiç implement edilmedi |
| Fortran I | 1957 | İlk implement edilen sürüm: 6 karakter isim, post-test DO döngüsü, formatted I/O, arithmetic IF; tip bildirimi yok |
| Fortran II | 1958 | Independent compilation (hocaya göre "the most important thing") + hata düzeltmeleri |
| Fortran IV | 1960–62 | Explicit type declarations, logical selection, alt program adları parametre olabilir; ANSI standardı 1966 |
| Fortran 77 | 1978 | Character string handling, logical loop control, IF-THEN-ELSE |
| Fortran 90 | 1990 | Modules, dynamic arrays, pointers, recursion, CASE, parameter type checking — ve ilk kez özellik silme |
| 95 / 2003 / 2008+ | — | 2003: OOP desteği, C ile birlikte çalışma; 2008: local scope blokları, co-arrays; en yenisi Fortran 2023 |
⭐ Lisp (1959): fonksiyonel devrim
MIT'de McCarthy'nin ("artificial intelligence" teriminin de babası) AI araştırması için tasarladığı LISt Processing dili. Fortran'da recursion ve conditional expression yoktu; AI'ın ihtiyacı olan sembolik hesap için yeni dil şarttı. Yapısı radikal derecede basit: yalnızca iki veri tipi — atoms ve lists; sözdizimi lambda calculus temelli.
(A B C D)
hem veri (liste) hem fonksiyon çağrısı (A fonksiyonu, B C D argümanları) olarak okunabilir — "a little bit peculiar".
Ve açık bir "you should know": "researchers say functional programming is much more better... than procedural programming."
"Neither the assignment statements nor the variables... are necessary. So, be careful with that."
- Scheme (MIT, 1970'lerin ortası): küçük, static scoping, fonksiyonlar first-class; eğitim için ideal. Hocanın itirafı: giriş dersini kendisi verse Scheme kullanırdı.
- Common Lisp: bütün lehçeleri birleştirme çabası → büyük ve karmaşık. Hocanın benzetmesi: Esperanto gibi — "the outcome was a mess."
- ML: fonksiyonel ama tipler compile time'da; type inference (bağlamdan tip çıkarımı) kullanır.
⭐ ALGOL 60: hiç yaygınlaşmadan her şeyi etkileyen dil
Hocanın bu derste en ağır vurguladığı dil. Sorun şuydu: her dil tek makineye bağlıydı, algoritma paylaşmak için evrensel, makineden bağımsız bir dil yoktu. ACM ve GAMM 1958'de masaya oturdu; hedefler: matematiksel notasyona yakınlık, algoritma tarifine uygunluk, makine koduna çevrilebilirlik. ALGOL 58 taslağının ardından 1960 Paris toplantısında ALGOL 60 doğdu. Getirdikleri:
- Block structure — yerel scope kavramı,
- İki parametre geçirme yöntemi: pass by value ve pass by name,
- Imperative dillerde ilk recursion (Lisp'te 1959'da vardı ama imperative dünyada yoktu),
- Stack-dynamic arrays — boyutu değişkenle belirlenen, bildirime gelindiğinde bellek ayrılan diziler.
⭐ COBOL (1959–60): iş dünyasının İngilizcesi
Grace Hopper'ın FLOW-MATIC'inden doğdu; temel fikir: "data processing programs should be written in English." Pentagon'daki tasarım toplantısının hedefleri bugün bile ders niteliğinde: basit İngilizce gibi görünmeli; daha az güçlü olmak pahasına kolay olmalı; bilgisayar kullanıcı tabanını genişletmeli. (Hocanın anekdotu: komitede yalnızca üretici firmalar ve DoD vardı, iş dünyasından kimse yoktu; toplantı da "bilimsel toplantıdan çok kavgaya" dönmüştü.)
- Katkılar: ilk macro facility; hiyerarşik veri yapılarının (records) ilk implementasyonu (dikkat — hoca özellikle düzeltti: kavramı ilk tanıtan Plankalkül'dü, COBOL ilk hayata geçiren); nested selection; 30 karaktere kadar tireli isimler; data division.
- DoD'nin zorunlu kıldığı ilk dil — hocaya göre DoD olmasaydı batardı; ama hâlâ en yaygın iş uygulaması dili. Güncel not: "IBM Europe is still looking for people who know COBOL."
⭐ BASIC (1964): kullanıcı zamanı devrimi
Kemeny & Kurtz, Dartmouth. Hedef kitle fen öğrencisi bile değil: dil "pleasant and friendly" olacak, ödev hızlı dönecek, erişim ücretsiz ve özel olacak. Asıl devrim şu cümlede: "user time is more important than computer time" — hocaya göre "that was very revolutionary", çünkü o güne dek makine insan emeğinden değerliydi. Timesharing'i geniş kullanıma sokan ilk dil. İlk sürümü mini bir dildi: 14 statement tipi, tek veri tipi (floating point). Güncel torunu: Visual Basic.
⭐ PL/I (1965): herkese her şey
1963'e gelindiğinde IBM'in iki ayrı dünyası (bilimsel: 7090+Fortran+SHARE; iş: 1401+COBOL+GUIDE) birbirinin özelliklerini istemeye başladı. İki tür makine + iki dil + iki destek ekibi çok pahalıydı; "çözüm": her iki işi de yapan tek makine (System/360) ve tek dil. PL/I, 3×3 komiteyle (3 IBM + 3 SHARE) beş ayda tasarlandı — "the first large-scale attempt to design a language for a broad spectrum of application areas."
- Aldıkları: ALGOL 60'tan recursion + block structure; Fortran IV'ten separate compilation; COBOL'dan data structures + I/O.
- İlk'leri: unit-level concurrency, exception handling, switch-selectable recursion, pointer data type, array cross-sections.
- Sorunu: çok büyük, çok karmaşık, birçok özellik kötü tasarlanmış — özellikle pointer. Hocanın anısı: "I can remember from my student times that it is a torture."
⭐ APL & SNOBOL: erken dinamik diller
İkisinin ortak önemi kategorik: dynamic typing + dynamic storage allocation kavramlarını tanıttılar.
Değişkenler tipizdir; tip de bellek de değer atandığı anda gelir (a=1 → integer, a=1.0 → real).
APL (Ken Iverson, IBM): aslında donanım tarifi için tasarlandı; operatör zenginliği yüzünden
"programs are very difficult to read". SNOBOL (Bell Labs): string pattern matching'in gücü, ama yavaş.
⭐ SIMULA 67: OOP'nin tohumu
Norveç'te Nygaard & Dahl, sistem simülasyonu için. İki tarihi katkı: coroutine — hocanın tanımıyla çağıran ve çağrılanın "somewhat equal relation" kurduğu alt program (o güne dek ilişki "master-slave" idi) — ve class, object, inheritance kavramları. Hocanın cümlesi: "data abstraction started with Simula 67" — OOP'ye giden yolu bu dil açtı.
⭐ ALGOL 68: orthogonality'nin dili
Lecture 1'deki orthogonality kavramına iki kez geri bağlandı ("remember yesterday"): orthogonality ilkesi üzerine kurulan ilk dil — az sayıda temel kavram + az sayıda birleştirme mekanizması. Sonuçları: user-defined data types (temel tipleri serbestçe birleştirebilmenin doğal ürünü), reference types, ve dynamic (flex) arrays — bildirimde boyut yok, atama geldiğinde bellek otomatik ayrılıyor. Kendisi tutmadı ama Pascal, C ve Ada'yı derinden etkiledi.
⭐ ALGOL'un torunları: Pascal, C ve Prolog dönemi
- Pascal (1971): Wirth (ALGOL 68 komitesinden ayrılan üye). Yeni hiçbir şey yok — küçük, basit, structured programming öğretimi için. 70'lerin ortasından 90'ların sonuna kadar programlama öğretiminin dili (hocanın kuşak anısı: "bizim gençliğimizde hangi mühendisliği okursan oku Pascal'la başlardın").
- C (1972): Ritchie, Bell Labs, sistem programlama için. Soy zinciri sınavlık: CPL → BCPL → B → C (+ ALGOL 68'den for/switch ve atama operatörleri). Karakteri tek cümle: "powerful set of operators, but poor type checking." UNIX'le yayıldı.
- Prolog (1972): Colmerauer & Roussel (Aix-Marseille) + Kowalski (Edinburgh). Formal logic tabanlı, non-procedural. Hocanın "how vs what" karşıtlığı: imperative dilde nasıl hesaplanacağını yazarsın; Prolog'da ne istediğini bildirirsin, çıkarımı motor yapar. Tanımı: "an intelligent database system that uses an inferencing process." Verimsizliği yüzünden dar alanda kaldı — ama hoca güncel bağ kurdu: "prompting is mostly based on logic" (LLM çağında logic yeniden değerli).
⭐ Ada: tarihin en büyük tasarım çabası
DoD'nin problemi: gömülü sistemlerde 450'den fazla farklı dil kullanılıyordu. Çözüm: tek ortak dil. Yüzlerce kişi, ~8 yıl, dev bütçe; gereksinim dokümanları sınavlık bir dizi: Strawman → Woodman → Tinman → Ironman → Steelman (1975–78). İsim, tarihin ilk programcısı Augusta Ada Byron'dan. Katkılar: packages (data abstraction), ayrıntılı exception handling, generics, tasking modeliyle concurrency. Ders niteliğindeki dipnot: kullanılabilir ilk derleyici, tasarımdan beş yıl sonra geldi — "not good for language design." Ada 95 OOP'yi type derivation ile ekledi; DoD zorunluluğu kalkınca ve C++ yükselince popülerliği düştü.
⭐ OOP çağı: Smalltalk → C++ → Java
- Smalltalk: Alan Kay'in (Xerox PARC) öngörüsünün ürünü; ilk TAM object-oriented dil — data abstraction + inheritance + dynamic binding. GUI tasarımının da öncüsü.
- C++ (1980): Stroustrup, Bell Labs. Formül: C'nin imperative gücü + SIMULA 67'nin OO özellikleri. Hem prosedürel hem OO desteklediği için büyük ve karmaşık; OOP dalgasıyla hızla yayıldı; ANSI standardı 1997. (Akrabalar: Objective-C/Swift — Apple; Delphi — Hejlsberg'in nesne yönelimli Pascal'ı.)
- Java (1990'ların başı, Sun): gömülü elektronik için C++ yetersizdi (güvenilmezdi). Java = C++'ın "smaller, simpler, safer" hali: struct/union/enum yok, pointer arithmetic yok, coercion'ların yarısı yok; pointer yerine reference; yalnızca OOP. Taşınabilirliği JVM + JIT sağlar. (Hocanın anekdotu: Sun'ın Java'lı tüketici cihazları hiç satılmadı — dili kurtaran web oldu.)
Scripting dilleri ve .NET
| Dil | Kimlik | Hocanın altını çizdiği |
|---|---|---|
| Perl | Larry Wall, 1987; UNIX admin + CGI | Değişken isimleri sigil'le başlar ($ @ %); implicit variables "somehow dangerous"; aslında ara dile derlenir |
| JavaScript | Netscape+Sun; client-side, purely interpreted | Java ile alakası yok: Java strongly typed, JavaScript dynamically typed; benzerlik sadece sözdizimi |
| PHP | Lerdorf; server-side, purely interpreted | Form işleme + veritabanı erişimi; HTML içine gömülür |
| Python | "artık sadece scripting dili değil" | lists, tuples (immutable list), dictionaries; list comprehension fikri Haskell'den |
| Ruby | Matsumoto ("Matz"), Japonya | Saf OO: her veri obje, operatörler bile metot (yeniden tanımlanabilir) |
| C# | .NET'in amiral gemisi (2000) | C++ + Java + Delphi karışımı; delegates, properties, sınırlı dynamic typing; hızlı evriliyor |
Markup/programlama melezleri: XSLT (XML'i görüntülemek için dönüştürür; döngü yapıları var — "dil midir?" tartışması) ve JSP/JSTL (HTML elemanı biçiminde programlama yapıları).
⭐⭐ "İlk"ler tablosu — bu bölümün altın özeti
Hocanın anlatımında her dilin etiketi bir "ilk"ti. Quiz ve vizenin en olası eşleştirme sorusu:
| İlk | Dil |
|---|---|
| İlk programlama dili (tasarım; hiç implement edilmedi) | Plankalkül |
| İlk implement edilen yüksek seviyeli dil | Fortran I |
| İlk makineden bağımsız dil + formal syntax'lı (BNF) ilk dil | ALGOL 60 |
| Imperative dillerde ilk recursion, block structure, stack-dynamic arrays | ALGOL 60 |
| İlk macro facility + records'un ilk implementasyonu + DoD'nin ilk zorunlu dili | COBOL |
| Timesharing'i yaygınlaştıran ilk dil | BASIC |
| İlk concurrency, exception handling, pointer tipi, array cross-sections | PL/I |
| Dynamic typing + dynamic storage allocation öncüleri | APL & SNOBOL |
| İlk class/object/inheritance + coroutine (data abstraction'ın başlangıcı) | SIMULA 67 |
| Orthogonality üzerine kurulan ilk dil | ALGOL 68 |
| İlk TAM object-oriented dil (+ dynamic binding) | Smalltalk |
⭐ Karşıtlıklar — hocanın sevdiği kıyaslar
- Java ↔ JavaScript: isim benzerliği aldatmaca; strongly typed ↔ dynamically typed.
- Client-side ↔ server-side: JavaScript tarayıcıda, PHP sunucuda çalışır.
- How ↔ what: imperative "nasıl"ı, logic programming "ne"yi tarif eder.
- Scheme ↔ Common Lisp: küçük/temiz/eğitimlik ↔ büyük/karmaşık/endüstriyel ("Esperanto gibi, sonuç karman çorman").
- Pass by value ↔ pass by name: ikisi de ALGOL 60'ta doğdu.
Son yarım saatte aynı problem (uzunluğu 100'den küçük bir listeyi oku; ortalamadan büyük eleman sayısını bul) Fortran 95, Lisp, ALGOL 60, Basic, PL/I, Pascal, C, Ada, Java, Perl, JavaScript ve C# ile gösterildi. COBOL'unki bilerek farklı bir program (stok/rapor örneği) — çünkü "COBOL is not [for] mathematics." Hoca bu programların çalışır durumda olduğunu, online derleyicilerde denenebileceğini söyledi — vize öncesi birebir alıştırma malzemesi.
3 · Syntax, Semantics & Parsing
13 Temmuz oturumunun tamamı — dersin en teknik ve sınava en yakın bölümü. (Not: Ch.3'ün ikinci yarısı — attribute grammars ve semantik tanımlama yöntemleri — bu derste işlenmedi.)
⭐ Syntax ve semantics: biçim ile anlam
Hoca dersin ilk 40 dakikasını bu iki tanıma ayırdı — quiz için birincil aday:
- Syntax: ifadelerin, deyimlerin ve program birimlerinin biçimi/yapısı.
- Semantics: aynı şeylerin anlamı.
"Ahmet" analojisiyle anlattı: gözün harf dizisini görmesi ve kelimeyi tanıması syntax; beynin
"bu bir erkek ismidir" demesi semantics. İki kilit cümlesi:
"In a well-designed programming language, semantics should follow directly from the syntax"
(if A > B yazımı, anlamını sezdirmeli) ve
"describing syntax is easier than describing the semantics" — çünkü syntax için evrensel kabul görmüş
bir notasyon (BNF) var, semantics için hâlâ yok. Dil tanımını üç kitle okur: diğer dil tasarımcıları,
implementer'lar ve programcılar.
Terminoloji zinciri (hoca iki kez anlattı — iki kez anlatılan her şey gibi sınav adayı):
| Terim | Tanım (hocanın cümlesiyle) | Örnek |
|---|---|---|
| sentence | "a string of characters over some alphabet" | a = b + 0; |
| language | "a set of sentences" | Java'daki tüm geçerli programlar |
| lexeme | "the lowest level syntactic unit" | sum, *, begin |
| token | "a category of lexemes" | sum, total → IDENT |
Bir dili formal tanımlamanın iki yolu: recognizer (girdi dizisinin dile ait olup olmadığına karar veren cihaz — derleyicinin syntax kontrolü böyledir) ve generator (dilin cümlelerini üreten cihaz — hocanın metaforuyla "her düğmeye bastığında bir cümle üreten makine"). İnsanlar tarif olarak generator'ı tercih eder; recognizer'ı tarif olarak kullanmak deneme-yanılma gerektirir.
Hocanın iki kez tekrarladığı kilit eşleme: token'ların biçimini regular grammar'lar, programlama dillerinin syntax'ını (birkaç istisna dışında) context-free grammar'lar tarif eder. Chomsky'nin 4 dil sınıfından programlama dilleri için işe yarayan ikisi bunlar. Ve ezber cümle: BNF ≡ context-free grammar (eşdeğerdirler); BNF bir metalanguage'dir.
⭐ BNF: kuralların anatomisi
Bir BNF kuralı (rule ya da production) iki yandan oluşur:
LHS (sol taraf) her zaman tek bir
nonterminal;
RHS (sağ taraf) terminal
ve/veya nonterminal dizisi. Alternatifler | (VEYA) ile ayrılır. Grammar = sonlu, boş olmayan kural kümesi
+ özel bir start symbol. LHS'i kendi RHS'inde yeniden gören kurala recursive rule denir — listeler böyle tarif edilir:
<ident_list> → ident
| ident , <ident_list>
Hocanın kendi kedisinden ilhamla yazdığı İngilizce grammar örneği ("the tall man ate the cat") derste adım adım türetildi — aynı grammar "tall cat ate the man" gibi cümleleri de üretir; grammar neyi üretebiliyorsa dil odur.
⭐⭐ Türetim (derivation) ve parse tree
Derivation: start symbol'den başlayıp kuralları tekrar tekrar uygulayarak, yalnızca terminal içeren bir cümleye
ulaşmak. Aradaki her dizi bir sentential form;
sadece terminal kalan son hâli sentence. => "derives" diye okunur. Her adımda en soldaki nonterminal
açılıyorsa leftmost derivation, en sağdaki açılıyorsa rightmost — ve önemli sonuç:
türetim sırası dili değiştirmez.
<program> → <stmts> <stmts> → <stmt> | <stmt> ; <stmts> <stmt> → <var> = <expr> <var> → a | b | c | d <expr> → <term> + <term> | <term> - <term> <term> → <var> | constSoru:
a = b + 0 geçerli mi? Leftmost türetim:
<program> => <stmts> => <stmt>
=> <var> = <expr>
=> a = <expr>
=> a = <term> + <term>
=> a = <var> + <term>
=> a = b + <term>
=> a = b + const (0) ✓ geçerli
Parse tree, türetimin hiyerarşik (ağaç) gösterimi: kök start symbol, iç düğümler nonterminal'ler, yapraklar terminal'ler. Unambiguous bir grammar'da her türetimin parse tree'si tektir — leftmost da yapsan rightmost da yapsan aynı ağaç çıkar.
⭐ Ambiguity: bir cümle, iki ağaç
Bir grammar, aynı cümle için iki veya daha fazla farklı parse tree üretebiliyorsa ambiguous'tur. Neden ciddi bir problem? Hocanın iki kez tekrarladığı cümle: "compiler generates code based on the parse tree — two different parse trees means the code cannot be unique." Yani aynı program iki farklı anlama derlenebilir.
Derste çözülen örnek: <expr> → <expr> <op> <expr> | const,
<op> → / | - grammar'ında const - const / const iki ağaç verir
(önce çıkarma mı, önce bölme mi?). Çözüm: öncelik seviyelerini grammar'ın katmanlarına gömmek:
<expr> → <expr> - <term> | <term> <term> → <term> / const | const
Böylece / her zaman ağacın daha altında kalır ve kural şudur:
ağaçta daha aşağıda olan operatör önce hesaplanır = önceliği daha yüksektir.
Aynı öncelikte iki operatör varsa devreye associativity girer (soldan mı sağdan mı gruplama —
bunu da grammar'daki recursion'ın yönü belirler).
- "Bir grammar'ın ambiguous olup olmadığını belirlemek matematiksel olarak imkânsızdır" — hocanın cümlesi; pratik işaret: aynı cümle için birden fazla leftmost (veya rightmost) türetim varsa ambiguous'tur.
- Dangling else: Java'nın if-then-else grammar'ı ambiguous'tur; çözüm matched/unmatched ayrımı. Hoca detayı açıkça kitaba havale etti: "very good explained in Sebesta's printed book page 124" — oku.
- EBNF, BNF'ten güçlü DEĞİLDİR: "the extensions do not enhance the descriptive power of BNF; they only increase its readability and writability."
⭐ EBNF: üç kolaylık
| Uzantı | Anlamı | Örnek |
|---|---|---|
[ ... ] | Opsiyonel kısım | <proc_call> → ident [ ( <expr_list> ) ] |
( ... | ... ) | Alternatif grubu | <term> → <term> (+ | -) const |
{ ... } | Tekrar (0 veya daha çok) | <ident> → letter { letter | digit } |
Bu ayraçlar meta symbol'dür — notasyon aracı, terminal değil. BNF'teki sol-recursive
<expr> → <expr> + <term> | ... kuralları EBNF'te
<expr> → <term> {(+|-) <term>} biçimine sadeleşir.
⭐ Part 2 — Lexical analysis: karakterden token'a
Lexical analyzer, hocanın tanımıyla "essentially a pattern matcher for character strings" ve parser'ın front end'i. Teknik olarak syntax analysis'in parçasıdır ama ayrı tutulur; parser'ın ihtiyaç duydukça çağırdığı bir fonksiyondur ("give me the next token"). Yan görevleri: boşluk ve yorumları atlamak, isimleri symbol table'a koymak, token içi hataları (bozuk sayı sabiti gibi) raporlamak.
Lexical ile syntax analysis'i ayırmanın 3 gerekçesi — hoca bunu iki kez anlattı, hatta "biraz hızlı geçtim, tekrar edeyim" diyerek geri döndü:
- Simplicity: lexical analiz daha basit tekniklerle (finite automaton) çözülür; ayırmak parser'ı sadeleştirir.
- Efficiency: derleme süresinin ciddi bölümü lexer'da geçer; ayrıysa yalnız lexer'ı optimize edersin.
- Portability: lexer dosya okur, buffer'lar — platforma bağımlıdır; parser her zaman taşınabilir kalır.
Matematiksel temel: lexer bir finite automaton'dur ve regular language'ları tanır; tasarımı state diagram (yönlü graf: düğümler durum, oklar girdi karakteri) ile yapılır. Naif diyagram devasa olur; iki akıllı sadeleştirme:
- Character class: 52 harfi tek "letter", 10 rakamı tek "digit" sınıfına indir — identifier tanırken hangi harf olduğunun önemi yok.
- Reserved word'lere ayrı diyagram yok: hepsini identifier gibi tanı, sonra table lookup ile "bu aslında reserved word mü?" diye bak. Her keyword için ayrı dal çizmek "not very intelligent."
Sebesta'nın front.c lexer'ının üç yardımcı alt programı (isimleriyle sınavlık):
getChar (sonraki karakteri al, sınıfını belirle), addChar (karakteri kurulan lexeme'e ekle),
lookup (lexeme reserved word mü?). Hoca (sum + 47) / total girdisinin token döküm çıktısını
satır satır okudu ve kodun s.166–170'te olduğunu, çalıştığını söyledi ("I tested the code. It works.").
İnce ayrım: symbol table'a isimleri lexer koyar; attribute'ları derleyicinin sonraki fazları doldurur.
⭐ Parsing: ağacı yukarıdan mı, aşağıdan mı kurarsın?
Parser'ın iki hedefi: (1) tüm syntax hatalarını bulmak, anlamlı mesaj vermek ve recovery yapmak (toparlanıp devam etmek ki tek derlemede olabildiğince çok hata bulunsun), (2) parse tree'yi (ya da izini) üretmek — çeviri bu ağaç üzerinden yapılır.
| — | Top-down | Bottom-up |
|---|---|---|
| Ağacı kurma yönü | Kökten yapraklara | Yapraklardan köke |
| Türetim | Leftmost derivation (preorder) | Rightmost derivation'ın tersi |
| Algoritmalar | Recursive descent (kodlanmış), LL (tablo sürümlü) | LR ailesi (shift-reduce) |
Hocanın ezber formülü: "root–leftmost, leaves–rightmost. Top-down, bottom-up." Pratik parser'lar girdide yalnızca bir token ileriye bakar (lookahead). Açılımlar da ezber: LL = Left-to-right scan + Leftmost derivation; LR = Left-to-right scan + Rightmost derivation. Karmaşıklık: rastgele bir unambiguous grammar'ı parse etmek O(n³); derleyiciler grammar'ların uygun bir alt kümesiyle O(n)'de çalışır.
⭐ Recursive-descent parsing
Fikir zarif: grammar'daki her nonterminal için bir alt program yaz; nonterminal'in üretebileceği cümleleri o alt program parse etsin. EBNF bu iş için biçilmiş kaftan çünkü nonterminal sayısını azaltır. Derste şu grammar'ın C kodu satır satır izlendi:
<expr> → <term> {(+ | -) <term>}
<term> → <factor> {(* | /) <factor>}
<factor> → id | int_constant | ( <expr> )
void expr() {
term(); /* ilk term */
while (nextToken == ADD_OP || nextToken == SUB_OP) {
lex(); /* +/- yi geç */
term(); /* sonraki term */
}
}
Kodlama kuralları: RHS'teki her terminal için sıradaki token'la karşılaştır (uymazsa hata);
her nonterminal için onun alt programını çağır. Birden fazla RHS varsa doğru olanı
lookahead token'a bakarak seç; hiçbiri uymuyorsa syntax error (factor() böyle yapar).
Konvansiyon: her parsing rutini, sıradaki token'ı nextToken'da bırakır.
Hocanın morali yüksek yorumu: "a recursive descent parser can be easily written... writing a compiler is not such a big issue."
Top-down parsing'in iki düşmanı var:
- Left recursion: grammar'da doğrudan ya da dolaylı sol recursion varsa top-down parser'a temel olamaz (expr() kendini sonsuz çağırırdı). Mekanik bir dönüşümle giderilebilir (hoca şemayı gösterip "that's too much into parsing" diyerek detayı atladı — sınavda mekaniği değil, kuralı bil).
- Pairwise disjointness eksikliği: Aynı nonterminal'in iki RHS'inin FIRST kümeleri
(o RHS'ten türetilebilecek ilk terminal'ler) kesişmemeli (kesişim boş olmalı) —
yoksa tek token lookahead ile hangi RHS'e gireceğini bilemezsin. (Dikkat: hoca derste cümleyi bir an ters kurdu;
doğrusu budur ve örneği de doğru çözdü:
A → a | aBikisi deaile başladığı için problemli.) Çözüm: left factoring — ortak baş kısmı dışarı al, kalanı yeni bir nonterminal'e taşı.
⭐ Bottom-up parsing ve LR ailesi
Bottom-up'ta problem tersine döner: eldeki sentential form'un içinde, bir önceki adıma dönmek için LHS'iyle değiştirilmesi (reduce edilmesi) gereken alt diziyi — handle'ı — bulmak. Tanım sınavlık: handle = right sentential form'un en soldaki simple phrase'i; parsing de "handle pruning" (budama) olarak düşünülebilir. Mekanizma shift-reduce:
- Shift: sıradaki token'ı parse stack'in tepesine taşı.
- Reduce: stack tepesindeki handle'ı, ait olduğu kuralın LHS'iyle değiştir.
- + Accept (parse tamam, hata yok) ve Error.
LR parser'ların avantajları: hemen tüm programlama dili grammar'larında çalışırlar, hataları mümkün olan en erken anda yakalarlar ve LR grammar sınıfı, LL ile parse edilebilenlerin üst kümesidir. Dezavantaj: tabloyu elle üretmek pratik değil — yacc/bison gibi araçlar üretir. Knuth'un içgörüsü: girdi ne kadar uzun olursa olsun olası parse durumu sayısı küçük ve sonludur; her durum bir state olarak stack'te saklanabilir. Tablo iki parçadır: ACTION (satır=state, sütun=terminal; hücreler S6="shift + state 6'yı push et", R4="kural 4 ile reduce") ve GOTO (satır=state, sütun=nonterminal; reduce sonrası hangi state'e geçileceği). Tablodaki boş hücreler = syntax error.
4 · Names, Bindings & Scopes
14 Temmuz oturumu — Ch.5 baştan sona bitirildi; ders sonunda Blackboard quizi yapıldı. (Data types, Lecture 5'e kaldı; attribute grammars ve semantik yöntemleri kesin olarak atlandı.)
Bu bölümün çatısı, Lecture 1'deki cümleye dayanıyor: imperative diller von Neumann mimarisinin soyutlamasıdır ve variable, bir bellek hücresinin soyutlamasıdır. Bu bölüm o soyutlamayı parçalarına ayırıyor. (Karşıt uç hatırlatması: saf fonksiyonel dillerde değişken hiç yok.)
İsimler: küçük görünen büyük tasarım soruları
- Uzunluk: çok kısa isim anlam taşıyamaz. Fortran I'de 6 karakterdi; C99'da sınır yok ama yalnızca ilk 63 karakter anlamlı (linker'ın gördüğü external isimlerde 31); Java/C#'ta hepsi anlamlı.
- Özel karakterler: PHP'de tüm değişkenler
$ile, Perl'de tipi belirten sigil'lerle ($skaler,@dizi,%hash), Ruby'de@instance /@@class değişkeni ile başlar. - Case sensitivity: okunabilirliğe zarar verir — birbirine benzeyen isimler farklı şeylerdir. Hocanın örneği:
C-tabanlı dillerde durum daha da kötü çünkü hazır isimler karışık büyük-küçük harfli
(
IndexOutOfBoundsException). - ⭐ Special words: reserved word
programcı tarafından yeniden tanımlanamaz; keyword
yalnızca belirli bağlamlarda özeldir (Fortran'da keyword'ler değişken adı olarak kullanılabilir!).
Çok fazla reserved word çakışma yaratır — COBOL'da 300 tane var; hocanın örneği:
herkes
lengthdiye değişken ister ama COBOL izin vermez. (Sayıyı ezberleme; "çok fazla olursa problem" fikri yeter.)
⭐ Variable = altı nitelikli bir paket (sextuple)
Ezber adayı tanım — bir değişken şu altılıdır: name, address, value, type, lifetime, scope.
- Name: her değişkende olmayabilir (heap'teki isimsiz nesneler).
- Address: bağlı olduğu bellek adresi — aynı değişken farklı zamanlarda/yerlerde farklı adreste olabilir. İki isim aynı adrese erişebiliyorsa bunlar alias'tır (pointer, reference ve union'lar yaratır) — okunabilirlik düşmanı, çünkü bir değişkenin değeri başka bir isme atamayla değişebilir.
- ⭐ Value: hücrenin içeriği. Kritik çift: l-value = adres, r-value = değer. r-value'ya ulaşmak için önce l-value'yu bilmek gerekir.
- Type: değer aralığını ve geçerli işlemleri belirler — hocaya göre "the most important attribute" (Lecture 5'in konusu).
- Lifetime ve scope: aşağıda.
⭐⭐ Binding: her şeyin bir bağlanma zamanı var
Binding = bir varlık ile bir nitelik arasındaki ilişki (değişken↔tip, değişken↔değer, sembol↔işlem). Binding time = bu ilişkinin kurulduğu an. Beş klasik zaman:
| Zaman | Örnek |
|---|---|
| Language design time | * sembolü → çarpma işlemi |
| Language implementation time | int → değer aralığı/gösterimi |
| Compile time | int count; → count'un tipi |
| Load time | C/C++ static değişkeni → bellek hücresi |
| Run time | Non-static lokal değişken → bellek hücresi; değişkenin değeri |
count = count + 5 satırını parça parça analiz etti — vize açık uçlusu için birebir format:
count'un tipi → compile timecount'un olası değer kümesi → language implementation time+'ın buradaki anlamı → compile time (operand tiplerine göre)5literalinin iç gösterimi → compiler design timecount'un değeri → execution (run) time
Static binding: run time'dan önce kurulur ve program boyunca değişmez. Dynamic binding: çalışma sırasında
kurulur ya da değişebilir. Hocanın tuzak uyarısı: dillerdeki static keyword'ü ile static binding
aynı şey değildir — ilişkili ama farklı kavramlar.
⭐ Tip bağlama (type binding)
- Explicit declaration:
int x;gibi bildirimle. - Implicit declaration: kurala/geleneğe göre — Fortran'ın meşhur kuralı: I–N arası harfle başlayan isimler integer, gerisi real. Yazılabilirliğe küçük katkı, güvenilirliğe büyük zarar.
- Type inference:
C#
var a = 5;→ int,var a = 5.0;→ double; "the initial value sets the type." ML, Haskell, F#, VB 9+ da bağlamdan çıkarır. - Dynamic type binding: tip, bildirimle değil atamayla gelir (JavaScript, Python, Ruby, PHP;
C#'ta sınırlı
dynamic). JavaScript örneği:list = [2, 4.33, 6, 8];sonralist = 17.3;— aynı isim önce dizi, sonra skaler. Avantaj: esneklik (generic kod). Bedeli: sürekli çalışma zamanı tip kontrolü (maliyet) + derleyicinin tip hatası yakalayamaması. Ruby'de iş bir adım öte: tüm değişkenler tipsiz referanstır.
⭐ Lifetime: değişken ne zaman doğar, ne zaman ölür?
Lifetime = değişkenin bir bellek hücresine bağlı kaldığı süre: allocation ile başlar, deallocation ile biter. Dört kategori — her birinin avantaj/dezavantaj çifti sınavın eşleştirme klasiği:
| Kategori | Bağlanma | Örnek | Artı / Eksi |
|---|---|---|---|
| Static | Çalışma öncesi; hep aynı hücre | C/C++ fonksiyon içi static | + verimli (direct addressing), history-sensitive · − recursion desteklenmez |
| Stack-dynamic | Bildirim elaborate edilince (run time, stack'te) | C/Java lokal değişkenleri | + recursion mümkün, bellek tasarrufu · − alloc/dealloc maliyeti, history-sensitive olamaz, dolaylı adresleme |
| Explicit heap-dynamic | Programcının açık komutuyla (new/delete), pointer/reference üzerinden | C++ dinamik nesneler; Java'da TÜM nesneler | + dinamik yapılar (liste, ağaç) · − verimsiz ve güvenilmez |
| Implicit heap-dynamic | Yalnızca atamayla; tüm nitelikler her atamada yeniden bağlanır | APL'de her şey; Perl/JS/PHP string ve dizileri | + en yüksek esneklik · − verimsiz + derleyicinin hata yakalama gücü kaybolur |
⭐⭐ Scope: isim nereden görünür?
Scope = değişkenin görünür (okunabilir/atanabilir) olduğu deyimlerin aralığı. Bir birimde bildirilen değişkenler oranın local, görünüp de orada bildirilmemiş olanlar nonlocal değişkenleridir; global'ler nonlocal'in özel hâlidir.
⭐ Static scope
ALGOL 60'tan gelir; program metnine dayanır. Bir ismin hangi bildirime bağlanacağını bulmak için: önce lokale bak, bulamazsan bir dış katmana (static parent), sonra onun dışına (static ancestor'lar)... Aynı isimli daha "yakın" bir bildirim, dıştakini gizler (hiding/shadowing). Hocanın tam işlediği örnek:
function big() {
var x = 3;
function sub1() { var x = 7; ... sub2(); ... }
function sub2() { ... x = 3; ... } /* hangi x? */
sub1();
}
Static scoping: sub2'de x bildirimi yok → dış katmana çık → big'in x'i (sub1'inki değil —
metinsel kapsayan sub1 değil big'dir). Diğer araçlar: blocks (ALGOL 60 mirası; C/C++'ta iç blokta aynı isimle
değişken gizleme legal, Java/C#'ta hataya açık diye yasak), fonksiyonel dillerin
LET construct'ları (ilk kısım isimleri değerlere bağlar, ikinci kısım kullanır), C99/C++/Java/C#'ta bildirimin
herhangi bir yerde yapılabilmesi (scope bildirimden blok sonuna; C#'ın "tüm blok" diyen dokümantasyonu yanıltıcıdır —
yine de kullanmadan önce bildirmek zorundasın), for içinde bildirim (scope = for gövdesi).
Global scope ayrıntıları: C/C++'ta declaration (yalnız nitelik bildirir — extern int x;)
ile definition (bellek de ayırır) farklıdır; istediğin kadar uyumlu declaration, ama yalnızca tek definition.
PHP'de fonksiyon içinden global'e erişim $GLOBALS dizisi ya da global bildirimiyle;
Python'da global bir değişkene fonksiyon içinde atama yapmak için global (iç içe fonksiyonlarda
bir üst katman için nonlocal) gerekir.
Static scoping eleştirisi: çoğu durumda gereğinden fazla erişim verir; program evrildikçe yapı bozulur — lokaller globalleşir ("developers discard structure when it gets in the way").
⭐ Dynamic scope
Metne değil çağrı zincirine dayanır — hocanın sloganıyla "temporal versus spatial" (zaman, mekâna karşı). İsim, o ana kadarki çağrı zincirinde geriye doğru aranır. Aynı örnekte: big → sub1 → sub2 çağrı sırasıyla gelindiyse, sub2'deki x sub1'in x'idir (en son aktif bildirim). Avantajı pratiklik (parametre taşımak gerekmez); bedelleri ağır: çağıran her şeyin değişkenleri görünür (güvenilirlik ↓), static type checking imkânsız, okunabilirlik kötü, erişim yavaş.
int ver() {
static int k; /* k: fonksiyon dışından GÖRÜNMEZ (scope) */
k = k + 5; /* ama çağrılar arasında YAŞAR (lifetime) */
return k;
}
Ardışık üç çağrı 5, 10, 15 döndürür — k "not visible, but still alive." Hocanın altını çizdiği not:
bu Java'da çalışmaz (Java'da metod içi static değişken yok).
"This does not work in Java!"
Referencing environment: bir deyimde görünür tüm isimlerin kümesi. Static-scoped dilde = lokaller + tüm kapsayan scope'ların görünür değişkenleri; dynamic-scoped dilde = lokaller + tüm aktif (başlamış, bitmemiş) alt programların görünür değişkenleri.
⭐ Named constants: yalnızca bir kez, bellek bağlanırken değer bağlanan "değişkenler" —
okunabilirlik ve değiştirilebilirlik için (programı parametrize eder). Değer bağlama static ise manifest constant denir.
C# ayrımı sınavlık: const → compile time'da, readonly → çalışma zamanında (dinamik) bağlanır.
Vize Soru Havuzu
Deneme sınavının devamı: transkriptlerden çıkan, hocanın sorabileceği her şey — ders ders. Soruya tıkla, cevabı açılır.
⭐ = hocanın doğrudan söylediği, tekrarladığı veya "important" dediği noktaya dayanıyor; önce bunları bitir. Yıldızsızlar tamamlayıcı — vakit kalırsa.
⭐⭐ Quiz 1'in GERÇEK soruları (14 Temmuz, Blackboard)
Hocanın soru stilinin birebir örneği — vize çoktan seçmelileri büyük olasılıkla bu kalıpta olacak. (Sonuç: 90/100; yalnız Q8 gitti.)
Q1Which programming paradigm is Prolog primarily associated with? (Imperative / Functional / Object-Oriented / Logic)
Q2Which of the following is a syntactic error? (Infinite recursion / Missing a semicolon / Dividing by zero / Using an undeclared variable)
Q3Which language was primarily designed for AI applications? (LISP / COBOL / Fortran / Ada)
Q4In BNF, what does the symbol ::= mean? (Optional syntax / Defines a rule in a grammar / Ends a production / Assigns semantics)
::= (bu rehberdeki ok → ile aynı), LHS'in RHS olarak tanımlandığını söyler.Q5Which parsing method is typically used by recursive descent parsers? (Bottom-up / Top-down / Operator-precedence / Shift-reduce)
Q6Which best characterizes the von Neumann architecture's influence on programming languages? (Abstract syntax trees / Emphasis on recursion / Logical inference / Sequential execution with variables and assignments)
Q7What is a disadvantage of too much writability? (Slower execution / More readable / More strongly typed / Too many different ways to express the same thing)
Q8 ⚠Which is NOT a reason for studying programming languages? (Increased ability to express ideas / Improved background for choosing appropriate languages / Better understanding of program efficiency / Facilitation of compiler design)
Q9Which best describes orthogonality? (Only one data structure / Syntax errors at runtime / A small set of primitive constructs can be combined in a small number of ways / Combining multiple operators in one expression)
Q10What is the main function of a lexical analyzer? (Building parse trees / Handling syntax rules / Breaking input into tokens / Removing comments and whitespace)
Lecture 1 — Giriş & Motivasyon
S1 ⭐Programlama dili kavramlarını okumanın 6 gerekçesini sayın.
S2 ⭐"İnsanlar en iyi bildiği dili, hiç uygun olmasa bile kullanır." Hocanın bu gözlemine verdiği iki örneği ve dersin ana hedefini yazın.
S3"The depth at which people can think is influenced by the expressive power of the language" cümlesi derste hangi bağlamda kullanıldı?
S4 ⭐Beş programming domain'i, ihtiyaçlarını ve tipik dillerini eşleştirin.
S5AI neden dizi (array) değil linked list ister?
S6 ⭐Dört dil değerlendirme kriterini sayın; hangi faktörler ÜÇÜNÜ birden etkiler?
S7 ⭐Simplicity'nin üç düşmanı nedir? Java'dan örnek verin.
count=count+1, cnt+=1, cnt++, ++cnt, 3) aşırı operator overloading.S8 ⭐Orthogonality nedir? Aşırısı neden tehlikelidir?
S9 ⭐C'deki static kelimesi neden kötü tasarım örneğidir?
S10Reliability'yi besleyen üç dil özelliği nedir; aliasing niye zararlıdır?
S11Cost'un bileşenlerini sayın; hoca hangisinin çoğu zaman en büyük kalem olduğunu söyledi?
S12Portability, generality ve well-definedness'i tanımlayın.
S13 ⭐von Neumann mimarisinin iki temel özelliği nedir; imperative dillerle üç eşleşmesini yazın.
S14Fetch-execute cycle'ın adımlarını sırayla yazın.
S15 ⭐von Neumann bottleneck nedir ve neden bilgisayar hızının birincil sınırlayıcısıdır?
S16 ⭐Metodoloji kronolojisi: dönemleri akımlarla eşleştirin (1950'ler / 60 sonu / 70 sonu / 80 ortası).
S17 ⭐Dört dil kategorisi nedir? OOP dilleri nereye girer?
S18 ⭐Üç tasarım trade-off'unu birer örnekle yazın.
S19 ⭐Compilation'ın dört fazını sırayla ve görevleriyle yazın. Symbol table nedir?
S20Pure interpretation'ın avantajı ve iki dezavantajı nedir? Hangi alanla geri döndü?
S21 ⭐Java'nın klasik taşınabilirlik hikâyesini anlatın (hybrid implementation) ve JIT'i tanımlayın.
S22Preprocessor ne yapar?
#include dosyayı yapıştırır, #define metni açar.S23PYPL ile TIOBE endeksleri metodolojik olarak nasıl ayrılır?
Lecture 2 — Dillerin Evrimi
S24 ⭐Fortran'ın geliştirildiği ortamın 4 özelliğini yazın ve bunların tasarıma üç yansımasını gösterin.
S25 ⭐IBM 704 neden "derlenen dil" çağını başlattı?
S26 ⭐Fortran I'in implicit typing kuralı nedir ve nereden gelir?
S27 ⭐Fortran sürümlerini yenilikleriyle eşleştirin: I, II, IV, 77, 90.
S28Plankalkül hakkında üç çarpıcı gerçek yazın.
S29Short Code ve Speedcoding'i birer cümleyle karakterize edin.
S30 ⭐Lisp'in yalnızca iki veri tipi nedir? Saf fonksiyonel programlamada ne yoktur?
(A B C D) hem veri hem fonksiyon çağrısı olabilir.S31 ⭐Hocanın örnek vize sorusu: Lisp fonksiyonel doğdu, neden imperative özellikler kazandı?
S32Scheme ile Common Lisp'i karşılaştırın.
S33 ⭐ALGOL 60'ın dört yeniliğini, iki büyük başarısını ve başarısızlık nedenlerini yazın.
S34ALGOL 60'ın üç tasarım hedefi neydi?
S35 ⭐Hocanın örnek vize sorusu: COBOL'un en büyük avantajı/katkısı neydi?
S36COBOL tasarım hedeflerinden en çarpıcısı hangisiydi?
S37 ⭐BASIC'in devrimci fikri neydi?
S38 ⭐Hocanın örnek vize sorusu: PL/I'ın katkıları nelerdi ve neden başarısız oldu?
S39 ⭐APL ve SNOBOL hangi iki kavramın öncüsüdür? Tanımlayın.
S40 ⭐SIMULA 67'nin iki tarihi katkısı nedir? Coroutine'i tanımlayın.
S41 ⭐ALGOL 68'in tasarım ilkesi neydi ve üç katkısı nedir?
S42Pascal neden bu kadar yaygınlaştı, yeniliği neydi?
S43 ⭐C'nin soy zincirini yazın ve karakterini tek cümleyle özetleyin.
S44 ⭐Prolog'daki "how vs what" ayrımını açıklayın; hocanın Prolog tanımı neydi?
S45 ⭐Ada: neden yapıldı, gereksinim dizisi neydi, dört katkısı ve tarihî dersi nedir?
S46 ⭐İlk TAM object-oriented dil hangisidir ve "tam"ın üç bileşeni nedir?
S47C++'ın formülü nedir; neden büyük ve karmaşıktır?
S48 ⭐Java, C++'tan neleri çıkardı ve neden?
S49 ⭐Java ile JavaScript'in gerçek ilişkisi nedir?
S50Perl, Python ve Ruby için hocanın altını çizdiği birer özellik söyleyin.
S51C# hangi dillerin karışımıdır ve hangi platformun amiral gemisidir?
S52Ders kapanışındaki "aynı program farklı dillerde" örneğinde problem neydi ve COBOL neden farklıydı?
Lecture 3 — Syntax, Semantics & Parsing
S53 ⭐Syntax ve semantics'i tanımlayın; iyi tasarlanmış dilde ikisinin ilişkisi ne olmalıdır?
if A > B görünüşünden anlamı sezilmeli. Syntax'ı tarif etmek daha kolaydır çünkü evrensel notasyonu (BNF) vardır, semantics'in yoktur.S54 ⭐Sentence, language, lexeme, token — dördünü tanımlayıp lexeme/token ilişkisine örnek verin.
S55Recognizer ile generator'ı karşılaştırın; insanlar tarif olarak hangisini neden tercih eder?
S56 ⭐Chomsky'nin sınıflarından hangileri programlama dilleri için önemlidir ve hangisi neyi tarif eder?
S57BNF kuralının anatomisi: LHS/RHS kuralları, grammar ve start symbol tanımı.
| ile. Grammar: sonlu, boş olmayan kural kümesi; start symbol zorunlu. LHS'i kendi RHS'inde görünen kural recursive'dir (listeler böyle tanımlanır).S58 ⭐Derivation, sentential form, sentence tanımları; leftmost/rightmost farkı ve önemli sonuç.
=> "derives". Leftmost: her adımda en soldaki nonterminal açılır. Sonuç: türetim sırası dili DEĞİŞTİRMEZ.S59 ⭐Şu grammar'da (rehberdeki S17'deki) b = a + d türetilebilir mi? Leftmost derivation yazın.
S60 ⭐Ambiguity tanımı, neden ciddi problem ve nasıl fark edilir?
S61 ⭐Precedence grammar'a nasıl gömülür? Ağaç konumu ne anlama gelir?
expr → expr - term | term; term → term / const | const — böylece / hep ağacın altında kalır. Kural: ağaçta daha AŞAĞIDA olan önce değerlenir = önceliği yüksektir.S62Associativity ne zaman devreye girer ve grammar'da neyle ifade edilir?
S63Dangling else problemi nedir, çözümü hangi ayrımla yapılır?
S64 ⭐EBNF'in üç uzantısını sembolleriyle yazın; EBNF, BNF'ten güçlü müdür?
[ ] opsiyon, ( | ) alternatif grubu, { } tekrar (0+). Güçlü DEĞİLDİR: "the extensions do not enhance the descriptive power" — yalnız okunabilirlik/yazılabilirlik. Ayraçlar meta symbol'dür, terminal değil.S65 ⭐Lexical ve syntax analysis'i ayırmanın üç gerekçesini açıklayın.
S66 ⭐Lexical analyzer'ı üç sıfatla tanımlayın ve yan görevlerini sayın.
S67Lexer kurmanın üç yaklaşımı nedir?
S68 ⭐State diagram'ı devasa olmaktan kurtaran iki sadeleştirme nedir?
S69getChar, addChar, lookup ne yapar? front.c örneğinin girdisi neydi?
(sum + 47) / total — token kodlarıyla döküm; EOF = −1.S70Parser'ın iki hedefi nedir? Recovery neden önemlidir?
S71 ⭐Top-down ve bottom-up parsing'i türetim yönleriyle eşleştirin; LL ve LR neyin kısaltmasıdır?
S72Genel unambiguous grammar parsing'i ile derleyici parsing'inin karmaşıklığı nedir?
S73 ⭐Recursive-descent parser'ın temel fikri nedir ve neden EBNF ile kurulur?
S74 ⭐Top-down parsing'in iki düşmanı nedir ve çözümleri?
A → a | aB.S75 ⭐Handle nedir? Shift ve reduce eylemlerini tanımlayın.
S76 ⭐LR parser'ların dört avantajı ve tek pratik dezavantajı nedir?
S77ACTION ve GOTO tablolarının satır/sütunları nedir; R4, S6 ve boş hücre ne demektir?
Lecture 4 — Names, Bindings & Scopes
S78 ⭐Variable'ın altı niteliğini (sextuple) sayın; hoca hangisini "en önemli" ilan etti?
S79C99'da isim uzunluğu kuralları nedir? Case sensitivity neden okunabilirliğe zarar verir?
S80 ⭐Keyword ile reserved word farkı nedir? COBOL örneği ne anlatır?
length bile değişken olamaz. (Sayıyı ezberleme; "çok olursa problem" fikri yeter.)S81 ⭐l-value ve r-value nedir; hangisi olmadan diğerine erişilemez?
S82Alias nasıl oluşur, neden zararlıdır?
S83 ⭐Beş binding time'ı birer örnekle yazın.
*→çarpma. Language implementation: int'in aralığı. Compile: int count → tip. Load: C static değişkeni → hücre. Run: non-static lokal → hücre; değişkenin değeri.S84 ⭐count = count + 5 için beş bağlanmayı zamanlarıyla analiz edin.
S85 ⭐Static binding ile dillerdeki static keyword'ü aynı şey midir?
static keyword: dile göre farklı anlamlar taşır (compile-time yaratım, dosya görünürlüğü...).S86Explicit/implicit declaration ve type inference'ı örneklerle ayırın.
int x;. Implicit: kural/gelenekle — Fortran I–N kuralı; Basic/Perl/JS/PHP'de var; writability +, reliability −. Inference: C# var a = 5.0 → double, "the initial value sets the type" (ML/Haskell/F#) — tip yine compile time'da sabitlenir.S87 ⭐Dynamic type binding nedir; avantajı ve iki bedeli?
list=[2,4.33] sonra list=17.3; Python/Ruby/PHP). Avantaj: esneklik/generic kod. Bedeller: sürekli run-time tip kontrolü + yorumlama maliyeti; derleyici tip hatası yakalayamaz. (Ruby'de tüm değişkenler tipsiz referanstır.)S88 ⭐Dört lifetime kategorisini tanımlayıp her birine artı/eksi yazın.
S89Elaboration ne demektir?
S90 ⭐Scope tanımı; local/nonlocal/global ayrımı nedir?
S91 ⭐Static scoping'de isim aranırken izlenen süreç nedir? Static parent/ancestor ve hiding nedir?
S92 ⭐big/sub1/sub2 örneğinde (big→sub1→sub2 çağrısı) sub2'deki x, static ve dynamic scoping'de hangi x'tir?
S93İç blokta dış bloktaki isimle değişken bildirmek hangi dillerde legal, hangilerinde yasaktır?
S94LET construct'ın iki parçası nedir, hangi dillerde görülür?
S95C/C++'ta declaration ile definition farkı nedir? extern ne işe yarar?
extern int x; = "declare without define" — başka dosyada tanımlı.S96PHP ve Python'da fonksiyon içinden global değişkene erişim kuralları nedir?
$GLOBALS dizisi ya da global bildirimi. Python: global'i okumak serbest ama fonksiyon içinde ATAMAK için global bildirimi şart; iç içe fonksiyonda bir üst katman için nonlocal.S97Static scoping'in iki eleştirisi nedir?
S98 ⭐Dynamic scoping'in avantajı ve dört dezavantajı nedir?
S99 ⭐Scope ile lifetime farkını C'deki fonksiyon içi static int k ile ispatlayın. Java'da olur mu?
S100Referencing environment'ı static ve dynamic scoped diller için ayrı ayrı tanımlayın.
S101 ⭐Named constant nedir? C#'ın iki türünü bağlanma zamanlarıyla ayırın.
const → compile time; readonly → run time (dinamik).S102İmperative diller neyin soyutlamasıdır ve saf fonksiyonel dillerle temel karşıtlığı nedir?
Lecture 5–10 · 21, 27, 28 Temmuz ve 3, 4, 10 Ağustos dersleri. Final ağırlığı %40. Buradan sonrası tamamen final için: önce radar (ne çıkar, nasıl çalışılır), sonra altı dersin detaylı anlatımı, sonra deneme sınavı ve soru havuzu. Dönem 10 Ağustos'ta kapandı — kapsam artık kesin.
Final Sınav Radarı
Vize sonrası altı dersin (Lecture #5–#10) transkriptleri, slaytları ve syllabus çapraz okunarak çıkarılan analiz. 10 Ağustos son dersiyle güncellendi.
| Ders | Tarih | Sebesta | Konu | Süre | Ağırlık tahmini |
|---|---|---|---|---|---|
| Lecture #5 | 21 Tem | Ch.6 | Data Types | 285 dk (iki oturumluk) | ⭐⭐⭐ en yüksek |
| Lecture #6 | 27 Tem | Ch.7–8 | Expressions & Assignment + Control Structures | 228 dk | ⭐⭐⭐ |
| Lecture #7 | 28 Tem | Ch.9 | Subprograms (+ Quiz 2) | 227 dk | ⭐⭐⭐ |
| Lecture #8 | 3 Ağu | Ch.10 | Implementing Subprograms | 112 dk (asenkron) | ⭐⭐ |
| Lecture #9 | 4 Ağu | Ch.11 | ADTs & Encapsulation (+ Quiz 3) | 166 dk | ⭐⭐ |
| Lecture #10 | 10 Ağu | Ch.12 | Support for OOP (+ Quiz 4, dersin hemen ardından) | tam transkript ✅ | ⭐⭐ en taze konu |
Kapsam artık kesin: dönem 10 Ağustos'ta kapandı. Ch.13 (concurrency) ve Ch.14 (exception/event handling) hiç işlenmedi — ilk derste planlanmışlardı ama yaz okulunun altı haftasına sığmadı. Hocanın kapanış cümlesi: "that should also conclude now our examination… which also means that we now finally closed this course."
Üç net çıkarım:
- Format = vize formatı. Yani 10–15 çoktan seçmeli + 3–5 açık uçlu, kavramsal ağırlıklı, kod sorusu gelirse dil serbest. Aşağıdaki Deneme Sınavı tam bu formatta kurulmuştur.
- Kapsam = TÜM DÖNEM (Ch.1–12). Vize konuları resmen kapsamda — bu artık çıkarım değil, hocanın doğrudan ifadesi. Rehberin vize bölümünü de mutlaka bir kez geç.
- Ağırlık merkezi = vize sonrası (Ch.6–12). Yani çalışma zamanının büyük kısmı buraya, vize bölümüne hızlı bir tekrar turu.
| Bölüm | Durum | Finaldeki yeri |
|---|---|---|
| Ch.1–5 (Lecture #1–#4) | ✅ Vizede soruldu | Kapsamda — ama ağırlığı düşük. Rehberin vize bölümünden hızlı tekrar |
| Ch.6–11 (Lecture #5–#9) | ✅ İşlendi, tam transkript + slayt | Finalin gövdesi — zamanının çoğu buraya |
| Ch.12 (Lecture #10, OOP desteği) | ✅ 10 Ağustos'ta işlendi — transkript + slayt elimizde | En taze konu, aşağıda tam bölüm olarak eklendi |
| Ch.13 · Ch.14 (concurrency, exception handling) | ❌ Hiç işlenmedi | Kapsam dışı — dönem Ch.12 ile kapandı |
Ağırlıklar ve not durumun
| Bileşen | Ağırlık | Durum |
|---|---|---|
| Quiz'ler | %20 | Quiz 1: 90/100 · Quiz 2: 100/100 · Quiz 3: 100/100 — üçünün ortalaması 96,7 · Quiz 4: 10 Ağustos'ta yapıldı |
| Vize | %40 | 20 Temmuz, yüz yüze |
| Final | %40 | Tüm dönem (Ch.1–12), ağırlık Ch.6–12'de |
Ne demek: Final tek başına notun %40'ı — vizeyle eşit ağırlıkta. Syllabus'un dediği gibi ders içi etkinlikler %60, final %40.
Format — artık tahmin değil, hocanın teyidi
- 10–15 çoktan seçmeli + 3–5 açık uçlu. Seçmeliler kısmen tanım, açık uçlular kavrayış.
- Sorular kavramsal: "questions will be more conceptual… not coding so much."
- Açık uçluların kalıbı: "What is the difference between this concept and this?" — final konuları bu kalıba fazlasıyla uygun: array vs record, free vs discriminated union, reference counting vs mark-sweep, deep vs shallow access, static vs stack-dynamic locals…
- Tarih/yıl ezberi sorulmaz. Quiz 1'de Ch.2 tarih detayı sıfır çıkmıştı — bu doğrulanmış bir gözlem.
- Kod sorusu gelirse dil serbest.
| Quiz | Tarih / o günkü ders | Sorular nereden geldi | O günkü dersten soru |
|---|---|---|---|
| Quiz 2 | 28 Tem — Subprograms (Ch.9) | Ch.3 (BNF, parser), Ch.5 (binding, scoping, dynamic type binding), Ch.6 (data types, strong typing), Ch.7 (referential transparency), Ch.2 (ALGOL, Smalltalk) | SIFIR |
| Quiz 3 | 4 Ağu — ADTs (Ch.11) | Ch.5 (named constants, dynamic scoping), Ch.3 (BNF), Ch.7 (side effect, short-circuit, operand evaluation, compound assignment), Ch.8 (loop türleri), Ch.1 (readability) | SIFIR |
- Hoca tüm dönemden birikimli soruyor. Bu artık teyitli: 10 Ağustos'ta "tüm dönemi kapsıyor, ama ağırlık vize sonrasına kayacak" dedi. Vize konuları (binding, scope, BNF, dil tarihi) çıkabilir — rehberin vize bölümünü de bir kez geç.
- En sevdiği alanlar belli: binding & scoping, BNF/parser, data types & type checking, expressions (side effect, short-circuit) ve control structures. Bunlar iki quiz'de de tekrarlandı — finalin çekirdeği bu olacak.
- En son işlenen konu quiz'de çıkmıyor — ama bu finalde çıkmayacağı anlamına gelmez; quiz'ler kısa olduğu için hoca "oturmuş" konuları soruyor olabilir.
En olası 26 soru konusu — öncelik sırasıyla
Aşağıdaki sıralama şu üç sinyalin kesişiminden çıkarıldı: (a) hocanın sözlü vurgusu ("very important", "the main difference", "remember"), (b) slaytta ayrı bir sayfaya veya kutuya konmuş olması, (c) hocanın vize formatındaki "karşılaştırma" kalıbına uygunluk.
| # | Konu | Ders | Neden |
|---|---|---|---|
| 1 | Array'in dört kategorisi (static / fixed stack-dynamic / fixed heap-dynamic / heap-dynamic) | L5 | Slaytta 5 ayrı sayfa; her kategori dil örnekleriyle eşleştirilmiş |
| 2 | Beş parameter passing yöntemi + avantaj/dezavantajları | L7 | Bölümün merkezi; hoca tek tek avantaj/dezavantaj saydı |
| 3 | Dangling pointer vs lost heap-dynamic variable (memory leak) | L5 | Slaytta "garbage / dangling" formülü ayrıca verilmiş |
| 4 | Reference counting vs mark-sweep (eager/lazy) | L5 | Tam karşılaştırma kalıbı; her ikisinin de avantaj+dezavantajı net |
| 5 | Free union vs discriminated union; Java/C#'ta union yok | L5 | "Güvenlik kaygısının yansıması" cümlesi çok sevilir |
| 6 | Strong typing tanımı + hangi dil neden strongly typed değil | L5 | C/C++'ın iki gerekçesi (parametre denetimi atlanabilir, union denetlenmez) |
| 7 | Name vs structure type equivalence | L5 | Klasik ikili; structure'ın "aynı yapıdakiler ayırt edilemez" sorunu |
| 8 | Functional side effect + slayttaki fun1() kodunun C ve Java çıktısı | L6 | Hoca soruyu açıkça öğrenciye bıraktı |
| 9 | Referential transparency — tanım + saf fonksiyonel diller neden hep sağlar | L6 | "Değişkenleri yok" mantık zinciri |
| 10 | Short-circuit evaluation — tanım + slayttaki LIST[index] örneği | L6 | Somut hata senaryosu; C/C++/Java'nın &/&& ayrımı |
| 11 | Dangling else ve Java'nın static semantics kuralı | L6 | Vizedeki ambiguity konusunun devamı |
| 12 | 1960'lar kanıtı: tüm algoritmalar two-way selection + pretest loop ile kodlanabilir | L6 | Slaytta ayrı sayfa, tek cümlelik "önemli sonuç" |
| 13 | parameter profile vs protocol | L7 | İki satırlık tanım farkı — MC için ideal |
| 14 | Deep / shallow / ad hoc binding (parametre olan subprogram'ın ortamı) | L7 | Slaytta kodlu örnek + hangi scoping'e doğal olduğu |
| 15 | Closure tanımı + ne zaman gerekli | L7 | "Nested subprogram'sız static-scoped dilin closure'a ihtiyacı yok" cümlesi |
| 16 | Coroutine — resume, çoklu giriş, "interleaved but not overlapped" | L7 | Ayırt edici, tek bölüme özgü kavram |
| 17 | activation record vs activation record instance; biçim static / boyut dynamic | L8 | Bölümün merkez ayrımı |
| 18 | static chain + (chain_offset, local_offset) hesabı | L8 | Slaytta tam tablolu örnek — sayısal soru gelebilir |
| 19 | ADT'nin iki koşulu ve her birinin avantajları | L9 | Bölümün tanım çekirdeği |
| 20 | Java vs C++ ADT farkları (destructor yok, hepsi sınıf, package scope…) | L9 | Slaytta madde madde listelenmiş; "Java DOES NOT have Destructors" kutusu |
| 21 | OOP'nin üç dayanağı (ADT/encapsulation + inheritance + polymorphism/dynamic binding) | L10 | Slaytın Summary'sinin ilk maddesi; hoca "three pillars" diye tekrarladı |
| 22 | Subclass vs subtype — "is-a" ilişkisi ve substitution principle | L10 | Slaytta ayrı sayfa; tam karşılaştırma kalıbı: "subclasses inherit implementation; subtypes inherit interface and behavior" |
| 23 | Multiple inheritance — iki dezavantajı, diamond problemi, virtual çözümü | L10 | Hoca "neden Java'da yok?" sorusunu açıkça sordu; cevap: karmaşıklık + verimsizlik |
| 24 | Interface vs abstract class (slaytta iki sayfalık tablo) | L10 | Karşılaştırma sorusunun ideal adayı; Java 8 default notu dahil |
| 25 | Exclusivity of objects — üç yaklaşım ve her birinin avantaj/dezavantajı | L10 | Tasarım sorularının ilki; slaytta 3×2 madde hâlinde |
| 26 | vtable / CIR — dinamik bağlamanın gerçeklenmesi | L10 | Bölümün tek "implementation" konusu; Ch.10'daki activation record mantığının OOP karşılığı |
Tekrar eden temalar — dersin "omurgası"
| Konu | Hangi ölçüte bağlanır |
|---|---|
| Enumeration types | readability + reliability (renk sayı değil; derleyici aralık denetler) |
| Boolean type | readability |
| Operator overloading | readability (iki yönlü: iyi kullanılırsa artırır, kötü kullanılırsa düşürür) |
| Coercion | reliability ↓ (derleyicinin hata yakalaması azalır) |
| Aliasing (pass-by-reference) | readability ↓ → reliability ↓ → verification zorlaşır |
| goto | readability — 1960–70'lerin tartışmasının ana kaygısı |
| Parametre tip denetimi | reliability |
| Information hiding (ADT) | reliability + modifiability |
| Kontrol yapısı zenginliği | writability ↔ dil büyüklüğü/sadeliği trade-off'u |
| Inheritance (Ch.12) | writability ↑ (reuse → verimlilik) ama maintainability ↓ (sınıflar arası bağımlılık) |
| Dynamic binding (Ch.12) | writability/genişletilebilirlik ↑ ↔ verimlilik ↓ — klasik trade-off |
- Array kategorileri — subscript aralığı ve storage ne zaman bind ediliyor
- String uzunluğu — static / limited dynamic / dynamic
- Type checking — tip binding'leri static ise denetim de static olabilir
- Local değişkenler — static vs stack-dynamic (ve recursion sonucu)
- Scoping'in gerçeklenmesi — static chain vs deep/shallow access
- Activation record — biçim static, boyut dynamic
- Mesajın metoda bağlanması (Ch.12) — C++
virtualile seçmeli dynamic; Java varsayılan dynamic (final/static/privatehariç); Smalltalk/Ruby tamamen dynamic
Çalışma planı — sırayla
- Önce tanımlar. Her bölümdeki "birebir ezber" kutularını çıkar: data type, descriptor, object, array, record, associative array, union, pointer, type checking, coercion, strong typing, profile, protocol, closure, coroutine, activation record, ADT'nin iki koşulu, abstraction, naming encapsulation, message / message protocol, subtype, polymorphic variable, abstract method & abstract class, CIR, vtable. Quiz 1'in dersi: slayttaki ifadeyle.
- Sonra karşılaştırma tabloları. Yukarıdaki 20 maddelik listenin her satırı için iki sütunlu bir tablo kur ve kapalı kitap yaz.
- Sonra "hangi dil ne yapar" tabloları. Bunlar MC'nin ana kaynağı. Özellikle: C/C++'ın istisnaları, Java'nın yokları (union yok, goto yok, destructor yok, metot parametresi yok), Ada'nın ayrıcalıkları (dönüş tipiyle overload ayrımı, coercion yok, in/out/inout), ML/F#'ın katılığı (coercion yok).
- En son sayısal/kodlu örnekler. Access function hesabı, (chain_offset, local_offset),
fun1()side effect çıktısı, C# parameter collision. Bunlar az sayıda ama ayırt edici sorulardır. - Soru havuzunu çöz (aşağıda) ve yanlışlarını ilgili bölüme dönerek kapat.
- union yok (C# de yok — güvenlik kaygısı)
- goto yok (C#'ta var)
- destructor yok — garbage collector var
- metot adları parametre olarak geçirilemez (C/C++'ta fonksiyon pointer'ı geçirilebilir)
- gerçek iki boyutlu array yok — array of arrays
- generic koleksiyonlarda indexing yok ve primitive saklanamaz (C#'ta indexing var)
- metot içinde
staticlocal değişken yasal değil - operator overloading yok (C++'tan kopyalanmadı, sonra C#'a girdi)
- multiple inheritance yok — yerine interface (Ch.12); C++'ta var, C#'ta yok
- parentless (üst sınıfsız) sınıf yok — her şey
Object'ten türer; C++'ta standalone sınıf olabilir - procedural programlama desteği yok — C++ hibrit, Java değil
- Ama var: range checking, zorunlu parametre tip denetimi, package scope, etiketli
break/continue
5 · Data Types
Ch.6 · 21 Temmuz dersi (tek oturumda iki haftalık konu) · Slayt: Lecture #5 — finalin en büyük ve en yoğun bölümü
Temel tanımlar — ezberlenecek üçlü
Bölümün ilk üç slaydı doğrudan tanım sorusu malzemesi. Hoca üçünü de tek tek okudu:
| Terim | Tanım (slayttaki hâliyle) |
|---|---|
| data type | Bir veri nesneleri kümesi ve bu nesneler üzerinde önceden tanımlı işlemler kümesi. |
| descriptor | Bir değişkenin özniteliklerinin toplamı. Bellekte özniteliklerin saklandığı alan. |
| object | Kullanıcı tanımlı (abstract data) bir tipin örneği (instance). |
Neden tip sistemi? — hocanın "üç önemli şey"i
Slaytta olmayan ama hocanın uzun uzun anlattığı bir çerçeve. "Three important things come into mind" dedi ve error detection'ı 1. sıraya koydu. Açık uçlu soru adayı:
- Error detection (hata yakalama) — en pratik gerekçe. type checking süreci doğrudan tip sistemi tarafından yönetilir.
- Modularization (modülerleştirme) — modüller arası (cross-module) tip denetimi, arayüzlerin tutarlılığını garanti eder → yeniden kullanılabilirlik.
- Documentation (belgeleme) — tip bildirimleri programın verisi hakkında bilgi belgeler, davranışı hakkında ipucu verir.
- Öznitelikler tamamen static → descriptor yalnız compile time'da gerekir; derleyici onu symbol table'ın parçası olarak kurar.
- Öznitelikler dynamic → descriptor'ın bir kısmı veya tamamı run time boyunca korunmalıdır.
- Her hâlükârda descriptor type checking ve allocation kodu üretiminde kullanılır.
Primitive data types
Tanım: Başka veri tipleri cinsinden tanımlanmayan tipler. Bazıları doğrudan donanımın yansımasıdır, bazıları küçük bir yazılım desteği ister. Hocanın benzetmesi: primitive tipler alfabe, yapısal tipler o alfabeyle kurulan kelimeler ve cümleler.
Integer
- Neredeyse her zaman donanımın birebir yansıması → eşleme (mapping) trivial.
- Bir dilde sekiz kadar farklı integer tipi olabilir. Java'nın işaretli boyutları:
byte, short, int, long. - C/C# ayrıca unsigned tipler sunar (ikili veri için kullanışlı). Java'da unsigned yok.
0010 → ones complement 1101 → +1 → 1110 (two's complement)
Peki neden ones complement yetmiyor? Çünkü ones complement'te iki tane sıfır olur — pozitif sıfır ve negatif sıfır. Hoca bunu "biggest problem" diye niteledi. Bu tam bir "neden" sorusu adayı. "the biggest disadvantage of ones complement notation is that you would have two zeros"
Floating point
- Gerçek sayıları modeller ama yalnızca yaklaşık olarak. Matematikte sayılar sürekli, bilgisayarda ayrık.
- π ve e gibi sonsuz sayılar sonlu bellekte tam gösterilemez — terabaytlarca bellek olsa da.
- Ondalık→ikili dönüşüm de sorunlu:
0.1(decimal) ikili tabanda0.000110011001100…şeklinde devreder. - Bilimsel kullanım için dil en az iki tip sunmalı:
floatvedouble. - IEEE Floating-Point Standard 754 — sayıyı üç parçaya böler:
Parça 32-bit 64-bit sign (işaret) 1 bit 1 bit exponent (üs) 8 bit 11 bit fraction (kesir) 23 bit 52 bit - precision = kesir kısmının doğruluğu (bit cinsinden) · range = kesir aralığı + üs aralığının birleşimi. Bu ikisini karıştırma.
Complex ve Decimal
| Tip | Kim destekler | Nasıl | Avantaj / Dezavantaj |
|---|---|---|---|
| complex | C99, Fortran, Python | İki float: reel + sanal kısım. Python: (7 + 3j) | — |
| decimal | COBOL (temel), C# | Sabit sayıda ondalık basamak, BCD (binary coded decimal) kodlu | + accuracy (kesin) − limited range, wastes memory |
Avantaj: accuracy —
0.1'i floating point kayıpsız saklayamaz, decimal saklar. Dezavantaj: bellek israfı + sınırlı aralık. Hocanın somut örneği: 6 basamaklı BCD sayı 24 bit tutar, aynı sayı saf ikilide 20 bit yeter.
Boolean ve Character
- Boolean: hepsinin en basiti, iki değer. Bit ile gösterilebilir ama çoğunlukla byte kullanılır.
En büyük avantajı: readability. ALGOL 60'ta tanıtıldı.
İstisna: C89'un boolean tipi yoktu — sayısal ifadeleri koşul olarak kullandı (0 = false, sıfırdan farklı = true). C99/C++'ta boolean var ama sayısal ifade de hâlâ koşul olabiliyor; Java ve C#'ta olamaz. - Character: sayısal kodlama olarak saklanır.
Kodlama Genişlik Not ASCII 0–127 (128 karakter) En yaygın; İngilizce için yeterliydi Unicode UCS-2 16 bit Çoğu doğal dilin karakteri. Orijinal olarak Java'da kullanıldı. İlk 128 karakteri ASCII ile birebir aynı. Unicode UCS-4 32 bit Fortran, 2003'ten itibaren
Character string types
Tanım: değerleri karakter dizileri olan tip. İki tasarım sorusu var — hoca "the two important issues" dedi:
- Primitive bir tip mi, yoksa sadece özel bir array mi?
- String'in uzunluğu static mi dynamic mi?
Tipik işlemler: assignment/copying · comparison (=, >) · catenation (birleştirme) · substring reference · pattern matching.
Not: substring reference, array'lerde slice adını alacak — aynı fikrin iki adı.
| Dil | String yaklaşımı |
|---|---|
| C, C++ | Primitive değil — char array + fonksiyon kütüphanesi. strcpy, strcat, strcmp, strlen |
| SNOBOL4 | Primitive — tarihteki ilk string manipülasyon dili, gelişmiş pattern matching |
| Fortran, Python | Primitive tip + atama ve birkaç işlem |
| Java, C#, Ruby, Swift | String sınıfı üzerinden primitive |
| Perl, JavaScript, Ruby, PHP | Yerleşik pattern matching — regular expression'larla |
Uzunluk seçenekleri — üç kategori
| Kategori | Ne demek | Diller | Descriptor |
|---|---|---|---|
| Static | Uzunluk sabit, derlemede belli | COBOL, Java String sınıfı | Compile-time descriptor (3 alan: tip adı · uzunluk · ilk karakterin adresi) |
| Limited dynamic | Bildirilen bir maksimuma kadar değişebilir | C, C++ | Run-time descriptor gerekebilir (maksimum uzunluk · geçerli uzunluk · adres) — ama C/C++'ta yok |
| Dynamic | Maksimum yok | SNOBOL4, Perl, JavaScript | Run-time descriptor şart; en büyük sorun allocation/deallocation |
strlen null karakteri saymaz — bu detay çoktan seçmelide sorulabilir.
Ordinal ve enumeration types
Ordinal type: olası değerler kümesi pozitif tamsayılarla kolayca eşleştirilebilen tip.
Java'daki primitive ordinal örnekleri: integer, char, boolean.
Enumeration type: tüm olası değerler, tanımda isimlendirilmiş sabitler olarak verilir.
enum days {mon, tue, wed, thu, fri, sat, sun}; — içeride örtük olarak 0,1,2… atanır ama açıkça da atanabilir.
reliability'ye katkı: derleyici denetleyebilir → (1) işlemler denetlenir — renkler toplanamaz; (2) enum değişkenine tanımlı aralık dışında değer atanamaz.
C#, F#, Swift ve Java 5.0, C++'tan daha iyi destek verir — çünkü bu dillerde enum değişkenleri integer'a coerce edilmez, kendi başına bir tiptir. Ayırt edici nokta tam olarak budur.
Üç tasarım sorusu: (1) bir enum sabiti birden fazla tip tanımında görünebilir mi, görünürse tipi nasıl denetlenir?
(2) enum değerleri integer'a coerce edilir mi? (3) başka tipler enum'a coerce edilir mi?
Hocanın notu: "all these design issues are somehow related to type checking".
Array types
Tanım (birebir ezberlenecek): array, homogeneous bir veri elemanı topluluğudur; her eleman ilk elemana göre konumuyla (position) tanımlanır.
- Subscript'ler için hangi tipler yasal?
- Eleman referanslarındaki subscript ifadeleri range checked mi?
- Subscript aralıkları ne zaman bind edilir?
- Allocation ne zaman olur?
- Ragged (jagged) mı, rectangular mı, ikisi de mi?
- Maksimum subscript sayısı kaç?
- Array nesneleri initialize edilebilir mi?
- Slice destekleniyor mu?
| Konu | Diller |
|---|---|
| Subscript sözdizimi parantez ( ) | Fortran, Ada — Ada bilinçli tercih: array referansı da fonksiyon çağrısı da birer mapping, uyum için |
| Subscript sözdizimi köşeli [ ] | Diğer çoğu dil |
| Subscript tipi: yalnız integer | Fortran, Java |
| Subscript tipi: ordinal tipler (integer, char, boolean, enum) | C, C++ |
| Range checking YOK | C, C++, Perl, Fortran |
| Range checking VAR | Java, ML, C# |
a(j) array elemanı mı, fonksiyon çağrısı mı belli olmaz.
Array'in dört kategorisi — en olası sınav sorusu
Kategoriler üç şeye göre belirlenir: subscript aralıklarının bind'ı, storage'ın bind'ı, storage'ın nereden ayrıldığı.
| Kategori | Subscript aralığı | Allocation | Avantaj | Örnek |
|---|---|---|---|---|
| Static | statik bind | statik, run-time öncesi | efficiency — dinamik ayırma yok | C/C++'ta static nitelemeli array'ler |
| Fixed stack-dynamic | statik bind | bildirim anında (stack) | space efficiency | C/C++'ta static olmayan array'ler |
| Fixed heap-dynamic | dinamik ama ayırma sonrası sabit | istendiğinde, heap'ten | — | C malloc, C++ new, Java'da tüm non-generic array'ler |
| Heap-dynamic | dinamik, defalarca değişebilir | dinamik, heap | flexibility — array büyüyüp küçülebilir | Java ArrayList, C# List, Perl, JavaScript, Python, Ruby |
static olmayan bir array hangi kategoridedir?" → fixed stack-dynamic.
(b) "Hangi kategori esneklik (arrayin büyüyüp küçülmesi) sağlar?" → heap-dynamic.
Hocanın vurguladığı dezavantaj: heap-dynamic'te allocation/deallocation uzun sürer ve çalışma boyunca defalarca olabilir.
Array'in diğer özellikleri
- Heterogeneous array: elemanları aynı tipte olmak zorunda değil → Perl, Python, JavaScript, Ruby.
- Rectangular: tüm satırlar eşit uzunlukta. Jagged (ragged): satırlar farklı uzunlukta — array of arrays olduğunda mümkün.
C, C++, Java jagged destekler. F# ve C# ikisini de destekler. - Slice: bir array'in alt yapısı; "bir referanslama mekanizmasından başka bir şey değildir".
Yalnızca array işlemleri olan dillerde anlamlıdır. Python
vector[3:6], Rubylist.slice(2,2). - APL vektör/matris işlemlerinde en güçlü operatör setini sunar.
Fortran elemental işlemler sağlar:
A = A + Biki array'in eleman çiftlerini toplar.
Array implementasyonu — access function
Tek boyutlu için erişim fonksiyonu:
address(list[k]) = address(list[lower_bound])
+ ((k − lower_bound) × element_size)
Çok boyutlu için iki yerleşim düzeni var — bu ayrım kesin bilinmeli:
| Düzen | 1 2 3 / 4 5 6 / 7 8 9 nasıl saklanır | Kim |
|---|---|---|
| Row major order | 1 2 3 4 5 6 7 8 9 | Çoğu dil |
| Column major order | 1 4 7 2 5 8 3 6 9 | Fortran |
Location(a[i,j]) = address(a[row_lb, col_lb])
+ (((i − row_lb) × n) + (j − col_lb)) × element_size
a[2,3], integer array, a[1,1] adresi 500:location(a[2,3]) = 500 + (((2−1)×7) + (3−1)) × 4 = 500 + (7+2)×4 = 536
Associative arrays
Tanım: sırasız bir veri elemanı topluluğu; elemanlar key denen eşit sayıda değerle indekslenir. Kullanıcı tanımlı key'ler saklanmak zorundadır (normal array'de indeks saklanmaz — fark bu).
Tasarım soruları: elemanlara referansın biçimi ne? Boyut static mi dynamic mi?
Yerleşik tip olduğu diller: Perl, Python, Ruby, Swift.
| Dil | Sözdizimi |
|---|---|
| Perl (hash) | İsim % ile başlar · %hi_temps = ("Mon" => 77, …) · erişim süslü parantez: $hi_temps{"Wed"} · silme delete · keys operatörü anahtar dizisini döndürür |
| Python (dictionary) | { } ile kurulur · erişim köşeli parantez: Dict["model"] · silme del · yeni key ile ekleme · len(Dict) |
Record types
Tanım: possibly heterogeneous bir veri elemanı topluluğu; elemanlar isimleriyle tanımlanır. (Array ile karşıtlığı buradan kur: array homojen + konumla, record heterojen + isimle.)
2. Tanımlama: array konumla (subscript), record isimle (field name).
3. Hız: Array elemanına erişim, record alanına erişimden çok daha yavaştır — çünkü subscript'ler dinamiktir, field name'ler statiktir. Record'da dinamik subscript kullanılabilirdi ama o zaman type checking imkânsızlaşır ve çok daha yavaş olurdu.
4. Bellek: record alanları için beginning'e göre offset adres tutulur.
Tasarım soruları: alan referansının sözdizimsel biçimi nedir? Elliptical reference'a izin var mı?
| Biçim | Örnek |
|---|---|
COBOL — seviye numaraları ile iç içe record; OF ile referans | FIRST OF EMP-NAME OF EMP-REC |
| Diğerleri — dot notation, özyinelemeli tanım | emp.age |
Fully qualified reference: tüm record isimlerini içerir. Elliptical reference: belirsizlik olmadığı sürece
record isimlerinin atlanmasına izin verir — COBOL'da FIRST, FIRST OF EMP-NAME ve
FIRST OF EMP-REC üçü de aynı alana elliptical referanstır.
Tuple ve List types
| Tip | Tanım / Not |
|---|---|
| Tuple | Record'a benzer, ama elemanlar isimsiz. Python, ML, F#'ta fonksiyonların birden çok değer döndürmesini sağlar. Python'da liste ile yakın akraba ama immutable. |
| List | Lisp/Scheme'de parantezle, virgülsüz: (A B C D). Veri ile kod aynı biçimdedir — yorumlayıcı hangisi olduğunu bilmeli, veri ise kesme işaretiyle quote edilir: '(A B C). |
| İşlem | Ne yapar | Örnek |
|---|---|---|
| CAR | Listenin ilk elemanı | (CAR '(A B C)) → A |
| CDR | İlk eleman çıkarıldıktan sonra kalanı | (CDR '(A B C)) → (B C) |
| CONS | 1. parametreyi 2. parametreye (listeye) ekler | (CONS 'A (B C)) → (A B C) |
| LIST | Parametrelerinden yeni liste yapar | (LIST 'A 'B '(C D)) → (A B (C D)) |
:: (ikili operatör, 3 :: [5,7,9]) · CAR → hd · CDR → tl.
ML listeleri köşeli parantez + virgül ve elemanlar aynı tipte olmalı.
F#: ML gibi ama noktalı virgül ayırıcı, hd/tl List sınıfının metotları.
Python listeleri: array görevi de görür; Scheme/Lisp/ML/F#'ın aksine mutable; elemanlar herhangi tipte olabilir;
indeks 0'dan başlar; del ile eleman silinir.
List comprehension: küme gösteriminden türetilmiştir. Orijinali Haskell'ındır: [n * n | n <- [1..10]].
Python: [x * x for x in range(6) if x % 3 == 0] → [0, 9].
Union types
Tanım: değişkenlerinin çalışma sırasında farklı zamanlarda farklı tipte değerler saklamasına izin veren tip. (Hocanın vurgusu: during execution, not compilation.)
Tasarım soruları: type checking gerekli mi? Union'lar record'ların içine gömülmeli mi?
| Free union | Discriminated union | |
|---|---|---|
| Type checking | Yok — dil desteği yok | Var — discriminant adlı tip göstergesi hangi alanın kullanılacağını söyler |
| Diller | C, C++ | Ada, ML, Haskell, F# |
| Güvenlik | Unsafe | Safe |
el1.intEl = 27; x = el1.floatEl; →
27'nin bit gösterimi float değişkene atanır, sonuç anlamsızdır.Java ve C# union'ı hiç desteklemez — slayt bunu "programlama dillerinde artan güvenlik kaygısının yansıması" diye açıklar. Bu, çoktan seçmelide çok sevilen bir maddedir.
Pointer ve Reference types
Pointer tanımı: değer aralığı bellek adresleri + özel bir nil değeri olan tip.
İki şey sağlar: indirect addressing gücü ve dinamik belleği yönetme yolu.
Beş tasarım sorusu: pointer değişkeninin scope/lifetime'ı nedir? · heap-dynamic değişkenin lifetime'ı nedir? · pointer'lar işaret edecekleri tip bakımından kısıtlı mı? · pointer'lar dinamik depolama yönetimi için mi, indirect addressing için mi, ikisi için mi? · dil pointer mı, reference mı, ikisini de mi desteklemeli?
İki temel işlem: assignment (pointer'a yararlı bir adres atamak) ve
dereferencing (pointer'ın gösterdiği yerdeki değeri almak). Dereferencing explicit (C++: j = *ptr) veya implicit olabilir.
| Problem | Ne olur | Diğer adı |
|---|---|---|
| Dangling pointer | Pointer, deallocate edilmiş bir heap-dynamic değişkeni gösteriyor | "dangerous" (slaytın kendi notu) |
| Lost heap-dynamic variable | Ayrılmış ama artık erişilemeyen heap değişkeni: p1 bir nesneyi gösteriyor, sonra başka bir nesneye yönlendiriliyor → eskisi kayıp | garbage; bu sürece memory leakage denir |
• Nesne, binding'den uzun yaşarsa → garbage
• Binding, nesneden uzun yaşarsa → dangling reference
Dangling pointer'a iki çözüm
| Yöntem | Nasıl çalışır | Maliyet |
|---|---|---|
| Tombstone (mezar taşı) | Heap'te fazladan bir hücre; pointer yalnızca tombstone'u gösterir. Değişken deallocate edilince tombstone kalır ama nil yapılır. | Zaman ve alan bakımından pahalı |
| Locks-and-keys | Pointer değeri (key, address) çifti. Heap değişkeni = değişken + integer lock hücresi. Erişimde key ile lock karşılaştırılır; eşleşmezse run-time error. | Kopyalarda key de kopyalanmalı |
C/C++ pointer'ları
- Son derece esnek ama dikkatle kullanılmalı — hoca "assembly'deki adresler gibi" dedi.
- Nerede/ne zaman ayrılmış olursa olsun herhangi bir değişkeni gösterebilir.
- Pointer arithmetic mümkün:
*(p+5)≡stuff[5]≡p[5]. - Domain type sabit olmak zorunda değil:
void *herhangi bir tipi gösterebilir, type checked edilebilir ama dereference edilemez.
Reference types
| Dil | Durum |
|---|---|
| C++ | reference type — özel bir pointer türü, ağırlıklı olarak formal parametreler için. Hem pass-by-reference hem pass-by-value avantajları. |
| Java | C++'ın reference'ını genişletir ve pointer'ları tamamen değiştirir. Reference'lar adres değil, nesnelere referanstır. |
| C# | Hem Java'nın reference'ları hem C++'ın pointer'ları. |
Slaytın çarpıcı cümlesi: "Pointers are like goto's — they widen the range of cells that can be accessed by a variable." (goto kontrolü savurur, pointer erişimi savurur.)
Ama: dinamik veri yapıları için pointer/reference zorunludur — "so we can't design a language without them". Yani cevap "pointer kötüdür" değil, "tehlikeli ama vazgeçilmez, bu yüzden diller onu ehlileştirmeye çalışır" olmalı.
Heap management ve garbage collection
Çok karmaşık bir run-time süreci. İki eksen: single-size cells vs variable-size cells. Çöp toplamada iki yaklaşım var — bu ikili neredeyse kesin sorulur:
| Reference counter | Mark-sweep | |
|---|---|---|
| Yaklaşım | Eager (istekli) — geri kazanım kademeli | Lazy (tembel) — geri kazanım, boş alan listesi bitince |
| Mekanizma | Her hücrede bir sayaç: kaç pointer beni gösteriyor | Her hücrede fazladan bir bit. Hepsi garbage işaretlenir → tüm pointer'lar izlenir, erişilebilenler "garbage değil" işaretlenir → kalanlar boş listeye döner |
| Dezavantaj | Alan maliyeti, çalışma zamanı maliyeti, dairesel bağlı hücrelerde çuvallar | Orijinal hâlinde çok seyrek çalışırdı; çalışınca uygulamada ciddi gecikme |
| Avantaj | Intrinsically incremental — uygulamada büyük gecikme olmaz | Dairesel yapıları da toplar |
| Modern çözüm | — | incremental mark-sweep — daha sık çalıştırarak gecikmeyi önler |
Optional types
Bir değişkenin şu anda değeri olmadığını belirtmesi gerektiğinde kullanılır.
C#, F#, Swift destekler. C#'ta reference tipler zaten optional'dır (null);
value type'lar (struct) tip adına soru işareti eklenerek optional yapılır: int? x;.
Değersizlik null'dır; Swift'te nil kullanılır.
Type checking, strong typing, type equivalence
| Terim | Tanım |
|---|---|
| type checking | Bir operatörün operand'larının uyumlu tiplerde olmasını sağlama etkinliği. |
| compatible type | Operatör için ya yasal olan ya da dil kurallarınca derleyici üretimi kodla yasal bir tipe örtük çevrilebilen tip. |
| coercion | Bu otomatik/örtük çevrimin adı. |
| type error | Bir operatörün uygunsuz tipte bir operand'a uygulanması. |
Static/dynamic bağlantısı: tüm tip binding'leri static ise type checking'in neredeyse tamamı static yapılabilir. Binding'ler dynamic ise type checking de dynamic olmak zorundadır.
Strong typing: bir dil, tip hataları her zaman yakalanıyorsa strongly typed'dır. Avantajı: tip hatasına yol açan değişken yanlış kullanımlarının saptanabilmesi.
| Dil | Strongly typed mı? | Neden |
|---|---|---|
| C, C++ | Hayır | Parametre tip denetimi atlanabilir; union'lar type checked değil |
| Java, C# | Neredeyse | Açık tip dönüşümü (explicit casting) yüzünden |
| ML, F# | Evet | — |
| Ada | Java'dan daha etkili | Java'nın atama coercion'ları C++'ın yarısı kadar olsa da Ada'nınki hâlâ daha güçlü |
Type equivalence — iki yaklaşım
| Name type equivalence | Structure type equivalence | |
|---|---|---|
| Kural | İki değişken aynı bildirimde ya da aynı tip adını kullanan bildirimlerdeyse tipleri eşdeğerdir | Tipleri aynı yapıya sahipse eşdeğerdir |
| Uygulama | Kolay | Zor |
| Esneklik | Çok kısıtlayıcı — integer'ın subrange'i integer'a eşdeğer değil; formal parametre, actual parametreyle aynı tipte olmalı | Daha esnek |
| Sorun | — | Aynı yapıdaki tipler ayırt edilemez — ikisi de float olan iki farklı hız birimi karışır |
Structure equivalence'ın açık soruları: alan adları farklı ama yapı aynı olan iki record eşdeğer mi? Yalnızca subscript'leri farklı ([1..10] ve [0..9]) iki array tipi eşdeğer mi? Bileşenleri farklı yazılmış iki enum eşdeğer mi?
- Bir dilin veri tipleri, o dilin tarzını ve kullanışlılığını belirleyen büyük bir etkendir.
- Çoğu imperative dilin primitive tipleri: numeric, character, boolean.
- Kullanıcı tanımlı enumeration ve subrange tipleri readability ve reliability'yi artırır.
- Array ve record çoğu dilde vardır.
- Pointer, adresleme esnekliği ve dinamik depolama yönetimi için kullanılır.
6 · Expressions, Assignment & Control Structures
Ch.7–8 · 27 Temmuz dersi · Slayt: Lecture #6 (iki parçalı) — vizeden sonraki ilk konu
Aritmetik expression'ların 6 tasarım sorusu
- Operator precedence kuralları?
- Operator associativity kuralları?
- Operand değerlendirme sırası?
- Operand değerlendirmesinin side effect'leri?
- Operator overloading?
- Expression'larda tip karışımı (type mixing)?
Operatör aritesi: unary = 1 operand · binary = 2 operand · ternary = 3 operand.
Hoca bunu ayrıca "remember that" diye tekrarladı.
Çoğu dilde binary operatörler infix; Scheme ve LISP'te prefix (Perl'de de bazı prefix binary'ler var).
Çoğu unary operatör prefix, ama C tabanlı dillerde ++ ve -- hem prefix hem postfix olabilir.
Precedence ve associativity
| Kavram | Ne belirler |
|---|---|
| precedence | Farklı öncelik seviyesindeki komşu operatörlerin değerlendirilme sırası |
| associativity | Aynı öncelik seviyesindeki komşu operatörlerin değerlendirilme sırası |
Tipik öncelik sırası: parantez → unary operatörler → ** (varsa) → *, / → +, -
Tipik associativity: soldan sağa; ama ** sağdan sola. Fortran'da unary operatörler bazen sağdan sola.
APL istisnası (kesin sınav malzemesi): tüm operatörlerin önceliği eşittir ve hepsi sağdan sola associate eder.
Her ikisi de parantezle ezilebilir.
Scheme / Common Lisp: tüm aritmetik ve mantık işlemleri açıkça çağrılan alt programlardır.
a + b * c şöyle yazılır: (+ a (* b c))
Conditional expression (C tabanlı diller): average = (count == 0) ? 0 : sum / count
— bir if-else'e denk ama ifade olduğu için değer üretir.
Operand değerlendirme sırası ve side effect'ler
Operand değerlendirmenin dört durumu: (1) değişkenler — bellekten fetch; (2) sabitler — bazen bellekten, bazen doğrudan makine komutunun içinde; (3) parantezli ifadeler — önce tüm operand ve operatörler değerlendirilir; (4) en ilginç durum: operand bir fonksiyon çağrısı olduğunda.
Problem: Bir ifadede geçen fonksiyon, aynı ifadenin başka bir operand'ını değiştirirse sonuç değerlendirme sırasına bağlı hâle gelir.
int a = 5;
int fun1() {
a = 17;
return 3;
}
int main() {
a = a + fun1();
printf("%d\n", a);
}
Soldaki a önce okunursa: 5 + 3 = 8fun1() önce çalışırsa: a artık 17 → 17 + 3 = 20C/C++'ta sonuç tanımsızdır (derleyiciye bağlı); Java'da 8'dir — çünkü Java operand'ların soldan sağa değerlendirilmiş görünmesini zorunlu kılar. Hoca soruyu "those are the questions what I leave for you to think about it" diyerek bıraktı — yani sınav adayı.
Side effect'e iki çözüm
| Çözüm | Nasıl | Avantaj | Dezavantaj |
|---|---|---|---|
| 1. Yasakla | Dil tanımı functional side effect'e izin vermesin: fonksiyonlarda two-way parametre yok, non-local referans yok | "It works!" (slaytın kendi ifadesi) | Tek yönlü parametrelerin esneksizliği ve non-local referans yokluğu |
| 2. Sırayı sabitle | Dil tanımı operand değerlendirme sırasını sabit kılsın | Sonuç deterministik | Derleyici optimizasyonlarını kısıtlar — Java bu yolu seçti (soldan sağa) |
Referential transparency
result1 = (fun(a) + b) / (fun(a) − c);
temp = fun(a);
result2 = (temp + b) / (temp − c);
fun'ın side effect'i yoksa → result1 = result2. Varsa → referential transparency ihlal edilmiştir.Avantajı: Programın semantiğini anlamak çok daha kolaydır — fonksiyon matematiksel bir fonksiyon gibi okunur.
Saf fonksiyonel diller her zaman referentially transparent'tır. Neden? Çünkü değişkenleri yoktur. Fonksiyon state tutamaz (state local değişkende tutulurdu); dışarıdan bir değer kullanıyorsa o sabit olmak zorundadır. Dolayısıyla fonksiyonun değeri yalnızca parametrelerine bağlıdır.
Bu, vizedeki "Lisp neden fonksiyoneldi ama imperative'e kaydı" sorusunun kardeşidir — aynı mantık zinciri.
Overloaded operators
Tanım: Bir operatörün birden fazla amaçla kullanılması.
Bazıları yaygın ve zararsız (+ hem int hem float için); bazıları sorunlu.
* ve & problemi — hoca uzun anlattı
& binary operatör olarak bitwise AND, unary operatör olarak adres alma.
* hem çarpma hem dereference.İki zarar:
- Derleyicinin hata yakalama yeteneği kaybolur — bir operand'ın unutulması saptanabilir bir hata olmalıydı, ama unary yorumu geçerli olduğu için hata sayılmaz.
- Okunabilirlik kaybı.
Kullanıcı tanımlı operator overloading: C++, C#, F# (ve Ada, Python, Ruby) izin verir.
Makul kullanılırsa okunabilirliğe katkıdır (metot çağrısından kaçınılır, ifade doğal görünür).
Riskleri: kullanıcı anlamsız işlemler tanımlayabilir (hocanın örneği: +'yı çarpma yapmak);
operatörler anlamlı olsa bile okunabilirlik zarar görebilir.
Tarihsel not (hoca "very interesting" dedi): Operator overloading, C++'ın Java'ya kopyalanmayan özelliklerinden biridir
— ama sonra C#'a girmiştir. C++'ta bazı operatörler overload edilemez: sınıf/struct üye operatörü . ve
scope resolution ::.
Type conversions
| Narrowing conversion | Widening conversion | |
|---|---|---|
| Tanım | Nesneyi, orijinal tipin tüm değerlerini içeremeyen bir tipe çevirir | Nesneyi, orijinal tipin tüm değerlerine en azından yaklaşık karşılık verebilen bir tipe çevirir |
| Örnek | float → int, double → float | int → float |
| Güvenlik | Kayıplı — precision ve aralık kaybı | Neredeyse her zaman güvenli — büyüklük korunur, ama doğruluk azalabilir |
Mixed-mode expression: operand'ları farklı tipte olan ifade.
Coercion: örtük (implicit) tip dönüşümü — derleyici ya da run-time sistemi başlatır.
Neden gerekir? Hocanın açıklaması: bilgisayarlarda farklı tipte operand alan ikili işlem yoktur,
o yüzden mixed-mode'a izin veren dil örtük dönüşüm kuralları tanımlamak zorundadır.
| Dil | Coercion politikası |
|---|---|
| Çoğu dil | Tüm numeric tipler ifadelerde widening ile coerce edilir |
| ML, F# | İfadelerde hiç coercion yok — hata yakalama önceliklidir |
Coercion'ın dezavantajı: derleyicinin tip hatası yakalama yeteneğini azaltır.
Bedeli: hem tip denetimi hem dönüşüm run-time'da yapılmak zorunda → çok pahalı; üstelik ifadelerde programcı hatalarını saptama olanağı da yok oluyor, çünkü herhangi bir tip herhangi bir tiple birleşebiliyor.
Vize radarındaki "PL/I'ın katkıları" sorusunun final tarafındaki devamı budur.
Explicit conversion (cast): C tabanlı dillerde "casting" denir. C: (int)angle · F#: float(sum)
— F#'ın sözdizimi fonksiyon çağrısına benzer.
Expression hataları
İki kaynak: (1) aritmetiğin doğasındaki sınırlar — sıfıra bölme; (2) bilgisayar aritmetiğinin sınırları — overflow.
Overflow: sonuç register'a sığmayacak kadar büyük · Underflow: sığmayacak kadar küçük.
Bunlar run-time error'dır ve çoğu zaman run-time sistem tarafından görmezden gelinir.
Bu hatalara bazen exception denir (Ch.14'ün konusu).
Relational ve Boolean expressions
- Relational expression: ilişkisel operatörler + çeşitli tiplerde operand → sonuç bir Boolean gösterimi.
Eşitsizlik sembolü diller arasında çok değişir:
!=,/=,~=,.NE.,<>,#. - JavaScript ve PHP'de fazladan
===ve!==var —==/!=gibi ama operand'larını coerce etmezler. Ruby'de aynı ayrım:==coercion yapar,eql?yapmaz. - C89'un Boolean tipi yoktur —
intkullanır (0 false, sıfırdan farklı true).
a < b < c yasal bir ifadedir ama beklediğin şeyi yapmaz:1. Soldaki operatör değerlendirilir → 0 veya 1 üretir.
2. Bu sonuç üçüncü operand (c) ile karşılaştırılır.
Yani matematiksel "b, a ile c arasında mı" anlamı çıkmaz.
| FORTRAN 77 | FORTRAN 90 | C | Ada |
|---|---|---|---|
| .AND. | and | && | and |
| .OR. | or | || | or |
| .NOT. | not | ! | not |
| — | — | — | xor |
Short-circuit evaluation
Aritmetik örnek:
(13 * a) * (b / 13 − 1) — a sıfırsa ikinci parantezi hesaplamaya gerek yok.Short-circuit OLMAMASININ problemi (slayttaki kod):
index = 0;
while (index <= length) && (LIST[index] != value)
index++;
index == length olduğunda LIST[index] indeksleme hatası verir
(LIST'in uzunluğu length−1 ise). Short-circuit varsa ikinci koşul hiç değerlendirilmez ve hata olmaz.
| Dil | Durum |
|---|---|
| C, C++, Java | Olağan Boolean operatörleri (&&, ||) short-circuit;
ayrıca short-circuit olmayan bitwise Boolean operatörleri (&, |) de sunar |
| Ruby, Perl, ML, F#, Python | Tüm mantık operatörleri short-circuit |
Yan etki riski: short-circuit, ifadelerdeki side effect problemini açığa çıkarır:
(a > b) || (b++ / 3) — a > b doğruysa b++ hiç çalışmaz.
Assignment statements
Genel sözdizimi: <target_var> <assign_operator> <expression>
Operatör: = (Fortran, BASIC, C tabanlı) · := (Ada).
='in eşitlik ilişkisel operatörüyle overload edilmesi kötüdür —
C tabanlı diller tam bu yüzden =='i ilişkisel operatör yaptı.
| Biçim | Açıklama | Örnek |
|---|---|---|
| Conditional target | Atama hedefi koşullu (Perl) | ($flag ? $total : $subtotal) = 0 |
| Compound assignment | Kısayol. ALGOL'de tanıtıldı, C ve C tabanlı diller benimsedi | a += b ≡ a = a + b |
| Unary assignment | Artırma/azaltmayı atamayla birleştirir | sum = ++count (önce artır, sonra ata)sum = count++ (önce ata, sonra artır)-count++ (önce artır, sonra negatifle) |
| Assignment as expression | Atama bir değer üretir ve operand olarak kullanılabilir — C tabanlı diller, Perl, JavaScript | while ((ch = getchar()) != EOF) {…} |
| Multiple assignment | Perl ve Ruby: çok hedefli çok kaynaklı atama | ($first, $second) = ($second, $first); → yer değiştirme |
"Assignment as expression"in dezavantajı: bir başka tür expression side effect'i.
Fonksiyonel dillerde atama ve mixed-mode assignment
Fonksiyonel dillerde tanımlayıcılar yalnızca değerlerin isimleridir.
ML: isimler val ile değere bağlanır (val fruit = apples + oranges;);
aynı isim için ikinci bir val gelirse bu yeni ve farklı bir isimdir.
F#: let, ML'in val'i gibidir ama ayrıca yeni bir scope yaratır.
| Dil | Mixed-mode assignment kuralı |
|---|---|
| Fortran, C, Perl, C++ | Herhangi numeric değer, herhangi numeric değişkene atanabilir |
| Java, C# | Yalnızca widening atama coercion'ları yapılır |
| Ada | Hiç atama coercion'ı yok |
Part 2 — Statement-Level Control Structures
- İfadeler içinde — operator associativity ve precedence (Lecture #6 Part 1)
- Program birimleri arasında — fonksiyon/altprogram (Lecture #7)
- Program deyimleri arasında — selection / iteration (burası)
Hoca bunu "one important result of this research and argumentation in the 1960s" diye tanıttı.
Control structure tanımı: bir kontrol deyimi ve onun çalışmasını yönettiği deyimler.
Tasarım sorusu: bir kontrol yapısının birden çok girişi olmalı mı?
Selection statements
Tanım: iki veya daha çok yürütme yolu arasında seçim yapma aracı. İki kategori: two-way selector ve multiple-way selector.
Two-way'in üç tasarım sorusu: kontrol ifadesinin biçimi ve tipi nedir? · then/else clause'ları nasıl belirtilir? · iç içe seçicilerin anlamı nasıl belirtilmeli?
- Kontrol ifadesi aritmetik olabilen diller: C89, C99, Python, C++. Diğer çoğu dilde Boolean olmak zorunda.
- Perl: tüm clause'lar süslü parantezle sınırlanmak zorunda (compound olmalı).
- Python ve Ruby: clause'lar deyim dizileridir; Python girintiyle (indentation) tanımlar.
if (sum == 0)
if (count == 0)
result = 0;
else result = 1;
Hangi if bu else'i alır?Java'nın static semantics kuralı:
else, en yakın önceki if ile eşleşir.
Yani girintinin hiçbir hükmü yoktur — else içteki if'e aittir.Alternatif anlamı zorlamak için compound statement kullanılır:
if (sum == 0) {
if (count == 0)
result = 0;
}
else result = 1;
Bu çözüm C, C++, Java ve C#'ta kullanılır. Perl ise tüm clause'ları zorunlu compound yaparak sorunu baştan yok eder.
Multiple-way selection (switch/case)
Beş tasarım sorusu: kontrol ifadesinin biçimi/tipi? · seçilebilir segmentler nasıl belirtilir? · akış tek bir segmentle sınırlı mı? · case değerleri nasıl belirtilir? · temsil edilmeyen değerler ne olur?
- Kontrol ifadesi ordinal tip olabilir: integer, karakter, enumeration. (Java'da JDK 7+ ile sabit ifade string ve wrapper sınıfı da olabilir.)
- Seçilebilir segmentler deyim dizisi, blok veya compound statement olabilir.
- Tek bir yürütmede herhangi sayıda segment çalışabilir — segment sonunda örtük dallanma yoktur (fall-through).
defaultclause temsil edilmeyen değerler içindir;defaultyoksa deyim hiçbir şey yapmaz.
goto veya break) bitmek zorundadır.
Ayrıca C#'ta kontrol ifadesi ve case sabitleri string olabilir.
Ruby'nin iki case biçimi: (1) when + Boolean ifadeler; (2) bir case değeri + when değerleri.
if ile multiple-way: else-if zinciri — Python'da elif.
Iterative statements
Tekrar, iteration ya da recursion ile sağlanır. İki genel tasarım sorusu: iterasyon nasıl kontrol edilir? · kontrol mekanizması döngünün neresinde?
Counter-controlled loop: bir loop değişkeni + başlangıç, bitiş ve adım (stepsize) değerlerini belirtme yolu.
Üç tasarım sorusu: loop değişkeninin tipi ve scope'u? · loop değişkeni/parametreleri gövdede değiştirilebilir mi,
değiştirilirse kontrolü etkiler mi? · loop parametreleri bir kez mi yoksa her iterasyonda mı değerlendirilir?
for'unun tasarım tercihleri — ezberlenecek dörtlü
for ([expr_1] ; [expr_2] ; [expr_3]) statement
- Açık bir loop değişkeni yoktur.
- Her şey döngü içinde değiştirilebilir.
- Birinci ifade bir kez, diğer ikisi her iterasyonda değerlendirilir.
- C'de
forgövdesinin içine dallanmak yasaldır. - İkinci ifade yoksa → sonsuz döngü.
Python'ın for'u: for loop_variable in object: — object çoğunlukla bir range'tir.
İsteğe bağlı bir else clause'u vardır ve döngü normal biçimde sonlanırsa çalışır.
Logically-controlled loop: tekrar bir Boolean ifadeye dayanır (sayaca değil). İki tasarım sorusu: pretest mi posttest mi? · mantıksal döngü, sayma döngüsünün özel hâli mi olmalı yoksa ayrı bir deyim mi?
- C, C++: hem pretest (
while) hem posttest (do…while); kontrol ifadesi aritmetik olabilir; gövdeye dallanmak yasaldır. - Java: C/C++ gibi ama kontrol ifadesi Boolean olmalı, gövdeye yalnızca baştan girilebilir — Java'da
gotoyoktur. - Perl ve Ruby: iki pretest mantıksal döngü —
whileveuntil. Perl'de ayrıca iki posttest döngü var.
| Özellik | Diller |
|---|---|
Koşulsuz etiketsiz çıkış (break) | C, C++, Python, Ruby, C# |
| Koşulsuz etiketli çıkış | Java (break label), Perl (last) |
Etiketsiz continue | C, C++, Python |
Etiketli continue | Java, Perl |
break en içteki döngüyü sonlandırır; etiketli break dıştaki bir döngüyü sonlandırır.İç içe döngüler için tasarım soruları: koşul, çıkışın parçası olmalı mı? · kontrol birden fazla döngüden dışarı aktarılabilmeli mi?
Veri yapısına dayalı iterasyon (iterator): iterasyon sayısını veri yapısındaki eleman sayısı belirler. Kontrol mekanizması, seçilen sırada bir sonraki elemanı döndüren bir iterator fonksiyonu çağrısıdır; eleman kalmazsa döngü biter.
| Dil | Mekanizma |
|---|---|
| C | for ile kullanıcı tanımlı iterator kurulabilir: for (p=root; p!=NULL; traverse(p)) |
| PHP | current · next · reset |
| Java | Iterator arayüzünü gerçekleyen koleksiyonlar: next · hasNext (predicate) · remove |
| Java 5.0 | foreach denen ama for anahtar sözcüğünü kullanan biçim; Iterable gerçekleyen her sınıf için: for (String s : aList) |
| Perl | Array ve hash'ler için yerleşik foreach |
| C#, F# | Generic kütüphane sınıfları üzerinde foreach |
Unconditional branching (goto)
• Java'da
goto yoktur.• C#'ta vardır (switch içinde kullanılabilir).
• Slaytın kilit cümlesi: "Loop exit statements are restricted and somewhat camouflaged goto's" — yani
break/continue aslında kısıtlanmış ve kamufle edilmiş goto'lardır.
Hoca: başlangıçta goto "en önemli ve çok başarılı" yaklaşımlardan biriydi — bu tarihsel dengeyi kurmak açık uçlu cevabı güçlendirir.
Hocanın kendi cümlesi: "it is essentially a question how much a language should be expanded to increase its writability at the expense of its simplicity, size, and portability" — bu, dersin en başındaki readability/writability/reliability üçlüsünün buradaki yansımasıdır.
Ayrıca: fonksiyonel ve mantıksal programlama dilleri oldukça farklı kontrol yapıları kullanır.
7 · Subprograms
Ch.9 · 28 Temmuz dersi (Quiz 2 bu derste yapıldı) · Slayt: Lecture #7
Aynı örüntü Quiz 3'te de var (4 Ağustos, ADT dersi → ADT sorusu yok). Sonuç: hocanın quiz'leri o günkü dersi değil, birikimli olarak tüm dönemi yokluyor. Gerçek sorular ve bunun finale etkisi için → Quiz 2 & 3'ün gerçek soruları.
İki temel soyutlama — dersin çatısı
| Soyutlama | Ne zaman öne çıktı | Nerede işlenir |
|---|---|---|
| Process abstraction (süreç soyutlaması) | İlk günlerden beri vurgulandı | Bu bölüm (Ch.9) |
| Data abstraction (veri soyutlaması) | 1980'lerde vurgulandı | Ch.11 (Lecture #9) |
Hocanın eklediği kritik cümle: bugün ikisi eşit derecede önemli soyutlamalar sayılır. Bu, "process vs data abstraction" karşılaştırma sorusunun cevabıdır.
Subprogram'ların üç temel özelliği
- Her subprogram'ın tek bir giriş noktası (single entry point) vardır.
- Çağıran program, çağrılan subprogram çalışırken askıya alınır (suspended).
- Çağrılan subprogram bitince kontrol her zaman çağırana döner.
Temel tanımlar — tanım sorusu deposu
| Terim | Tanım |
|---|---|
| subprogram definition | Subprogram soyutlamasının arayüzünü ve eylemlerini tanımlar |
| subprogram call | Subprogram'ın çalıştırılması için açık bir istek |
| subprogram header | Tanımın ilk kısmı: ad + subprogram türü + formal parametreler |
| parameter profile (= signature) | Parametrelerin sayısı, sırası ve tipleri |
| protocol | parameter profile + (fonksiyonsa) dönüş tipi |
| subprogram declaration | Protokolü verir ama gövdeyi vermez. C/C++'ta buna prototype denir |
| formal parameter | Header'da listelenen ve subprogram içinde kullanılan dummy (kukla) değişken |
| actual parameter | Çağrı deyiminde kullanılan bir değer veya adres |
Yani protocol, profile'ı kapsar. "Overloaded subprogram'ların her versiyonu benzersiz bir protokole sahiptir" cümlesi de buraya bağlanır.
Dil istisnaları (tek tek sorulabilir):
- Python: fonksiyon tanımları çalıştırılabilirdir (executable) — diğer tüm dillerde çalıştırılabilir değildir.
- Ruby: fonksiyon tanımları sınıf tanımının içinde veya dışında olabilir; dışındaysa
Object'in metodudur ve nesnesiz çağrılabilir. - Lua: tüm fonksiyonlar anonimdir.
Actual/Formal parametre karşılığı
| Positional | Keyword | |
|---|---|---|
| Kural | Bağlama konuma göre: ilk actual → ilk formal | Actual parametreyle birlikte formal parametrenin adı belirtilir |
| Avantaj | Safe and effective (slaytın kendi ifadesi) | Parametreler herhangi bir sırada yazılabilir → karşılık hataları önlenir |
| Dezavantaj | Liste uzunsa programcı hata yapar | Kullanıcı formal parametre adlarını bilmek zorundadır |
Default değerler: C++, Python, Ruby, Ada, PHP formal parametrelere varsayılan değer verebilir. C++'ta default parametreler en sonda olmak zorundadır — çünkü parametreler konumsal olarak eşleşir.
| Dil | Değişken sayıda parametre nasıl |
|---|---|
| C# | Aynı tipte olmak kaydıyla; formal parametre params öneki alan bir array'dir |
| Ruby | Actual'lar bir hash literal'in elemanları olarak gönderilir; formal parametre yıldız ile öncelenir |
| Python | Bir yıldız → tuple; iki yıldız → hash/dictdef fun1(p1,p2,*p3,**p4) → fun1(2,4,6,8,mon=68,tue=72) ile p3=[6,8], p4={'mon':68,'tue':72} |
| Lua | Üç nokta (...) ile; for ya da çoklu atamayla erişilir |
Procedure vs Function
| Procedure | Function |
|---|---|
| Parametreli hesaplamaları tanımlayan deyimler topluluğu | Yapısal olarak procedure'a benzer ama semantik olarak matematiksel fonksiyonlara göre modellenmiştir |
| — | Side effect üretmemesi beklenir — ama pratikte program fonksiyonlarının side effect'i vardır |
Subprogram tasarım soruları (11 madde)
Hoca "subprogram'lar karmaşık yapılardır, bu yüzden çok soru var" dedi. Liste:
- Local değişkenler static mi dynamic mi?
- Subprogram tanımları başka subprogram tanımlarının içinde görünebilir mi? (nesting)
- Hangi parameter passing yöntemleri sunuluyor?
- Parametre tipleri denetleniyor mu?
- Subprogram'lar parametre olarak geçirilebiliyor ve nesting varsa, geçirilen subprogram'ın referencing environment'ı nedir?
- Functional side effect'lere izin var mı?
- Fonksiyonlardan hangi tipte değerler dönebilir?
- Fonksiyonlardan kaç değer dönebilir?
- Subprogram'lar overload edilebilir mi?
- Subprogram'lar generic olabilir mi?
- Nesting varsa closure destekleniyor mu?
Local referencing environments
| Stack-dynamic locals | Static locals | |
|---|---|---|
| Avantajlar | • Recursion desteği • Depolama bazı subprogram'lar arasında paylaşılır | Stack-dynamic'in dezavantajlarının tersi: allocation maliyeti yok, doğrudan adresleme, history sensitive olabilir |
| Dezavantajlar | • Allocation/deallocation ve initialization zamanı • Indirect addressing • Subprogram'lar history sensitive olamaz | • Recursion'ı destekleyemez • Depolama, etkin olmayan subprogram'ların local'leriyle paylaşılamaz |
Diller: çoğu çağdaş dilde local'ler stack-dynamic'tir. C tabanlı dillerde varsayılan stack-dynamic ama
static ile bildirilebilir. C++, Java, Python ve C#'ın metotlarında yalnızca stack-dynamic local'ler vardır.
int adder(int list[], int listlen) {
static int sum = 0; // static
int count; // stack dynamic
for (count = 0; count < listlen; count++)
sum += list[count];
return sum;
}
sum static, count stack-dynamic. Bu kod Java'da yasal değildir — slayt bunu özellikle not düşer.
Parameter passing — semantik modeller
| Mod | Veri akışı |
|---|---|
| In mode | Subprogram, actual parametreden veri alır |
| Out mode | Subprogram, actual parametreye veri iletir |
| Inout mode | Her ikisi |
Beş parameter passing yöntemi — bu bölümün kalbi
| Yöntem | Mod | Nasıl çalışır | Avantaj | Dezavantaj |
|---|---|---|---|---|
| Pass-by-value | in | Actual'ın değeri formal'i initialize eder; normalde kopyalayarak | Skalerler için hızlı (hem linkage hem erişim) | Kopyalıysa: ek depolama (iki kez saklanır) + büyük parametrelerde pahalı taşıma Access path ile yapılırsa: write-protect gerekir (kolay değil) ve indirect addressing yüzünden erişim pahalanır |
| Pass-by-result | out | Subprogram'a hiçbir değer iletilmez; formal local değişken gibi davranır, dönüşte değeri actual'a fiziksel taşımayla aktarılır | — | Ek depolama + kopyalama işlemi Actual parameter collision (aşağıda) |
| Pass-by-value-result | inout | İkisinin birleşimi. Diğer adı: pass-by-copy. Formal'lerin local depolaması vardır | — | Hem pass-by-result'ın hem pass-by-value'nun dezavantajları |
| Pass-by-reference | inout | Bir access path (adres) geçirilir. Diğer adı: pass-by-sharing. | Çok verimli — kopyalama yok, depolama tekrarı yok | • Erişim daha yavaş (indirect addressing) • İstenmeyen side effect / collision • İstenmeyen alias'lar — erişim genişler |
| Pass-by-name | inout | Metinsel yerine koyma (textual substitution): actual, formal'in tüm geçtiği yerlere metin olarak konur. Formal'ler çağrı anında bir erişim yöntemine bağlanır; değere/adrese asıl bağlanma referans veya atama anında olur | Geç bağlamada (late binding) esneklik | Gerçeklemesi karmaşık ve verimsiz; readability ve reliability'yi düşürür. Caller'ın referencing environment'ının geçirilmesini gerektirir |
sub(p1, p1); → hangi formal en son geri kopyalanırsa p1'in değeri o olur.sub(list[sub], sub); → list[sub]'un adresi subprogram'ın başında mı sonunda mı hesaplanacak?C# örneği (slaytta ayrı bir sayfa):
void Fixer(out int x, out int y) {
x = 17;
y = 35;
}
f.Fixer(out a, out a);
x önce atanırsa a = 35; y önce atanırsa a = 17.
Slaytın notu: bu sıra implementation dependent'tır. — Bu, "aşağıdakilerden hangisi belirsizdir" tipi soru için mükemmel bir adaydır.
fun(total, total); · fun(list[i], list[j]); · fun(list[i], i);Hocanın zinciri: aliasing → readability düşer → reliability düşer → program doğrulaması (verification) zorlaşır. Bu zinciri açık uçlu soruda aynen kullan.
Ek soru: geçirilen referans, çağrılan subprogram'da değiştirilebilir mi?
C'de mümkündür (bu yüzden C'de altprogram yazımını takip etmek zorlaşır).
Pascal ve C++'ta adres olan formal parametreler örtük olarak dereference edilir → bu tür değişiklikler engellenir.
Parameter passing'in gerçeklenmesi
Çoğu dilde parametre iletişimi run-time stack üzerinden olur. Pass-by-reference gerçeklemesi en kolayıdır — stack'e yalnızca bir adres konur. Pass-by-value'da değerler stack konumlarına kopyalanır ve o konumlar formal parametrelerin deposu olur. Pass-by-result, pass-by-value'nun tersidir.
void sub(int a, int b, int c, int d) · sub(w, x, y, z) ile:w → pass-by-value · x → pass-by-result · y → pass-by-value-result · z → pass-by-reference
Stack'te: a için değer, b için atama hedefi, c için hem değer hem atama, d için adres.
Büyük dillerin parameter passing yöntemleri
| Dil | Yöntem |
|---|---|
| C | Pass-by-value; pass-by-reference pointer/reference parametrelerle elde edilir |
| C++ | Pass-by-reference için özel bir pointer türü: reference type |
| Java | Tüm non-object parametreler by value → hiçbir metot bunları değiştiremez. Object parametreleri by reference. |
| Ada | Üç semantik mod: in, out, in out. in varsayılandır.out atanabilir ama okunamaz; in okunabilir ama atanamaz; in out ikisi de |
| Fortran 95+ | Parametreler in / out / inout olarak bildirilebilir (Ada'ya benzer) |
| C# | Varsayılan by value; by reference için hem formal hem actual ref ile öncelenir |
| PHP | C#'a çok benzer, farkı: actual veya formal'den yalnızca biri ref belirtebilir |
| Swift | Varsayılan by value; by reference için formal inout ile öncelenir |
| Perl | Tüm actual parametreler @_ adlı önceden tanımlı bir array'e örtük olarak konur |
| Python, Ruby | Pass-by-assignment — tüm veri değerleri nesnedir; actual, formal'e atanır |
Parametrelerin tip denetimi
Reliability için çok önemli sayılır. Hoca ısrarla tekrarladı.
| Politika | Diller |
|---|---|
| Hiç yok | FORTRAN 77, orijinal C |
| Her zaman zorunlu | Pascal, Java |
| Seçim kullanıcıya ait (prototype üzerinden) | ANSI C, C++ |
| Gerektirmez | Perl, JavaScript, PHP |
| Mümkün değil | Python, Ruby — değişkenlerin tipi yoktur, nesnelerin vardır |
Çok boyutlu array'lerin parametre olarak geçirilmesi
Row major order için:
address(mat[i,j]) = address(mat[0,0]) + i × number_of_columns + jBize gereken sütun sayısıdır, satır sayısı değil. Bu yüzden C/C++'ta:
void fun(int matrix[][10]) — ikinci köşeli parantez dolu olmak zorundadır.Sonuç: esnek subprogram yazmayı engeller. Çözüm: array'e pointer + boyutları ayrı parametre olarak geçir, storage mapping fonksiyonunu programcı yazsın.
| Dil | Yaklaşım |
|---|---|
| C/C++ | İlk subscript hariç tüm boyutların bildirilmesi zorunlu |
| Fortran | Boyutlar parametre olarak gönderilir ve formal parametrenin bildiriminde kullanılır. Fortran array'leri column major saklar. |
| Java, C# | Array'ler nesnedir; hepsi tek boyutludur ama elemanları array olabilir. Her array length/Length sabitini miras alır.Slaytın notu: Java'nın gerçek iki boyutlu array'i yoktur — gerçek 2D'de elemanlar bitişik bellek bloğundadır, Java'da değil. |
Parameter passing'in tasarım gerilimi
Bu ikisi çatışır: iyi programlama, değişkenlere sınırlı erişimi önerir → mümkün olduğunca tek yönlü. Ama büyük yapılar için pass-by-reference daha verimlidir.
Hocanın verdiği pratik kural (çağdaş yazılım mühendisliği ilkesi):
- Parametreler yoluyla caller'a veri dönmeyecekse → in-mode kullan.
- Çağrılan subprogram'a veri aktarılmayacaksa → out-mode kullan.
Parametre olarak subprogram adları
İki mesele: (1) parametre tipleri denetleniyor mu? (2) parametre olarak gönderilen subprogram için doğru referencing environment nedir?
- C ve C++: fonksiyonlar parametre olarak geçirilemez ama fonksiyon pointer'ları geçirilebilir ve tipleri parametre tiplerini de içerdiği için tip denetimi yapılabilir.
- Java, metot adlarının parametre olarak geçirilmesine izin vermez.
| Binding | Hangi ortam kullanılır | Hangi dil için doğal |
|---|---|---|
| Shallow binding | Geçirilen subprogram'ı çalıştıran çağrı deyiminin ortamı | Dynamic-scoped diller |
| Deep binding | Geçirilen subprogram'ın tanımının ortamı | Static-scoped diller |
| Ad hoc binding | Subprogram'ı geçiren çağrı deyiminin ortamı | — |
sub1 içinde x, sub3 içinde x=3,
sub4 içinde x=4; sub3 → sub4(sub2) → subx() → sub2 çalışır ve x'i yazar.
Hangi x? deep binding → sub1'in x'i (1) · ad hoc → sub3'ün x'i (3) · shallow → sub4'ün x'i (4).
Subprogram'ları dolaylı çağırma
Ne zaman gerekir: çağrılabilecek birkaç subprogram varsa ve doğru olanı çalışma zamanına kadar bilinmiyorsa — tipik örnek: event handling ve GUI'ler.
- C/C++: function pointer'lar üzerinden.
- C#: metot pointer'ları delegate denen nesneler olarak gerçeklenir.
public delegate int Change(int x);—intalıpintdöndüren herhangi bir metotla örneklenebilir. Bir delegate birden fazla adres tutabilir → buna multicast delegate denir.
Fonksiyonlar için tasarım soruları
Side effect'lere izin var mı? — Ada gibi parametreler side effect'i azaltmak için her zaman in-mode olmalı.
| Dil | Dönebilen tipler |
|---|---|
| Çoğu imperative dil | Dönüş tiplerini kısıtlar |
| C | Array ve fonksiyon dışında her tip |
| C++ | C gibi + kullanıcı tanımlı tipler |
| Java, C# | Her tip — ama metotlar tip olmadığı için metot döndürülemez |
| Python, Ruby | Metotlar first-class object'tir → döndürülebilirler |
Overloaded ve Generic subprograms
Overloaded subprogram: aynı referencing environment'ta başka bir subprogram'la aynı ada sahip subprogram.
Her versiyonun benzersiz bir protokolü vardır.
C++, Java, C#, Ada önceden tanımlı overloaded subprogram'lar içerir ve kullanıcının da yazmasına izin verir.
Ada'nın ayrıcalığı: overloaded bir fonksiyonun dönüş tipi çağrıları ayırt etmek için kullanılabilir
→ yani Ada'da iki overloaded fonksiyon aynı parametrelere sahip olabilir. Diğer dillerde olamaz.
| Tür | Nasıl sağlanır |
|---|---|
| Ad hoc polymorphism | Overloaded subprogram'lar |
| Subtype polymorphism | T tipindeki bir değişken, T'den türetilmiş herhangi bir nesneye erişebilir (OOP dilleri) |
| Parametric polymorphism | Generic parametre alan subprogram. Slaytın notu: dynamic binding'in ucuz bir compile-time ikamesi |
| Dil | Generic gerçeklemesi |
|---|---|
| C++ | Versiyonlar örtük olarak yaratılır (çağrıda adı geçince ya da & ile adresi alınınca).
template <class Type> clause'u ile öncelenir |
| Java 5.0 | C++'tan dört farkı: 1. Generic parametreler sınıf olmak zorunda 2. Generic metotlar yalnızca bir kez, gerçekten generic metotlar olarak örneklenir 3. Geçirilebilecek sınıf aralığına kısıt konabilir ( <T extends Comparable>)4. Wildcard tipler ( Collection<?>) |
| C# 2005 | Java 5.0'a benzer. Farkları: derleyici çıkarabiliyorsa çağrıda tip parametreleri atlanabilir; C# wildcard desteklemez |
| F# | Tipi belirleyemezse generic çıkarır — automatic generalization. Tipler kesme işareti + harf ile gösterilir ('a).
Parametreler aritmetik operatörlerle kullanılırsa generic bile olsalar tip kısıtlanır;
tip çıkarımı ve coercion yokluğu yüzünden F#'ın generic fonksiyonları C++/Java/C#'tan çok daha az kullanışlıdır. |
Kullanıcı tanımlı overloaded operatörler: Ada, C++, Python, Ruby.
Python örneği: def __add__(self, second): — x + y aslında x.__add__(y)'dir.
Closures
Ne zaman gerekir? (üç koşullu mantık zinciri)
- Referencing environment, subprogram programın herhangi bir yerinden çağrılabiliyorsa gereklidir.
- Nested subprogram'a izin vermeyen static-scoped bir dilin closure'a ihtiyacı yoktur.
- Closure yalnızca subprogram çevreleyen scope'lardaki değişkenlere erişebiliyorsa ve her yerden çağrılabiliyorsa gerekir.
- Desteklemek için gerçekleme, bazı değişkenlere unlimited extent sağlamak zorunda kalabilir — çünkü subprogram, normalde artık yaşamayan bir non-local değişkene erişebilir.
function makeAdder(x) {
return function(y) {return x + y;}
}
var add10 = makeAdder(10);
var add5 = makeAdder(5);
add10(20) // 30
add5(20) // 25
Closure, makeAdder'ın döndürdüğü anonim fonksiyondur — x'i yanında taşır.
C# karşılığı: iç içe anonim delegate ile aynı closure yazılır;
Func<int,int>
int alıp int döndüren bir delegate belirtir.
Hocanın notu: "closures are much more important when you have nested environments".
Coroutines
- Buna symmetric control da denir: çağıran ve çağrılan daha eşit bir temeldedir (normal subprogram'da ilişki asimetriktir — biri efendi, biri hizmetkâr).
- Coroutine çağrısının adı resume'dur.
- İlk resume başa gider; sonraki çağrılar en son çalıştırılan deyimin hemen ardından girer.
- Coroutine'ler birbirlerini tekrar tekrar, hatta sonsuza dek resume edebilir.
- Program birimlerinin quasi-concurrent (yarı eşzamanlı) çalışmasını sağlar: yürütme iç içe geçer (interleaved) ama üst üste binmez (not overlapped).
- Subprogram tanımı, subprogram'ın temsil ettiği eylemleri anlatır.
- Subprogram'lar fonksiyon veya procedure olabilir.
- Local değişkenler stack-dynamic veya static olabilir.
- Üç parameter passing modeli: in, out, inout.
- Bazı diller operator overloading'e izin verir.
- Subprogram'lar generic olabilir.
- Closure = subprogram + referencing environment'ı.
- Coroutine = birden çok girişi olan özel subprogram.
8 · Implementing Subprograms
Ch.10 · 3 Ağustos dersi (elektrik kesintisi nedeniyle asenkron kayıt) · Slayt: Lecture #8
Subprogram linkage — genel semantik
Tanım: Bir dilin subprogram çağrı ve dönüş işlemlerine birlikte subprogram linkage denir.
- Parameter passing yöntemleri
- Local değişkenlerin stack-dynamic ayrılması
- Çağıran programın execution status'unun saklanması
- Kontrolün aktarılması ve dönüşün ayarlanması
- Subprogram nesting destekleniyorsa non-local değişkenlere erişimin ayarlanması
- in mode ve inout mode parametrelerin değerleri geri döndürülmeli
- Stack-dynamic local'lerin deallocation'ı
- Execution status'un geri yüklenmesi
- Kontrolün caller'a döndürülmesi
"Simple" subprogram'ların gerçeklenmesi
| Call semantics | Return semantics |
|---|---|
|
• Caller'ın execution status'unu sakla • Parametreleri geçir • Dönüş adresini çağrılana geçir • Kontrolü çağrılana aktar |
• pass-by-value-result / out mode parametre varsa güncel değerleri actual'lara taşı • Fonksiyonsa dönüş değerini caller'ın alabileceği bir yere taşı • Caller'ın execution status'unu geri yükle • Kontrolü caller'a geri aktar |
Gerekli depolama: status bilgisi · parametreler · dönüş adresi · (fonksiyonsa) dönüş değeri · geçici değerler (temporaries).
activation record = kod-olmayan kısmın biçimi / yerleşimi (format, layout)
activation record instance (ARI) = bu biçimin somut bir örneği — belirli bir subprogram etkinleşmesine ait veri topluluğu.
Ayrımı şöyle tut: activation record bir şablon, ARI o şablonun doldurulmuş bir kopyası. Bu ayrım neredeyse kesin sorulur.
Stack-dynamic local değişkenlerle gerçekleme
Activation record daha karmaşık olur çünkü:
- Derleyici, local değişkenlerin örtük allocation/deallocation'ı için kod üretmelidir.
- Recursion desteklenmelidir — bu, bir subprogram'ın aynı anda birden çok etkinleşmesi olasılığını ekler.
- Activation record'un biçimi static'tir ama boyutu dynamic olabilir. (Çok sevilen bir ayrım.)
- Dynamic link, caller'ın activation record instance'ının tepesini gösterir.
- Bir ARI, subprogram çağrıldığında dinamik olarak yaratılır.
- ARI'lar run-time stack'te bulunur.
- Environment Pointer (EP) run-time sistem tarafından korunur ve her zaman o an çalışan program biriminin ARI'sının tabanını gösterir.
- Her subprogram etkinleşmesi — recursive olsun olmasın — stack'te yeni bir ARI yaratır. Bu, parametrelerin, local'lerin ve dönüş adresinin ayrı kopyalarını sağlar.
Gözden geçirilmiş çağrı/dönüş eylemleri
| Aşama | Eylemler |
|---|---|
| Caller actions (çağıranın yaptıkları) |
• Bir ARI yarat • Mevcut program biriminin execution status'unu sakla • Parametreleri hesapla ve geçir • Dönüş adresini çağrılana geçir • Kontrolü aktar |
| Prologue (çağrılanın giriş eylemleri) |
• Eski EP'yi stack'e dynamic link olarak sakla ve yeni değeri kur • Local değişkenleri ayır |
| Epilogue (çağrılanın çıkış eylemleri) |
• pass-by-value-result / out-mode parametre varsa değerleri actual'lara taşı • Fonksiyonsa değerini caller'ın erişebileceği yere taşı • Stack pointer'ı güncel EP−1'e ayarla; EP'yi eski dynamic link'e kur • Caller'ın execution status'unu geri yükle • Kontrolü geri aktar |
Dynamic chain ve local_offset
local_offset: Local değişkenlere, activation record'un başlangıcına göre offset'leriyle erişilir (başlangıç adresi EP'dedir). Bu offset'in adı local_offset'tir.
Bir local değişkenin local_offset'i derleyici tarafından, derleme zamanında belirlenebilir.
Erişim formülü:
adres = EP + local_offsetSlayttaki örnek:
fun1 içinde s'nin local_offset'i 3, t'ninki 4.
int factorial(int n) {
if (n <= 1) return 1;
else return (n * factorial(n − 1));
}
void main() {
int value;
value = factorial(3);
}
Her factorial çağrısı stack'te yeni bir ARI yaratır. Hocanın vurguladığı nokta:
fonksiyonun kodu, parametrenin güncel değerini, özyinelemeli çağrının döndürdüğü değerle çarpar;
ilk dönüş değeri 1'dir ve sonra stack geri sarılırken çarpımlar birikir.
Slaytta "stacks for calls" ve "stacks for returns" diye iki ayrı şema var — ikisine de bak.
Nested subprograms
Bazı C tabanlı olmayan static-scoped diller (Fortran 95+, Ada, Python, JavaScript, Ruby, Swift) stack-dynamic local kullanır ve subprogram'ların iç içe olmasına izin verir.
Temel gerçek: non-local erişilebilen tüm değişkenler, stack'teki bir ARI'nın içindedir.
- Doğru activation record instance'ı bul ← zor olan kısım budur
- O ARI içindeki doğru offset'i belirle ← kolay olan kısım
Neden 1. adım garanti çalışır? Çünkü static semantics kuralları, referans verilebilecek tüm non-local değişkenlerin, referans anında stack'te bulunan bir ARI'da ayrılmış olmasını garanti eder.
Static chain — static scoping'in gerçeklenmesi
| Terim | Tanım |
|---|---|
| static link | A subprogram'ının ARI'sındaki static link, A'nın static parent'ının ARI'larından birini gösterir |
| static chain | Belirli ARI'ları birbirine bağlayan static link zinciri; bir ARI'yı tüm static ancestor'larına bağlar |
| static_depth | Bir static scope ile ilişkili tamsayı: o scope'un iç içe geçme derinliği |
| chain_offset | Referansı içeren subprogram'ın static_depth'i eksi bildirimi içeren subprogram'ın static_depth'i |
| Yöntem | |
|---|---|
| Verimsiz (inefficient) | Değişkeni içeren ARI, static chain aranarak bulunur — değişkeni içeren bir static ancestor ARI bulunana kadar |
| Verimli (efficient) | Scope'ların iç içe geçmesi derleme zamanında bilindiği için, derleyici izlenmesi gereken static chain uzunluğunu önceden hesaplayabilir |
main → bigsub → sub2 → sub3 → sub1 çağrı sırasında:
| Konum | Değişken | (chain_offset, local_offset) |
|---|---|---|
sub1 içinde a = b + c | a | (0, 3) — kendi ARI'sında |
| b | (1, 4) — bir halka yukarıda | |
| c | (1, 5) | |
sub3 içinde e = b + a | e | (0, 4) |
| b | (1, 4) | |
| a | (2, 3) — iki halka yukarıda |
Static chain bakımı ve değerlendirmesi
Çağrı anında: ARI kurulmalı · dynamic link zaten eski stack top pointer'ıdır · static link, static parent'ın en güncel ARI'sını göstermelidir. İki yöntem: (1) dynamic chain'i ara; (2) subprogram çağrı ve tanımlarını, değişken referans ve tanımları gibi ele al.
- Nesting derinliği büyükse non-local referans yavaştır (zincirde çok halka gezilir).
- Zaman-kritik kod yazmak zorlaşır:
- (a) Non-local referansların maliyetini belirlemek zordur.
- (b) Kod değişiklikleri nesting derinliğini değiştirebilir, dolayısıyla maliyeti de değiştirir.
Blocks
Tanım: Değişkenler için kullanıcının belirlediği local scope'lar.
{ int temp;
temp = list[upper];
list[upper] = list[lower];
list[lower] = temp;
}
temp'in lifetime'ı, kontrol bloğa girdiğinde başlar.
Avantajı: aynı ada sahip başka hiçbir değişkenle çakışmaz.
| Blokları gerçekleme — iki yöntem | Nasıl |
|---|---|
| 1. Blokları parametresiz subprogram gibi ele al | Her zaman aynı yerden çağrılır; her bloğun bir activation record'u vardır ve blok her çalıştığında bir instance yaratılır |
| 2. Statik ayırma | Bir blok için gereken maksimum depolama derleme zamanında belirlenebildiği için, bu alan activation record'da local değişkenlerden sonra ayrılabilir |
Dynamic scoping'in gerçeklenmesi
| Deep access | Shallow access | |
|---|---|---|
| Mekanizma | Non-local referanslar, dynamic chain üzerindeki ARI'lar aranarak bulunur | Local'ler merkezî bir yere konur |
| Gerçekleme | — | • Her değişken adı için bir stack, veya • Her değişken adı için bir girdisi olan merkezî tablo |
| Sorunlar | • Zincirin uzunluğu statik olarak belirlenemez • Her ARI değişken adlarını taşımak zorundadır | — |
• binding → parametre olarak geçirilen subprogram'ın referencing environment'ı hangisi
• access → dynamic scoping'de non-local değişkene nasıl ulaşılır
- Subprogram linkage semantiği, gerçeklemeden çok sayıda eylem gerektirir.
- Simple subprogram'ların eylemleri görece basittir.
- Stack-dynamic diller daha karmaşıktır.
- Stack-dynamic local'li ve nested subprogram'lı diller iki bileşene sahiptir: asıl kod ve activation record.
- ARI'lar, diğer şeylerin yanında formal parametreleri ve local değişkenleri içerir.
- Static chain'ler, nested subprogram'lı static-scoped dillerde non-local erişimin başlıca yöntemidir.
- Dynamic-scoped dillerde non-local erişim, dynamic chain ya da bir merkezî değişken tablosu yöntemiyle gerçeklenebilir.
9 · Abstract Data Types & Encapsulation
Ch.11 · 4 Ağustos dersi (Quiz 3 bu derste yapıldı) · Slayt: Lecture #9 · elindeki son kayıt
Hoca dersi kapatırken slaytın cümlesini genişletti — açık uçlu bir soruda bu genişletilmiş hâli kullan: "The concept of abstract data types and their use in program design was a milestone in the development of programming as an engineering discipline… that was one of the reasons why we have today's software engineering as an engineering discipline." Ekleyeceğin ikinci cümle: kavram görece basit olsa da, kullanımı ancak diller onu desteklemek üzere tasarlanınca kullanışlı ve güvenli hâle geldi.
- Kuş = iki kanat, iki bacak, kuyruk, tüy (en anlamlı öznitelikler).
- "Karga bir kuştur" dedikten sonra karganın kanatlarını, bacaklarını tarif etmeye gerek kalmaz — onları kuş soyutlamasından alırız. Kargayı artık siyah olmak, gürültücü olmak gibi kendine özgü özniteliklerle tarif ederiz.
- Hocanın nitelemesi: abstraction "karmaşıklığa karşı bir silah" (a weapon against complexity) — programcının temel özniteliklere odaklanıp ikincil olanları göz ardı etmesini sağlar.
fly() koydun.
Sonra penguen ve devekuşunun uçmadığını fark ettin. fly() yerine move() / changeLocation()
koyarsın — kartal ve serçe gibi istemciler için hiçbir şey değişmez; kimi uçar, kimi yüzer, kimi koşar,
ama hepsi konum değiştirir. İç temsili değiştirdin, istemci kodu etkilenmedi — ADT'nin birinci koşulunun
tüm faydası bu tek örnekte.
Slaytın kendi örneği de aynı fikri anlatır: stack'in gerçeklemesi linked list'ten array'e çevrilirse stack tipini tanımlayan kod değişir ama istemcilerin hiçbirinde değişiklik gerekmez. Ama bir işlemin protokolü değişirse istemciler de değişmek zorundadır.
Abstraction kavramı
- Abstraction kavramı programlamada (ve bilgisayar biliminde) temeldir.
- Neredeyse tüm diller process abstraction'ı subprogram'larla destekler.
- Neredeyse 1980'den beri tasarlanan tüm diller data abstraction'ı destekler.
| Dönem | Ne oldu |
|---|---|
| 1940'lar | Plankalkül, process abstraction'ı destekleyen ilk dil — process abstraction dil tasarımındaki en eski soyutlamadır |
| 1960'lar | Data abstraction'ın evrimi başlar: COBOL'un ilk sürümleri, record veri yapısıyla |
| 1980'ler | Data abstraction yaygınlaşır; 1980'den sonra tasarlanan neredeyse tüm diller destekler |
Floating point örneği (adım adım):
- Tip, float veri saklayacak değişken yaratma aracı sunar ✔ (ADT koşulu)
- Bu tipin nesnelerini işlemek için bir işlem kümesi sunar ✔
- Değerin bellek hücresindeki gerçek biçimi kullanıcıdan gizlidir ✔ (information hiding) — kullanıcı temsilin parçalarını doğrudan değiştiremez, yalnızca dilin verdiği işlemleri kullanabilir
Bu, Lecture #5'teki IEEE 754 konusunu ADT çerçevesine bağlar — iki bölümü birleştiren soru gelirse hazır ol.
Abstract data type — iki koşullu tanım
- Tipin nesnelerinin temsili (representation), bu nesneleri kullanan program birimlerinden gizlidir; dolayısıyla mümkün olan tek işlemler, tipin tanımında sağlananlardır.
- Tipin bildirimi ve tip üzerindeki işlemlerin protokolleri tek bir sözdizimsel birimde (single syntactic unit) bulunur. Diğer program birimlerinin, tanımlı tipten değişken yaratmasına izin verilir.
Avantajlar — hangi koşuldan hangi avantaj geliyor
| 1. koşulun (gizleme) avantajları | 2. koşulun (tek birim) avantajları |
|---|---|
|
• Reliability — veri temsili gizlendiği için kullanıcı kodu nesnelere doğrudan erişemez veya temsile bağımlı olamaz;
böylece temsil, kullanıcı kodunu etkilemeden değiştirilebilir • Programcının farkında olması gereken kod ve değişken aralığını azaltır • İsim çakışmaları daha az olasıdır |
• Bir program organizasyonu yöntemi sağlar • Modifiability'ye yardım eder — bir veri yapısıyla ilgili her şey bir aradadır • Ayrı derleme (separate compilation) |
Dilin ADT için sağlaması gerekenler (üç madde):
- Tip tanımını kapsülleyecek bir sözdizimsel birim
- Tip adlarını ve subprogram header'larını istemcilere görünür kılan, ama asıl tanımları gizleyen bir yöntem
- Bazı ilkel işlemlerin dil işlemcisinin içine gömülü olması
Üç tasarım sorusu: Abstract tipler parametreleştirilebilir mi? · Hangi erişim denetimleri sunuluyor? · Tipin spesifikasyonu, gerçeklemesinden fiziksel olarak ayrı mı?
Dil örneği: C++
- Temeli: C'nin
structtipi + Simula 67'nin sınıfları. (Simula 67 vurgusu vizedeki tarih dersinin devamı.) - class kapsülleme aracıdır. Bir sınıf bir tiptir.
- Bir sınıfın tüm örnekleri üye fonksiyonların tek bir kopyasını paylaşır; ama her örneğin kendi veri üyeleri kopyası vardır. (Bu ayrım çok sorulur.)
- Örnekler static, stack dynamic veya heap dynamic olabilir.
| Clause | Ne için |
|---|---|
| private | Gizlenen varlıklar |
| public | Arayüz varlıkları |
| protected | Inheritance için (Ch.12) |
Constructor ve Destructor
| Constructor | Destructor | |
|---|---|---|
| Görev | Örneklerin veri üyelerini başlatan fonksiyonlar — nesneyi yaratmazlar | Bir örnek yok edildikten sonra temizlik; genelde heap depolamasını geri kazanmak |
| Ek görev | Nesnenin bir kısmı heap-dynamic ise depolama da ayırabilir | — |
| Ne zaman çağrılır | Örnek yaratıldığında örtük; açıkça da çağrılabilir | Nesnenin lifetime'ı bittiğinde örtük; açıkça da çağrılabilir |
| Ad | Sınıf adıyla aynı | Sınıf adı, önünde tilde (~) |
Slaytta ayrı bir kutuda vurgulanmış. Bu, "Java ile C++'ın ADT desteği arasındaki fark nedir" sorusunun en kolay puanlık maddesidir.
class Stack {
private:
int *stackPtr, maxLen, topPtr;
public:
Stack() { // constructor
stackPtr = new int[100];
maxLen = 99;
topPtr = -1;
};
~Stack() {delete [] stackPtr;}; // destructor
void push(int number) { … };
void pop() { … };
int top() { … };
int empty() { … };
}
Ayrı derleme örgüsü: Stack.h (arayüz = prototipler) + Stack.cpp (gerçekleme).
Bu ikiye bölme, ADT'nin "spesifikasyon gerçeklemeden fiziksel olarak ayrı mı" tasarım sorusunun cevabıdır.
friend: C++ bazı ilgisiz birim veya fonksiyonlara private üyelere erişim vermek için friend fonksiyon/sınıflarını sunar — slaytın notu: "Necessary in C++".
Dil örneği: Java
- Tüm kullanıcı tanımlı tipler sınıftır (C++'ta
structda olabilir). - Tüm nesneler heap'ten ayrılır ve reference değişkenlerle erişilir.
- Sınıflardaki tek tek varlıkların access control modifier'ı vardır (clause değil).
- Tüm nesneler için örtük garbage collection (destructor yok).
- İkinci bir scoping mekanizması: package scope — friend'in yerine kullanılabilir. Bir paketteki tüm sınıflarda, access control modifier'ı olmayan tüm varlıklar paket boyunca görünürdür.
Dil örneği: C#
- C++ ve Java temelli.
- İki erişim belirteci ekler:
internalveprotected internal. - Tüm sınıf örnekleri heap dynamic'tir.
- Tüm sınıflar için varsayılan constructor vardır.
- Çoğu heap nesnesi için garbage collection kullanılır, destructor nadiren kullanılır.
struct'lar, inheritance'ı desteklemeyen hafif sınıflardır.
C# property'leri sunar: getter ve setter'ı açık metot çağrısı gerektirmeden gerçeklemenin yolu.
public class Weather {
public int DegreeDays { // property
get { return degreeDays; }
set {
if (value < 0 || value > 30)
Console.WriteLine("Value is out of range: {0}", value);
else degreeDays = value; }
}
private int degreeDays;
}
…
w.DegreeDays = degreeDaysToday; // setter çalışır
oldDegreeDays = w.DegreeDays; // getter çalışır
Dikkat: kullanım alan erişimi gibi görünür ama arkada metot çalışır — property'nin bütün fikri budur.
Dil örneği: Ruby
| Özellik | Ruby'de |
|---|---|
| Kapsülleme aracı | class |
| Local değişkenler | "Normal" adlar |
| Instance değişkenleri | Tek @ ile başlar |
| Class değişkenleri | Çift @@ ile başlar |
| Instance metotları | Ruby fonksiyon sözdizimi (def … end) |
| Constructor | initialize adında ve sınıf başına yalnızca bir tane; new çağrılınca örtük çalışır.
Daha fazla constructor gerekiyorsa farklı adları olmalı ve new'i açıkça çağırmalıdırlar |
| Erişim | private veya public; varsayılan public |
| Sınıflar | Dinamiktir (çalışma zamanında değişebilir) |
Parameterized ADTs (generic classes)
Yalnızca statik tipli diller için bir sorundur — dinamik tipli dilde zaten her şey saklanabilir. Bu cümle sınavda "neden Python'da generic'e gerek yok" biçiminde sorulabilir.
Diğer adı: generic classes. Destekleyenler: C++, Java 5.0, C# 2005.
| Dil | Nasıl |
|---|---|
| C++ | İki düzey: (a) parametreli constructor ile kısmen generic (Stack stk(150););
(b) eleman tipini parametrelemek için sınıfı templated class yap:
template <class Type> class Stack {…} → örnekleme Stack<int> myIntStack; |
| Java 5.0 | • Generic parametreler sınıf olmak zorunda • En yaygın generic tipler koleksiyonlar: LinkedList, ArrayList• Çıkarılan nesneleri cast etme ihtiyacını ortadan kaldırır • Yapıda birden çok tip bulunma sorununu ortadan kaldırır • Generic koleksiyon sınıfları primitive saklayamaz • Indexing desteklenmez Stack2<String> myStack = new Stack2<String>(); |
| C# 2005 | Java 5.0'a benzer, farkları: wildcard sınıflar yok; Array, List, Stack, Queue, Dictionary için önceden tanımlı; parameterized yapıların elemanlarına indexing ile erişilebilir (Java'nın tersi) |
Encapsulation constructs
- Subprogram'lara bölmenin ötesinde bir organizasyon yolu
- Bir kısmi derleme yolu — programın tamamından küçük derleme birimleri
| Yöntem | Açıklama |
|---|---|
| Nested subprograms | Subprogram tanımlarını, onları kullanan mantıksal olarak daha büyük subprogram'ların içine yerleştirerek organize etme. Destekleyenler: Python, JavaScript, Ruby |
| C'de encapsulation | Bir veya birkaç subprogram içeren dosyalar bağımsız derlenebilir; arayüz bir header dosyasına konur; #include ile dahil edilir.Problem 1: linker, header ile gerçekleme arasındaki tipleri denetlemez. Problem 2: pointer'ların doğasındaki sorunlar. |
| C++'ta encapsulation | C gibi header + kod dosyası tanımlanabilir; ya da sınıflar kullanılabilir (sınıf arayüz = prototipler, üye tanımları ayrı dosyada). friend'ler private üyelere erişim verir |
| C# assemblies | Uygulama programlarına tek bir DLL veya çalıştırılabilir gibi görünen bir dosya topluluğu.
Her dosya ayrı derlenebilen bir modül içerir. DLL, çalışan programa tek tek link'lenen sınıf ve metotlar topluluğudur.internal: bir sınıfın internal üyesi, bulunduğu assembly'deki tüm sınıflara görünürdür. |
| Specifier | Same assembly | Other assembly | |||
|---|---|---|---|---|---|
| Declared class | Other class | Derived class | Other class | Derived class | |
| private | Yes | No | No | No | No |
| public | Yes | Yes | Yes | Yes | Yes |
| protected | Yes | No | Yes | No | Yes |
| internal | Yes | Yes | Yes | No | No |
| protected internal | Yes | Yes | Yes | No | Yes |
| private protected (7.2) | Yes | No | Yes | No | No |
internal = "assembly içinde public, dışında private".
Naming encapsulations
Sorun: Büyük programlar çok sayıda global isim tanımlar; bunları mantıksal gruplara ayırmanın yolu gerekir.
Tanım: Bir naming encapsulation, isimler için yeni bir scope yaratmak üzere kullanılır.
| Mekanizma | Dil | Nasıl |
|---|---|---|
| Namespace | C++, C# | Her kütüphane kendi namespace'ine konabilir; dışarıda kullanılan isimler namespace ile nitelenir |
| Package | Java | Birden çok sınıf tanımı içerebilir; bir paketteki sınıflar kısmî friend'dir.
İstemciler tam nitelenmiş ad ya da import bildirimi kullanır |
| Module | Ruby | Ruby sınıfları da naming encapsulation'dır, ama ayrıca module'ler vardır.
Tipik olarak sabit ve metot topluluklarını kapsüller. Modüller örneklenemez ve alt sınıflanamaz; değişken tanımlayamazlar. Modülde tanımlı metotlar modülün adını içermelidir; içeriğe erişim require metoduyla istenir |
| Specifier | Same Package | Different Package | |||
|---|---|---|---|---|---|
| Same Class | Other Class | Derived class | Other class | Derived class | |
| no modifier | Yes | Yes | Yes | No | No |
| private | Yes | No | No | No | No |
| protected | Yes | Yes | Yes | No | Yes |
| public | Yes | Yes | Yes | Yes | Yes |
protected, aynı paketteki diğer sınıflara da açıktır
— C++'ta ise protected yalnızca türetilmiş sınıflara açıktır. Slayt bu farkı "Different than C++" diye işaretlemiş.
- ADT kavramı ve program tasarımında kullanımı, dillerin gelişiminde bir kilometre taşıydı.
- ADT'nin iki temel özelliği: verinin ilgili işlemleriyle paketlenmesi ve information hiding.
- Ada, ADT'leri simüle eden package'lar sunar.
- C++'ta veri soyutlaması sınıflarla sağlanır.
- Java'nın veri soyutlaması C++'ınkine benzer.
- C++, Java 5.0 ve C# 2005 parameterized ADT'leri destekler.
- C++, C#, Java ve Ruby naming encapsulation sağlar.
10 · Support for Object-Oriented Programming
Ch.12 · 10 Ağustos dersi (Quiz 4 dersin hemen ardından) · Slayt: Lecture #10 · dönemin son dersi
Bölümün pusulası — hocanın kendi kurduğu soru: "What should I consider when I'm creating a language which will support the object-oriented paradigm?" Bütün bölüm bu sorunun yedi alt sorusu (tasarım sorusu) ve beş dilin bunlara verdiği farklı cevaplar üzerine kurulu. Açık uçlu bir soruda bu çerçeveyi kurmak tek başına puandır.
⭐⭐ OOP'nin üç dayanağı ve temel kavramlar
- Abstract data types (= encapsulation) — Lecture #9'un konusu
- Inheritance — "inheritance is the central theme in OOP and languages that support it"
- Polymorphism (= dynamic binding)
- Kökler: Simula 67. Kavram oradaydı ama tam olarak gelişmemişti (sınıf/ADT fikri vardı).
- Gerçek başlangıç: Smalltalk 80. Inheritance ve polymorphism dahil tam desteği sunan ilk dil; hocanın deyimiyle "the father of all object-oriented programming languages".
- Hoca tartışmayı da aktardı: kimileri kökeni Simula 67'ye dayandırır, kimileri Smalltalk'u saf model kabul eder — ama "bu büyük bir mesele değil, üzerinde durmayacağız" dedi, yani sınavda bu tartışma sorulmaz.
⭐ Inheritance — neden icat edildi?
Ama ADT'lerle yeniden kullanımın iki problemi var:
| Problem | Neden sorun |
|---|---|
| 1. Değişiklik zorunluluğu | "ADTs are difficult to reuse — always need changes": var olan tipin özellikleri yeni kullanım için hemen hiçbir zaman tam uygun değildir. Değişiklik yapan kişi eski kodu anlamak zorundadır — ve genellikle asıl yazar o değildir. Üstelik değişiklik tüm istemci programlarda da değişiklik gerektirebilir. |
| 2. Hepsi aynı düzeyde | "All ADTs are independent and at the same level": aralarında ata–torun ilişkisi kurulamaz, hepsi kardeş gibidir. Bu yüzden programı, çözdüğü problem uzayına benzer biçimde organize etmek çok zordur. |
Hocanın uyarısı: "ADT'ler OOP için kötüdür" diye anlama — desteklerler ama yetmezler; yalnızca ADT'ye dayanmak software reuse için yeterli değildir.
| Kavram | OOP'deki adı |
|---|---|
| ADT | class |
| Class'ın örneği | object |
| Miras alan sınıf | derived class (C-tabanlı) / subclass (Java) |
| Miras alınan sınıf | parent class / superclass |
| Nesneler üzerindeki işlemleri tanımlayan subprogram | method |
| Metot çağrısı | message |
| Bir nesnenin tüm metotlarının topluluğu | message protocol / message interface |
Message: bir nesneye gönderilen mesaj, onun metotlarından birini çalıştırma isteğidir; ve metodun işleyeceği verinin en az bir kısmı nesnenin kendisinin parçasıdır.
Hocanın cümlesi: "Objects have methods that define processes the object can perform on itself." Nesneler ADT olduğundan, verisini manipüle etmenin tek yolu budur.
"Message ile subprogram call arasındaki fark nedir?" tam bir açık uçlu soru kalıbıdır — cevabı bu iki paragraf.
Bir subclass ebeveyninden üç şekilde farklılaşabilir
- Subclass, miras aldıklarına değişken ve/veya metot ekleyebilir.
- Subclass, miras aldığı bir veya birden çok metodun davranışını değiştirebilir (override). Değiştirilmiş metot aynı ada ve çoğu zaman aynı protokole sahiptir.
- Parent class, bazı değişken veya metotlarını private tanımlayabilir — bunlar subclass'ta görünmez.
| Kaç tane | Ne yapar | |
|---|---|---|
| Class variable | sınıf başına bir (one/class) | Sınıfa aittir, nesnelere değil; tek kopya |
| Instance variable | nesne başına bir (one/object) | Nesnenin state'ini saklar. Aynı sınıfın iki nesnesi arasındaki tek fark, instance değişkenlerinin durumudur |
| Class method | — | Sınıfa gönderilen mesajları kabul eder. Sınıfın hiç örneği olmasa bile çağrılabilir |
| Instance method | — | Nesnelere gönderilen mesajları kabul eder; yalnızca sınıfın nesneleri üzerinde çalışır |
İroni — açık uçluda çok işe yarar: ADT'lerin en güçlü olumlu özelliği birbirinden bağımsız olmalarıydı (bkz. Lecture #9). Inheritance tam da bu gücü bozar. Yani reuse kazanırsın, bağımsızlığı kaybedersin — klasik bir trade-off.
Tek vs çok: Tek ebeveynden türeme single inheritance; ilişki bir derivation tree ile gösterilir. Multiple inheritance'ta ilişki tree değil, derivation graph ile gösterilir. (Bu ayrım tam bir MC sorusudur.)
- Bir sınıf, varlıklarını subclass'larından gizleyebilir
- Bir sınıf, varlıklarını istemcilerinden gizleyebilir
- Bir sınıf, varlıklarını istemcilerinden gizleyip subclass'larına gösterebilir — işte bu
protected'tır
| Belirteç | Sınıf içi | Subclass | İstemci |
|---|---|---|---|
| private | ✔ | ✘ | ✘ |
| protected | ✔ | ✔ | ✘ |
| public | ✔ | ✔ | ✔ |
protected'ı "gelecek derste konuşacağız" diye ertelemişti —
işte o gelecek ders burası, çünkü protected'ın anlamı ancak inheritance ile ortaya çıkar.
⭐⭐ Dynamic binding (polymorphism)
Dynamic binding ne zaman devreye girer: Bir sınıf hiyerarşisi metot override eden sınıflar içeriyorsa ve bu metotlar polymorphic bir değişken üzerinden çağrılıyorsa, doğru metoda bağlanma dinamik olur (çalışma zamanında).
Faydası (slaytın kendi cümlesi): yazılım sistemlerinin hem geliştirme hem bakım sırasında daha kolay genişletilmesini sağlar.
İki tanım daha — sınavda ikisi karıştırılarak sorulur:
| Terim | Tanım |
|---|---|
| abstract method | Tanım (definition/gövde) içermeyen metot — yalnızca bir protokol tanımlar |
| abstract class | En az bir virtual (abstract) metot içeren sınıf |
| Kritik kural | Bir abstract class örneklenemez (cannot be instantiated) |
⭐⭐ OOP dilleri için 7 tasarım sorusu
Bölümün iskeleti. Aşağıdaki her dil bölümü, bu yedi soruya verilen farklı cevaplar olarak okunmalı.
- The exclusivity of objects — her şey nesne mi?
- Are subclasses subtypes? — "is-a" ilişkisi geçerli mi?
- Single and multiple inheritance
- Object allocation and deallocation
- Dynamic and static binding
- Nested classes
- Initialization of objects
1 · Exclusivity of objects — üç yaklaşım
| Yaklaşım | Avantaj | Dezavantaj |
|---|---|---|
| Her şey nesne (saf OOP; Smalltalk, Ruby) | Zarafet (elegance) ve saflık/tekdüzelik | Basit nesnelerde işlemler yavaş — basit işlemler bile message passing ile yapılmak zorunda |
| Tam bir tip sistemine nesneler eklemek (imperatif dilin tüm tipleri korunur + object typing modeli) |
Basit nesnelerde hızlı işlemler | Kafa karıştırıcı bir tip sistemi — iki tür varlık ortaya çıkar (yeni kullanıcı için zor) |
| Primitive'ler için imperatif tipleme, geri kalan her şey nesne (Java, C#) |
Basit nesnelerde hızlı işlemler + görece küçük bir tip sistemi | İki tip sistemi yüzünden hâlâ bir miktar karışıklık |
int, double, char primitive; Integer, Double,
Character wrapper sınıfları. Aynı işi yapan iki tür varlık vardır — biri nesneler, biri primitive'ler üzerinde.
Kapanış cümlesi (açık uçluda kullan): "Bu karışıklık problemine zarif bir çözüm yoktur; kullanıcılar tip sistemlerinin bu karmaşıklığıyla yaşamayı öğrenmek zorundadır."
2 · Subclass'lar subtype mıdır? — ⭐ en olası karşılaştırma sorusu
b) Subtype tanımı: B, A'dan türetilmişse ve A'da olan her şey B'de de varsa, ayrıca B nesnesi A nesnesinin yerinde kullanıldığında davranışı A nesnesininkiyle özdeşse, B A'nın subtype'ıdır. Kısaca: "is-a" ilişkisi geçerliyse subtype'tır.
c) Şart: Subclass yalnızca değişken/metot ekleyebilir ve miras alınan metotları "uyumlu (compatible)" biçimde override edebilir. Bu tanım, parent'ta public olan bir varlığın subclass'ta public olmamasını yasaklar — yani public varlıklar subclass'a public olarak miras kalmalıdır. (Subclass ek üyeler ekleyip yine de subtype kalabilir.)
Buradan çıkan iki sonuç: her subclass subtype değildir ve her subtype subclass değildir.
Hocanın açık bıraktığı soru: "Subclass'ların subtype olup olmadığı meselesi teorik mi pratik mi?" Cevabı vermedi, "bunu düşünün" dedi — açık uçlu bir soru olarak sorulma ihtimali var. Savunulabilir cevap: pratiktir, çünkü doğrudan polymorphism'in güvenli çalışıp çalışmayacağını belirler.
3 · Single vs multiple inheritance
İki dezavantajı (slaytta böyle, ezberle):
- Dil ve gerçekleme karmaşıklığı — kısmen isim çakışmaları (name collisions) yüzünden
- Potansiyel verimsizlik — multiple inheritance ile dynamic binding daha pahalıya gelir (slaytın kendi notu: "but not much" — çok değil)
Hocanın çerçevesi: Bu bir fiyat sorusudur — "bu bedeli ödeyip esnekliği alacak mıyım, yoksa ödemeyip yalnızca single inheritance mı sunacağım?"
Yaygın çözüm: interface. Interface abstract class'a benzer: metotları bildirilir ama tanımlanmaz, örneklenemez ve multiple inheritance'a alternatif olarak kullanılır. Java'da multiple inheritance yoktur, ama interface'ler bizi onun esnekliğine yaklaştırır.
4 · Nesnelerin allocation ve deallocation'ı
- ADT gibi davranıyorlarsa her yerden ayrılabilirler: run-time stack'ten ya da
newile açıkça heap'ten. - Hepsi heap-dynamic ise: referanslar pointer veya reference değişkeniyle tekdüze (uniform) olur → atama basitleşir, dereferencing örtük olabilir.
- Nesneler stack dynamic ise: subtype'larla ilgili bir problem çıkar — object slicing.
İkinci soru: (heap değişkenleri için) deallocation explicit mi implicit mi?
5 · Dynamic vs static binding · 6 · Nested classes · 7 · Initialization
| Tasarım sorusu | Gerilim | Yaygın çözüm |
|---|---|---|
| Binding | Hiçbiri dynamic değilse dynamic binding'in avantajlarını kaybedersin; hepsi dynamic ise verimsizdir (static binding daha hızlıdır) | "Maybe the design should allow the user to specify" — kullanıcı/programcı seçsin.
Bedeli: dilin gerçeklenmesi daha karmaşık olur. Modern OOP dillerinin tercihi budur (C++ virtual, C# virtual/override) |
| Nested classes | Bir sınıfa yalnızca tek bir sınıf ihtiyaç duyuyorsa, onu herkesin göreceği biçimde tanımlamak için hiçbir neden yoktur → motivasyon: information hiding. Bazı durumlarda yeni sınıf, doğrudan başka bir sınıfın değil bir subprogram'ın içine yerleştirilir | Asıl tasarım sorusu görünürlüktür: nesting class'ın hangi olanakları nested class'a görünür, ve tersi? |
| Initialization | Nesneler yaratılırken değerlere ilklenir mi? Örtük mü açık mı? Bir subclass nesnesi yaratıldığında parent class üyeleri nasıl ilklenir — örtük mü, programcı mı yapmalı? |
Hocanın dürüst notu: burada yalnızca sorular vardır, genel bir reçete yoktur; cevap dile ve duruma bağlıdır |
Dil örneği: Smalltalk — saf OOP
- Her şey bir nesnedir —
5bile primitive değil, 5 değerini tutan bir nesnedir - Tüm nesnelerin kendi local belleği vardır
- Tüm hesaplama, nesnelerin nesnelere mesaj göndermesiyle yapılır
- İmperatif dillerin hiçbir görünümü yoktur
- Tüm nesneler heap'ten ayrılır; tüm deallocation örtüktür
- Smalltalk sınıfları başka sınıfların içine nested edilemez
| Konu | Smalltalk'ta |
|---|---|
| Inheritance | Subclass, superclass'ın tüm instance değişkenlerini, instance metotlarını ve class metotlarını miras alır.
Kendi instance değişkenleri ata sınıflardakilerden farklı adlarda olmalıdır. Tüm subclass'lar subtype'tır — çünkü hiçbir şey gizlenemez. Tüm inheritance implementation inheritance'tır. · Multiple inheritance yok. |
| Dynamic binding | Mesajların metotlara tüm bağlanması dynamic'tir.
Süreç: mesajın gönderildiği nesnede metot aranır; bulunamazsa superclass'ta, o da olmazsa bir üstte…
superclass'ı olmayan system class'a kadar. Smalltalk'taki tek tip denetimi dynamic'tir ve tek tip hatası, bir nesneye eşleşen metodu olmayan bir mesaj gönderilmesidir. |
| Değişkenler | Tipsizdir; herhangi bir ad herhangi bir nesneye bağlanabilir → dynamic polymorphism. Tüm Smalltalk kodu bu anlamda generic'tir |
- Dilin sözdizimi basit ve düzenlidir (simple and regular)
- Küçük bir dilin sağladığı gücün iyi bir örneğidir — tek ama güçlü bir kavram etrafında kurulmuş (sınıf hiyerarşisi + inheritance + nesneler + message passing)
- Geleneksel derlenen imperatif dillere göre yavaştır
- Dynamic binding, tip hatalarının çalışma zamanına kadar fark edilmemesine yol açar
- Grafik kullanıcı arayüzünü (GUI) tanıttı — pencereler, fare, açılır menüler 1980'lerde onunla geldi
- En büyük etkisi: OOP'nin ilerlemesi (advancement of OOP)
Dil örneği: C++ — hibrit
- C ve Simula 67'den evrildi — en çok kullanılan OOP dillerinden biri
- Karma (mixed) tip sistemi — C ile geriye dönük uyumluluk için: geleneksel imperatif tipler + sınıf yapısı. Bu yüzden saf değil, hibrit bir dildir; metotları da fonksiyonları da destekler
- Constructor ve destructor'lar
- Sınıf varlıklarına ayrıntılı erişim denetimleri
- Bir C++ sınıfı hiçbir sınıfın subclass'ı olmak zorunda değildir (standalone olabilir) — Smalltalk ve Java'nın tersi
| Belirteç | Anlamı |
|---|---|
| private | Yalnızca sınıfta ve friend'lerde görünür — subclass'ların subtype olmasını engeller |
| public | Subclass'larda ve istemcilerde görünür |
| protected | Sınıfta ve subclass'larda görünür, istemcilerde görünmez |
| Derivation | Etkisi |
|---|---|
| Private derivation | Miras alınan public ve protected üyeler subclass'ta private olur |
| Public derivation | Public ve protected üyeler subclass'ta da public ve protected kalır |
class base_class {
private: int a; float x; // hiçbir yerde görünmez
protected: int b; float y;
public: int c; float z;
};
class subclass_1 : public base_class { … };
// b ve y → protected; c ve z → public
class subclass_2 : private base_class { … };
// b, y, c, z → HEPSİ private
// hiçbir türetilmiş sınıf base_class'ın hiçbir üyesine erişemez
:: ile yeniden görünür kılınabilir:
class subclass_3 : private base_class {
base_class :: c; // c yeniden dışa açılıyor
…
}
Private derivation'ın motivasyonu (slaytta ayrı sayfa):
Bir sınıf, görünmesi zorunlu üyeler sunar (bu yüzden public tanımlanmışlardır);
türetilmiş sınıf yeni üyeler ekler ama kendi istemcilerinin, parent'ın üyelerini görmesini istemez —
parent'ta public olmak zorunda olsalar bile.
::) ile referanslanabilir:
class Thread { ... }
class Drawing { ... }
class DrawThread : public Thread, public Drawing { … }
Diamond (elmas) problemi: BC temel sınıf; D1 ve D2 ondan türüyor;
Z hem D1'den hem D2'den türüyor →
BC'nin x üyesi Z'ye iki kez geliyor.
class BC { protected: int x; }
class D1: public BC { … } // yol 1
class D2: public BC { … } // yol 2
class Z : public D1, public D2 { … } // x İKİ KEZ gelir ✗
// ÇÖZÜM: virtual inheritance
class D1: public virtual BC { … }
class D2: public virtual BC { … }
class Z : public D1, public D2 { … } // x BİR KEZ gelir ✓
Sınav notu: "Multiple inheritance'ın dezavantajı nedir?" sorusunun somut örneği budur —
cevabına diamond'ı ve virtual çözümünü ekle.
virtual ve pure virtual
Varsayılan: C++'ta üye fonksiyonlar statik olarak bağlanır —
dynamic binding istiyorsan açıkça istemelisin. (Java'nın tam tersi!)
- Bir metot
virtualtanımlanırsa polymorphic değişkenler üzerinden çağrılabilir ve mesajlara dinamik bağlanır. - Bir pure virtual function'ın hiç tanımı yoktur — sözdizimi:
virtual void draw() = 0;(= 0"pure virtual" demenin tuhaf ama standart yolu). Amacı: gerçeklemesini vermeden bir fonksiyonun arayüzünü sağlamak. - En az bir pure virtual fonksiyonu olan sınıf abstract class'tır ve örneklenemez.
- Hocanın notu: C++'ta abstract class ayrı bir reserved word ile işaretlenmez (bazı dillerin tersine) ve tamamen tanımlanmış metotlar da içerebilir.
class Shape { public: virtual void draw() = 0; ... }; // abstract
class Circle : public Shape { public: void draw() { ... } ... };
class Rectangle : public Shape { public: void draw() { ... } ... };
class Square : public Rectangle { public: void draw() { ... } ... };
Square* sq = new Square;
Rectangle* rect = new Rectangle;
Shape* ptr_shape;
ptr_shape = sq; // bir Square'i gösteriyor
ptr_shape->draw(); // DİNAMİK bağlanır → Square::draw
rect->draw(); // STATİK bağlanır → Rectangle::draw
Slaytın notu: Base metot virtual ise C++ eşleşen override metodu otomatik olarak virtual yapar;
yine de açıklık için hepsini virtual yaz.
// STACK'ten
Square sq; Rectangle rect;
rect = sq; // Square'in VERİ ÜYELERİ kopyalanır (object slicing!)
rect.draw(); // → Rectangle::draw çağrılır
// HEAP'ten
Square *sq = new Square;
Rectangle *rect = new Rectangle;
rect = sq; // POINTER ataması
rect->draw(); // → Square::draw çağrılır
Kural: stack'te değer/veri kopyalanır (polymorphism çalışmaz, slicing olur);
heap'te pointer atanır (polymorphism çalışır).
Evaluation — slaytın karşılaştırması:
- C++ kapsamlı erişim denetimleri sunar (Smalltalk sunmaz)
- C++ multiple inheritance sunar
- C++'ta programcı tasarım zamanında, hangi metotların static hangilerinin dynamic bağlanacağına kendisi karar vermek zorundadır — static binding daha hızlıdır!
- Smalltalk'ın tip denetimi dynamic'tir: esnek ama bir miktar güvensiz
- Yorumlama ve dynamic binding yüzünden Smalltalk, C++'tan ~10 kat yavaştır
Dil örneği: Java
Slayt bu bölümü açıkça "C++'tan farklar" üzerinden kuruyor — sınav sorusu da büyük olasılıkla bu eksende gelir.
- Primitive tipler hariç tüm veri nesnedir
- Tüm primitive tiplerin bir veri değeri saklayan wrapper sınıfları vardır
(
int→Integer). Primitive'in nesneye örtük dönüştürülmesine boxing denir; Java 5.0'dan sonra otomatiktir (autoboxing) - Tüm nesneler heap-dynamic'tir, reference değişkenlerle erişilir ve çoğu
newile ayrılır - Tüm sınıflar
Objectkök sınıfının torunudur — bu sayedetoString,equalsgibi ortak metotlar bir kez tanımlanıp herkese miras kalır - Depolama geri kazanımı için garbage collection;
finalizemetodu, çöp toplayıcı bir nesnenin belleğini geri almak üzereyken örtük olarak çağrılır
| C++ | Java | |
|---|---|---|
| Varsayılan binding | Static — dynamic istiyorsan virtual yaz |
Dynamic — tüm mesajlar dinamik bağlanır |
| İstisnalar | — | final (override edilemez → dynamic binding anlamsız),
static ve private (ikisi de override'ı engeller) → static bağlanır |
| Multiple inheritance | Var | Yok — yerine interface |
| Parentless sınıf | Olabilir | Olamaz |
| Subclass = subtype? | private üye/private derivation varsa hayır | Tüm subclass'lar subtype'tır |
final hakkında hocanın eklediği: Bir sınıf final ise alt sınıflanamaz;
final sınıftaki tüm metotlar örtük olarak final'dır, yani hepsi statik bağlanır.
Avantajı: sınıfta değişikliğe izin verilmez (güvenlik/kararlılık); dezavantajı:
küçük değişiklik gerektiren yeniden kullanımları da engeller.
public interface Comparable <T> {
public int comparedTo (T b);
}
Mixin (karışım): Bir sınıftan miras alıp ayrıca bir interface implemente ederek
multiple inheritance'ı simüle edebilirsin — interface'in sabit ve metotları,
superclass'tan gelenlerle karışır; üstüne subclass'ta yeni veri ve metotlar da tanımlanabilir.
| INTERFACE | ABSTRACT CLASS | |
|---|---|---|
| Kod içerebilir mi | Hiç kod veremez, varsayılan kod bile veremez
(Not: Java 8'den itibaren interface default kod içerebilir) |
Tam kod, varsayılan kod ve/veya override edilmesi gereken stub'lar verebilir |
| Kaç tane | Bir sınıf birden çok interface implemente edebilir | Bir sınıf yalnızca bir abstract class'ı extend edebilir |
| Yeni metot eklemek | Evrendeki tüm gerçeklemeleri bulup her birine somut gerçekleme yazman gerekir | Varsayılan bir gerçekleme verebilirsin → mevcut kod değişmeden çalışmaya devam eder |
| Esneklik | Mevcut gerçeklemelerle tek satır kod ortaklığı olmayan yeni bir modül yazabilirsin; sıfırdan başlarsın | Abstract class'ı olduğu gibi kullanmak zorundasın — iyisiyle kötüsüyle. Yazarı sana bir yapı dayatmıştır; yazar ne kadar iyiyse o kadar iyi |
- Hepsi, nesting class hariç, paketlerindeki tüm sınıflardan gizlidir
- Doğrudan nested edilen non-static sınıflara inner class denir; bir inner class, nesting class'ının üyelerine erişebilir (private üyeleri dahil) — çünkü her örneği, ait olduğu nesting class örneğine açık bir pointer taşır
- Static nested class bu pointer'ı taşımaz → nesting class'ın üyelerine erişemez (C++'ın nested class'ları gibi davranır)
- Nested class'lar anonim olabilir
- Local nested class: nesting class'ının bir metodunun içinde tanımlanır; access specifier kullanılmaz, scope'u her zaman nesting class'ıyla sınırlıdır
// STATIC nested: dış sınıfın örneğine GEREK YOK
class Foo { static class Bar { } }
class Driver{ Foo.Bar b = new Foo.Bar(); }
// NON-STATIC (inner): önce dış sınıf örneklenmeli
class Foo { class Bar { } }
class Driver{ Foo i = new Foo();
Foo.Bar b = i.new Bar(); }
Ezber cümlesi: "a static inner class can be instantiated without first creating an instance of the outer class;
a non-static inner class cannot."
- OOP'yi destekleme kararları C++'ınkine benzer, ama OOP ilkelerine bağlılık daha tutarlıdır
- Prosedürel programlama desteği yok
- Parentless sınıf yok
- Dynamic binding, metot çağrılarını tanımlara bağlamanın "normal" yoludur
- Interface'ler multiple inheritance için basit bir destek biçimi sağlar
Dil örneği: C#
- OOP desteği Java'ya benzer; sınıf tanımlarken C++'ın sözdizimini kullanır
- Hem class hem struct içerir — struct'lar daha az güçlü, stack-dynamic yapılardır ve inheritance'ları yoktur
- Single inheritance — multiple inheritance yok (Java gibi)
- Parent'tan miras alınan bir metot, türetilmiş sınıfta
newile işaretlenerek değiştirilebilir; parent sürümü hâlâbase.önekiyle çağrılabilir (base.Draw()) - Parent'ın hiçbir üyesi private değilse subclass'lar subtype'tır
- Tüm C# sınıfları nihayetinde tek bir kök sınıftan —
Object— türer
- Base sınıftaki metot →
virtual - Türetilmiş sınıflardaki karşılıkları →
override - Abstract metotlar
abstractile işaretlenir ve tüm subclass'larda gerçeklenmek zorundadır
public class Shape { public virtual void Draw() { . . . } }
public class Circle : Shape { public override void Draw() { . . . } }
public class Rectangle : Shape { public override void Draw() { . . . } }
public class Square : Rectangle { public override void Draw() { . . . } }
Karıştırma tuzağı: new = metodu gizler (hiding); override = metodu dinamik olarak ezer.
İkisi farklı şeydir.
Nested classes: Doğrudan nested edilen bir C# sınıfı, Java'nın static nested class'ı gibi davranır; C# Java'nın non-static (inner) sınıfları gibi davranan nested sınıfları desteklemez.
Evaluation: C#, görece yeni tasarlanmış C-tabanlı bir OO dildir; C# ile Java'nın OOP desteği arasındaki farklar görece küçüktür.
Dil örneği: Ruby — saf OOP, ama farklı
- Her şey bir nesnedir; tüm hesaplama message passing ile yapılır
- Sınıf tanımları çalıştırılabilirdir (executable) ve yürütme sırasında açık kalır → var olan bir tanıma ikincil tanımlarla üye eklenebilir, istediğin kadar çok kez. Bir sınıfın o anki tanımı, çalıştırılmış tüm tanımlarının birleşimidir.
- Metot tanımları da çalıştırılabilirdir → bir program, bir
if/else'in iki dalına iki farklı tanım koyarak çalışma zamanında hangi metot tanımının geçerli olacağını seçebilir. Hocanın uyarısı: çok esnek, ama dikkatli değilsen derleme değil çalışma zamanı hataları üretir. - Tüm değişkenler nesnelere tipsiz (type-less) referanslardır
- Erişim denetimi veri ile metotlarda farklıdır: tüm veri için private'tır ve değiştirilemez; metotlar public, private veya protected olabilir
- Metot erişimi çalışma zamanında denetlenir
- Getter ve setter'lar kısayollarla tanımlanabilir
- Nesneler
newile yaratılır;newörtük olarak constructor'ı çağırır — adıinitialize - Subclass tanımı:
class MyClass < SuperClass—<işaretiyle - Ruby sınıfları nested edilebilir, ama nested sınıfın, nesting sınıfın değişken/metotlarına özel erişimi yoktur (C++ gibi)
| Konu | Ruby'de |
|---|---|
| Inheritance | Miras alınan metotların erişim denetimi, parent'takinden farklı olabilir Subclass'lar zorunlu olarak subtype DEĞİLDİR — Smalltalk'ın tam tersi, ayırt edici bir madde |
| Dynamic binding | Tüm değişkenler tipsiz ve polymorphic'tir → tüm bağlamalar dinamiktir |
| Evaluation | Abstract class'ları desteklemez Multiple inheritance'ı tam desteklemez Erişim denetimleri, OOP destekleyen diğer dillerinkinden zayıftır |
⭐ OO yapıların gerçeklenmesi — CIR ve vtable
- Instance değişkenleri için depolama yapıları — hocanın deyimiyle görece kolay olan
- Mesajların metotlara dinamik bağlanması — asıl zorluk burada
Instance data storage — Class Instance Record (CIR)
| Özellik | Açıklama |
|---|---|
| Ne saklar | Class instance record (CIR), bir nesnenin state'ini saklar |
| Ne zaman kurulur | Static — derleme zamanında kurulur |
| Inheritance | Sınıfın bir parent'ı varsa, subclass'ın instance değişkenleri parent'ın CIR'ına eklenir |
| Erişim maliyeti | CIR static olduğu için tüm instance değişkenlerine erişim record'lardaki gibi yapılır → verimli |
Hocanın bağlantısı: C++'ta sınıflar C'nin record (struct) yapısının uzantısı olarak tanımlanır — bu yüzden instance değişkenlerinin depolanması bir record gibi görünür ve öyle de gerçeklenir. Bu, Lecture #5'teki record erişimi ile birebir aynı mantıktır.
⭐ Dynamic binding'in gerçeklenmesi — vtable
- Statik bağlanan metotların CIR'da yer alması gerekmez; dinamik bağlanacak metotların CIR'da girdisi olmak zorundadır.
- Dinamik bağlanan metot çağrıları, CIR'daki bir pointer üzerinden ilgili koda bağlanır.
- Bu depolama yapısının adı: virtual method table (vtable).
- Metot çağrıları, vtable'ın başlangıcına göre offset olarak temsil edilebilir
— Ch.10'daki
local_offsetmantığının OOP karşılığı. - Bir ata sınıfın polymorphic değişkenleri her zaman doğru tipteki nesnenin CIR'ını gösterir — polymorphism'in çalışma mekanizması tam olarak budur.
public class A {
public int a, b;
public void draw() { . . . }
public int area() { . . . }
}
public class B extends A {
public int c, d;
public void draw() { . . . } // override
public void sift() { . . . } // yeni
}
Hocanın anlattığı tablo mantığı — ezberlemesi kolay:
- A'nın CIR'ı: [vtable pointer] +
a+b. A'nın vtable'ıdrawveareakodlarını gösterir. - B'nin CIR'ı: A'nınkine
cvedeklenir. B'nin vtable'ında üç girdi olur:draw→ B'nin kendi draw'ı (override edildi);area→ A'nın area'sı (override edilmedi, A'ya işaret eder);sift→ B'nin sift'i.
- OO programlama üç temel kavram içerir: ADT (encapsulation), inheritance, dynamic binding (polymorphism).
- Başlıca tasarım sorunları: exclusivity of objects · subclasses ve subtypes · type checking ve polymorphism · single ve multiple inheritance · dynamic binding · nesnelerin explicit/implicit deallocation'ı · nested classes.
- Smalltalk saf bir OO dildir.
- C++'ın iki ayrı tip sistemi vardır (hibrit).
- Java, C++ gibi hibrit değildir; yalnızca OOP'yi destekler.
- C#, C++ ve Java temellidir.
- Ruby görece yeni bir saf OOP dilidir; OOP desteğinde bazı yeni fikirler sunar.
- OOP'yi gerçeklemek bazı yeni veri yapıları gerektirir (CIR, vtable).
| Smalltalk | C++ | Java | C# | Ruby | |
|---|---|---|---|---|---|
| Saflık | Saf OOP | Hibrit | Yalnızca OOP | Yalnızca OOP | Saf OOP |
| Her şey nesne mi | Evet | Hayır (karma tip sistemi) | Hayır (primitive'ler) | Hayır (primitive + struct) | Evet |
| Multiple inheritance | Yok | Var | Yok (interface) | Yok | Tam desteklemez |
| Binding varsayılanı | Tamamen dynamic | Static (virtual ile dynamic) | Dynamic (final/static/private hariç) | Static (virtual+override) | Tamamen dynamic |
| Subclass = subtype? | Her zaman | Hayır (private ile bozulur) | Her zaman | Parent'ta private yoksa | Zorunlu değil |
| Allocation | Hep heap, implicit dealloc | Stack / heap / static | Hep heap + GC | Heap + GC (struct stack) | Heap |
| Nested class | Yok | Var, özel erişim yok | Var, inner erişebilir | Var, yalnızca static gibi | Var, özel erişim yok |
| Abstract class | — | =0 pure virtual | abstract + interface | abstract | Desteklemez |
Final Soru Havuzu
Final kapsamının tamamı, ders ders. Soruya tıkla, cevabı açılır.
⭐ = hocanın doğrudan söylediği, tekrarladığı veya "important" dediği ya da slaytta ayrı bir sayfaya konmuş noktaya dayanıyor; önce bunları bitir.
⭐⭐ Quiz 2 ve Quiz 3'ün GERÇEK soruları
Hocanın soru stilinin en güvenilir örneği — ikisinde de 100/100. Dikkat: her ikisi de o günkü dersten değil, tüm dönemden soruldu (bkz. radar). Quiz 2'de şıklar ve işaretlenen cevaplar elimizde; Quiz 3'te yalnızca sorular var, cevaplar ders materyalinden yeniden kuruldu.
Quiz 2 — 28 Temmuz, 15 dk, 10 soru × 10 puan (100/100)
Q2-1Which of the following best defines binding in programming languages?
Q2-2Which language first introduced the concept of structured programming?
Q2-3In static scoping, how is the binding of a variable determined?
Q2-4Which of the following is NOT a benefit of syntax-directed translation?
Q2-5Which of the following is true regarding strongly typed languages?
Q2-6What is a key advantage of dynamic type binding?
Q2-7Which of the following is a non-primitive data type?
Q2-8Which of the following best describes referential transparency?
Q2-9Which of the following describes the job of a parser?
Q2-10Which of the following languages introduced object-oriented programming concepts like encapsulation and inheritance?
Quiz 3 — 4 Ağustos, 15 dk, 10 soru × 10 puan (100/100)
Bu quiz'in sonuç ekranında yalnızca soru metinleri var, şıklar yok. Aşağıdaki cevaplar ders materyalinden yeniden kuruldu — soru metinleri birebir gerçektir, cevaplar kavram düzeyindedir.
Q3-1What is the main advantage of using named constants over literals?
Q3-2What is the primary purpose of Backus-Naur Form (BNF)?
Q3-3Which of the following best describes a side effect in an expression?
Q3-4Which of the following types of loops is best when the number of iterations is known before execution?
for). Sayı önceden bilinmiyorsa logically-controlled (while) kullanılır. Ch.8.Q3-5Which of the following languages introduced short-circuit boolean evaluation as a language feature?
Q3-6Which of the following language features most improves readability?
Q3-7In dynamic scoping, how is a variable's binding resolved?
Q3-8Which of the following expression evaluation strategies guarantees that all operands are evaluated, regardless of short-circuit conditions?
& ve |) sağlar — &&/|| ise short-circuit'tir. Ch.7 · Rehberdeki short-circuit tablosuyla birebir.Q3-9Which of the following is a compound assignment operator?
+= (ve -=, *=, /=). ALGOL'de tanıtıldı, C ve C tabanlı diller benimsedi. Tuzak: == ilişkisel, = basit atama, ++ unary atama operatörüdür. Ch.7.Q3-10Which of the following control structures allows a program to repeatedly execute a block until a condition becomes false?
while döngüsü — ön testli (pretest) mantıksal kontrollü döngü: koşul doğru olduğu sürece çalışır, yanlış olunca durur. (do…while son testlidir; for sayaç kontrollüdür; until Perl/Ruby'de tersini yapar.) Ch.8.Lecture 5 · Data Types (Ch.6)
⭐1Bir data type nedir?
⭐2Descriptor nedir ve ne zaman compile-time, ne zaman run-time'da bulunur?
⭐3Bu derste object ne demektir? OOP'deki nesneden farkı nedir?
⭐4Bir dilde tip sistemi neden vardır? Üç gerekçe.
5Primitive data type tanımı nedir?
⭐6Negatif tamsayılar için neden ones complement yerine two's complement kullanılır?
0010 → 1101 → +1 → 1110.7IEEE 754'te 32-bit bir floating point sayı hangi parçalara ayrılır?
⭐8Precision ile range arasındaki fark nedir?
⭐9Decimal tipin avantajı ve dezavantajları nelerdir? Hangi dillerde vardır?
10Boolean tipin en büyük avantajı nedir ve hangi dilde tanıtılmıştır?
11C89'un boolean tipi konusundaki istisnası nedir? Java/C# nasıl davranır?
int kullanır (0 = false, sıfırdan farklı = true). C99 ve C++'ta boolean tipi vardır ama sayısal ifadeler de koşul olarak kullanılabilir. Java ve C#'ta bu mümkün değildir — koşul Boolean olmak zorundadır.12ASCII, UCS-2 ve UCS-4 arasındaki farklar nelerdir?
⭐13Character string tipinin iki tasarım sorusu nedir?
14String için tipik işlemler nelerdir?
⭐15String uzunluğunun üç kategorisi nedir, hangi diller hangisini kullanır?
16C/C++'ta hangi string kütüphane fonksiyonları vardır ve strlen null karakteri sayar mı?
strcpy (kopyala), strcat (birleştir), strcmp (leksikografik karşılaştır), strlen (uzunluk). strlen null karakteri saymaz.17Tarihte string manipülasyonunu ilk destekleyen dil hangisidir?
18Hangi diller yerleşik pattern matching (regular expression) sunar?
19Ordinal type nedir? Java'daki primitive ordinal örnekleri nelerdir?
integer, char, boolean.⭐20Enumeration type readability ve reliability'ye nasıl katkı yapar?
⭐21C#, F#, Swift ve Java 5.0 enumeration desteğinde C++'tan neden daha iyidir?
22Enumeration tiplerinin üç tasarım sorusu nedir?
⭐23Array tanımı nedir?
⭐24Array'in dört kategorisini, subscript bind'ı ve allocation'ı ile açıklayın.
static array'ler)Fixed stack-dynamic: subscript statik bağlı, allocation bildirim anında → avantaj space efficiency. (C/C++
static'siz array'ler)Fixed heap-dynamic: binding dinamik ama ayırma sonrası sabit; depolama heap'ten. (C
malloc, C++ new, Java'nın tüm non-generic array'leri)Heap-dynamic: subscript ve allocation dinamik, defalarca değişebilir → avantaj flexibility. (Java
ArrayList, C# List, Perl, JavaScript, Python, Ruby)25Heap-dynamic array'lerin dezavantajı nedir?
26Hangi diller array indekslerinde range checking yapar, hangileri yapmaz?
27Hangi diller subscript olarak yalnız integer, hangileri ordinal tipleri kabul eder?
28Ada neden array indekslemede parantez kullanır?
29Heterogeneous array nedir, hangi diller destekler?
30Rectangular ve jagged array farkı nedir? Hangi diller neyi destekler?
⭐31Slice nedir ve ne zaman anlamlıdır?
vector[3:6] · Ruby: list.slice(2, 2).⭐32Row major ve column major order nedir? Hangi dil hangisini kullanır?
33Tek boyutlu bir array'in access function'ı nedir?
address(list[k]) = address(list[lower_bound]) + ((k − lower_bound) × element_size). C/C++/Java'da lower_bound = 0.34Associative array tanımı nedir ve normal array'den hangi noktada ayrılır?
35Perl hash'lerinde ve Python dictionary'lerinde sözdizimi nasıldır?
% ile başlar, literal parantezle; erişim süslü parantez $hi_temps{"Wed"}; silme delete; keys operatörü anahtar dizisini döndürür. Python: { } ile kurulur; erişim köşeli parantez Dict["model"]; silme del; yeni key ile ekleme; uzunluk len(Dict).⭐36Record tanımı nedir ve array'den farkları nelerdir?
37Fully qualified ve elliptical reference nedir?
FIRST, FIRST OF EMP-NAME ve FIRST OF EMP-REC üçü de aynı alana elliptical referanstır.38COBOL record'ları nasıl tanımlar?
OF, diğerleri dot notation kullanır.⭐39Tuple nedir, record'dan farkı ne?
⭐40Scheme'de CAR, CDR, CONS, LIST ne yapar?
(CAR '(A B C)) → A. CDR: ilk eleman çıkarıldıktan sonra kalan — (CDR '(A B C)) → (B C). CONS: 1. parametreyi 2. parametreye (listeye) ekler — (CONS 'A (B C)) → (A B C). LIST: parametrelerinden yeni liste yapar. ML karşılıkları: CONS → ::, CAR → hd, CDR → tl.41Lisp/Scheme'de veri ile kod arasındaki ilişki nedir?
(A B C) veri olarak literal bir listedir; kod olarak A fonksiyonunun B ve C parametreleriyle uygulanmasıdır. Yorumlayıcının ayırt edebilmesi için veri kesme işaretiyle quote edilir: '(A B C).42Python listeleri ile Scheme/ML listelerinin farkı nedir?
del ile eleman silinir.43List comprehension nereden gelir, hangi dilde orijinaldir?
[n * n | n <- [1..10]]. Python: [x * x for x in range(6) if x % 3 == 0].⭐44Union tanımı nedir?
⭐45Free union ile discriminated union arasındaki fark nedir?
Discriminated union: her union, hangi alanın kullanılacağını söyleyen discriminant adlı bir tip göstergesi içerir → safe. Ada, ML, Haskell, F#.
Free union'ın tehlikesi:
el1.intEl = 27; x = el1.floatEl; → 27'nin bit gösterimi float'a atanır, sonuç anlamsız.⭐46Java ve C# union'ı neden desteklemez?
47Union'ların iki tasarım sorusu nedir?
⭐48Pointer tipi nedir ve neyi sağlar?
nil değeri olan tip. İki şey sağlar: indirect addressing gücü ve dinamik belleği yönetme yolu; heap'te dinamik yaratılan alana erişimi mümkün kılar.49Pointer'ların iki temel işlemi nedir?
*ptr) veya implicit olabilir.⭐50Dangling pointer ile lost heap-dynamic variable arasındaki fark nedir?
Slaytın formülü: nesne binding'den uzun yaşarsa → garbage; binding nesneden uzun yaşarsa → dangling reference.
⭐51Dangling pointer sorununa iki çözüm nedir?
Locks-and-keys: pointer değeri (key, address) çiftidir; heap değişkeni değişken + integer lock hücresidir; erişimde key ile lock karşılaştırılır, eşleşmezse run-time error.
52C/C++'ta void * ne yapabilir, ne yapamaz?
53C/C++'ta pointer aritmetiği nasıl çalışır?
float stuff[100]; float *p; p = stuff; ise: *(p+5) ≡ stuff[5] ≡ p[5]; genel olarak *(p+i) ≡ stuff[i] ≡ p[i].⭐54C++, Java ve C#'ın reference type yaklaşımları nasıl farklılaşır?
⭐55"Pointers are like goto's" ne demektir? Pointer'lardan vazgeçilebilir mi?
⭐56Reference counting ile mark-sweep arasındaki farklar nelerdir?
Mark-sweep (lazy): her hücrede fazladan bir bit; boş alan listesi bitince çalışır. Hepsi garbage işaretlenir → pointer'lar izlenir, erişilebilenler işaretlenir → kalanlar boş listeye döner. − Orijinal hâlinde çok seyrek çalışırdı, çalışınca ciddi gecikme. Modern çözüm: incremental mark-sweep.
57Optional type nedir, hangi dillerde vardır?
null); value type'lar (struct) tip adına soru işareti eklenerek optional yapılır: int? x;. Swift'te değersizlik nil'dir.⭐58Type checking, compatible type, coercion ve type error tanımlarını verin.
⭐59Type binding'ler ile type checking arasındaki ilişki nedir?
⭐60Strong typing tanımı nedir? Hangi diller strongly typed'dır?
C/C++ değil: parametre tip denetimi atlanabilir + union'lar type checked değil. Java/C# neredeyse: explicit casting yüzünden. ML/F# evet. Ada, Java'dan daha etkili.
⭐61Coercion ile strong typing arasındaki ilişki nedir?
⭐62Name ve structure type equivalence arasındaki fark nedir?
Structure: tipleri aynı yapıya sahipse eşdeğerdir. Daha esnek ama uygulaması zor; sorunu: aynı yapıdaki tipler ayırt edilemez (ikisi de float olan iki farklı hız birimi karışır).
63Structure type equivalence'ın açık soruları nelerdir?
Lecture 6 · Expressions, Assignment & Control Structures (Ch.7–8)
⭐64Imperative dillerin "özü" nedir?
⭐65Aritmetik expression'ların altı tasarım sorusu nedir?
66Precedence ile associativity arasındaki fark nedir?
⭐67APL'in operatör kuralları neden istisnadır?
** sağdan sola).68Hangi dillerde binary operatörler prefix'tir?
++/-- hem prefix hem postfix olabilir.69Ruby ve Scheme'de operatörler nasıl gerçeklenmiştir?
a + b * c → (+ a (* b c)).⭐70Functional side effect nedir ve neden problem yaratır?
⭐71Side effect problemine iki çözüm nedir, avantaj/dezavantajları?
(2) Sırayı sabitle: + Deterministik. − Derleyici optimizasyonlarını kısıtlar. Java bu yolu seçti (soldan sağa).
⭐72Referential transparency nedir, saf fonksiyonel diller neden her zaman sağlar?
Saf fonksiyonel diller neden: değişkenleri yoktur → fonksiyon state tutamaz; dışarıdan kullandığı değer sabit olmak zorundadır → fonksiyonun değeri yalnızca parametrelerine bağlıdır.
⭐73Operator overloading'in C/C++'ta yarattığı iki zarar nedir?
& binary iken bitwise AND, unary iken adres alma; * hem çarpma hem dereference.74Hangi diller kullanıcı tanımlı operator overloading'e izin verir? C++'ta hangi operatörler overload edilemez?
. ve scope resolution ::.⭐75Operator overloading'in Java ile ilişkisi nedir?
⭐76Narrowing ve widening conversion tanımları nedir?
⭐77Mixed-mode expression ve coercion neden gereklidir? Dezavantajı nedir?
⭐78PL/I'ın aşırı coercion örneği nedir ve bedeli neydi?
79Expression hatalarının iki kaynağı nedir?
⭐80JavaScript/PHP'de === ile == arasındaki fark nedir? Ruby'deki karşılığı?
=== ve !==, ==/!= gibidir ama operand'larını coerce etmezler. Ruby'de aynı ayrım: == coercion yapar, eql? yapmaz.⭐81C'de a < b < c ifadesi ne yapar?
⭐82Short-circuit evaluation nedir ve olmamasının problemi nedir?
while (index <= length) && (LIST[index] != value) — index == length olduğunda LIST[index] indeksleme hatası verir. Short-circuit varsa ikinci koşul hiç değerlendirilmez.83Short-circuit ve side effect ilişkisi nedir?
(a > b) || (b++ / 3) — a > b doğruysa b++ hiç çalışmaz.⭐84C tabanlı diller neden =='i ilişkisel operatör yaptı?
='in eşitlik ilişkisel operatörü için overload edilmesi kötüdür (atama ile karışır). Ada ise atama için := kullanır.85Compound assignment operatörleri hangi dilde tanıtıldı?
a += b ≡ a = a + b.86sum = ++count ile sum = count++ arasındaki fark nedir?
++count: önce artır, sonra ata. count++: önce ata, sonra artır. -count++: önce artır, sonra negatifle.87"Assignment as expression" nedir, dezavantajı nedir?
while ((ch = getchar()) != EOF) {…}. Dezavantajı: bir başka tür expression side effect'i.88Perl/Ruby'de multiple assignment nasıl kullanılır?
($first, $second, $third) = (20, 30, 40);. ($first, $second) = ($second, $first); yasaldır ve yer değiştirme (interchange) yapar.⭐89Mixed-mode assignment kuralları dillerde nasıl farklılaşır?
90ML'in val'i ile F#'ın let'i arasındaki fark nedir?
let'i ayrıca yeni bir scope yaratır. ML'de aynı isim için ikinci bir val gelirse bu yeni ve farklı bir isimdir.⭐91Kontrol akışının üç seviyesi nedir?
⭐921960'larda kontrol yapıları hakkında kanıtlanan "önemli sonuç" nedir?
93Control structure tanımı nedir?
⭐94Dangling else problemi nedir, Java nasıl çözer?
if'lerde else'in hangi if'e ait olduğu belirsizliği. Java'nın static semantics kuralı: else, en yakın önceki if ile eşleşir. Alternatif anlamı zorlamak için compound statement kullanılır (C, C++, Java, C#). Perl tüm clause'ları zorunlu compound yaparak sorunu baştan yok eder.95Hangi dillerde if kontrol ifadesi aritmetik olabilir?
⭐96C/C++/Java switch'inin dört tasarım tercihi nedir?
default temsil edilmeyen değerler içindir; yoksa deyim hiçbir şey yapmaz.⭐97C#'ın switch'i C'den nasıl ayrılır?
goto veya break) bitmelidir. Ayrıca kontrol ifadesi ve case sabitleri string olabilir.98Ruby'nin iki case biçimi nedir?
when + Boolean ifadeler (case değeri yok). (2) Bir case değeri + when değerleri.⭐99Counter-controlled loop'un üç tasarım sorusu nedir?
⭐100C'nin for'unun tasarım tercihleri nelerdir?
101C++ (ve C99) for'u C89'dan iki noktada nasıl ayrılır? Java/C#?
102Python'ın for'undaki else clause'u ne zaman çalışır?
103Logically-controlled loop'un iki tasarım sorusu nedir?
⭐104Java'nın döngüleri C/C++'tan nasıl ayrılır?
goto yoktur. C/C++'ta mantıksal kontrollü döngünün gövdesine dallanmak yasaldır ve kontrol ifadesi aritmetik olabilir.⭐105Etiketli ve etiketsiz break/continue hangi dillerde vardır?
break label), Perl (last). Etiketsiz continue: C, C++, Python. Etiketli continue: Java, Perl.Kural: etiketsiz break en içteki döngüyü, etiketli break dıştaki bir döngüyü sonlandırır.
106Veri yapısına dayalı iterasyon (iterator) nasıl çalışır?
Iterator arayüzü — next, hasNext, remove. Java 5.0: Iterable gerçekleyen sınıflar için "foreach" denen ama for anahtar sözcüğünü kullanan biçim.⭐107goto tartışması hangi kaygı üzerineydi? Java ve C# ne yapar?
goto yoktur; C#'ta vardır (switch içinde kullanılabilir). Slaytın kilit cümlesi: döngü çıkış deyimleri (break vb.) kısıtlanmış ve kamufle edilmiş goto'lardır.⭐108Kontrol yapısı zenginliği hangi ödünleşimi doğurur?
Lecture 7 · Subprograms (Ch.9)
⭐109İki temel soyutlama nedir, ne zaman öne çıktılar?
⭐110Subprogram'ların üç temel özelliği nedir?
⭐111parameter profile ve protocol tanımları nedir?
112formal ve actual parametre nedir?
113subprogram declaration nedir, C/C++'ta ne denir?
114Python, Ruby ve Lua'nın fonksiyon tanımı konusundaki istisnaları nelerdir?
Object'in metodudur ve nesnesiz çağrılabilir. Lua: tüm fonksiyonlar anonimdir.⭐115Positional ve keyword parametre karşılığının avantaj/dezavantajları nelerdir?
Keyword: actual ile birlikte formal'in adı belirtilir. + Parametreler herhangi sırada yazılabilir → karşılık hataları önlenir. − Kullanıcı formal parametre adlarını bilmek zorundadır.
116C++'ta default parametreler neden en sonda olmak zorundadır?
117Python'da * ve ** parametreleri ne yapar?
def fun1(p1,p2,*p3,**p4) ile fun1(2,4,6,8,mon=68,tue=72) → p3=[6,8], p4={'mon':68,'tue':72}.⭐118Procedure ile function arasındaki fark nedir?
⭐119Stack-dynamic local değişkenlerin avantaj ve dezavantajları nelerdir?
⭐120Static local değişkenlerin en büyük dezavantajı nedir?
121Hangi dillerin metotlarında yalnızca stack-dynamic local'ler vardır?
static ile bildirilebilir — bu Java'da yasal değildir.⭐122Parameter passing'in üç semantik modeli nedir?
⭐123Pass-by-value'nun avantaj ve dezavantajları nelerdir?
⭐124Pass-by-result nasıl çalışır ve hangi problemi doğurur?
sub(p1, p1)'de hangi formal en son kopyalanırsa o kazanır. C# örneğinde f.Fixer(out a, out a) sonucu implementation dependent'tır (17 veya 35).125Pass-by-value-result'ın diğer adı nedir ve dezavantajı?
⭐126Pass-by-reference'ın diğer adı nedir, avantaj ve dezavantajları?
fun(total,total), fun(list[i],list[j]), fun(list[i],i).⭐127Aliasing hangi zinciri tetikler?
⭐128Pass-by-name nasıl çalışır?
129Geçirilen referans çağrılan subprogram'da değiştirilebilir mi?
⭐130Java'da parametreler nasıl geçirilir?
⭐131Ada'nın üç parametre modu nasıl çalışır?
in varsayılandır. out atanabilir ama okunamaz; in okunabilir ama atanamaz; in out ikisi de.132C# ile PHP'nin ref kullanımı arasındaki fark nedir?
ref ile öncelenmelidir. PHP: yalnızca biri (actual veya formal) belirtebilir.133Python ve Ruby hangi parameter passing yöntemini kullanır?
⭐134Parametre tip denetimi hangi dillerde nasıldır?
⭐135Çok boyutlu bir array parametre olarak geçirilirken derleyicinin neyi bilmesi gerekir?
void fun(int matrix[][10]) yazılır; ilk subscript hariç tüm boyutlar bildirilmelidir. Sonuç: esnek subprogram yazmayı engeller. Çözüm: array'e pointer + boyutları ayrı parametre olarak geçir.136Java'nın gerçek iki boyutlu array'i var mıdır?
length/Length sabitini miras alır.⭐137Parameter passing tasarımındaki iki değerlendirme neden çatışır?
⭐138Shallow, deep ve ad hoc binding nedir?
139C/C++ ve Java, subprogram'ları parametre olarak geçirme konusunda ne yapar?
⭐140Delegate nedir? Multicast delegate ne demektir?
public delegate int Change(int x); — int alıp int döndüren herhangi metotla örneklenebilir. Bir delegate birden fazla adres tutabilir → multicast delegate. Dolaylı çağrı tipik olarak event handling ve GUI'lerde gerekir.⭐141Fonksiyonlardan hangi tipler döndürülebilir?
⭐142Overloaded subprogram nedir? Ada'nın ayrıcalığı nedir?
⭐143Polymorphism'in üç türü nedir?
⭐144Java 5.0 generic'lerinin C++'tan dört farkı nedir?
<T extends Comparable>). (4) Wildcard tipler (Collection<?>).145C# 2005 generic'leri Java 5.0'dan nasıl ayrılır?
146F#'ın generic'leri neden daha az kullanışlıdır?
'a gösterimi).⭐147Closure nedir, ne zaman gerekir?
⭐148Coroutine nedir? Hangi dilde doğrudan desteklenir?
Lecture 8 · Implementing Subprograms (Ch.10)
⭐149Subprogram linkage nedir?
⭐150Bir subprogram çağrısının genel semantiği hangi beş şeyi içerir?
⭐151Activation record ile activation record instance arasındaki fark nedir?
⭐152Activation record'un biçimi ve boyutu hakkında ne söylenebilir?
⭐153Dynamic link ve EP (Environment Pointer) neyi gösterir?
154Recursive olmayan bir subprogram çağrısı da ARI yaratır mı?
⭐155Prologue ve epilogue eylemleri nelerdir?
Epilogue (çıkış): value-result/out parametrelerin değerlerini actual'lara taşı; fonksiyonsa değerini caller'ın erişebileceği yere taşı; stack pointer'ı güncel EP−1'e ayarla ve EP'yi eski dynamic link'e kur; execution status'u geri yükle; kontrolü geri aktar.
⭐156Dynamic chain nedir?
⭐157local_offset nedir ve ne zaman belirlenir?
adres = EP + local_offset.158Hangi diller nested subprogram'a izin verir ve stack-dynamic local kullanır?
⭐159Non-local bir referansı bulmanın iki adımı nedir, hangisi zordur?
⭐160Static link, static chain, static_depth ve chain_offset tanımlarını verin.
⭐161Non-local referans için verimli ve verimsiz yöntemler nelerdir?
⭐162Static chain'in iki problemi nedir?
163Çağrı anında static link nasıl kurulur?
164Block nedir ve nasıl gerçeklenir?
İki gerçekleme: (1) blokları parametresiz subprogram gibi ele al — her bloğun activation record'u olur; (2) maksimum depolama derleme zamanında belirlenebildiği için bu alan activation record'da local değişkenlerden sonra ayrılır.
⭐165Dynamic scoping deep access ve shallow access ile nasıl gerçeklenir?
Shallow access: local'ler merkezî bir yere konur — her değişken adı için bir stack, ya da her değişken adı için bir girdisi olan merkezî tablo.
166Static-scoped ve dynamic-scoped dillerde non-local erişimin başlıca yöntemleri nelerdir?
Lecture 9 · ADTs & Encapsulation (Ch.11)
⭐167Abstraction nedir?
⭐168Diller process ve data abstraction'ı ne zamandan beri destekler?
⭐169Abstract data type'ın iki koşulu nedir?
⭐170ADT'nin birinci koşulunun avantajları nelerdir?
⭐171ADT'nin ikinci koşulunun avantajları nelerdir?
172Bir dilin ADT desteği için sağlaması gereken üç şey nedir?
173ADT'lerin üç tasarım sorusu nedir?
⭐174C++'ın sınıf yapısının temeli nedir ve örnekler neyi paylaşır?
struct tipi + Simula 67'nin sınıfları. Bir sınıf bir tiptir. Tüm örnekler üye fonksiyonların tek bir kopyasını paylaşır; ama her örneğin kendi veri üyeleri kopyası vardır. Örnekler static, stack dynamic veya heap dynamic olabilir.⭐175C++'ta constructor ve destructor nasıl çalışır?
⭐176Java'nın destructor'ı var mıdır?
⭐177C++'ta friend ne işe yarar?
⭐178Java'nın ADT desteğini C++'tan ayıran beş nokta nedir?
⭐179C#'ın eklediği erişim belirteçleri nelerdir? internal ne demektir?
internal ve protected internal. internal bir üye, bulunduğu assembly'deki tüm sınıflara görünürdür — yani "assembly içinde public, dışında private".180C#'ta struct nedir?
⭐181C#'ın property'si hangi sorunu çözer?
⭐182Ruby'de instance ve class değişkenleri nasıl adlandırılır? Constructor nedir?
@ ile başlar. Class: çift @@ ile başlar. Constructor: initialize adında ve sınıf başına yalnızca bir tane; new çağrılınca örtük çalışır. Daha fazlası gerekiyorsa farklı adları olmalı ve new'i açıkça çağırmalıdırlar. Erişim varsayılanı public; sınıflar dinamiktir.⭐183Parameterized ADT nedir ve hangi diller için bir sorundur?
⭐184Java 5.0'ın parameterized sınıflarının kısıtları nelerdir?
185C# 2005'in parameterized sınıfları Java 5.0'dan nasıl ayrılır?
⭐186Encapsulation neden gereklidir?
187Hangi diller nested subprogram'ı destekler?
⭐188C'de encapsulation'ın iki problemi nedir?
⭐189C# assembly nedir?
⭐190Naming encapsulation nedir ve dillerde nasıl gerçeklenir?
import kullanır. Ruby: module.⭐191Ruby module'lerinin kısıtları nelerdir?
require metoduyla istenir.⭐193Process abstraction'ı destekleyen ilk dil hangisidir? Data abstraction'ın evrimi ne zaman başladı?
⭐194Data abstraction'ın yaygınlaşması neden process abstraction'ınkini izlemek zorundaydı?
⭐195"Bütün yerleşik (built-in) veri tipleri aslında ADT'dir" ne demektir? Floating point üzerinden açıklayın.
Floating point: (1) değişken yaratma aracı sunar ✔ (2) bir işlem kümesi sunar ✔ (3) değerin bellekteki gerçek biçimi kullanıcıdan gizlidir ✔ — kullanıcı temsilin parçalarını doğrudan değiştiremez, yalnızca dilin verdiği işlemleri kullanabilir. Üç koşul da sağlanıyor.
⭐196Information hiding, taşınabilirliği (portability) nasıl sağlar? Tarihsel örnek nedir?
Tarihsel kanıt: IEEE 754 (1980'lerin ortası) öncesinde her bilgisayar mimarisinin kendi floating point temsili vardı; değerleri bir makineden diğerine taşımak büyük bir sorundu. Standart bir veri soyutlaması gelince sorun ortadan kalktı.
⭐197Abstraction'ı hocanın kuş örneğiyle açıklayın. Neden "karmaşıklığa karşı bir silah"tır?
"Karmaşıklığa karşı silah" olmasının nedeni: programcının temel özniteliklere odaklanıp ikincil olanları göz ardı etmesini sağlar — karga üzerinde kod yazarken bacak/kanat değişkenlerini düşünmek zorunda kalmazsın.
⭐198Bir ADT'nin iç temsilini değiştirmek istemci kodunu etkiler mi? Peki protokolünü değiştirmek?
Ama bir işlemin protokolü değişirse istemciler de değişmek zorundadır.
Hocanın kuş versiyonu:
fly() → move() değişiminde kartal/serçe istemcileri etkilenmez; kimi uçar, kimi yüzer, kimi koşar ama hepsi konum değiştirir.⭐192Java'da protected, C++'takinden nasıl farklıdır?
protected, aynı paketteki diğer sınıflara da açıktır (yalnız türetilmiş sınıflara değil). Slayt bu farkı "Different than C++" diye işaretlemiştir. Ayrıca Java'da modifier'sız (default) erişim, aynı paket içinde her yere açık ama paket dışına kapalıdır.Lecture 10 · Support for OOP (Ch.12)
Dönemin son dersi. Hoca 10 Ağustos'ta finalin "tüm dönemi kapsayacağını ama ağırlığın vize sonrasına kayacağını" söyledi — bu bölüm hem en taze hem de ağırlık merkezinin içinde.
⭐199Bir dilin object-oriented sayılması için desteklemesi gereken üç dil özelliği nedir?
⭐200ADT'lerle software reuse'un iki problemi nedir? Inheritance bunları nasıl çözer?
⭐201Inheritance'ın dezavantajı nedir? Neden ironiktir?
⭐202Message ile message protocol nedir? Bir message'ın kaç parçası vardır?
⭐203Bir message ile bir subprogram çağrısı arasındaki fark nedir?
⭐204Bir subclass, ebeveyninden hangi üç şekilde farklılaşabilir?
⭐205Class variable ile instance variable farkı nedir? Class method ne zaman çağrılabilir?
206Single ve multiple inheritance'ta sınıf ilişkileri nasıl gösterilir?
⭐207Polymorphic variable nedir? Dynamic binding ne zaman devreye girer?
⭐208Abstract method ve abstract class nedir? Hangi kural kesindir?
⭐209OOP dilleri için yedi tasarım sorusu nedir?
⭐210Exclusivity of objects için üç yaklaşım ve avantaj/dezavantajları nedir?
⭐⭐211Subclass ile subtype arasındaki fark nedir? "Principle of substitution" nedir?
⭐⭐212Multiple inheritance'ın iki dezavantajı ve avantajı nedir? Diamond problemi nedir?
x Z'ye iki kez gelir. Çözüm: class D1 : public virtual BC → x bir kez gelir.⭐213Object slicing nedir ve ne zaman ortaya çıkar?
Rectangle rect; Square sq; rect = sq; → yalnızca veri üyeleri kopyalanır ve rect.draw() Rectangle'ın draw'ını çağırır. Heap'te (pointer ataması) böyle bir sorun yoktur.⭐214Nested class'ların motivasyonu nedir? Asıl tasarım sorusu hangisidir?
⭐215Smalltalk'ta inheritance ve dynamic binding nasıl çalışır?
⭐216Smalltalk'ın değerlendirmesi (avantaj/dezavantaj) nedir?
⭐217C++'ta private derivation ile public derivation farkı nedir? Private derivation neden kullanılır?
::) ile tek tek yeniden görünür kılınabilir (reexportation).⭐⭐218C++'ta virtual ve pure virtual ne demektir?
virtual void draw() = 0;; amacı gerçeklemesini vermeden arayüz sağlamak. En az bir pure virtual fonksiyonu olan sınıf abstract class'tır ve örneklenemez. Not: C++'ta abstract class ayrı bir reserved word'le işaretlenmez ve tamamen tanımlı metotlar da içerebilir.⭐219C++'ın değerlendirmesi nedir (Smalltalk ile karşılaştırmalı)?
⭐⭐220Java'da hangi metotlar statik bağlanır?
final (override edilemez → dynamic binding anlamsız), static ve private (ikisi de override'ı engeller). Bu, C++'ın tam tersidir (orada varsayılan static'tir, dynamic için virtual gerekir).⭐221Java'da bir sınıfı final yapmanın avantajı ve dezavantajı nedir?
⭐⭐222Interface ile abstract class arasındaki farklar nelerdir?
default kod olabilir); abstract class tam kod, varsayılan kod veya stub verebilir. Sayı: bir sınıf birçok interface implemente edebilir, ama yalnızca bir abstract class extend edebilir. Yeni metot eklemek: interface'te tüm gerçeklemeleri bulup her birine kod yazman gerekir; abstract class'ta varsayılan gerçekleme verirsin, mevcut kod bozulmadan çalışır. Esneklik: interface'te sıfırdan başlarsın; abstract class'ta yazarın dayattığı yapıyla yaşarsın.⭐223Java'da inner class ile static nested class farkı nedir?
i.new Bar()). Static nested: bu pointer yoktur → üyelere erişemez, ama dış sınıfın örneği olmadan örneklenebilir (new Foo.Bar()). Nested class'lar anonim de olabilir; local nested class bir metodun içinde tanımlanır ve access specifier kullanmaz.224Boxing nedir?
int → Integer). Java 5.0'dan itibaren otomatiktir (autoboxing). Bu, "exclusivity of objects" tasarım sorusunun Java'daki izidir: iki tür varlık (primitive + nesne) bir arada bulunur.⭐225Java'nın OOP değerlendirmesinde C++'tan ayrılan noktalar nelerdir?
⭐226C#'ta dynamic binding nasıl sağlanır? new ile override farkı nedir?
virtual, türetilmiş metotlar override. Abstract metotlar abstract ile işaretlenir ve tüm subclass'larda gerçeklenmek zorundadır. new metodu gizler (hiding) — parent sürümü base.Draw() ile hâlâ çağrılabilir; override ise dinamik olarak ezer. Tüm C# sınıfları nihayetinde Object'ten türer.227C#'ta struct ve nested class hakkında ne bilmelisin?
⭐228Ruby'nin OOP desteğini ayırt eden özellikler nelerdir?
if/else dallarına iki tanım koyarak çalışma zamanında hangisinin geçerli olacağını seçebilir. Tüm değişkenler tipsiz referanslardır. Erişim denetimi veri ile metotlarda farklıdır: tüm veri private'tır ve değiştirilemez; metotlar public/private/protected olabilir ve erişim çalışma zamanında denetlenir. Constructor: initialize. Subclass sözdizimi: class MyClass < Super.⭐229Ruby'nin OOP değerlendirmesindeki üç eksiklik nedir?
⭐230Class instance record (CIR) nedir? Neden erişim verimlidir?
⭐⭐231vtable nedir ve nasıl çalışır?
Örnek (A → B extends A, draw override edilmiş): B'nin vtable'ında
draw → B'nin kendi kodu, area → A'nın kodu (override edilmedi), sift → B'nin kodu.⭐232Beş dili saflık, multiple inheritance ve binding varsayılanı açısından sırala.
C++: hibrit (iki tip sistemi) · MI var · varsayılan static (
virtual ile dynamic) · private ile subtype bozulur.Java: yalnızca OOP · MI yok (interface) · varsayılan dynamic (
final/static/private hariç) · tüm subclass'lar subtype · inner class erişebilir.C#: C++ + Java · MI yok ·
virtual+override · struct'larda inheritance yok.Ruby: saf OOP · MI'yı tam desteklemez · tamamen dynamic · subclass ≠ subtype · abstract class yok.
Terim Dipnotları
Metinde şöyle görünen° her terimin tek tek açıklaması — alfabetik. Terimler İngilizce bırakıldı çünkü sınav İngilizce; açıklamalar Türkçe.
- abstraction — soyutlama
- Karmaşık bir yapıyı, iç detaylarını görmeden/bilmeden tanımlayıp kullanabilme. Örn. bir fonksiyonu çağıran, içini bilmek zorunda değildir. Writability'nin temel bileşenlerinden.
- ADT — abstract data type — soyut veri tipi
- Veriyi ve o veri üzerindeki işlemleri tek pakette toplayıp iç temsili gizleyen soyutlama (örn. stack: push/pop var, dizinin kendisi gizli). 1970'lerin sonundaki "data abstraction" akımının ürünü; OOP'nin ilk bileşeni.
- alias / aliasing — takma ad
- Aynı bellek hücresine birden fazla isimle erişilebilmesi. Pointer'lar, reference'lar ve C/C++ union'ları yaratır. Tehlikesi: bir değişkenin değeri, başka bir isme yapılan atamayla değişebilir — okuyan kişi tüm takma adları aklında tutmak zorundadır. Kısıtlanması reliability'yi artırır.
- ALU — arithmetic logic unit
- CPU'nun aritmetik (+,−,×,÷) ve mantık (AND, OR...) işlemlerini yapan birimi. Hocanın benzetmesi: işi yapan "katır"; beyin ise control unit'tir.
- binding — bağlama
- Bir varlık ile bir nitelik arasında ilişki kurulması: değişken↔tip, değişken↔değer,
*↔çarpma. Kurulduğu ana binding time denir (language design / implementation / compile / load / run time). Run time'dan önce kurulup değişmeyene static, çalışırken kurulan/değişene dynamic binding denir. - BNF — Backus-Naur Form
- Programlama dili syntax'ını tarif etmek için kullanılan kural notasyonu; John Backus'un ALGOL 58 için icat ettiği, Peter Naur'un geliştirdiği biçim. Context-free grammar'lara eşdeğerdir; bir metalanguage'dir.
- von Neumann bottleneck
- Bellek ile CPU arasındaki bağlantının, komut işleme hızından çok daha yavaş olması; bilgisayar hızının birincil sınırlayıcısı. Hocanın örneği: yavaş disk + hızlı işlemci arasında tek erişimde milyonlarca cycle boşa gidebilir.
- byte code
- Kaynak kod ile makine kodu arasındaki taşınabilir ara temsil. Java derleyicisi kaynak kodu byte code'a çevirir; byte code'u her platformdaki JVM çalıştırır — taşınabilirliğin sırrı budur.
- control unit
- CPU'nun komutları çözen ve diğer birimleri yöneten "beyni"; fetch-execute döngüsünü yürütür.
- derivation — türetim
- Start symbol'den başlayıp grammar kurallarını tekrar tekrar uygulayarak yalnızca terminal içeren bir cümleye ulaşma süreci. Her adımda en soldaki nonterminal açılıyorsa leftmost, en sağdaki açılıyorsa rightmost derivation. Türetim sırası dili değiştirmez.
- elaboration
- Bir bildirime (declaration) bağlı kodun, çalışma anında o noktaya gelindiğinde yürütülmesi — stack-dynamic değişkenlerin belleği bu anda ayrılır. Tanım gereği "always occurs during run time."
- exception handling
- Çalışma zamanı hatasını (sıfıra bölme, dosya yok...) yakalayıp programın çökmek yerine düzeltici aksiyon alabilmesi. Reliability'nin bileşeni; yüksek seviyede ilk kez PL/I'da, ayrıntılı biçimde Ada'da.
- fetch-execute cycle
- CPU'nun sonsuz döngüsü: program counter'ın gösterdiği komutu bellekten getir → sayacı artır → komutu çöz → çalıştır → başa dön.
- finite automaton — sonlu otomat
- Sonlu sayıda durum (state) arasında, girdiye göre geçiş yapan soyut makine. Regular language'ları tanır; lexical analyzer matematiksel olarak budur. (Parser ise daha güçlü bir makine olan pushdown automaton'dur.)
- first-class entity
- Bir değerin dilde "birinci sınıf vatandaş" olması: değişkene atanabilir, parametre olarak geçirilebilir, fonksiyondan döndürülebilir. Scheme'de fonksiyonlar first-class'tır.
- floating point
- Ondalıklı sayıların bilgisayardaki gösterimi ve aritmetiği (örn. 3.14). Bilimsel hesaplamanın temel ihtiyacı; IBM 704 bunu ilk kez donanımda yaptı ve derlenen dillerin (Fortran) önünü açtı.
- handle
- Bottom-up parsing'de, eldeki right sentential form içinde bir önceki adıma dönmek için LHS'iyle değiştirilmesi (reduce) gereken alt dizi. Tanım: right sentential form'un en soldaki simple phrase'i. Parsing = "handle pruning."
- inheritance — kalıtım
- Bir sınıfın, başka bir sınıfın veri ve davranışlarını devralıp üzerine ekleme/değiştirme yapabilmesi. OOP formülünün ikinci bileşeni (SIMULA 67'de doğdu).
- interpreter — yorumlayıcı
- Kaynak kodu çevirmeden, satır satır okuyup doğrudan yürüten program — "software simulation of a machine." Hata ayıklamayı kolaylaştırır ama 10–100 kat yavaştır.
- IR — instruction register
- Bellekten getirilen komutun, çözülüp çalıştırılmak üzere konulduğu CPU register'ı.
- JIT — just-in-time compilation
- Ara dile çevrilmiş programın alt programlarını, çağrıldıkları anda makine koduna derleyip sonraki çağrılar için saklayan sistem. Hocanın tanımı: "essentially delayed compilers." Java ve .NET böyle çalışır.
- JVM — Java Virtual Machine
- Java byte code'unu çalıştıran sanal makine: byte code interpreter + run-time system. Byte code'u olan her platformda Java programı değişmeden çalışır.
- keyword
- Yalnızca belirli bağlamlarda özel anlam taşıyan kelime. Reserved word'den farkı: bağlam dışında kullanıcı ismi olabilir (Fortran'da keyword'ler değişken adı yapılabilir).
- lambda calculus
- Hesaplamayı yalnızca fonksiyon tanımlama ve uygulama ile ifade eden biçimsel sistem (Church, 1930'lar). Lisp'in ve tüm fonksiyonel dillerin sözdizimsel/kuramsal temeli.
- language (formal)
- Biçimsel tanım: bir alfabe üzerindeki cümlelerin (sentence) kümesi. "Java dili" = geçerli tüm Java programlarının kümesi.
- left recursion
- Bir kuralın kendi LHS'ini RHS'in en solunda içermesi (
A → A α), doğrudan ya da dolaylı. Top-down parser'ı imkânsız kılar (rutin kendini sonsuz çağırır); mekanik dönüşümle giderilir. - lexeme
- Dilin en küçük sözdizimsel birimi:
sum,*,begin,47. Lexical analyzer karakter dizisini lexeme'lere böler; her lexeme bir token kategorisine aittir. - lexical analysis
- Derlemenin ilk fazı: kaynak koddaki karakterleri anlamlı birimlere (lexeme/token) ayırma. Bunu yapan bileşen lexical analyzer (lexer): "essentially a pattern matcher for character strings"; parser'ın front-end'i olarak, parser her istediğinde sıradaki token'ı verir. Yan işleri: boşluk/yorum atlama, isimleri symbol table'a koyma.
- lifetime
- Değişkenin belirli bir bellek hücresine bağlı kaldığı süre — allocation ile başlar, deallocation ile biter. Zamansal (temporal) bir kavramdır; scope ile karıştırma (o metinseldir). Dört kategori: static, stack-dynamic, explicit heap-dynamic, implicit heap-dynamic.
- linked list — bağlı liste
- Her elemanın bir sonrakinin adresini (işaretçisini) tuttuğu veri yapısı. Boyutu dinamik büyür; AI'ın sembolik verisi için dizilerden uygundur — Lisp'in temel yapısı.
- linking & loading
- Kullanıcı kodunu, sistem/kütüphane program birimleriyle birleştirip belleğe yüklenebilir tek parça hâline getirme. Ortaya çıkan bütün: load module (executable image).
- l-value
- Bir değişkenin adresi — atamanın sol tarafında görünen yüzü.
x = 5'te x'in l-value'su kullanılır ("5'i x'in adresine yaz"). - metalanguage
- Başka bir dili tarif etmek için kullanılan dil. BNF, programlama dillerinin metalanguage'idir.
- nonterminal
- Grammar'da sözdizimsel yapı sınıflarını temsil eden soyutlama (sözdizim değişkeni); köşeli ayraçla yazılır:
<expr>,<stmt>. Kurallarla açılır; nihai programda görünmez. - opcode — operation code
- Makine komutunun "ne yapılacak" kısmını kodlayan bit deseni (kalan bitler genelde operand adresi). Hocanın hayali makinesi: 16 bit = 4 bit opcode + 12 bit adres.
- operator overloading
- Aynı operatörün, operand tiplerine göre farklı işlemler yapması (
+: tamsayı toplama, ondalık toplama, string birleştirme...). Az miktarda doğal; aşırısı okunabilirliği bozar. - orthogonality
- Az sayıda temel yapının, az sayıda kuralla her kombinasyonu geçerli olacak şekilde birleştirilebilmesi. Ne kadar ortogonal → o kadar az istisna → o kadar kolay öğrenme. Aşırısı ise hataların derleyiciden kaçmasına yol açar. ALGOL 68 bu ilke üzerine kurulan ilk dildir.
- paradigm — paradigma
- Programlamaya yaklaşım biçimi/felsefesi: imperative (adım adım komut), functional (fonksiyon uygulama), logic (kural + çıkarım), OOP (nesneler). Dersin ana hedefi: probleme göre paradigma seçebilmek.
- parse tree
- Bir türetimin hiyerarşik gösterimi: kök start symbol, iç düğümler nonterminal, yapraklar terminal. Derleyici kodu bu ağaçtan üretir — ambiguity bu yüzden ciddi problemdir. Ağaçta daha aşağıdaki operatör önce hesaplanır (yüksek öncelik).
- PC — program counter
- Bir sonraki çalıştırılacak komutun bellek adresini tutan register; her fetch'ten sonra artırılır.
- polymorphism — çok biçimlilik
- Aynı çağrının, nesnenin gerçek tipine göre çalışma zamanında farklı davranışlara bağlanması (örn.
shape.draw()daireyse daire, kareyse kare çizer). OOP formülünün üçüncü bileşeni. - preprocessor
- Derlemeden hemen önce kodu işleyip gömülü makroları genişleten araç — "essentially a macro expander." C'nin
#includeve#define'ı klasik örnek. - referencing environment
- Bir deyimde görünür olan tüm isimlerin kümesi. Static-scoped dilde: lokaller + kapsayan scope'ların görünürleri. Dynamic-scoped dilde: lokaller + tüm aktif alt programların görünürleri.
- reserved word
- Kullanıcının isim olarak kullanamayacağı özel kelime (
if,while...). Okunabilirliğe yardım eder; ama çok fazlası çakışma yaratır (COBOL: 300 tane —lengthbile yasak). - r-value
- Bir değişkenin değeri — atamanın sağ tarafında görünen yüzü.
y = x'te x'in r-value'su okunur. r-value'ya erişmek için önce l-value (adres) bilinmelidir. - scope — kapsam
- Bir değişkenin görünür (okunabilir/atanabilir) olduğu deyimlerin aralığı. Metinsel (spatial) bir kavramdır. Static scope program metnine, dynamic scope çağrı zincirine göre belirlenir.
- sentence
- Bir alfabe üzerindeki karakter dizisi; bir dilin elemanı. Türetim tamamlandığında elde edilen, yalnızca terminal içeren dizi de sentence'tır.
- sentential form
- Türetimin her adımındaki sembol dizisi (terminal + nonterminal karışık olabilir). Yalnızca terminallerden oluşanı sentence'tır.
- symbol table
- Derleme boyunca isimlerin ve niteliklerinin (tip vb.) tutulduğu veri yapısı — hocanın tanımıyla "a database for the compilation process." İsimleri lexer koyar; nitelikleri derleyicinin sonraki fazları doldurur.
- terminal
- Grammar'ın daha fazla açılamayan sembolleri: lexeme'ler ve token'lar (
if,+,const...). Parse tree'nin yaprakları terminallerdir. - token
- Lexeme'lerin kategorisi:
sumvetotallexeme'leri IDENT token'ına aittir;+gibi tek lexeme'li token'lar da vardır. Lexer içinde genelde tamsayı kodlarla temsil edilir. - type checking
- İşlemlerin, operand tiplerinin uyumluluğu açısından denetlenmesi (derleme ya da çalışma zamanında). Tip hatalarını yakalar; reliability'nin bileşeni.
- type inference
- Tipin bildirimsiz, bağlamdan çıkarılması — çoğunlukla ilk değerden: C#'ta
var a = 5.0;→ double. ML, Haskell, F#'ın temel mekanizması. (Dynamic typing ile karıştırma: inference'ta tip compile time'da sabitlenir.) - von Neumann architecture
- Veri ve programın aynı bellekte durduğu, belleğin CPU'dan ayrı olduğu, komut ve verinin ikisi arasında taşındığı mimari. Neredeyse tüm bilgisayarların temeli; imperative dillerin de kalıbı (variable = hücre, assignment = taşıma).
- — Final terimleri (Ch.6–12) —
- Aşağıdakiler vize sonrası altı dersin terimleridir.
- activation record
- Çalışan bir subprogram'ın kod-olmayan kısmının (local değişkenler ve değişebilen veri) biçimi/yerleşimi — bir şablon. Somut doldurulmuş kopyasına activation record instance (ARI) denir. Biçimi static, boyutu dynamic olabilir.
- actual parameter
- Subprogram çağrısında kullanılan değer veya adres. Karşıtı: formal parameter.
- abstract data type (ADT)
- İki koşulu sağlayan kullanıcı tanımlı tip: (1) nesnelerinin temsili gizlidir, tek mümkün işlemler tipin tanımında sağlananlardır; (2) tip bildirimi ve işlem protokolleri tek bir sözdizimsel birimdedir. Kısaca: information hiding + packaging.
- associative array (ilişkisel dizi)
- Elemanları key'lerle indekslenen sırasız topluluk. Normal array'den farkı: kullanıcı tanımlı key'ler saklanmak zorundadır. Perl'de hash, Python'da dictionary.
- BCD (binary coded decimal)
- Her ondalık basamağın ayrı ikili kodla saklanması. decimal tipin gerçekleme biçimi; kesinlik kazandırır ama bellek israf eder.
- chain_offset
- Referansı içeren subprogram'ın static_depth'i eksi bildirimi içeren subprogram'ın static_depth'i — yani static chain'de "kaç halka yukarı çıkılacağı". Non-local referans
(chain_offset, local_offset)çiftiyle temsil edilir. - closure
- Bir subprogram ve onun tanımlandığı referencing environment. Nested subprogram'a izin vermeyen static-scoped bir dilin closure'a ihtiyacı yoktur.
- coercion
- Örtük (implicit) tip dönüşümü; derleyici ya da run-time sistem başlatır. Mixed-mode ifadeleri mümkün kılar ama derleyicinin tip hatası yakalama yeteneğini azaltır ve strong typing'i zayıflatır.
- coroutine
- Birden çok girişi olan ve bunları kendisi yöneten subprogram; çağrısına resume denir. Symmetric control sağlar; yürütme interleaved but not overlapped (quasi-concurrent). Doğrudan Lua'da desteklenir.
- dangling pointer
- Deallocate edilmiş bir heap-dynamic değişkeni gösteren pointer. Formül: binding nesneden uzun yaşarsa dangling reference; nesne binding'den uzun yaşarsa garbage. Çözümler: tombstone, locks-and-keys.
- decimal type
- Sabit sayıda ondalık basamağı BCD kodlu saklayan tip; iş uygulamaları (para) içindir. + accuracy · − sınırlı aralık, bellek israfı. COBOL için temel, C# de sunar.
- deep access / shallow access
- Dynamic scoping'in gerçeklenme yöntemleri. Deep: non-local referanslar dynamic chain'de aranır (zincir uzunluğu statik belirlenemez, her ARI değişken adı taşımalı). Shallow: local'ler merkezî bir yerde tutulur (isim başına stack ya da merkezî tablo). deep/shallow binding ile karıştırma.
- deep / shallow / ad hoc binding
- Parametre olarak geçirilen bir subprogram'ın hangi referencing environment'ı kullanacağı. Deep: tanımının ortamı (static-scoped diller için doğal). Shallow: onu çalıştıran çağrının ortamı (dynamic-scoped için doğal). Ad hoc: onu geçiren çağrının ortamı.
- delegate
- C#'ta metot pointer'ının nesne biçimi. Belirli bir protokole uyan herhangi bir metotla örneklenebilir; birden fazla adres tutabilen türüne multicast delegate denir.
- descriptor
- Bir değişkenin özniteliklerinin toplamı. Öznitelikler tamamen static ise yalnız compile-time'da (symbol table'ın parçası), dynamic ise run-time boyunca korunur.
- discriminant
- Bir union'da hangi alanın kullanılacağını söyleyen tip göstergesi. Discriminant içeren union'a discriminated union (safe) denir; içermeyene free union (unsafe, type checking yok).
- dynamic chain (call chain)
- Belirli bir andaki stack'teki dynamic link'lerin topluluğu. Dynamic link, caller'ın ARI'sının tepesini gösterir.
- EP (Environment Pointer)
- Run-time sistemin koruduğu, o an çalışan program biriminin ARI'sının tabanını gösteren işaretçi. Local erişim:
adres = EP + local_offset. - enumeration type
- Tüm olası değerleri, tanımda isimlendirilmiş sabitler olarak verilen ordinal tip. readability (renk sayı değil) ve reliability (derleyici işlem ve aralık denetler) sağlar. C#, F#, Swift, Java 5.0 C++'tan iyidir çünkü enum değişkenlerini integer'a coerce etmezler.
- formal parameter
- Subprogram header'ında listelenen ve gövdede kullanılan dummy (kukla) değişken.
- garbage collection
- Erişilemez hâle gelmiş heap belleğinin geri kazanılması. İki yaklaşım: reference counting (eager, kademeli; dairesel yapılarda çuvallar) ve mark-sweep (lazy, boş liste bitince; çalışınca gecikme yaratır — modern hâli incremental mark-sweep).
- generic subprogram (polymorphic subprogram)
- Farklı çağrılarda farklı tiplerde parametre alan subprogram; parametric polymorphism sağlar — dynamic binding'in ucuz bir compile-time ikamesi.
- heap-dynamic array
- Subscript aralıklarının bind'ı ve depolama ayırması dinamik olan, defalarca değişebilen array. Avantajı flexibility; dezavantajı allocation/deallocation maliyeti. Java
ArrayList, C#List, Python, Ruby, Perl, JavaScript. - IEEE 754
- Floating point standardı. 32-bit: 1 sign + 8 exponent + 23 fraction. 64-bit: 1 + 11 + 52. precision = kesir doğruluğu; range = kesir + üs aralıklarının birleşimi.
- information hiding
- Bir tipin iç temsilinin kullanıcı kodundan gizlenmesi. ADT'nin birinci koşulu; reliability sağlar çünkü temsil, kullanıcı kodunu etkilemeden değiştirilebilir.
- internal (C#)
- Bir üyeyi, bulunduğu assembly'deki tüm sınıflara görünür kılan erişim belirteci — "assembly içinde public, dışında private".
- local_offset
- Bir local değişkenin, activation record'un başlangıcına göre offset'i. Derleyici tarafından derleme zamanında belirlenebilir.
- memory leakage (bellek sızıntısı)
- Ayrılmış heap değişkenlerinin erişilemez hâle gelme (garbage olma) süreci. Örnek: p1 bir nesneyi gösterirken başka bir nesneye yönlendirilir, eskisi kaybolur.
- mixed-mode expression
- Operand'ları farklı tipte olan ifade. Bilgisayarlarda farklı tipte operand alan ikili işlem olmadığı için dil, örtük dönüşüm (coercion) kuralları tanımlamak zorundadır. ML ve F#'ta ifadelerde hiç coercion yoktur.
- name / structure type equivalence
- Name: aynı bildirimde ya da aynı tip adını kullanan bildirimlerdeki değişkenler eşdeğerdir — kolay ama çok kısıtlayıcı. Structure: yapıları aynıysa eşdeğerdir — esnek ama zor; sorunu, aynı yapıdaki farklı anlamlı tiplerin ayırt edilememesi.
- optional type
- Bir değişkenin şu anda değeri olmadığını belirtebilmesini sağlayan tip. C#, F#, Swift. C#'ta struct'lar tip adına
?eklenerek optional yapılır (int? x;); değersizliknull, Swift'tenil. - ordinal type
- Olası değerleri pozitif tamsayılarla kolayca eşleştirilebilen tip. Java'daki primitive örnekleri: integer, char, boolean.
- parameter profile (signature) · protocol
- profile: parametrelerin sayısı, sırası ve tipleri. protocol: profile + (fonksiyonsa) dönüş tipi. Overloaded subprogram'ların her versiyonu benzersiz bir protokole sahiptir.
- pass-by-name
- Actual parametrenin, formal'in tüm geçtiği yerlere metinsel olarak konması. Geç bağlamada esneklik sağlar; gerçeklemesi karmaşık ve verimsizdir, readability/reliability düşürür.
- pass-by-reference (pass-by-sharing)
- Değer yerine bir access path (adres) geçirilir. + verimli (kopyalama yok) · − erişim yavaş, istenmeyen side effect ve alias'lar → readability ↓ → reliability ↓ → verification zorlaşır.
- pass-by-result
- Out-mode gerçekleme: subprogram'a değer iletilmez, formal local değişken gibi davranır, dönüşte değeri actual'a taşınır. Actual parameter collision riski taşır (
sub(p1, p1)). - pass-by-value
- In-mode gerçekleme: actual'ın değeri formal'i initialize eder, normalde kopyalayarak. Skalerler için hızlı; büyük parametrelerde taşıma pahalı.
- pointer
- Değer aralığı bellek adresleri +
nilolan tip. Indirect addressing gücü ve dinamik bellek yönetimi sağlar. "Pointer'lar goto gibidir — bir değişkenin erişebileceği hücre aralığını genişletirler." Ama dinamik veri yapıları için zorunludur. - primitive data type
- Başka veri tipleri cinsinden tanımlanmayan tip. Bazıları donanımın doğrudan yansımasıdır (integer), bazıları küçük yazılım desteği ister.
- process abstraction / data abstraction
- İki temel soyutlama. Process: ilk günlerden beri vurgulandı, subprogram'larla sağlanır. Data: 1980'lerde vurgulandı, ADT'lerle sağlanır. Bugün ikisi eşit derecede önemli sayılır.
- referential transparency
- Aynı değere sahip iki ifadenin, programın davranışını değiştirmeden her yerde birbirinin yerine konabilmesi. Saf fonksiyonel diller her zaman sağlar — çünkü değişkenleri yoktur, fonksiyon state tutamaz, değeri yalnızca parametrelerine bağlıdır.
- record
- Possibly heterogeneous bir veri elemanı topluluğu; elemanlar isimleriyle tanımlanır. Array'den farkı: array homogeneous + konumla; array erişimi record erişiminden yavaştır çünkü subscript'ler dinamik, field name'ler statiktir.
- short-circuit evaluation
- Sonucun, tüm operand/operatörler değerlendirilmeden belirlendiği ifade. C/C++/Java'da
&&/||short-circuit, bitwise&/|değil; Ruby, Perl, ML, F#, Python'da tüm mantık operatörleri short-circuit. - functional side effect
- Bir fonksiyonun two-way bir parametreyi ya da non-local (global) bir değişkeni değiştirmesi. İfadenin sonucu operand değerlendirme sırasına bağlı hâle gelir. İki çözüm: yasaklamak, ya da değerlendirme sırasını sabitlemek (Java: soldan sağa).
- slice (dilim)
- Bir array'in alt yapısı; "bir referanslama mekanizmasından başka bir şey değildir". Yalnızca array işlemleri olan dillerde anlamlıdır. String'lerdeki karşılığı substring reference.
- static chain
- Bir ARI'yı tüm static ancestor'larına bağlayan static link zinciri; static-scoped, nested subprogram'lı dillerde non-local erişimin başlıca yöntemidir. Problemleri: derin nesting'de yavaşlık, ve kod değişikliğinin erişim maliyetini değiştirmesi.
- strong typing
- Tip hatalarının her zaman yakalanması. C/C++ değildir (parametre denetimi atlanabilir, union'lar denetlenmez); Java/C# neredeyse (explicit casting); ML/F# evet; Ada Java'dan daha etkilidir. Coercion kuralları strong typing'i ciddi biçimde zayıflatır.
- tombstone · locks-and-keys
- Dangling pointer'a iki çözüm. Tombstone: pointer yalnızca ara bir heap hücresini gösterir; değişken silinince tombstone nil yapılır — zaman ve alan bakımından pahalı. Locks-and-keys: pointer (key, address) çiftidir, erişimde key ile lock karşılaştırılır; eşleşmezse run-time error.
- tuple
- Record'a benzer ama elemanları isimsiz tip. Python, ML, F#'ta fonksiyonların birden çok değer döndürmesini sağlar; Python'da immutable'dır.
- two's complement
- Negatif tamsayı gösterimi: pozitif hâlin bit'leri ters çevrilir (ones complement), sonra 1 eklenir. Ones complement yerine tercih edilmesinin nedeni: ones complement'te iki tane sıfır (pozitif ve negatif sıfır) olur.
- union type
- Değişkenlerinin, çalışma sırasında farklı zamanlarda farklı tipte değerler saklamasına izin veren tip. C/C++ free union sunar (unsafe); Ada, ML, Haskell, F# discriminated union sunar (safe); Java ve C# hiç desteklemez — artan güvenlik kaygısının yansıması.
- alias (takma ad)
- Aynı bellek hücresine birden fazla isimle erişilebilmesi. Pass-by-reference'ın başlıca dezavantajlarından biri; readability'yi düşürür, dolayısıyla reliability'yi ve program verification'ı zorlaştırır.
- — OOP desteği terimleri (Ch.12 · Lecture #10) —
- Dönemin son dersinin terimleri.
- message (mesaj)
- Bir metot çağrısının OOP'deki adı. İki parçası vardır: metot adı ve hedef nesne. Subprogram çağrısından farkı: işlenecek verinin en az bir kısmı nesnenin kendisinin parçasıdır.
- message protocol · message interface
- Bir nesnenin tüm metotlarının topluluğu. Java'daki
interfacekavramının kökeni budur. - class variable · instance variable
- Class variable: sınıfa aittir, sınıf başına bir kopya (one/class). Instance variable: nesne başına bir (one/object); nesnenin state'ini saklar. Aynı sınıfın iki nesnesi arasındaki tek fark instance değişkenlerinin durumudur. Class metodu, sınıfın hiç örneği olmasa bile çağrılabilir.
- polymorphic variable
- Bir sınıfta tanımlanan; o sınıfın ve tüm torunlarının nesnelerine referans verebilen değişken. Dynamic binding'in taşıyıcısıdır: override edilmiş metotlar bunun üzerinden çağrılınca bağlanma çalışma zamanında yapılır.
- dynamic binding (dinamik bağlama)
- Mesajın hangi metoda karşılık geldiğinin çalışma zamanında belirlenmesi — polymorphism'in gerçekleşme biçimi. Yazılımın hem geliştirme hem bakım sırasında daha kolay genişletilmesini sağlar. C++'ta
virtualile istenir, Java'da varsayılandır, Smalltalk/Ruby'de tektir. - abstract method · abstract class
- Abstract method: tanımı (gövdesi) olmayan, yalnızca bir protokol belirten metot. Abstract class: en az bir virtual/abstract metot içeren sınıf — örneklenemez. C++'ta karşılığı
virtual void f() = 0;(pure virtual). - subtype (alt tip)
- Ebeveyniyle is-a ilişkisi taşıyan türetilmiş sınıf: nesneleri, ebeveyn nesnesinin yerine konduğunda aynı davranışı gösterir (principle of substitution). Ezber cümlesi: subclasses inherit implementation; subtypes inherit interface and behavior. Her subclass subtype değildir.
- principle of substitution
- Bir sınıfın değişkeni, atalarından birinin değişkeninin yerine tip hatası oluşturmadan ve programın davranışını değiştirmeden konabiliyorsa dil bu ilkeyi destekler.
- object slicing (nesne dilimleme)
- Nesneler stack dynamic olduğunda subtype'larla ortaya çıkan budanma (truncation): subclass nesnesi, parent tipinde ayrılmış bir yere kopyalanınca fazlalık veri kesilir. C++'ta
rect = sq;stack'te slicing yapar; heap'te pointer ataması olduğu için sorun çıkmaz. - diamond problem (elmas problemi)
- Multiple inheritance'ta, ortak bir atadan iki farklı yolla türeyen sınıfın aynı üyeyi iki kez miras alması. C++'ın çözümü virtual inheritance:
class D1 : public virtual BC— üye bir kez gelir. - mixin (karışım)
- Bir sınıftan miras alıp ayrıca bir interface implemente ederek multiple inheritance'ı simüle etme. Interface'in sabit ve metotları, superclass'tan gelenlerle karışır.
- interface
- Yalnızca metot bildirimleri ve isimlendirilmiş sabitler içerebilen yapı; örneklenemez. Java'da multiple inheritance'ın yerine geçer. Abstract class'tan farkı: kod veremez (Java 8'den beri
defaulthariç), ama bir sınıf birden çok interface implemente edebilir. - CIR — class instance record
- Bir nesnenin state'ini saklayan yapı; static'tir, derleme zamanında kurulur. Sınıfın parent'ı varsa subclass'ın instance değişkenleri parent'ın CIR'ına eklenir. Static olduğu için erişim record'lardaki gibi verimlidir.
- vtable — virtual method table
- Dinamik bağlanacak metotların CIR'daki pointer'lar üzerinden koda bağlandığı tablo. Metot çağrıları tablonun başına göre offset olarak temsil edilebilir. Override edilmeyen bir metot için parent'ın koduna işaret eder.
- boxing · autoboxing
- Java'da bir primitive değerin, wrapper sınıfının nesnesine örtük dönüştürülmesi (
int→Integer). Java 5.0'dan itibaren otomatiktir. "Exclusivity of objects" tasarım sorusunun Java'daki izi: iki tür varlık bir arada.
Bu rehber; on ders oturumunun tam transkriptleri (6, 7, 13, 14, 21, 27, 28 Temmuz ve 3, 4, 10 Ağustos 2026 — whisper large-v3 ile çıkarıldı) ve hocanın slaytları (Lecture 0–10) işlenerek hazırlandı. Vize bölümü 17 Temmuz'da, final bölümü 07.08.2026'de eklendi; Lecture #10 (Ch.12 · Support for OOP) ve hocanın final açıklamaları 10.08.2026'da eklendi — dönem bu dersle kapandı, kapsam artık kesindir. Transkriptler ve ders bazlı analiz raporları transcripts/, slayt metinleri slides-text/ klasöründe duruyor.