<başarı> ::= <bu-rehber> { <tekrar> } <sınav>

Concepts of Programming Languages Sıfırdan Çalışma Rehberi

Ders SE 309/323 · İzmir Ekonomi Üniv. yaz okulu Hoca Dr. Samsun M. Başarıcı Kitap Sebesta, 12. baskı Kaynak 10 ders videosunun tam transkripti + slaytlar Kapsam Vize (Ch.1–5) + Final (Ch.6–12)
<ders> ::= <künye> <değerlendirme> <takvim>

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şenAdetAğırlıkNot
Vize (midterm)1%40Yaz okulunun ~3. haftası, muhtemelen Salı; önceden duyurulacak
Quiz4%20Panopto üzerinden, 5–10 soru, 5–15 dk; Blackboard'dan duyurulur
Final1%40Dö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.
Bölüm I Vize Kapsamı — Ch.1–5

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.

<radar> ::= <ne-çıkar> <ne-çıkmaz> <nasıl-sorar>

Vize Sınav Radarı

Hocanın kendi ağzından, sınav hakkında söylediği her şey tek yerde.

Hocanın sınav tarifi
  • 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.
Vize istihbaratı — 14 Temmuz dersinden
  • 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.
Quiz 1 gerçekleşti — format artık tahmin değil, veri
  • 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ış.

<lecture-1> ::= <neden> <domains> <kriterler> <mimari> <kategoriler> <implementation>

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:

  1. Fikirleri ifade etme gücü artar — daha çok yapı bilirsen daha çok çözüm düşünebilirsin.
  2. Doğru dili seçebilirsin — probleme göre dil/paradigma seçimi bu dersin ana hedefi.
  3. Yeni dilleri kolay öğrenirsin — kavramlar ortak; sözdizimi detay.
  4. 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.
  5. Bildiğin dilleri daha iyi kullanırsın — dilinin az bilinen köşelerini keşfedersin.
  6. Bilişimin genel ilerlemesine katkı — popüler dilin her zaman en iyi dil olmadığını görebilen bir nesil.
Quiz 1'de çıktı — tuzağa dikkat

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.

Hocanın vurgusu Ders boyunca en az üç kez tekrarladığı senaryo: OOP bilen bir öğrenciye Sudoku çözdürsen gidip Java ile yazar; oysa "it would be maybe better to code using Prolog." İnsanlar en iyi bildiği dili, hiç uygun olmasa bile kullanıyor. Aynı şekilde bir LLM yazacaksan OOP değil belki logic programming daha iyi bir seçim. Bu "probleme göre dil seç" fikri sınavda bir senaryo sorusu olarak karşına çıkabilir. "they use the language with which they are most familiar... even if that is very poorly suited"

⭐ 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
ScientificYoğun floating-point hesap, diziler/matrisler, sayaçlı döngülerFortran
BusinessRapor üretimi, ondalık (decimal) aritmetik, karakter verisiCOBOL
Artificial intelligenceSayı değil sembol işleme; dizi değil linked listLISP, Prolog, Scheme
SystemsSürekli çalışan yazılımda verimlilik (OS, sürücüler)C
WebKarma ihtiyaçlar: markup + script + genel amaçlıHTML, PHP, Java(Script)
Hocanın vurgusu AI satırındaki mantığı özellikle açtı: yapay zekâ "symbolic computation" yapar — sayılarla değil isimlerle/sembollerle uğraşır, veriyi dizide değil bağlı listelerde tutar. LISP'in adının LISt Processing olması tesadüf değil. "symbolic computation... names rather than numbers... linked lists rather than arrays"

⭐ 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. boolean yoksa int'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).

Sınav radarı — kriter/faktör eşlemesi

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 aliasingyalnı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").

Hocanın vurgusu 16-bit'lik hayali bir makinede (4 bit opcode + 12 bit adres) 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

KategoriKarakteriÖrnekler
ImperativeMerkezde variable + assignment + iteration; von Neumann'ın çocuğuC, Java, Python, Perl, JavaScript, C++
FunctionalHesaplama = fonksiyonları parametrelere uygulamakLISP, Scheme, ML, F#
LogicKural tabanlı; kurallar sırasız yazılır, çıkarım motoru çalışırProlog
Markup/programming hybridMarkup dillerine programlama eklentileriXSLT, JSTL
Hocanın vurgusu Sık yapılan hata: OOP'yi ayrı bir kategori sanmak. Hoca özellikle düzeltti: OOP ayrı kategori değildir; Java/C++/Python gibi OOP dilleri imperative ailenin içindedir. Scripting ve visual diller de öyle. "we include them into imperative languages"

⭐ 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:

  1. Lexical analysis: karakter dizisini lexeme'lere ayırır (identifier'lar, keyword'ler, operatörler, noktalama).
  2. Syntax analysis: lexeme'lerden programın hiyerarşik yapısını gösteren parse tree'leri kurar.
  3. 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.
  4. 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 codeJVM 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.

Ders dışı ama derste anlatıldı

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."

<lecture-2> ::= <ortam> <dil> { <ortam> <dil> } /* 1945 → bugün */

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."

Sınav radarı — en güçlü soru kalıbı

"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ümYılGetirdiği
Fortran 01954Tasarlandı, hiç implement edilmedi
Fortran I1957İlk implement edilen sürüm: 6 karakter isim, post-test DO döngüsü, formatted I/O, arithmetic IF; tip bildirimi yok
Fortran II1958Independent compilation (hocaya göre "the most important thing") + hata düzeltmeleri
Fortran IV1960–62Explicit type declarations, logical selection, alt program adları parametre olabilir; ANSI standardı 1966
Fortran 771978Character string handling, logical loop control, IF-THEN-ELSE
Fortran 901990Modules, 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
Hocanın vurgusu Fortran I'in implicit typing kuralını harf harf anlattı: adı I, J, K, L, M, N ile başlayan değişkenler integer, gerisi floating point. Sebep de tatlı: matematikçiler dizilerde i, j, k indekslerini kullanır. Ayrıca dönemin makinesi o kadar güvenilmezdi ki "400 satırdan uzun programlar nadiren doğru derlenirdi." 90 öncesi tüm Fortran derleyicileri "highly optimizing" idi; tüm tipler ve bellek çalışmadan önce sabitlenirdi. "variables whose name began with I, J, K, L, M, N were implicitly integer"

⭐ 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.

Hocanın vurgusu — "be careful with that" Saf fonksiyonel programlamada değişken de atama da YOKTUR; tekrar recursion'la, kontrol conditional expression'larla sağlanır. Hoca ayrıca listenin ikili doğasına dikkat çekti: (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.
Hocanın vurgusu — başarı ve başarısızlık aynı anda Başarı: 20 yıldan uzun süre algoritmaların yayın dili oldu; ilk makineden bağımsız dil; sözdizimi formal olarak tanımlanan ilk dil"like BNF, which we will see later in this course too" (yani Lecture 3'ün habercisi); ve "all subsequent imperative languages are based on that... even C#, Java." Başarısızlık: I/O'su ve string handling'i yoktu (makine bağımlılığı yaratır korkusuyla eklenmedi!), fazla esnekti, formal syntax korkuttu, Fortran yerleşikti ve IBM desteklemedi — özellikle ABD'de hiç tutmadı. "it was the standard way to publish algorithms for over 20 years"

⭐ 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

DilKimlikHocanın altını çizdiği
PerlLarry Wall, 1987; UNIX admin + CGIDeğişken isimleri sigil'le başlar ($ @ %); implicit variables "somehow dangerous"; aslında ara dile derlenir
JavaScriptNetscape+Sun; client-side, purely interpretedJava ile alakası yok: Java strongly typed, JavaScript dynamically typed; benzerlik sadece sözdizimi
PHPLerdorf; server-side, purely interpretedForm 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
RubyMatsumoto ("Matz"), JaponyaSaf 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:

İlkDil
İlk programlama dili (tasarım; hiç implement edilmedi)Plankalkül
İlk implement edilen yüksek seviyeli dilFortran I
İlk makineden bağımsız dil + formal syntax'lı (BNF) ilk dilALGOL 60
Imperative dillerde ilk recursion, block structure, stack-dynamic arraysALGOL 60
İlk macro facility + records'un ilk implementasyonu + DoD'nin ilk zorunlu diliCOBOL
Timesharing'i yaygınlaştıran ilk dilBASIC
İlk concurrency, exception handling, pointer tipi, array cross-sectionsPL/I
Dynamic typing + dynamic storage allocation öncüleriAPL & SNOBOL
İlk class/object/inheritance + coroutine (data abstraction'ın başlangıcı)SIMULA 67
Orthogonality üzerine kurulan ilk dilALGOL 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.
Dersin kapanışı

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.

<lecture-3> ::= <syntax-tarifi> <lexical-analiz> <parsing> /* Sebesta Ch.3–4 */

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ı):

TerimTanı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.

Sınav radarı — Chomsky eşlemesi

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.

Hocanın vurgusu — sınıf klasiği soru Şu grammar derste çözüldü ve hoca bunun normalde öğrenciye bıraktığı bir soru olduğunu söyledi: "Normally, if we would be in the class, I wouldn't give you the answer for that" — yani "şu cümle bu grammar'dan türetilebilir mi? Türetimi yazın" tipi soru, quiz/vize için en güçlü aday.
<program> → <stmts>
<stmts>   → <stmt> | <stmt> ; <stmts>
<stmt>    → <var> = <expr>
<var>     → a | b | c | d
<expr>    → <term> + <term> | <term> - <term>
<term>    → <var> | const
Soru: 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).

Sınav radarı — doğru/yanlış klasikleri
  • "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.

Sınav radarı — neredeyse garanti soru

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ü:

  1. Simplicity: lexical analiz daha basit tekniklerle (finite automaton) çözülür; ayırmak parser'ı sadeleştirir.
  2. Efficiency: derleme süresinin ciddi bölümü lexer'da geçer; ayrıysa yalnız lexer'ı optimize edersin.
  3. 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-downBottom-up
Ağacı kurma yönüKökten yapraklaraYapraklardan köke
TüretimLeftmost derivation (preorder)Rightmost derivation'ın tersi
AlgoritmalarRecursive 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 | aB ikisi de a ile 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.

<lecture-4> ::= <names> <variables> <binding> <lifetime> <scope> /* Sebesta Ch.5 */

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 length diye 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 timeint → değer aralığı/gösterimi
Compile timeint count; → count'un tipi
Load timeC/C++ static değişkeni → bellek hücresi
Run timeNon-static lokal değişken → bellek hücresi; değişkenin değeri
Hocanın vurgusu — tam işlenmiş örnek 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 time
  • count'un olası değer kümesi → language implementation time
  • +'ın buradaki anlamı → compile time (operand tiplerine göre)
  • 5 literalinin iç gösterimi → compiler design time
  • count'un değeri → execution (run) time
Gerekçesi de sınavlık: binding kavramı "a prerequisite for understanding the semantics of a programming language."

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]; sonra list = 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:

KategoriBağlanmaÖrnekArtı / Eksi
StaticÇalışma öncesi; hep aynı hücreC/C++ fonksiyon içi static+ verimli (direct addressing), history-sensitive · − recursion desteklenmez
Stack-dynamicBildirim 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-dynamicProgramcının açık komutuyla (new/delete), pointer/reference üzerindenC++ dinamik nesneler; Java'da TÜM nesneler+ dinamik yapılar (liste, ağaç) · − verimsiz ve güvenilmez
Implicit heap-dynamicYalnızca atamayla; tüm nitelikler her atamada yeniden bağlanırAPL'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ş.

Hocanın vurgusu — scope ≠ lifetime "Static scope is textual (spatial); lifetime is a temporal concept." Kanıt örneği C'deki static lokal:
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.

<deneme> ::= 15 * <çoktan-seçmeli> 5 * <açık-uçlu> /* vize formatının aynısı */

Vize Deneme Sınavı

Hocanın ilan ettiği vize formatında (10–15 çoktan seçmeli + 3–5 açık uçlu). Her soru, derste vurgulanan bir noktadan türetildi; cevapların altında kaynağı da yazıyor. Önce kendin çöz, sonra "Cevabı göster"e tıkla.

Bölüm A — Çoktan seçmeli

Soru 1 · Lecture 1

Sebesta'nın sınıflandırmasına göre Java, C++ ve Python gibi object-oriented diller hangi dil kategorisinde yer alır?

  1. Kendi başına "object-oriented" kategorisinde
  2. Imperative kategorisinde
  3. Functional kategorisinde
  4. Markup/programming hybrid kategorisinde
Cevabı göster
b) OOP ayrı bir kategori değildir; OOP destekleyen diller (scripting ve visual diller gibi) imperative ailenin içindedir. Kaynak: hocanın özellikle düzelttiği nokta — "we include them into imperative languages."
Soru 2 · Lecture 1

Aşağıdakilerden hangisi yalnızca reliability kriterini etkiler (readability veya writability'yi değil)?

  1. Simplicity
  2. Orthogonality
  3. Type checking
  4. Expressivity
Cevabı göster
c) Type checking, exception handling ve restricted aliasing üçlüsü yalnızca reliability'yi etkiler. Simplicity/orthogonality üç kriteri de; expressivity ise writability+reliability'yi etkiler. Kaynak: hocanın satır satır okuduğu kriter tablosu — "It is important for the reliability."
Soru 3 · Lecture 1

von Neumann mimarisi ile imperative diller arasındaki eşleşmelerden hangisi doğrudur?

  1. Variable → CPU register'ının soyutlaması
  2. Assignment → bellek-CPU arası taşımanın (piping) soyutlaması
  3. Iteration → önbelleğin (cache) soyutlaması
  4. Function call → fetch-execute döngüsünün soyutlaması
Cevabı göster
b) Variable bellek hücresinin, assignment ise piping'in soyutlamasıdır; iteration komutların bellekte bitişik durması sayesinde verimlidir. Kaynak: L1 + L4 girişinde tekrarlanan temel eşleme.
Soru 4 · Lecture 1

Java'nın her dizi erişiminde sınır (index) kontrolü yapması hangi ödünleşimin (trade-off) örneğidir?

  1. Readability ↔ writability
  2. Reliability ↔ cost of execution
  3. Writability ↔ reliability
  4. Portability ↔ generality
Cevabı göster
b) Kontrol güvenilirliği artırır ama çalıştırma maliyetini yükseltir. (Diğer ezber çift: APL = readability↔writability; C++ pointer = writability/flexibility↔reliability.) Kaynak: L1'in üç ezber trade-off örneği.
Soru 5 · Lecture 1

Hocanın tanımıyla "essentially delayed compilers" olan sistemler hangisidir?

  1. Preprocessor'lar
  2. Pure interpreter'lar
  3. JIT sistemleri
  4. Linker'lar
Cevabı göster
c) JIT, ara dile çevrilen programın alt programlarını çağrıldıkları anda makine koduna derler ve saklar (Java, .NET). Kaynak: L1 — hocanın tek cümlelik JIT tanımı.
Soru 6 · Lecture 2

Aşağıdaki "ilk" eşleştirmelerinden hangisi yanlıştır?

  1. İlk makineden bağımsız dil → ALGOL 60
  2. İlk tam object-oriented dil → SIMULA 67
  3. İlk pointer veri tipi → PL/I
  4. Records'un ilk implementasyonu → COBOL
Cevabı göster
b) SIMULA 67 class/object/inheritance kavramlarını tanıttı, ama ilk TAM OO dil Smalltalk'tır (data abstraction + inheritance + dynamic binding). İnce ayrım da hatırla: records kavramını Plankalkül tanıttı, COBOL ilk implement etti. Kaynak: L2 "İlk'ler" vurguları.
Soru 7 · Lecture 2

Fortran'ın tasarımını şekillendiren ortam koşullarından olmayan hangisidir?

  1. Makineler küçük ve güvenilmezdi
  2. Uygulamalar bilimseldi
  3. En önemli kaygı machine efficiency idi
  4. İş dünyası için güçlü rapor üretimi isteniyordu
Cevabı göster
d) Rapor üretimi/decimal aritmetik COBOL'un ortamıdır; Fortran'da string handling ve decimal aritmetik bilinçli olarak yoktu. Kaynak: hocanın en uzun anlattığı "environment of development" örneği.
Soru 8 · Lecture 2

ALGOL 60 hakkında hangisi yanlıştır?

  1. 20 yıldan uzun süre algoritma yayınlamanın standart yolu oldu
  2. Sözdizimi formal olarak (BNF ile) tanımlanan ilk dildir
  3. Ticari olarak en çok ABD'de başarılı oldu
  4. Imperative dillere recursion ve block structure'ı getirdi
Cevabı göster
c) Tam tersi: I/O eksikliği, Fortran'ın yerleşikliği ve IBM'in desteksizliği yüzünden özellikle ABD'de hiç yaygınlaşmadı — buna rağmen sonraki tüm imperative diller ona dayanır. Kaynak: L2'nin "başarı ve başarısızlık aynı anda" vurgusu.
Soru 9 · Lecture 2

Dynamic typing ve dynamic storage allocation kavramlarını tanıtan erken dil çifti hangisidir?

  1. Fortran ve COBOL
  2. APL ve SNOBOL
  3. Pascal ve C
  4. Ada ve Smalltalk
Cevabı göster
b) İkisinde de değişken tipsizdir; tip de bellek de değer atandığı anda bağlanır (a=1 → integer, a=1.0 → real). Kaynak: L2 — "variables are essentially untyped."
Soru 10 · Lecture 3

Chomsky'nin dil sınıflarıyla programlama dilleri arasındaki doğru eşleme hangisidir?

  1. Token biçimleri → context-free; dil syntax'ı → regular
  2. Token biçimleri → regular; dil syntax'ı → context-free
  3. Her ikisi de regular
  4. Her ikisi de context-sensitive
Cevabı göster
b) Lexer (finite automaton) regular grammar'la token'ları tanır; parser (pushdown automaton) context-free grammar'la (≡ BNF) syntax'ı tanır. Kaynak: hocanın iki kez tekrarladığı kilit cümle.
Soru 11 · Lecture 3

Bir grammar'ın ambiguous olması ne demektir ve neden problemdir?

  1. Grammar'da recursive kural vardır; parser sonsuz döngüye girer
  2. Aynı cümle için 2+ farklı parse tree üretir; derleyicinin üreteceği kod tek (unique) olamaz
  3. Grammar'da terminal yoktur; türetim hiç bitmez
  4. Start symbol birden fazladır; derivation başlayamaz
Cevabı göster
b) Derleyici kodu parse tree'den ürettiği için iki ağaç = iki olası anlam demektir. Bonus doğru/yanlış: "bir grammar'ın ambiguous olup olmadığını belirlemek matematiksel olarak imkânsızdır" — DOĞRU; pratik işaret birden çok leftmost (veya rightmost) türetimdir. Kaynak: L3'ün en kuvvetli vurgusu.
Soru 12 · Lecture 3

EBNF hakkında hangisi doğrudur?

  1. BNF'ten daha güçlüdür; BNF'in tarif edemediği dilleri tarif eder
  2. İfade gücü BNF ile aynıdır; yalnızca okunabilirlik ve yazılabilirlik kazandırır
  3. Yalnızca regular dilleri tarif edebilir
  4. Meta symbol içermez
Cevabı göster
b) [ ] (opsiyon), ( | ) (alternatif), { } (tekrar) yalnızca notasyon kolaylığıdır — "the extensions do not enhance the descriptive power of BNF." Kaynak: L3, klasik sınav cümlesi.
Soru 13 · Lecture 3

Lexical analysis ile syntax analysis'i ayırmanın hocanın saydığı üç gerekçesi hangi şıkta doğru verilmiştir?

  1. Simplicity, efficiency, portability
  2. Readability, writability, reliability
  3. Speed, security, scalability
  4. Abstraction, orthogonality, expressivity
Cevabı göster
a) Basitlik (lexer finite automaton'la basit çözülür), verimlilik (yalnız lexer'ı optimize edersin), taşınabilirlik (dosya okuyan lexer platforma bağımlı olabilir, parser hep taşınabilir). Kaynak: hocanın İKİ KEZ anlattığı, "neredeyse garanti" soru.
Soru 14 · Lecture 3

Bir grammar'da left recursion bulunması neyi imkânsız kılar?

  1. Bottom-up parsing'i
  2. Top-down parsing'i
  3. Lexical analizi
  4. Kod üretimini
Cevabı göster
b) Doğrudan ya da dolaylı left recursion içeren grammar top-down parser'a temel olamaz (recursive-descent rutini kendini sonsuz çağırır); dönüşümle giderilebilir. İkinci engel de pairwise disjointness eksikliğidir (FIRST kümeleri kesişmemeli; çözüm left factoring). Kaynak: L3 parsing bölümü.
Soru 15 · Lecture 4

count = count + 5; satırında count'un değerinin bağlanma zamanı nedir?

  1. Compile time
  2. Load time
  3. Language design time
  4. Run (execution) time
Cevabı göster
d) Tipi compile time'da, olası değer kümesi implementation time'da, +'ın anlamı compile time'da, 5'in gösterimi compiler design time'da, değeri run time'da bağlanır. Kaynak: L4'ün tam işlenmiş örneği.
Soru 16 · Lecture 4

Hangi lifetime kategorisi recursion'ı destekleyemez?

  1. Static
  2. Stack-dynamic
  3. Explicit heap-dynamic
  4. Implicit heap-dynamic
Cevabı göster
a) Static değişkenler çalışmadan önce tek bir hücreye bağlanır — her recursive çağrının kendi kopyası olamaz. Karşılığında direct addressing verimliliği ve history-sensitivity sağlar. (Java'da tüm nesnelerin explicit heap-dynamic olduğunu da hatırla.) Kaynak: L4 lifetime tablosu.

Bölüm B — Açık uçlu

Soru 17 · Grammar yorumlama (hocanın örnek vize sorusu tipi)

Aşağıdaki grammar veriliyor:

<program> → <stmts>
<stmts>   → <stmt> | <stmt> ; <stmts>
<stmt>    → <var> = <expr>
<var>     → a | b | c | d
<expr>    → <term> + <term> | <term> - <term>
<term>    → <var> | const

(i) d = c - const cümlesi bu dile ait midir? Leftmost derivation yazarak gösterin. (ii) a = b + c + d türetilebilir mi? Neden?

Cevabı göster
(i) Evet:
<program> => <stmts> => <stmt> => <var> = <expr> => d = <expr>
=> d = <term> - <term> => d = <var> - <term> => d = c - <term> => d = c - const ✓
(ii) Hayır. <expr> kuralı tam olarak iki term ve tek operatör üretir; üç operand'lı zincir (b + c + d) üretecek recursive bir yapı yok. Kaynak: hocanın "normalde cevabını vermem" dediği sınıf klasiği (a = b + 0 örneğinin varyasyonu).
Soru 18 · Lisp (hocanın birebir söylediği soru)

Lisp fonksiyonel bir dil olarak doğdu; ama zamanla imperative özellikler kazandı. Neden? (Hoca: "bir satırda cevaplanabilir.")

Cevabı göster
Verimlilik için — saf fonksiyonel bir dili von Neumann mimarisine verimli şekilde taşımak çok zordur; donanım variable/assignment modeline göre çalıştığından Lisp pratik kullanımda imperative öğeler kazandı. Kaynak: 14 Temmuz ara sohbeti — hocanın kendi örnek vize sorusu ve cevabı.
Soru 19 · Scoping karşılaştırması
function big() {
  var x = 3;
  function sub1() { var x = 7; ... sub2(); ... }
  function sub2() { ... x = 3; ... }
  sub1();
}

big → sub1 → sub2 çağrı sırasında, sub2 içindeki x hangi değişkendir — (i) static scoping'de, (ii) dynamic scoping'de? Kuralları da açıklayın.

Cevabı göster
(i) Static: big'in x'i. Kural metinseldir: sub2'de bildirim yok → metinsel kapsayan birime (big) çıkılır. sub1, sub2'yi kapsamaz, sadece çağırır. (ii) Dynamic: sub1'in x'i. Kural zamansaldır ("temporal versus spatial"): çağrı zincirinde geriye doğru ilk bildirim sub1'dedir. Dynamic scoping'in bedelleri: çağıranın değişkenleri görünür (güvenilirlik ↓), static type checking imkânsız, okunabilirlik ve hız düşük. Kaynak: L4'te tam işlenmiş örnek.
Soru 20 · Kavram farkı (hocanın "fark nedir?" kalıbı)

Scope ile lifetime arasındaki fark nedir? C'deki static int k; (fonksiyon içi) örneği üzerinden açıklayın. Bu örnek Java'da yazılabilir mi?

Cevabı göster
Scope metinsel/uzamsal bir kavramdır (isim kodun nerelerinden görünür); lifetime zamansaldır (değişken bellekte ne kadar yaşar). Fonksiyon içi static int k: scope'u fonksiyonun içidir (dışarıdan görünmez) ama lifetime'ı tüm program çalışmasıdır — çağrılar arasında değerini korur: "not visible, but still alive." Ardışık çağrılar 5, 10, 15 döndürür. Java'da yazılamaz — metod içi static değişken yoktur. Kaynak: L4'ün fosforlu vurgusu.
Soru 21 · Derleme süreci

Bir compiler'da lexical analysis ile syntax analysis neden ayrı tutulur? Üç gerekçeyi açıklayarak yazın ve her birinin pratikte ne kazandırdığını belirtin.

Cevabı göster
1) Simplicity: lexical analiz, finite automaton'a dayanan daha basit tekniklerle çözülür; lexer'ı ayırmak parser'ı sadeleştirir. 2) Efficiency: derleme süresinin önemli bölümü lexer'da geçer; ayrık olunca yalnızca lexer optimize edilir, parser'a dokunulmaz. 3) Portability: lexer girdi dosyası okur ve buffer'lar — platforma bağımlı parçalar içerebilir; parser ise her zaman taşınabilir kalır. Kaynak: hocanın iki kez anlattığı, dönüp tekrar ettiği gerekçeler.
<havuz> ::= { ⭐<yüksek-ihtimal> | <soru> } /* hocanın sözlerine dayalı */

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)
Logic. Prolog kural tabanlı, çıkarım motorlu tek büyük logic dili — L1 kategoriler + L2 Prolog anlatımı.
Q2Which of the following is a syntactic error? (Infinite recursion / Missing a semicolon / Dividing by zero / Using an undeclared variable)
Missing a semicolon. Hocanın derste verdiği örneğin ta kendisi: eksik noktalı virgülü syntax analyzer yakalar. (Sonsuz recursion ve sıfıra bölme çalışma zamanı; bildirimsiz değişken static semantics/semantic analiz işidir.)
Q3Which language was primarily designed for AI applications? (LISP / COBOL / Fortran / Ada)
LISP. Domain→dil eşlemesi: AI → sembolik hesap + linked list → LISP.
Q4In BNF, what does the symbol ::= mean? (Optional syntax / Defines a rule in a grammar / Ends a production / Assigns semantics)
It defines a rule in a grammar. ::= (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)
Top-down. Recursive descent = top-down'ın kodlanmış hâli (LL ailesi); shift-reduce ise bottom-up/LR tarafı.
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)
Sequential execution with variables and assignments. Variable=hücre, assignment=piping, komutlar sıralı — imperative dillerin kalıbı.
Q7What is a disadvantage of too much writability? (Slower execution / More readable / More strongly typed / Too many different ways to express the same thing)
Too many different ways to express the same thing — feature multiplicity (Java'nın 4 artırma yolu örneği). Yazması kolaylaşırken okunabilirlik ve güvenilirlik düşer.
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)
Anahtara göre: Better understanding of program efficiency. Quiz'in tek kaybedilen sorusu — "Facilitation of compiler design" işaretlendi, anahtar onu gerekçe saydı (0 puan). Tartışmalı bir anahtar; pratik ders: 6 gerekçeyi slayttaki birebir ifadeleriyle bil (express ideas / choose languages / learn new languages / significance of implementation / better use of known languages / advancement of computing) ve NOT-sorularında önce birebir eşleşenleri ele.
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)
A small set of primitive constructs can be combined in a small number of ways. Slayt cümlesinin birebir kendisi — tanımları slayt diliyle ezberlemenin değerine kanıt.
Q10What is the main function of a lexical analyzer? (Building parse trees / Handling syntax rules / Breaking input into tokens / Removing comments and whitespace)
Breaking input into tokens. Parse tree kurmak parser'ın işi; yorum/boşluk atlamak lexer'ın YAN görevi — "main function" vurgusuna dikkat, çeldirici tam oradan.

Lecture 1 — Giriş & Motivasyon

S1 ⭐Programlama dili kavramlarını okumanın 6 gerekçesini sayın.
1) Fikir ifade etme gücü artar, 2) probleme uygun dili seçebilirsin, 3) yeni dilleri kolay öğrenirsin, 4) implementation'ın önemini anlarsın, 5) bildiğin dilleri daha iyi kullanırsın, 6) bilişimin genel ilerlemesine katkı. Hoca ilk derste tek tek üzerinden geçti.
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.
Sudoku'yu OOP bilen herkes Java ile yazar ama Prolog daha uygundur; LLM benzeri bir sistem için OOP değil logic programming daha iyi olabilir. Ana hedef: probleme göre dil/paradigma seçebilmek.
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ı?
Dersi okuma gerekçelerinden "ability to express ideas": bildiğin dil yapıları düşünebildiğin çözümleri belirler; sözle tarif edemediğin yapıyı kavramsallaştırmak zordur.
S4 ⭐Beş programming domain'i, ihtiyaçlarını ve tipik dillerini eşleştirin.
Scientific → floating-point/dizi/döngü → Fortran. Business → rapor + decimal aritmetik → COBOL. AI → sembolik hesap + linked list → LISP/Prolog/Scheme. Systems → verimlilik → C. Web → karma → HTML/PHP/Java(Script).
S5AI neden dizi (array) değil linked list ister?
AI sayılarla değil sembollerle/isimlerle uğraşır ("symbolic computation"); veri boyutu ve yapısı dinamiktir — bağlı liste esner, dizi esnemez. LISP = LISt Processing.
S6 ⭐Dört dil değerlendirme kriterini sayın; hangi faktörler ÜÇÜNÜ birden etkiler?
Readability, writability, reliability, cost. Üçünü birden etkileyenler: simplicity, orthogonality, data types, syntax design. (Abstraction+expressivity → yalnız W+R; type checking, exception handling, restricted aliasing → yalnız reliability.)
S7 ⭐Simplicity'nin üç düşmanı nedir? Java'dan örnek verin.
1) Feature subset (dil o kadar büyük ki herkes farklı altkümesini öğrenir), 2) feature multiplicity — Java'da artırmanın 4 yolu: count=count+1, cnt+=1, cnt++, ++cnt, 3) aşırı operator overloading.
S8 ⭐Orthogonality nedir? Aşırısı neden tehlikelidir?
Az sayıda temel yapının az kuralla, her kombinasyon geçerli olacak şekilde birleşebilmesi; az istisna = kolay öğrenme. Aşırısı: neredeyse her kombinasyon geçerliyse hatalar derleyiciden kaçar (writability faktöründeki uyarı).
S9 ⭐C'deki static kelimesi neden kötü tasarım örneğidir?
Aynı kelime iki farklı anlam taşır: fonksiyon içinde "compile time'da yarat/çağrılar arası yaşat", dosya düzeyinde "yalnız bu dosyadan görünür". Form ile anlam kopuk → readability düşer.
S10Reliability'yi besleyen üç dil özelliği nedir; aliasing niye zararlıdır?
Type checking, exception handling, kısıtlı aliasing. Aliasing = aynı hücreye birden çok isim; değer "başka" bir isim üzerinden değişebilir, okuyan herkesi yanıltır.
S11Cost'un bileşenlerini sayın; hoca hangisinin çoğu zaman en büyük kalem olduğunu söyledi?
Eğitim, program yazma, derleme, çalıştırma, dil sistemi (ücretsiz derleyici var mı), düşük güvenilirliğin faturası, bakım. En büyüğü çoğu zaman bakım (1970 sonrası readability'nin önem kazanma sebebi).
S12Portability, generality ve well-definedness'i tanımlayın.
Portability: programın başka implementasyona kolay taşınması. Generality: geniş uygulama alanına uygunluk. Well-definedness: dilin resmî tanımının eksiksiz ve kesin olması.
S13 ⭐von Neumann mimarisinin iki temel özelliği nedir; imperative dillerle üç eşleşmesini yazın.
1) Veri ve program aynı bellekte, 2) bellek CPU'dan ayrı, aralarında taşıma (piping). Eşleşme: variable=bellek hücresi, assignment=piping, iteration=verimli (komutlar bitişik).
S14Fetch-execute cycle'ın adımlarını sırayla yazın.
PC'nin gösterdiği komutu bellekten getir → PC'yi artır → komutu decode et → çalıştır → sonsuza dek tekrarla. (Komut IR'a yüklenir; aritmetik ALU'da.)
S15 ⭐von Neumann bottleneck nedir ve neden bilgisayar hızının birincil sınırlayıcısıdır?
Bellek–CPU bağlantısının hızı, komut işleme hızından çok düşüktür; CPU veriyi bekler. Hocanın örneği: yavaş disk + i5/i7 arasında tek erişimde 15–20 milyon cycle boşa gidebilir.
S16 ⭐Metodoloji kronolojisi: dönemleri akımlarla eşleştirin (1950'ler / 60 sonu / 70 sonu / 80 ortası).
1950'ler: machine efficiency (donanım pahalı). 60 sonu: people efficiency — structured programming, top-down, stepwise refinement. 70 sonu: veri odaklılık — data abstraction/ADT. 80 ortası: OOP = data abstraction + inheritance + polymorphism.
S17 ⭐Dört dil kategorisi nedir? OOP dilleri nereye girer?
Imperative, functional, logic, markup/programming hybrid. OOP ayrı kategori DEĞİL — Java/C++/Python imperative'in içinde ("we include them into imperative languages"). Logic = kural tabanlı, kurallar sırasız.
S18 ⭐Üç tasarım trade-off'unu birer örnekle yazın.
Reliability↔execution cost: Java dizi sınır kontrolü. Readability↔writability: APL (kompakt ama okunmaz). Writability/flexibility↔reliability: C++ pointer'ları ("a nightmare for all students").
S19 ⭐Compilation'ın dört fazını sırayla ve görevleriyle yazın. Symbol table nedir?
Lexical analysis (karakter→lexical unit), syntax analysis (→parse tree), semantic analysis (ara kod + anlam hataları; ör. eksik noktalı virgülü syntax, uyumsuz iç içe if'i semantic yakalar), code generation. Symbol table = "a database for the compilation process". Sonra linking → load module.
S20Pure interpretation'ın avantajı ve iki dezavantajı nedir? Hangi alanla geri döndü?
Avantaj: kolay hata ayıklama (hata anında, satırıyla). Dezavantaj: 10–100 kat yavaş, daha çok bellek. Web scripting (JavaScript, PHP) ile geri döndü.
S21 ⭐Java'nın klasik taşınabilirlik hikâyesini anlatın (hybrid implementation) ve JIT'i tanımlayın.
Kaynak → byte code → her platformdaki JVM yorumlar = taşınabilirlik. JIT: alt programı ilk çağrıldığında makine koduna derler, saklar — "essentially delayed compilers". .NET de böyle.
S22Preprocessor ne yapar?
Derlemeden hemen önce makroları genişletir ("macro expander") — C'de #include dosyayı yapıştırır, #define metni açar.
S23PYPL ile TIOBE endeksleri metodolojik olarak nasıl ayrılır?
PYPL: Google'da dil tutorial'ı aramalarını sayar. TIOBE: kullanım anketi/aramalara dayanır. Hoca 2026 tablosundan C'nin yükselişini "hardware close programming" trendiyle yorumladı; Rust'ı da işleyeceğini söyledi.

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.
Ortam: makineler küçük/güvenilmez, uygulamalar bilimsel, metodoloji/araç yok, machine efficiency birinci kaygı. Yansıma: dinamik bellek yok, iyi dizi + sayaçlı döngü var, string/decimal/güçlü I-O yok (iş dünyası hedef değildi).
S25 ⭐IBM 704 neden "derlenen dil" çağını başlattı?
Floating point'i donanımda yaptı. O güne dek FP yazılımla yapılıyordu ve yorumlama maliyeti onun gölgesinde saklanabiliyordu; donanım gelince "there was no place to hide the cost of interpretation" — çeviri (compile) zorunlu hâle geldi.
S26 ⭐Fortran I'in implicit typing kuralı nedir ve nereden gelir?
I, J, K, L, M, N ile başlayan isimler integer; gerisi floating point. Kaynağı matematik geleneği: i, j, k dizilerin alt indisleridir.
S27 ⭐Fortran sürümlerini yenilikleriyle eşleştirin: I, II, IV, 77, 90.
I (1957): ilk implementasyon — 6 karakter isim, post-test DO, formatted I/O, arithmetic IF, tip bildirimi yok. II: independent compilation ("the most important thing") + bug fix. IV: explicit tip bildirimi, logical IF, subprogram adı parametre (ANSI 1966). 77: string handling, logical loop control, IF-THEN-ELSE. 90: modules, dynamic arrays, pointers, recursion, CASE + ilk özellik silme.
S28Plankalkül hakkında üç çarpıcı gerçek yazın.
1945'te tasarlandı ama 1972'ye kadar yayımlanmadı ve hiç implement edilmedi; buna rağmen floating point, array ve records içeren ilk dildi. (Zuse binary çalışan makineler yapmıştı — hocaya göre "the father of computer".)
S29Short Code ve Speedcoding'i birer cümleyle karakterize edin.
Short Code (Mauchly, 1949): saf yorumlamayla çalışan ilk pseudocode — makine kodundan ~50 kat yavaş ("automatic programming"). Speedcoding (Backus, IBM 701): matematik pseudo-op'ları; kullanıcıya yalnız 700 kelime bellek kalıyordu.
S30 ⭐Lisp'in yalnızca iki veri tipi nedir? Saf fonksiyonel programlamada ne yoktur?
Atoms ve lists. Değişken ve atama YOKTUR ("be careful with that") — tekrar recursion'la, kontrol conditional expression'la; sözdizimi lambda calculus'a dayanır. (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ı?
Verimlilik. Saf fonksiyonel dili von Neumann mimarisine verimli taşımak çok zordur; donanım variable/assignment modeliyle çalışır. (Hoca: "a question I can answer in one line.")
S32Scheme ile Common Lisp'i karşılaştırın.
Scheme: küçük, static scoping, first-class fonksiyonlar, eğitim için ideal. Common Lisp: lehçeleri birleştirme çabası — büyük/karmaşık; hocanın benzetmesi Esperanto: "the outcome was a mess."
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.
Yenilik: block structure (scope), pass by value + pass by name, imperative'de ilk recursion, stack-dynamic arrays. Başarı: 20+ yıl algoritma yayın dili; ilk makineden bağımsız dil; ilk formal syntax (BNF); sonraki tüm imperative dillerin atası. Başarısızlık: I/O ve string yok, fazla esnek, formal syntax ürküttü, Fortran yerleşikti, IBM desteklemedi → özellikle ABD'de tutmadı.
S34ALGOL 60'ın üç tasarım hedefi neydi?
Matematiksel notasyona yakınlık, yayınlarda algoritma tarifine uygunluk, makine koduna çevrilebilirlik.
S35 ⭐Hocanın örnek vize sorusu: COBOL'un en büyük avantajı/katkısı neydi?
İlk ticari başarılı iş (business) diliydi: basit İngilizce görünümü bilgisayar kullanıcı tabanını genişletti; ilk macro facility, records'un (hiyerarşik veri) ilk implementasyonu, data division ayrımı; DoD'nin zorunlu kıldığı ilk dil — hâlâ en yaygın iş uygulaması dili.
S36COBOL tasarım hedeflerinden en çarpıcısı hangisiydi?
"Must be easy to use, even if that means it will be less powerful" — güç yerine erişilebilirlik bilinçli tercih edildi. (İnce ayrım: records kavramını Plankalkül tanıttı, COBOL ilk implement etti.)
S37 ⭐BASIC'in devrimci fikri neydi?
"User time is more important than computer time" — o güne dek makine insandan değerliydi. Fen dışı öğrenciler için, timesharing'i yaygınlaştıran ilk dil (Kemeny & Kurtz, Dartmouth). İlk sürüm: 14 statement tipi, tek veri tipi.
S38 ⭐Hocanın örnek vize sorusu: PL/I'ın katkıları nelerdi ve neden başarısız oldu?
İlk'ler: unit-level concurrency, exception handling, switch-selectable recursion, pointer tipi, array cross-sections. Başarısızlık: her iki dünyaya (bilimsel+iş) birden hizmet hedefi dili devasa ve karmaşık yaptı; birçok özellik kötü tasarlandı (hocanın anısı: pointer "a torture").
S39 ⭐APL ve SNOBOL hangi iki kavramın öncüsüdür? Tanımlayın.
Dynamic typing (değişken tipsiz; tip atanan değerden gelir: a=1 int, a=1.0 real) ve dynamic storage allocation (bellek atama anında ayrılır). APL ayrıca "okunması çok zor program" örneğidir.
S40 ⭐SIMULA 67'nin iki tarihi katkısı nedir? Coroutine'i tanımlayın.
1) Class, object, inheritance kavramları ("data abstraction started with Simula 67"), 2) coroutine: çağıran ve çağrılanın eşit ilişki kurduğu alt program — o güne dek ilişki master-slave idi.
S41 ⭐ALGOL 68'in tasarım ilkesi neydi ve üç katkısı nedir?
Orthogonality üzerine kurulan ilk dil (az kavram + az birleştirme mekanizması). Katkılar: user-defined data types, reference types, dynamic/flex arrays (bildirimde sınır yok, atama bellek ayırır). Pascal, C ve Ada'yı derinden etkiledi.
S42Pascal neden bu kadar yaygınlaştı, yeniliği neydi?
Yeniliği YOKTU — küçük ve basitti; structured programming öğretimi için tasarlandı (Wirth). 70'lerin ortasından 90'ların sonuna kadar programlama öğretiminin dili oldu.
S43 ⭐C'nin soy zincirini yazın ve karakterini tek cümleyle özetleyin.
CPL → BCPL → B → C (+ ALGOL 68 etkisi). Karakteri: "powerful set of operators, but poor type checking"; UNIX ile yayıldı; sistem dili olarak tasarlanıp her alanda kullanıldı.
S44 ⭐Prolog'daki "how vs what" ayrımını açıklayın; hocanın Prolog tanımı neydi?
Imperative'de NASIL 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" (predicate calculus + resolution). Güncel bağ: "prompting is mostly based on logic."
S45 ⭐Ada: neden yapıldı, gereksinim dizisi neydi, dört katkısı ve tarihî dersi nedir?
DoD gömülü sistemlerde 450+ dil kullanıyordu → tek ortak dil. Gereksinimler: Strawman→Woodman→Tinman→Ironman→Steelman (1975–78). Katkılar: packages (data abstraction), ayrıntılı exception handling, generics, tasking (concurrency). Ders: kullanılabilir ilk derleyici tasarımdan ~5 yıl sonra geldi — "not good for language design." (Ada 95: OOP via type derivation.)
S46 ⭐İlk TAM object-oriented dil hangisidir ve "tam"ın üç bileşeni nedir?
Smalltalk (Alan Kay, Xerox PARC): data abstraction + inheritance + dynamic binding. GUI tasarımının da öncüsü. (SIMULA 67 kavramları tanıttı ama tam implementasyon Smalltalk.)
S47C++'ın formülü nedir; neden büyük ve karmaşıktır?
C'nin imperative gücü + SIMULA 67'nin OO özellikleri. Hem prosedürel hem OO desteklediği için büyük/karmaşık; OOP dalgasıyla hızla yayıldı (ANSI 1997).
S48 ⭐Java, C++'tan neleri çıkardı ve neden?
Gömülü cihazlar için güvenlik/sadelik: struct, union, enum, pointer arithmetic ve coercion'ların yarısı çıkarıldı; pointer yerine reference; yalnızca OOP. "Smaller, simpler, safer."
S49 ⭐Java ile JavaScript'in gerçek ilişkisi nedir?
Yalnızca sözdizimi benzerliği. Java strongly typed + hybrid/JIT; JavaScript dynamically typed + purely interpreted, client-side script dili. (PHP ise server-side'ın örneği.)
S50Perl, Python ve Ruby için hocanın altını çizdiği birer özellik söyleyin.
Perl: sigil'ler ($ @ %) tipleri belirtir; implicit variables "somehow dangerous". Python: lists, tuples (immutable list), dictionaries; list comprehension Haskell'den. Ruby: saf OO — her veri obje, operatörler bile metot.
S51C# hangi dillerin karışımıdır ve hangi platformun amiral gemisidir?
C++ + Java + Delphi temelli; .NET'in amiral gemisi (2000). Pointers, delegates, properties, enum'lar, sınırlı dynamic typing içerir; hızla evrilir.
S52Ders kapanışındaki "aynı program farklı dillerde" örneğinde problem neydi ve COBOL neden farklıydı?
Problem: uzunluğu 100'den küçük listeyi oku, ortalamadan büyük eleman sayısını bul (12 dilde). COBOL'a farklı program (stok/rapor) verildi çünkü "COBOL is not [for] mathematics."

Lecture 3 — Syntax, Semantics & Parsing

S53 ⭐Syntax ve semantics'i tanımlayın; iyi tasarlanmış dilde ikisinin ilişkisi ne olmalıdır?
Syntax = ifade/deyim/program birimlerinin biçimi; semantics = anlamı. İlke: "semantics should follow directly from the syntax" — 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.
Sentence: alfabe üzerindeki karakter dizisi. Language: cümleler kümesi. Lexeme: en küçük sözdizimsel birim (sum, *, begin). Token: lexeme kategorisi — sum ve total lexeme'leri IDENT token'ına aittir.
S55Recognizer ile generator'ı karşılaştırın; insanlar tarif olarak hangisini neden tercih eder?
Recognizer girdinin dile aitliğine karar verir (derleyicinin syntax kontrolü); generator dilin cümlelerini üretir (düğmeli makine metaforu). İnsanlar generator'ı tercih eder — recognizer'ı tarif olarak kullanmak deneme-yanılma gerektirir.
S56 ⭐Chomsky'nin sınıflarından hangileri programlama dilleri için önemlidir ve hangisi neyi tarif eder?
Regular grammar'lar → token'ların biçimini; context-free grammar'lar → (birkaç istisna dışında) dillerin syntax'ını. BNF ≡ CFG; BNF bir metalanguage'dir.
S57BNF kuralının anatomisi: LHS/RHS kuralları, grammar ve start symbol tanımı.
LHS: her zaman TEK nonterminal. RHS: terminal ve/veya nonterminal dizisi; alternatifler | 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ç.
Derivation: start symbol'den kural uygulaya uygulaya cümleye ulaşmak; her ara dizi sentential form; yalnız terminal kalan hâli sentence; => "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.
Evet: program ⇒ stmts ⇒ stmt ⇒ var = expr ⇒ b = expr ⇒ b = term + term ⇒ b = var + term ⇒ b = a + term ⇒ b = a + var ⇒ b = a + d ✓. (Hocanın sınıf klasiği format: "geçerli mi, türetin.")
S60 ⭐Ambiguity tanımı, neden ciddi problem ve nasıl fark edilir?
Aynı cümle için 2+ farklı parse tree üretebilen grammar ambiguous'tur. Problem: kod parse tree'den üretilir → kod tek olamaz. Tespit: matematiksel olarak imkânsız (genel algoritma yok); pratik işaret: birden çok leftmost (veya rightmost) türetim.
S61 ⭐Precedence grammar'a nasıl gömülür? Ağaç konumu ne anlama gelir?
Öncelik katmanlarıyla: 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?
Aynı öncelikte iki operatör yan yana gelince (a/b*c); hangi taraftan gruplanacağını söyleyen semantik kuraldır ve grammar'daki recursion'ın yönüyle (sol/sağ) ifade edilir.
S63Dangling else problemi nedir, çözümü hangi ayrımla yapılır?
İç içe if'lerde else'in hangi if'e ait olduğunun belirsizliği — Java'nın if-then-else grammar'ı ambiguous. Çözüm: matched/unmatched nonterminal ayrımı. Hoca detayı Sebesta s.124'e havale etti ("oku").
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.
Simplicity: lexer finite automaton'la basit çözülür, parser sadeleşir. Efficiency: derleme süresinin büyük payı lexer'da — ayrıysa yalnız onu optimize edersin. Portability: lexer dosya okur/buffer'lar (platforma bağımlı olabilir), parser hep taşınabilir. (Hoca iki kez anlattı.)
S66 ⭐Lexical analyzer'ı üç sıfatla tanımlayın ve yan görevlerini sayın.
Pattern matcher (karakter dizileri için), parser'ın front-end'i, parser'ın çağırdığı bir fonksiyon ("sıradaki token'ı ver"). Yan görevler: boşluk/yorum atlamak, isimleri symbol table'a koymak, token içi hataları raporlamak.
S67Lexer kurmanın üç yaklaşımı nedir?
1) Formal token tanımı + araçla üretilen table-driven lexer, 2) state diagram çiz + programını elle yaz, 3) state diagram çiz + table-driven implementasyonu elle kur.
S68 ⭐State diagram'ı devasa olmaktan kurtaran iki sadeleştirme nedir?
1) Character class'lar: 52 harf tek "letter", 10 rakam tek "digit" sınıfı. 2) Reserved word'lere ayrı dal çizmemek: hepsini identifier gibi tanı, sonra table lookup ile kontrol et.
S69getChar, addChar, lookup ne yapar? front.c örneğinin girdisi neydi?
getChar: sonraki karakteri al, sınıfını belirle (nextChar/charClass). addChar: karakteri kurulmakta olan lexeme'e ekle. lookup: lexeme reserved word mü bak. Örnek girdi: (sum + 47) / total — token kodlarıyla döküm; EOF = −1.
S70Parser'ın iki hedefi nedir? Recovery neden önemlidir?
1) TÜM syntax hatalarını bul, anlamlı mesaj ver, toparlan (recovery) — tek derlemede olabildiğince çok hata bulunsun; kötü recovery sahte hatalar üretir. 2) Parse tree (veya izini) üret — çevirinin temeli.
S71 ⭐Top-down ve bottom-up parsing'i türetim yönleriyle eşleştirin; LL ve LR neyin kısaltmasıdır?
Top-down: kökten, leftmost derivation, preorder ("root–leftmost"). Bottom-up: yapraklardan, rightmost derivation'ın TERSİ ("leaves–rightmost"). LL = Left-to-right scan + Leftmost derivation; LR = Left-to-right + Rightmost. Pratik parser'lar 1 token lookahead kullanır.
S72Genel unambiguous grammar parsing'i ile derleyici parsing'inin karmaşıklığı nedir?
Genel: O(n³) — pratik değil. Derleyiciler grammar'ların uygun alt kümesinde O(n) (linear) çalışır.
S73 ⭐Recursive-descent parser'ın temel fikri nedir ve neden EBNF ile kurulur?
Her nonterminal için bir alt program; o nonterminal'in üretebildiği cümleleri o parse eder. EBNF nonterminal sayısını azalttığı için idealdir. Kodlama: RHS'teki terminal → token karşılaştır; nonterminal → alt programını çağır; çok RHS varsa lookahead ile seç, uymuyorsa hata.
S74 ⭐Top-down parsing'in iki düşmanı nedir ve çözümleri?
1) Left recursion (doğrudan/dolaylı): top-down'a temel olamaz; mekanik dönüşümle giderilir. 2) Pairwise disjointness eksikliği: aynı nonterminal'in RHS'lerinin FIRST kümeleri kesişmemeli (BOŞ kesişim); kesişiyorsa left factoring ile ortak baş dışarı alınır. Örnek problem: A → a | aB.
S75 ⭐Handle nedir? Shift ve reduce eylemlerini tanımlayın.
Handle: right sentential form'un en soldaki simple phrase'i — reduce edilecek parça (parsing = handle pruning). Shift: sıradaki token'ı stack'e koy. Reduce: stack tepesindeki handle'ı kuralın LHS'iyle değiştir. (+ Accept ve Error.)
S76 ⭐LR parser'ların dört avantajı ve tek pratik dezavantajı nedir?
Hemen tüm PL grammar'larında çalışır; diğer bottom-up'lardan geniş sınıf, aynı verim; hatayı en erken yakalar; LR sınıfı LL'in ÜST KÜMESİdir. Dezavantaj: tablo elle üretilemez — yacc/bison gibi araç gerekir.
S77ACTION ve GOTO tablolarının satır/sütunları nedir; R4, S6 ve boş hücre ne demektir?
ACTION: satır=state, sütun=TERMINAL. GOTO: satır=state, sütun=NONTERMINAL (reduce sonrası state). S6="shift + state 6 push", R4="kural 4 ile reduce", boş hücre=syntax error. Knuth'un içgörüsü: olası parse durumları sonlu ve azdır → state olarak saklanır.

Lecture 4 — Names, Bindings & Scopes

S78 ⭐Variable'ın altı niteliğini (sextuple) sayın; hoca hangisini "en önemli" ilan etti?
Name, address, value, type, lifetime, scope. En önemlisi TYPE ("the most important attribute" — Lecture 5'in konusu). Variable = bellek hücresinin soyutlaması.
S79C99'da isim uzunluğu kuralları nedir? Case sensitivity neden okunabilirliğe zarar verir?
Sınır yok ama ilk 63 karakter anlamlı; external isimlerde 31. Case sensitivity: benzer görünen isimler farklı şeylerdir; C-tabanlı dillerde hazır isimler karışık harfli olduğundan (IndexOutOfBoundsException) daha da kötü.
S80 ⭐Keyword ile reserved word farkı nedir? COBOL örneği ne anlatır?
Reserved word hiçbir bağlamda kullanıcı ismi olamaz; keyword yalnız belirli bağlamlarda özeldir (Fortran'da yeniden tanımlanabilir). COBOL'un 300 reserved word'ü çakışma örneği — 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?
l-value = değişkenin adresi, r-value = değeri. r-value'ya erişmek için önce l-value'yu (adresi) bilmek gerekir.
S82Alias nasıl oluşur, neden zararlıdır?
Pointer, reference ve union'larla — aynı hücreye iki isim. Zarar: değer başka isim üzerinden değişebilir; okuyan tüm takma adları bilmek zorunda (readability/reliability ↓).
S83 ⭐Beş binding time'ı birer örnekle yazın.
Language design: *→ç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.
count'un tipi → compile time; olası değer kümesi → implementation time; +'ın anlamı → compile time (operand tiplerinden); 5'in iç gösterimi → compiler design time; count'un DEĞERİ → run time. (Hoca: binding, "a prerequisite for understanding semantics.")
S85 ⭐Static binding ile dillerdeki static keyword'ü aynı şey midir?
HAYIR — hocanın açık tuzak uyarısı: ilişkili ama farklı kavramlar. Static binding: run time'dan önce kurulup değişmeyen bağlanma. 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.
Explicit: 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?
Tip atamayla gelir (JS: 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.
Static: çalışma öncesi, hep aynı hücre — verimli + history-sensitive / RECURSION YOK. Stack-dynamic: bildirim elaborate olunca — recursion var / alloc-dealloc maliyeti, history-sensitive olamaz. Explicit heap-dynamic: new/delete, pointer'la — dinamik yapılar / verimsiz+güvenilmez (Java'da TÜM nesneler böyle). Implicit heap-dynamic: yalnız atamayla, tüm nitelikler her atamada — en esnek / verimsiz + hata tespiti kaybı (APL; Perl/JS/PHP string-dizi).
S89Elaboration ne demektir?
Bildirime bağlı kodun, çalışma anında o satıra gelindiğinde yürütülmesi (stack-dynamic değişkene bellek bu anda bağlanır) — tanımı gereği hep run time'da olur.
S90 ⭐Scope tanımı; local/nonlocal/global ayrımı nedir?
Scope = değişkenin görünür (referans/atama yapılabilir) olduğu deyim aralığı. Local: o birimde bildirilenler; nonlocal: görünen ama orada bildirilmeyenler; global: nonlocal'in özel hâli.
S91 ⭐Static scoping'de isim aranırken izlenen süreç nedir? Static parent/ancestor ve hiding nedir?
Önce lokal bildirimlere bak; yoksa metinsel kapsayan birime (static parent), sonra onun kapsayanlarına (static ancestors) çık. Daha yakın aynı isimli bildirim dıştakini gizler (hiding/shadowing).
S92 ⭐big/sub1/sub2 örneğinde (big→sub1→sub2 çağrısı) sub2'deki x, static ve dynamic scoping'de hangi x'tir?
Static: BIG'in x'i (metinsel kapsayan big'dir; sub1 sadece çağırandır). Dynamic: SUB1'in x'i (çağrı zincirinde geriye ilk bildirim). Slogan: "temporal versus spatial."
S93İç blokta dış bloktaki isimle değişken bildirmek hangi dillerde legal, hangilerinde yasaktır?
C ve C++'ta legal (ALGOL 60 mirası blocks); Java ve C#'ta hataya çok açık diye YASAK.
S94LET construct'ın iki parçası nedir, hangi dillerde görülür?
1. parça isimleri değerlere bağlar, 2. parça o isimleri kullanır. Scheme, ML, F# (F#'ta girinti scope'u sınırlar).
S95C/C++'ta declaration ile definition farkı nedir? extern ne işe yarar?
Declaration yalnız nitelikleri bildirir (bellek yok), definition bellek de ayırır. Kural: istediğin kadar uyumlu declaration, yalnız TEK definition. 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?
PHP: $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?
1) Çoğu durumda gereğinden fazla erişim verir. 2) Program evrildikçe yapı bozulur — lokaller globalleşir ("developers discard structure when it gets in the way"); bu güvenlik riski de doğurur.
S98 ⭐Dynamic scoping'in avantajı ve dört dezavantajı nedir?
Avantaj: pratiklik — parametre taşımak gerekmez. Dezavantajlar: çağıranın tüm değişkenleri çağrılana görünür (reliability ↓), static type checking İMKÂNSIZ, okunabilirlik kötü (tipi statik belirlenemez), erişim yavaş.
S99 ⭐Scope ile lifetime farkını C'deki fonksiyon içi static int k ile ispatlayın. Java'da olur mu?
Scope metinsel: k fonksiyon dışından görünmez. Lifetime zamansal: k tüm program boyunca yaşar, çağrılar arası değer korur — ardışık çağrılar 5, 10, 15 döndürür: "not visible, but still alive." Java'da OLMAZ (metod içi static değişken yok).
S100Referencing environment'ı static ve dynamic scoped diller için ayrı ayrı tanımlayın.
Bir deyimde görünür TÜM isimlerin kümesi. Static: lokaller + tüm kapsayan scope'ların görünürleri. Dynamic: lokaller + tüm AKTİF (başlamış, bitmemiş) alt programların görünürleri.
S101 ⭐Named constant nedir? C#'ın iki türünü bağlanma zamanlarıyla ayırın.
Belleğe bağlanırken YALNIZCA BİR KEZ değer bağlanan değişken; okunabilirlik + programı parametrize etme. Static bağlananlara manifest constant denir. C#: const → compile time; readonly → run time (dinamik).
S102İmperative diller neyin soyutlamasıdır ve saf fonksiyonel dillerle temel karşıtlığı nedir?
von Neumann mimarisinin (bellek+işlemci) soyutlaması; variable = hücre. Saf fonksiyonel dillerde ise değişken ve atama hiç yoktur — hesap, fonksiyon uygulamasıyla yapılır.
Bölüm II Final Kapsamı — Ch.6–12

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> ::= <kapsam> <ağırlık> <format> <strateji>

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.

Final kapsamı — hangi bölümler
DersTarihSebestaKonuSüreAğırlık tahmini
Lecture #521 TemCh.6Data Types285 dk (iki oturumluk)⭐⭐⭐ en yüksek
Lecture #627 TemCh.7–8Expressions & Assignment + Control Structures228 dk⭐⭐⭐
Lecture #728 TemCh.9Subprograms (+ Quiz 2)227 dk⭐⭐⭐
Lecture #83 AğuCh.10Implementing Subprograms112 dk (asenkron)⭐⭐
Lecture #94 AğuCh.11ADTs & Encapsulation (+ Quiz 3)166 dk⭐⭐
Lecture #1010 AğuCh.12Support 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."

⭐⭐ Hocanın finalle ilgili SON sözleri — 10 Ağustos, quiz 4 öncesi Hoca son dersin bitiminde, Quiz 4'ü başlatmadan hemen önce Türkçe olarak finali anlattı. Bu, elimizdeki en güncel ve en doğrudan sınav istihbaratı: "Sınav vize sınavınızla aynı olacak. Yani kavramlar açısından testler var, açık uçlu sorular var vs. Tıpkı vize sınavınız gibi." "Sınav konularına gelince, tabii ki final sınavı olduğu için tüm dönemi kapsıyor, ama tabii ki ağırlık vize sonrası kısımlara kayacak." (Kayıt Türkçe konuşuluyor; yukarıdaki cümleler transkriptten sadeleştirildi — "vize" kelimesi otomatik transkriptte "visa" olarak geçiyor.)

Üç net çıkarım:
  1. 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.
  2. 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ç.
  3. 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.
Bu ifade, iki quiz'den çıkardığımız "hoca birikimli soruyor" gözlemini birebir doğruluyor — aşağıdaki quiz analizini o gözle oku.
Kapsam tablosu — nihai hâli
BölümDurumFinaldeki yeri
Ch.1–5 (Lecture #1–#4)✅ Vizede sorulduKapsamda — ama ağırlığı düşük. Rehberin vize bölümünden hızlı tekrar
Ch.6–11 (Lecture #5–#9)✅ İşlendi, tam transkript + slaytFinalin gövdesi — zamanının çoğu buraya
Ch.12 (Lecture #10, OOP desteği)10 Ağustos'ta işlendi — transkript + slayt elimizdeEn taze konu, aşağıda tam bölüm olarak eklendi
Ch.13 · Ch.14 (concurrency, exception handling)Hiç işlenmediKapsam dışı — dönem Ch.12 ile kapandı
Not: Quiz 4 bu dersin hemen ardından yapıldı; hoca "we have now a quiz which will start in five minutes" dedi. Quiz notların %20'lik dilime giriyor.

Ağırlıklar ve not durumun

BileşenAğırlıkDurum
Quiz'ler%20Quiz 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%4020 Temmuz, yüz yüze
Final%40Tü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

Hoca 10 Ağustos'ta "final, vizenin aynısı olacak" dedi — aşağıdakiler doğrudan geçerli
  • 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.
⭐ En değerli bulgu: quiz'ler birikimli, ders bazlı değil Quiz 2 ve Quiz 3'ün gerçek soruları elimizde ve çok net bir örüntü gösteriyor:
QuizTarih / o günkü dersSorular nereden geldiO günkü dersten soru
Quiz 228 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 34 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
Finale etkisi — üç çıkarım:
  1. 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ç.
  2. 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.
  3. 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.
Quiz 1'den çıkan tek ama önemli ders Tek yanlışın "PL çalışmanın nedeni olmayan şık" sorusuydu; cevap anahtarı "facilitation of compiler design"ı gerekçe saydı. Ders: tanımları ve listeleri slayttaki birebir ifadeyle ezberle, kendi mantığınla düzeltmeye çalışma. Bu final için daha da kritik, çünkü final bölümleri liste ağırlıklı (tasarım soruları, avantaj/dezavantaj listeleri).

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.

#KonuDersNeden
1Array'in dört kategorisi (static / fixed stack-dynamic / fixed heap-dynamic / heap-dynamic)L5Slaytta 5 ayrı sayfa; her kategori dil örnekleriyle eşleştirilmiş
2Beş parameter passing yöntemi + avantaj/dezavantajlarıL7Bölümün merkezi; hoca tek tek avantaj/dezavantaj saydı
3Dangling pointer vs lost heap-dynamic variable (memory leak)L5Slaytta "garbage / dangling" formülü ayrıca verilmiş
4Reference counting vs mark-sweep (eager/lazy)L5Tam karşılaştırma kalıbı; her ikisinin de avantaj+dezavantajı net
5Free union vs discriminated union; Java/C#'ta union yokL5"Güvenlik kaygısının yansıması" cümlesi çok sevilir
6Strong typing tanımı + hangi dil neden strongly typed değilL5C/C++'ın iki gerekçesi (parametre denetimi atlanabilir, union denetlenmez)
7Name vs structure type equivalenceL5Klasik ikili; structure'ın "aynı yapıdakiler ayırt edilemez" sorunu
8Functional side effect + slayttaki fun1() kodunun C ve Java çıktısıL6Hoca soruyu açıkça öğrenciye bıraktı
9Referential transparency — tanım + saf fonksiyonel diller neden hep sağlarL6"Değişkenleri yok" mantık zinciri
10Short-circuit evaluation — tanım + slayttaki LIST[index] örneğiL6Somut hata senaryosu; C/C++/Java'nın &/&& ayrımı
11Dangling else ve Java'nın static semantics kuralıL6Vizedeki ambiguity konusunun devamı
121960'lar kanıtı: tüm algoritmalar two-way selection + pretest loop ile kodlanabilirL6Slaytta ayrı sayfa, tek cümlelik "önemli sonuç"
13parameter profile vs protocolL7İki satırlık tanım farkı — MC için ideal
14Deep / shallow / ad hoc binding (parametre olan subprogram'ın ortamı)L7Slaytta kodlu örnek + hangi scoping'e doğal olduğu
15Closure tanımı + ne zaman gerekliL7"Nested subprogram'sız static-scoped dilin closure'a ihtiyacı yok" cümlesi
16Coroutine — resume, çoklu giriş, "interleaved but not overlapped"L7Ayırt edici, tek bölüme özgü kavram
17activation record vs activation record instance; biçim static / boyut dynamicL8Bölümün merkez ayrımı
18static chain + (chain_offset, local_offset) hesabıL8Slaytta tam tablolu örnek — sayısal soru gelebilir
19ADT'nin iki koşulu ve her birinin avantajlarıL9Bölümün tanım çekirdeği
20Java vs C++ ADT farkları (destructor yok, hepsi sınıf, package scope…)L9Slaytta madde madde listelenmiş; "Java DOES NOT have Destructors" kutusu
21OOP'nin üç dayanağı (ADT/encapsulation + inheritance + polymorphism/dynamic binding)L10Slaytın Summary'sinin ilk maddesi; hoca "three pillars" diye tekrarladı
22Subclass vs subtype — "is-a" ilişkisi ve substitution principleL10Slaytta ayrı sayfa; tam karşılaştırma kalıbı: "subclasses inherit implementation; subtypes inherit interface and behavior"
23Multiple inheritance — iki dezavantajı, diamond problemi, virtual çözümüL10Hoca "neden Java'da yok?" sorusunu açıkça sordu; cevap: karmaşıklık + verimsizlik
24Interface vs abstract class (slaytta iki sayfalık tablo)L10Karşılaştırma sorusunun ideal adayı; Java 8 default notu dahil
25Exclusivity of objects — üç yaklaşım ve her birinin avantaj/dezavantajıL10Tasarım sorularının ilki; slaytta 3×2 madde hâlinde
26vtable / CIR — dinamik bağlamanın gerçeklenmesiL10Bölümün tek "implementation" konusu; Ch.10'daki activation record mantığının OOP karşılığı

Tekrar eden temalar — dersin "omurgası"

Bu üçlü finalin her bölümünde karşına çıkacak Dersin ilk gününden beri kurulan readability / writability / reliability üçlüsü, final konularının her birinde değerlendirme ölçütü olarak geri geliyor. Açık uçlu bir soruda bu üçlüye bağlanmak neredeyse her zaman puan getirir:
KonuHangi ölçüte bağlanır
Enumeration typesreadability + reliability (renk sayı değil; derleyici aralık denetler)
Boolean typereadability
Operator overloadingreadability (iki yönlü: iyi kullanılırsa artırır, kötü kullanılırsa düşürür)
Coercionreliability ↓ (derleyicinin hata yakalaması azalır)
Aliasing (pass-by-reference)readability ↓ → reliability ↓ → verification zorlaşır
gotoreadability — 1960–70'lerin tartışmasının ana kaygısı
Parametre tip denetimireliability
Information hiding (ADT)reliability + modifiability
Kontrol yapısı zenginliğiwritability ↔ 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
İkinci omurga: static ↔ dynamic ekseni Vizedeki binding time konusu finalde her yere sızıyor. Bir soruda "static mi dynamic mi" geçiyorsa aynı mantığı uygula:
  • 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++ virtual ile seçmeli dynamic; Java varsayılan dynamic (final/static/private hariç); Smalltalk/Ruby tamamen dynamic
Genel kural: static = verimli ama esnek değil; dynamic = esnek ama pahalı. Bir avantaj/dezavantaj sorusunda tıkanırsan bu cümleye dön.

Çalışma planı — sırayla

  1. Ö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.
  2. 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.
  3. 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).
  4. 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.
  5. Soru havuzunu çöz (aşağıda) ve yanlışlarını ilgili bölüme dönerek kapat.
"Java'nın yokları" — tek kutuda toplandı, ezberlemesi kolay puan
  • 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 static local 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
<data-type> ::= <değer-kümesi> <işlem-kümesi>

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ü

Hocanın açılış cümlesi Normalde bu konu iki oturumda anlatılırdı; hoca zaman darlığı yüzünden tek uzun oturumda bitirdi. Yani slayt sayısı (97 slayt) ve konu yoğunluğu bakımından final kapsamındaki en ağır ders bu. "Normally we would be talking two weeks about that... but today, we will talk about the two sessions. And today, it will be a long session."

Temel tanımlar — ezberlenecek üçlü

Bölümün ilk üç slaydı doğrudan tanım sorusu malzemesi. Hoca üçünü de tek tek okudu:

TerimTanım (slayttaki hâliyle)
data typeBir veri nesneleri kümesi ve bu nesneler üzerinde önceden tanımlı işlemler kümesi.
descriptorBir değişkenin özniteliklerinin toplamı. Bellekte özniteliklerin saklandığı alan.
objectKullanıcı tanımlı (abstract data) bir tipin örneği (instance).
Tuzak — hoca özellikle uyardı Bu derste "object" kelimesi OOP'deki nesne demek değil. Burada object = kullanıcı tanımlı / abstract data type'ın bir örneği. Hoca bunu ayrıca vurguladı: "objects, what we mean here in this course are not the objects what you know from object oriented programming courses." Çoktan seçmelide "object" tanımı sorulursa slayttaki tanımı seç.

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ı:

  1. Error detection (hata yakalama) — en pratik gerekçe. type checking süreci doğrudan tip sistemi tarafından yönetilir.
  2. Modularization (modülerleştirme) — modüller arası (cross-module) tip denetimi, arayüzlerin tutarlılığını garanti eder → yeniden kullanılabilirlik.
  3. Documentation (belgeleme) — tip bildirimleri programın verisi hakkında bilgi belgeler, davranışı hakkında ipucu verir.
Descriptor ne zaman gerekir?
  • Ö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.
Hocanın uzun uzun anlattığı şey: neden two's complement? Negatif tamsayılar sign-magnitude ile saklanabilir (en soldaki bit işaret), ama bilgisayar aritmetiği için kötüdür. Bu yüzden çoğu bilgisayar two's complement kullanır: pozitif hâlinin bit'lerini ters çevir (ones complement), sonra 1 ekle.

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 tabanda 0.000110011001100… şeklinde devreder.
  • Bilimsel kullanım için dil en az iki tip sunmalı: float ve double.
  • IEEE Floating-Point Standard 754 — sayıyı üç parçaya böler:
    Parça32-bit64-bit
    sign (işaret)1 bit1 bit
    exponent (üs)8 bit11 bit
    fraction (kesir)23 bit52 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

TipKim desteklerNasılAvantaj / Dezavantaj
complexC99, Fortran, Pythonİki float: reel + sanal kısım. Python: (7 + 3j)
decimalCOBOL (temel), C#Sabit sayıda ondalık basamak, BCD (binary coded decimal) kodlu+ accuracy (kesin)
− limited range, wastes memory
Decimal — kesin çıkma ihtimali yüksek Hoca burayı ısrarla anlattı: decimal tip iş uygulamaları (para) içindir, büyük iş bilgisayarlarında donanım desteği bile vardır (SAP çalıştıran sistemler örneğini verdi).
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.
    KodlamaGenişlikNot
    ASCII0–127 (128 karakter)En yaygın; İngilizce için yeterliydi
    Unicode UCS-216 bitÇoğu doğal dilin karakteri. Orijinal olarak Java'da kullanıldı. İlk 128 karakteri ASCII ile birebir aynı.
    Unicode UCS-432 bitFortran, 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:

String'in iki tasarım sorusu — ezberle
  1. Primitive bir tip mi, yoksa sadece özel bir array mi?
  2. 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ı.

DilString yaklaşımı
C, C++Primitive değil — char array + fonksiyon kütüphanesi. strcpy, strcat, strcmp, strlen
SNOBOL4Primitive — tarihteki ilk string manipülasyon dili, gelişmiş pattern matching
Fortran, PythonPrimitive tip + atama ve birkaç işlem
Java, C#, Ruby, SwiftString sınıfı üzerinden primitive
Perl, JavaScript, Ruby, PHPYerleşik pattern matching — regular expression'larla

Uzunluk seçenekleri — üç kategori

KategoriNe demekDillerDescriptor
StaticUzunluk sabit, derlemede belliCOBOL, Java String sınıfıCompile-time descriptor (3 alan: tip adı · uzunluk · ilk karakterin adresi)
Limited dynamicBildirilen bir maksimuma kadar değişebilirC, C++Run-time descriptor gerekebilir (maksimum uzunluk · geçerli uzunluk · adres) — ama C/C++'ta yok
DynamicMaksimum yokSNOBOL4, Perl, JavaScriptRun-time descriptor şart; en büyük sorun allocation/deallocation
C/C++'ın null karakteri C ve C++ uzunluğu tutmaz; string'in sonunu özel bir karakterle (null, genelde 0) işaretler. Kütüphane fonksiyonları null'ı görene kadar çalışır. Hoca tek cümleyle vurguladı: "The null character is always very important."
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.

Enumeration'ın değerlendirmesi — klasik soru readability'ye katkı: rengi sayı olarak kodlamaya gerek kalmaz.
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.

Array'in 8 tasarım sorusu — slaytta madde madde
  1. Subscript'ler için hangi tipler yasal?
  2. Eleman referanslarındaki subscript ifadeleri range checked mi?
  3. Subscript aralıkları ne zaman bind edilir?
  4. Allocation ne zaman olur?
  5. Ragged (jagged) mı, rectangular mı, ikisi de mi?
  6. Maksimum subscript sayısı kaç?
  7. Array nesneleri initialize edilebilir mi?
  8. Slice destekleniyor mu?
KonuDiller
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 integerFortran, Java
Subscript tipi: ordinal tipler (integer, char, boolean, enum)C, C++
Range checking YOKC, C++, Perl, Fortran
Range checking VARJava, ML, C#
Tarihsel ayrıntı — hoca anlattı 1990 öncesi Fortran ve PL/I neden parantez seçti? Çünkü o dönemin delikli kartlarında köşeli parantez karakteri yoktu. Parantezin sakıncası: alt program çağrısıyla karışır — 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ığı.

KategoriSubscript aralığıAllocationAvantajÖrnek
Staticstatik bindstatik, run-time öncesiefficiency — dinamik ayırma yokC/C++'ta static nitelemeli array'ler
Fixed stack-dynamicstatik bindbildirim anında (stack)space efficiencyC/C++'ta static olmayan array'ler
Fixed heap-dynamicdinamik ama ayırma sonrası sabitistendiğinde, heap'tenC malloc, C++ new, Java'da tüm non-generic array'ler
Heap-dynamicdinamik, defalarca değişebilirdinamik, heapflexibility — array büyüyüp küçülebilirJava ArrayList, C# List, Perl, JavaScript, Python, Ruby
Nasıl sorulur Bu tablo iki yönlü sorulur: (a) "C'de 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], Ruby list.slice(2,2).
  • APL vektör/matris işlemlerinde en güçlü operatör setini sunar. Fortran elemental işlemler sağlar: A = A + B iki 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üzen1 2 3 / 4 5 6 / 7 8 9 nasıl saklanırKim
Row major order1 2 3 4 5 6 7 8 9Çoğu dil
Column major order1 4 7 2 5 8 3 6 9Fortran
Location(a[i,j]) = address(a[row_lb, col_lb])
                 + (((i − row_lb) × n) + (j − col_lb)) × element_size
Slayttaki sayısal örnek n=7, m=7, 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.

DilSö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.)

Array vs Record — hocanın "fundamental difference" dediği yer 1. Homojenlik: array homogeneous, record heterogeneous.
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 referansFIRST OF EMP-NAME OF EMP-REC
Diğerleri — dot notation, özyinelemeli tanımemp.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

TipTanım / Not
TupleRecord'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.
ListLisp/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).
Scheme liste işlemleri — ezberlenecek dörtlü
İşlemNe yaparÖrnek
CARListenin ilk elemanı(CAR '(A B C))A
CDRİlk eleman çıkarıldıktan sonra kalanı(CDR '(A B C))(B C)
CONS1. parametreyi 2. parametreye (listeye) ekler(CONS 'A (B C))(A B C)
LISTParametrelerinden yeni liste yapar(LIST 'A 'B '(C D))(A B (C D))
ML karşılıkları: CONS → :: (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 vs Discriminated union — kesin ayrım
Free unionDiscriminated union
Type checkingYok — dil desteği yokVardiscriminant adlı tip göstergesi hangi alanın kullanılacağını söyler
DillerC, C++Ada, ML, Haskell, F#
GüvenlikUnsafeSafe
Free union'ın tehlikesi (slayttaki örnek): 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.

Pointer'ların iki büyük problemi — kesin soru
ProblemNe olurDiğer adı
Dangling pointerPointer, deallocate edilmiş bir heap-dynamic değişkeni gösteriyor"dangerous" (slaytın kendi notu)
Lost heap-dynamic variableAyrılmış ama artık erişilemeyen heap değişkeni: p1 bir nesneyi gösteriyor, sonra başka bir nesneye yönlendiriliyor → eskisi kayıpgarbage; bu sürece memory leakage denir
Hafızada tutmanın kolay yolu (slaytın kendi formülü):
• Nesne, binding'den uzun yaşarsa → garbage
• Binding, nesneden uzun yaşarsa → dangling reference

Dangling pointer'a iki çözüm

YöntemNasıl çalışırMaliyet
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-keysPointer 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

DilDurum
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ı.
JavaC++'ı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ı.
Pointer'ların değerlendirmesi — açık uçlu soru adayı Sorunlar: dangling pointer, dangling object, heap yönetimi.
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 counting vs Mark-sweep
Reference counterMark-sweep
YaklaşımEager (istekli) — geri kazanım kademeliLazy (tembel) — geri kazanım, boş alan listesi bitince
MekanizmaHer hücrede bir sayaç: kaç pointer beni gösteriyorHer 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
DezavantajAlan maliyeti, çalışma zamanı maliyeti, dairesel bağlı hücrelerde çuvallarOrijinal hâlinde çok seyrek çalışırdı; çalışınca uygulamada ciddi gecikme
AvantajIntrinsically incremental — uygulamada büyük gecikme olmazDairesel yapıları da toplar
Modern çözümincremental 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

Dört tanım — birebir ezber
TerimTanım
type checkingBir operatörün operand'larının uyumlu tiplerde olmasını sağlama etkinliği.
compatible typeOperatör için ya yasal olan ya da dil kurallarınca derleyici üretimi kodla yasal bir tipe örtük çevrilebilen tip.
coercionBu otomatik/örtük çevrimin adı.
type errorBir 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.

DilStrongly typed mı?Neden
C, C++HayırParametre tip denetimi atlanabilir; union'lar type checked değil
Java, C#NeredeyseAçık tip dönüşümü (explicit casting) yüzünden
ML, F#Evet
AdaJava'dan daha etkiliJava'nın atama coercion'ları C++'ın yarısı kadar olsa da Ada'nınki hâlâ daha güçlü
Kritik bağlantı Coercion kuralları strong typing'i ciddi biçimde zayıflatır (C++ ↔ ML/F# karşıtlığı). Yani "coercion çok olan dil, strong typing'i o ölçüde kaybeder". Bu cümle sınavda ya doğrudan sorulur ya da bir "hangisi doğrudur" şıkkında gizlenir.

Type equivalence — iki yaklaşım

Name type equivalenceStructure type equivalence
Kuralİki değişken aynı bildirimde ya da aynı tip adını kullanan bildirimlerdeyse tipleri eşdeğerdirTipleri aynı yapıya sahipse eşdeğerdir
UygulamaKolayZor
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
SorunAynı 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?

Bu dersin özet cümlesi (slaytın Summary'si)
  • 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.
<statement> ::= <expression> | <assignment> | <selection> | <iteration>

6 · Expressions, Assignment & Control Structures

Ch.7–8 · 27 Temmuz dersi · Slayt: Lecture #6 (iki parçalı) — vizeden sonraki ilk konu

Bu dersin çerçevesi Hoca en başta şunu kurdu: expression'lar bir dilde hesaplamayı belirtmenin temel aracıdır ve imperative dillerin özü, assignment statement'ın baskın rolüdür. Expression değerlendirmesini anlamak için operator ve operand değerlendirme sıralarını bilmek gerekir. "for a language designer, for a language user, it is crucial to understand the expression evaluation"

Aritmetik expression'ların 6 tasarım sorusu

Slayttaki altı madde — liste sorusu adayı
  1. Operator precedence kuralları?
  2. Operator associativity kuralları?
  3. Operand değerlendirme sırası?
  4. Operand değerlendirmesinin side effect'leri?
  5. Operator overloading?
  6. 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

KavramNe belirler
precedenceFarklı öncelik seviyesindeki komşu operatörlerin değerlendirilme sırası
associativityAynı ö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.

İki uç örnek Ruby: tüm aritmetik, ilişkisel ve atama operatörleri, array indeksleme, shift ve bit işlemleri birer metot olarak gerçeklenmiştir → hepsi uygulama programlarınca override edilebilir.
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.

Functional side effect — bu dersin en olası sorusu Tanım: Bir fonksiyon, bir two-way parametreyi ya da bir non-local (global) değişkeni değiştirdiğinde functional side effect oluşur.
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.
Slayttaki kod — hocanın sınıfa sorduğu soru
int a = 5;
int fun1() {
    a = 17;
    return 3;
}
int main() {
    a = a + fun1();
    printf("%d\n", a);
}
Soldaki a önce okunursa: 5 + 3 = 8
fun1() önce çalışırsa: a artık 17 → 17 + 3 = 20

C/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ümNasılAvantajDezavantaj
1. YasaklaDil 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ı sabitleDil tanımı operand değerlendirme sırasını sabit kılsınSonuç deterministikDerleyici optimizasyonlarını kısıtlarJava bu yolu seçti (soldan sağa)

Referential transparency

Tanım + neden önemli Tanım: Programdaki aynı değere sahip iki ifade, programın davranışını değiştirmeden her yerde birbirinin yerine konabiliyorsa program referential transparency özelliğine sahiptir.
result1 = (fun(a) + b) / (fun(a) − c);

temp = fun(a);
result2 = (temp + b) / (temp − c);
fun'ın side effect'i yoksaresult1 = 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.

C/C++'ta * ve & problemi — hoca uzun anlattı & binary operatör olarak bitwise AND, unary operatör olarak adres alma. * hem çarpma hem dereference.
İki zarar:
  1. 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.
  2. 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 vs Widening — birebir tanım
Narrowing conversionWidening conversion
TanımNesneyi, orijinal tipin tüm değerlerini içeremeyen bir tipe çevirirNesneyi, orijinal tipin tüm değerlerine en azından yaklaşık karşılık verebilen bir tipe çevirir
Örnekfloat → int, double → floatint → float
GüvenlikKayı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.

DilCoercion politikası
Çoğu dilTü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.

PL/I'ın uç örneği — hocanın anlattığı, sınavda çıkabilecek anekdot PL/I aşırı esneklik istedi: bir karakter dizisi değişkeni, bir integer ile aritmetik operatörün operand'ı olabiliyordu. Run-time'da string sayısal değer için taranıyor; ondalık nokta varsa floating point varsayılıyor, diğer operand da floating point'e coerce ediliyordu.
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 yokturint kullanır (0 false, sıfırdan farklı true).
C'nin tuhaf davranışı — çok sevilen bir soru C'de 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 77FORTRAN 90CAda
.AND.and&&and
.OR.or||or
.NOT.not!not
xor

Short-circuit evaluation

Tanım + klasik örnek Tanım: Sonucun, tüm operand ve/veya operatörler değerlendirilmeden belirlendiği ifade.
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.
DilDurum
C, C++, JavaOlağan Boolean operatörleri (&&, ||) short-circuit; ayrıca short-circuit olmayan bitwise Boolean operatörleri (&, |) de sunar
Ruby, Perl, ML, F#, PythonTü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ürC tabanlı diller tam bu yüzden =='i ilişkisel operatör yaptı.

BiçimAçıklamaÖrnek
Conditional targetAtama hedefi koşullu (Perl)($flag ? $total : $subtotal) = 0
Compound assignmentKısayol. ALGOL'de tanıtıldı, C ve C tabanlı diller benimsedia += ba = a + b
Unary assignmentArtırma/azaltmayı atamayla birleştirirsum = ++count (önce artır, sonra ata)
sum = count++ (önce ata, sonra artır)
-count++ (önce artır, sonra negatifle)
Assignment as expressionAtama bir değer üretir ve operand olarak kullanılabilir — C tabanlı diller, Perl, JavaScriptwhile ((ch = getchar()) != EOF) {…}
Multiple assignmentPerl 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.

DilMixed-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
AdaHiç atama coercion'ı yok

Part 2 — Statement-Level Control Structures

Kontrol akışının üç seviyesi — çerçeve sorusu
  1. İfadeler içinde — operator associativity ve precedence (Lecture #6 Part 1)
  2. Program birimleri arasında — fonksiyon/altprogram (Lecture #7)
  3. Program deyimleri arasında — selection / iteration (burası)
1960'ların ünlü kanıtı — kesin sınav malzemesi 1960'larda kontrol yapıları üzerine çok tartışma oldu. Önemli bir sonuç kanıtlandı: Akış şemalarıyla temsil edilebilen tüm algoritmalar, yalnızca iki yönlü seçim (two-way selection) ve ön testli mantıksal döngüler (pretest logical loops) ile kodlanabilir.
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.
Dangling else — vizede BNF/ambiguity tarafında gördüğün problemin buradaki hâli
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?

C/C++/Java switch'inin dört tasarım tercihi — madde madde sorulabilir
  1. Kontrol ifadesi ordinal tip olabilir: integer, karakter, enumeration. (Java'da JDK 7+ ile sabit ifade string ve wrapper sınıfı da olabilir.)
  2. Seçilebilir segmentler deyim dizisi, blok veya compound statement olabilir.
  3. Tek bir yürütmede herhangi sayıda segment çalışabilir — segment sonunda örtük dallanma yoktur (fall-through).
  4. default clause temsil edilmeyen değerler içindir; default yoksa deyim hiçbir şey yapmaz.
C# farkı (çok sorulur): Bir static semantics kuralıyla birden fazla segmentin örtük yürütülmesini yasaklar — her segment koşulsuz bir dallanmayla (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?

C'nin 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 for gövdesinin içine dallanmak yasaldır.
  • İkinci ifade yoksa → sonsuz döngü.
Sürüm farkları: C++ (ve C99), C89'dan iki noktada ayrılır: kontrol ifadesi Boolean da olabilir ve başlangıç ifadesi değişken tanımı içerebilir (scope'u tanımdan gövde sonuna kadar). Java ve C#'ta kontrol ifadesi zorunlu Boolean'dır.

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 goto yoktur.
  • Perl ve Ruby: iki pretest mantıksal döngü — while ve until. Perl'de ayrıca iki posttest döngü var.
break ve continue — dil dil tablo
ÖzellikDiller
Koşulsuz etiketsiz çıkış (break)C, C++, Python, Ruby, C#
Koşulsuz etiketli çıkışJava (break label), Perl (last)
Etiketsiz continueC, C++, Python
Etiketli continueJava, Perl
Kural: etiketsiz 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.

DilMekanizma
Cfor ile kullanıcı tanımlı iterator kurulabilir: for (p=root; p!=NULL; traverse(p))
PHPcurrent · next · reset
JavaIterator arayüzünü gerçekleyen koleksiyonlar: next · hasNext (predicate) · remove
Java 5.0foreach denen ama for anahtar sözcüğünü kullanan biçim; Iterable gerçekleyen her sınıf için: for (String s : aList)
PerlArray ve hash'ler için yerleşik foreach
C#, F#Generic kütüphane sınıfları üzerinde foreach

Unconditional branching (goto)

goto tartışması — kavramsal soru adayı Kontrolü programda belirtilen bir yere aktarır. 1960'lar ve 70'lerin en hararetli tartışmalarından biri. Temel kaygı: readability.
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.
Bölümün sonuç cümlesi — doğrudan alıntılanabilir Seçim ve mantıksal ön test döngüsünün ötesindeki kontrol deyimi seçimi, dil büyüklüğü ile writability arasında bir trade-off'tur.
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.
<subprogram> ::= <header> <parameter-profile> <body>

7 · Subprograms

Ch.9 · 28 Temmuz dersi (Quiz 2 bu derste yapıldı) · Slayt: Lecture #7

Hocanın açılış vurgusu "Subprogram'lar programların temel yapı taşlarıdır, bu yüzden programlama dili tasarımının en önemli kavramları arasındadırlar." — bu yüzden ayrı bir bölüm ayrılmış. "As subprograms are the fundamental building blocks of programs, and therefore they are among the most important concepts in programming language design."
⚠ Quiz 2 bu derste yapıldı — ama subprogram sormadı 28 Temmuz dersinde, oturumun ortasında 10 soruluk Quiz 2 yapıldı. Gerçek sorulara bakıldığında: subprogram'larla ilgili tek bir soru bile yok. Sorular binding, static scoping, BNF/parser, strong typing, dynamic type binding, data types ve referential transparency'den geldi — yani önceki bölümlerden.

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ı

SoyutlamaNe 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

Slayttaki üç madde — birebir ezber
  1. Her subprogram'ın tek bir giriş noktası (single entry point) vardır.
  2. Çağıran program, çağrılan subprogram çalışırken askıya alınır (suspended).
  3. Çağrılan subprogram bitince kontrol her zaman çağırana döner.
Not: coroutine'ler tam olarak 1. ve 3. maddeyi ihlal ettiği için "özel" sayılır — bölüm sonunda göreceksin.

Temel tanımlar — tanım sorusu deposu

TerimTanım
subprogram definitionSubprogram soyutlamasının arayüzünü ve eylemlerini tanımlar
subprogram callSubprogram'ın çalıştırılması için açık bir istek
subprogram headerTanımın ilk kısmı: ad + subprogram türü + formal parametreler
parameter profile (= signature)Parametrelerin sayısı, sırası ve tipleri
protocolparameter profile + (fonksiyonsa) dönüş tipi
subprogram declarationProtokolü verir ama gövdeyi vermez. C/C++'ta buna prototype denir
formal parameterHeader'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
En sevilen ayrım: profile vs protocol parameter profile = sayı + sıra + tip. protocol = profile + dönüş tipi.
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ığı

PositionalKeyword
KuralBağlama konuma göre: ilk actual → ilk formalActual parametreyle birlikte formal parametrenin adı belirtilir
AvantajSafe and effective (slaytın kendi ifadesi)Parametreler herhangi bir sırada yazılabilir → karşılık hataları önlenir
DezavantajListe uzunsa programcı hata yaparKullanı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.

DilDeğişken sayıda parametre nasıl
C#Aynı tipte olmak kaydıyla; formal parametre params öneki alan bir array'dir
RubyActual'lar bir hash literal'in elemanları olarak gönderilir; formal parametre yıldız ile öncelenir
PythonBir yıldız → tuple; iki yıldız → hash/dict
def 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

İki kategori — kesin ayrım
ProcedureFunction
Parametreli hesaplamaları tanımlayan deyimler topluluğuYapısal olarak procedure'a benzer ama semantik olarak matematiksel fonksiyonlara göre modellenmiştir
Side effect üretmemesi beklenirama pratikte program fonksiyonlarının side effect'i vardır
Bu son cümle ("in practice, program functions have side effects") tam bir sınav cümlesidir: beklenti ile gerçeklik arasındaki farkı vurgular.

Subprogram tasarım soruları (11 madde)

Hoca "subprogram'lar karmaşık yapılardır, bu yüzden çok soru var" dedi. Liste:

  1. Local değişkenler static mi dynamic mi?
  2. Subprogram tanımları başka subprogram tanımlarının içinde görünebilir mi? (nesting)
  3. Hangi parameter passing yöntemleri sunuluyor?
  4. Parametre tipleri denetleniyor mu?
  5. Subprogram'lar parametre olarak geçirilebiliyor ve nesting varsa, geçirilen subprogram'ın referencing environment'ı nedir?
  6. Functional side effect'lere izin var mı?
  7. Fonksiyonlardan hangi tipte değerler dönebilir?
  8. Fonksiyonlardan kaç değer dönebilir?
  9. Subprogram'lar overload edilebilir mi?
  10. Subprogram'lar generic olabilir mi?
  11. Nesting varsa closure destekleniyor mu?

Local referencing environments

Stack-dynamic vs Static local — klasik avantaj/dezavantaj sorusu
Stack-dynamic localsStatic locals
AvantajlarRecursion 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
Hocanın vurgusu: static local'lerin "greatest disadvantage"ı recursion'ı destekleyememeleridir. Bu, Lecture #8'de "stack-dynamic local'lerin en önemli avantajı recursion desteğidir" diye tekrar edilir — iki kez vurgulanan şey sorulur.

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.

Slayttaki örnek
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 — her şeyin temeli
ModVeri akışı
In modeSubprogram, actual parametreden veri alır
Out modeSubprogram, actual parametreye veri iletir
Inout modeHer ikisi
İki kavramsal aktarım modeli: (1) değeri fiziksel olarak taşı; (2) değere bir erişim yolu (access path) taşı.

Beş parameter passing yöntemi — bu bölümün kalbi

YöntemModNasıl çalışırAvantajDezavantaj
Pass-by-valueinActual'ın değeri formal'i initialize eder; normalde kopyalayarakSkalerler 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-resultoutSubprogram'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ırEk depolama + kopyalama işlemi
Actual parameter collision (aşağıda)
Pass-by-value-resultinoutİkisinin birleşimi. Diğer adı: pass-by-copy. Formal'lerin local depolaması vardırHem pass-by-result'ın hem pass-by-value'nun dezavantajları
Pass-by-referenceinoutBir 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-nameinoutMetinsel 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 olurGeç bağlamada (late binding) esneklikGerçeklemesi karmaşık ve verimsiz; readability ve reliability'yi düşürür. Caller'ın referencing environment'ının geçirilmesini gerektirir
Parameter collision — slayttaki iki örnek Pass-by-result'ta: 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.
Pass-by-reference'ın alias problemi Slayttaki üç tehlikeli çağ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.

Slayttaki dört-yöntem-tek-şema örneği 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

DilYöntem
CPass-by-value; pass-by-reference pointer/reference parametrelerle elde edilir
C++Pass-by-reference için özel bir pointer türü: reference type
JavaTü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
PHPC#'a çok benzer, farkı: actual veya formal'den yalnızca biri ref belirtebilir
SwiftVarsayılan by value; by reference için formal inout ile öncelenir
PerlTüm actual parametreler @_ adlı önceden tanımlı bir array'e örtük olarak konur
Python, RubyPass-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ı.

PolitikaDiller
Hiç yokFORTRAN 77, orijinal C
Her zaman zorunluPascal, Java
Seçim kullanıcıya ait (prototype üzerinden)ANSI C, C++
GerektirmezPerl, JavaScript, PHP
Mümkün değilPython, Ruby — değişkenlerin tipi yoktur, nesnelerin vardır

Çok boyutlu array'lerin parametre olarak geçirilmesi

Hocanın "what we need to know" dediği kural Çok boyutlu bir array ayrı derlenen bir subprogram'a geçirilirse, derleyicinin storage mapping function'ı kurabilmek için array'in bildirilmiş boyutunu bilmesi gerekir.
Row major order için: address(mat[i,j]) = address(mat[0,0]) + i × number_of_columns + j
Bize 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.
DilYaklaşım
C/C++İlk subscript hariç tüm boyutların bildirilmesi zorunlu
FortranBoyutlar 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

Slaytın kendi başlığı: "the above considerations are in conflict" İki önemli değerlendirme: (1) Efficiency · (2) Tek yönlü mü çift yönlü mü veri aktarımı
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önmeyeceksein-mode kullan.
  • Çağrılan subprogram'a veri aktarılmayacaksaout-mode kullan.
Bu tam bir "hangisini ne zaman kullanmalı" açık uçlu sorusudur.

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 — kesin sınav sorusu
BindingHangi ortam kullanılırHangi dil için doğal
Shallow bindingGeçirilen subprogram'ı çalıştıran çağrı deyiminin ortamıDynamic-scoped diller
Deep bindingGeçirilen subprogram'ın tanımının ortamıStatic-scoped diller
Ad hoc bindingSubprogram'ı geçiren çağrı deyiminin ortamı
Slayttaki JavaScript örneği: sub1 içinde x, sub3 içinde x=3, sub4 içinde x=4; sub3sub4(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);int alıp int dö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ı.

DilDönebilen tipler
Çoğu imperative dilDönüş tiplerini kısıtlar
CArray 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, RubyMetotlar 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.

Polymorphism'in üç türü — çok olası soru
TürNasıl sağlanır
Ad hoc polymorphismOverloaded subprogram'lar
Subtype polymorphismT tipindeki bir değişken, T'den türetilmiş herhangi bir nesneye erişebilir (OOP dilleri)
Parametric polymorphismGeneric parametre alan subprogram. Slaytın notu: dynamic binding'in ucuz bir compile-time ikamesi
Generic / polymorphic subprogram tanımı: farklı çağrılarda farklı tiplerde parametreler alan subprogram.
DilGeneric 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.0C++'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# 2005Java 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

Tanım + ne zaman gerekir — kavramsal soru adayı Tanım: Bir closure, bir subprogram ve onun tanımlandığı referencing environment'tır.

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.
JavaScript closure — slayttaki örnek
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 fonksiyondurx'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

Coroutine — bölümün en ayırt edici kavramı Tanım: Birden çok girişi olan ve bu girişleri kendisi yöneten subprogram. Doğrudan Lua'da desteklenir.

  • 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).
Son madde neredeyse birebir sorulur — "interleaved but not overlapped" ifadesini aklında tut.
Bölümün özeti (slaytın Summary'si)
  • 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.
<linkage> ::= <call-semantics> <activation-record> <return-semantics>

8 · Implementing Subprograms

Ch.10 · 3 Ağustos dersi (elektrik kesintisi nedeniyle asenkron kayıt) · Slayt: Lecture #8

Bu ders neden farklı 3 Ağustos oturumu canlı değil: hoca elektrik/internet kesintisi yüzünden dersi offline kaydetmiş. Süresi diğerlerinin yarısı (112 dk) ama konu yoğunluğu yüksek ve çok görsel — slaytlardaki stack diyagramları transkriptte "burada görüyorsunuz" diye geçiliyor. Bu yüzden bu bölümde slayt şemalarını mutlaka aç ve bak; aşağıda şemaların anlattığını yazıya döktüm. "we had problems with our internet connection with electricity due to the blackout, now we are recording it offline"

Subprogram linkage — genel semantik

Tanım: Bir dilin subprogram çağrı ve dönüş işlemlerine birlikte subprogram linkage denir.

Çağrının genel semantiği — beş madde
  1. Parameter passing yöntemleri
  2. Local değişkenlerin stack-dynamic ayrılması
  3. Çağıran programın execution status'unun saklanması
  4. Kontrolün aktarılması ve dönüşün ayarlanması
  5. Subprogram nesting destekleniyorsa non-local değişkenlere erişimin ayarlanması
Dönüşün genel semantiği — dört madde:
  1. in mode ve inout mode parametrelerin değerleri geri döndürülmeli
  2. Stack-dynamic local'lerin deallocation
  3. Execution status'un geri yüklenmesi
  4. Kontrolün caller'a döndürülmesi
Not: slayt "in mode ve inout mode" diyor; mantık olarak geri taşınanlar out/inout'tur — sınavda slayttaki ifadeyi esas al.

"Simple" subprogram'ların gerçeklenmesi

Call semanticsReturn 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 — bu bölümün merkez kavramı Çalışan bir subprogram'ın iki ayrı parçası vardır: (1) asıl kod ve (2) kod-olmayan kısım (local değişkenler ve değişebilen veri).

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 kilit özellikleri — madde madde
  • 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şamaEylemler
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

İki tanım — ezber dynamic chain (= call chain): Belirli bir andaki stack'teki dynamic link'lerin topluluğu.

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_offset
Slayttaki örnek: fun1 içinde s'nin local_offset'i 3, t'ninki 4.
Recursion örneği — slayttaki factorial
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.

Non-local referansı bulmanın iki adımı
  1. Doğru activation record instance'ı bulzor olan kısım budur
  2. O ARI içindeki doğru offset'i belirle ← kolay olan kısım
Hocanın kendi cümlesi: "the most hard part is finding the correct activation record."
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

TerimTanım
static linkA subprogram'ının ARI'sındaki static link, A'nın static parent'ının ARI'larından birini gösterir
static chainBelirli ARI'ları birbirine bağlayan static link zinciri; bir ARI'yı tüm static ancestor'larına bağlar
static_depthBir static scope ile ilişkili tamsayı: o scope'un iç içe geçme derinliği
chain_offsetReferansı içeren subprogram'ın static_depth'i eksi bildirimi içeren subprogram'ın static_depth'i
İki adres bulma yöntemi — verimli vs verimsiz
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
Bu yüzden non-local referans (chain_offset, local_offset) çiftiyle temsil edilir — "kaç halka yukarı çık, sonra kaç birim içeri git".
Slayttaki JavaScript örneği — (chain_offset, local_offset) çiftleri main → bigsub → sub2 → sub3 → sub1 çağrı sırasında:
KonumDeğişken(chain_offset, local_offset)
sub1 içinde a = b + ca(0, 3) — kendi ARI'sında
b(1, 4) — bir halka yukarıda
c(1, 5)
sub3 içinde e = b + ae(0, 4)
b(1, 4)
a(2, 3) — iki halka yukarıda
Bu tabloyu okuyabilmek yeterli — sınavda benzer bir program verilip "bu referansın chain_offset'i kaçtır" diye sorulabilir.

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.

Static chain'in iki problemi — değerlendirme sorusu
  1. Nesting derinliği büyükse non-local referans yavaştır (zincirde çok halka gezilir).
  2. 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.

C örneği
{ 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öntemNasıl
1. Blokları parametresiz subprogram gibi ele alHer 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ırmaBir 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 vs Shallow access — bu bölümün ikinci kesin sorusu
Deep accessShallow access
MekanizmaNon-local referanslar, dynamic chain üzerindeki ARI'lar aranarak bulunurLocal'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
SorunlarZincirin uzunluğu statik olarak belirlenemez
Her ARI değişken adlarını taşımak zorundadır
Karıştırma uyarısı: static chain ↔ static scoping, deep/shallow accessdynamic scoping. Ayrıca Lecture #7'deki deep/shallow binding ile bu deep/shallow access farklı konulardır — hoca ikisini de aynı derste anmadı ama sınavda yan yana gelirse ayırt edebilmelisin:
binding → parametre olarak geçirilen subprogram'ın referencing environment'ı hangisi
access → dynamic scoping'de non-local değişkene nasıl ulaşılır
Bölümün özeti (slaytın Summary'si)
  • 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.
<ADT> ::= <gizlenmiş-temsil> <tek-sözdizimsel-birim>

9 · Abstract Data Types & Encapsulation

Ch.11 · 4 Ağustos dersi (Quiz 3 bu derste yapıldı) · Slayt: Lecture #9 · elindeki son kayıt

Neden bu bölüm önemli Lecture #7'de hoca "process abstraction ve data abstraction bugün eşit derecede önemli" demişti. İşte bu bölüm o cümlenin ikinci yarısı: data abstraction. Slaytın kendi Summary'si de ADT kavramını "dillerin gelişiminde bir kilometre taşı (milestone)" diye niteliyor — bu tür "önem" cümleleri açık uçlu soruların giriş cümlesidir.

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.
Hocanın kuş benzetmesi — dersin tamamına yayılan örnek Hoca abstraction'ı slayttaki tanımla bırakmadı, kendi örneğini kurdu ve bölüm boyunca ona döndü. Açık uçlu bir soruda "abstraction nedir" diye sorulursa bu örnekle cevaplamak tam isabet olur:
  • 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.
Devamı — information hiding'i anlatan hâli (bu kısım çok güçlü): Diyelim kuş sınıfına 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ı

Tanım + tarihsel çerçeve abstraction: Bir varlığın, yalnızca en anlamlı özniteliklerini içeren bir görünümü / temsili.

  • Abstraction kavramı programlamada (ve bilgisayar biliminde) temeldir.
  • Neredeyse tüm diller process abstractionsubprogram'larla destekler.
  • Neredeyse 1980'den beri tasarlanan tüm diller data abstraction'ı destekler.
Bu son iki madde "hangisi doğrudur" sorusunda birebir kullanılabilir — 1980 tarihini aklında tut.
Hocanın eklediği tarihsel zincir — slaytta yok, sorulabilir
DönemNe oldu
1940'larPlankalkül, process abstraction'ı destekleyen ilk dil — process abstraction dil tasarımındaki en eski soyutlamadır
1960'larData abstraction'ın evrimi başlar: COBOL'un ilk sürümleri, record veri yapısıyla
1980'lerData abstraction yaygınlaşır; 1980'den sonra tasarlanan neredeyse tüm diller destekler
Hocanın mantık zinciri (açık uçlu için değerli): Data abstraction'ın yaygınlaşması, process abstraction'ınkini zorunlu olarak izledi — çünkü her data abstraction'ın ayrılmaz ve zorunlu bir parçası onun işlemleridir, ve işlemler zaten process abstraction olarak tanımlanır. Yani önce "yapılacak şeyleri" soyutladık, sonraki mantıklı adım "üzerinde iş yaptığımız şeyleri" soyutlamaktı.
"Bütün yerleşik tipler zaten ADT'dir" — çok sevilebilecek bir soru Hoca üzerinde durdu: ADT kavramı yeni değildir — Fortran I'inkiler dahil tüm yerleşik (built-in) veri tipleri aslında abstract data type'tır, sadece öyle adlandırılmazlar.

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
Bunun pratik sonucu — taşınabilirlik (portability): Temsil gizli olduğu için, aynı dilin farklı gerçeklemeleri veriyi farklı biçimde temsil etse bile program taşınabilir. Hocanın tarihsel kanıtı: IEEE 754 (1980'lerin ortası) öncesinde her bilgisayar mimarisinin kendi floating point temsili vardı ve değerleri bir makineden diğerine taşımak büyük bir sorundu; standart bir veri soyutlaması gelince sorun ortadan kalktı.
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

Bu bölümün en kritik tanımı — birebir ezberle Bir abstract data type, aşağıdaki iki koşulu sağlayan kullanıcı tanımlı bir veri tipidir:
  1. 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.
  2. 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.
Sınav taktiği: "İki koşulu" sorusu geldiğinde birinciyi information hiding, ikinciyi packaging / encapsulation diye etiketle — puanı garantiler.

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):

  1. Tip tanımını kapsülleyecek bir sözdizimsel birim
  2. Tip adlarını ve subprogram header'larını istemcilere görünür kılan, ama asıl tanımları gizleyen bir yöntem
  3. 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 struct tipi + 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.
Information hiding — C++ üç clause
ClauseNe için
privateGizlenen varlıklar
publicArayüz varlıkları
protectedInheritance için (Ch.12)
Not: C++'ta bunlar clause'dur (bir bölüm başlatır); Java'da ise her varlığın kendi access modifier'ı vardır — bu, aşağıdaki Java karşılaştırmasının maddelerinden biridir.

Constructor ve Destructor

ConstructorDestructor
GörevÖrneklerin veri üyelerini başlatan fonksiyonlar — nesneyi yaratmazlarBir örnek yok edildikten sonra temizlik; genelde heap depolamasını geri kazanmak
Ek görevNesnenin 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ılabilirNesnenin lifetime'ı bittiğinde örtük; açıkça da çağrılabilir
AdSınıf adıyla aynıSınıf adı, önünde tilde (~)
Slaytın kırmızı notu — kesin çıkar "Java DOES NOT have Destructors. It has a Garbage Collector."
Slaytta ayrı bir kutuda vurgulanmış. Bu, "Java ile C++'ın ADT desteği arasındaki fark nedir" sorusunun en kolay puanlık maddesidir.
Slayttaki Stack sınıfı — C++
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

Java'nın C++'tan beş farkı — liste sorusu adayı
  1. Tüm kullanıcı tanımlı tipler sınıftır (C++'ta struct da olabilir).
  2. Tüm nesneler heap'ten ayrılır ve reference değişkenlerle erişilir.
  3. Sınıflardaki tek tek varlıkların access control modifier'ı vardır (clause değil).
  4. Tüm nesneler için örtük garbage collection (destructor yok).
  5. İkinci bir scoping mekanizması: package scopefriend'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: internal ve protected 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#'ın property'si — accessor sorununa çözüm Veri üyelerine erişim ihtiyacına ortak çözüm: accessor metotlar (getter / setter).
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

ÖzellikRuby'de
Kapsülleme aracıclass
Local değişkenler"Normal" adlar
Instance değişkenleriTek @ ile başlar
Class değişkenleriÇift @@ ile başlar
Instance metotlarıRuby fonksiyon sözdizimi (def … end)
Constructorinitialize 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şimprivate veya public; varsayılan public
SınıflarDinamiktir (çalışma zamanında değişebilir)

Parameterized ADTs (generic classes)

Tanım + kritik kısıt Parameterized ADT: herhangi tipte eleman saklayabilen bir ADT tasarlamayı sağlar.
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.
DilNası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.0Generic 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# 2005Java 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

Neden gerekir — iki ihtiyaç Büyük programların iki özel ihtiyacı vardır:
  1. Subprogram'lara bölmenin ötesinde bir organizasyon yolu
  2. Bir kısmi derleme yolu — programın tamamından küçük derleme birimleri
Açık çözüm: mantıksal olarak ilişkili subprogram'ları, ayrı derlenebilen bir birimde gruplamak. Bu topluluklara encapsulation denir ve genellikle kütüphanelere yerleştirilirler.
YöntemAçıklama
Nested subprogramsSubprogram 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 encapsulationBir 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 encapsulationC 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# assembliesUygulama 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.
C# erişim belirteçleri tablosu — slaytta aynen var, sorulabilir
SpecifierSame assemblyOther assembly
Declared classOther classDerived classOther classDerived class
privateYesNoNoNoNo
publicYesYesYesYesYes
protectedYesNoYesNoYes
internalYesYesYesNoNo
protected internalYesYesYesNoYes
private protected (7.2)YesNoYesNoNo
Okuma anahtarı: 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.

MekanizmaDilNasıl
NamespaceC++, C#Her kütüphane kendi namespace'ine konabilir; dışarıda kullanılan isimler namespace ile nitelenir
PackageJavaBirden ç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
ModuleRubyRuby 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
Java erişim belirteçleri — C++'tan farklı olduğu slaytta not düşülmüş
SpecifierSame PackageDifferent Package
Same ClassOther ClassDerived classOther classDerived class
no modifierYesYesYesNoNo
privateYesNoNoNoNo
protectedYesYesYesNoYes
publicYesYesYesYesYes
En sık sorulan satır: Java'da 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ş.
Bölümün özeti (slaytın Summary'si) — açık uçlu cevabın iskeleti
  • 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.
<OOP> ::= <ADT> <inheritance> <dynamic-binding>

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

Bu bölümü nasıl okumalısın Hoca daha ilk cümlede çerçeveyi çizdi: bu bir OOP dersi değil"you already know what object-oriented programming is… what we will discuss here is how the support for the object-oriented programming paradigm is realized in different programming languages." Yani sınavda "inheritance nedir" değil, "hangi dil bu konuda ne yapmış, neden, avantajı/dezavantajı ne" sorulur.

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

Slaytın Summary'sinin ilk maddesi — birebir ezberle Bir dilin object-oriented sayılabilmesi için üç dil özelliğini desteklemesi gerekir:
  1. Abstract data types (= encapsulation) — Lecture #9'un konusu
  2. Inheritance — "inheritance is the central theme in OOP and languages that support it"
  3. Polymorphism (= dynamic binding)
Sınav taktiği: Summary bu üçlüyü "ADTs (Encapsulation), inheritance, dynamic binding (Polymorphism)" diye parantezli veriyor — cevabında her iki adı da yaz, iki terimi eşleştirdiğini göstermiş olursun.
Tarihsel çerçeve — hocanın açtığı, slaytta olmayan kısım
  • 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.
Bugünkü tablo (slaytın Introduction'ı): OOP paradigması her yerde — C++ prosedürel + veri odaklı programlamayı da destekler (hibrit); CLOS fonksiyonel programlamayı destekler; Java ve C# başka paradigma desteklemez ama imperatif yapılarını kullanır; Smalltalk ve Ruby saf OOP dilleridir. Bazı fonksiyonel diller de OOP destekler ama bu bölümde ele alınmaz.

⭐ Inheritance — neden icat edildi?

Hocanın en çok zaman ayırdığı mantık zinciri — açık uçlu adayı Başlangıç (1980'lerin ortası–sonu): Yazılımcılar verimliliği artırmanın en umut verici yolunun software reuse olduğunu gördü. İlk aday: ADT'ler (encapsulation + access control ile).

Ama ADT'lerle yeniden kullanımın iki problemi var:
ProblemNeden 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.
Çözüm = inheritance. Yeni sınıfların var olanlar cinsinden tanımlanmasını sağlar (ortak parçaları miras alarak) ve böylece her iki problemi birden çözer: ADT'ler küçük değişikliklerle yeniden kullanılır ve sınıflar bir hiyerarşi içinde tanımlanabilir.

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.
Terminoloji — MC sorusunun ana kaynağı
KavramOOP'deki adı
ADTclass
Class'ın örneğiobject
Miras alan sınıfderived class (C-tabanlı) / subclass (Java)
Miras alınan sınıfparent class / superclass
Nesneler üzerindeki işlemleri tanımlayan subprogrammethod
Metot çağrısımessage
Bir nesnenin tüm metotlarının topluluğumessage protocol / message interface
Bir message'ın iki parçası vardır: metot adı ve hedef nesne. En basit durumda bir sınıf, ebeveyninin tüm varlıklarını miras alır.
⭐ Message vs subprogram call — hocanın altını çizdiği fark Subprogram: kendisine parametre olarak geçirilen ya da non-local/global erişilen veriyi işler. Yani veri dışarıdan gelir.
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

Slaytta numaralı — liste sorusu adayı
  1. Subclass, miras aldıklarına değişken ve/veya metot ekleyebilir.
  2. 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.
  3. Parent class, bazı değişken veya metotlarını private tanımlayabilir — bunlar subclass'ta görünmez.
Hocanın örneği (cevaba yazılabilir): Ebeveynin "konuşabilir" özelliğini miras alırsın; ekleme = "İngilizce konuşabilme" metodunu eklemek; override = "konuşma" metodunu kendine göre özelleştirmek. Overriding metodun amacı: subclass'ta, parent'takine benzer ama subclass nesnelerine özelleştirilmiş bir işlem sağlamak.
İki tür değişken, iki tür metot — kesin MC adayı
Kaç taneNe yapar
Class variablesınıf başına bir (one/class)Sınıfa aittir, nesnelere değil; tek kopya
Instance variablenesne 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 methodSınıfa gönderilen mesajları kabul eder. Sınıfın hiç örneği olmasa bile çağrılabilir
Instance methodNesnelere gönderilen mesajları kabul eder; yalnızca sınıfın nesneleri üzerinde çalışır
Hocanın örneği: araba sınıfının instance değişkenleri renk, model, yıl — örneklerde farklı değerler alırlar.
⭐ Inheritance'ın dezavantajı — "her şey güllük gülistanlık mı?" Hoca bu soruyu bilerek sordu ve cevabı slaytın son maddesi: Inheritance, sınıflar arasında karşılıklı bağımlılık (interdependency) yaratır ve bu bakımı zorlaştırı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.)
Erişim denetimi ve inheritance — üç görünürlük düzeyi Inheritance, access control'ü karmaşıklaştırır. Slaytın üç maddesi:
  • 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çiSubclassİstemci
private
protected
public
Bağlantı: Lecture #9'da hoca 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)

Tanımlar — birebir ezber bölgesi Polymorphic variable: Bir sınıfta tanımlanan, o sınıfın nesnelerine ve onun tüm torunlarının (descendants) nesnelerine referans verebilen (gösterebilen) değişken.

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:
TerimTanım
abstract methodTanım (definition/gövde) içermeyen metot — yalnızca bir protokol tanımlar
abstract classEn az bir virtual (abstract) metot içeren sınıf
Kritik kuralBir abstract class örneklenemez (cannot be instantiated)
Hocanın eklediği güçlü cümle: Dynamic binding sayesinde bir metodu kullanan kod, o metodun herhangi bir sürümü yazılmadan önce yazılabilir; yıllar sonra yeni türetilmiş sınıflar eklenebilir ve bu kodda hiçbir değişiklik gerekmez. Bu, tüm OOP'nin en yararlı özelliğidir.

⭐⭐ 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ı.

Slaytın listesi — sırasıyla ezberle
  1. The exclusivity of objects — her şey nesne mi?
  2. Are subclasses subtypes? — "is-a" ilişkisi geçerli mi?
  3. Single and multiple inheritance
  4. Object allocation and deallocation
  5. Dynamic and static binding
  6. Nested classes
  7. Initialization of objects

1 · Exclusivity of objects — üç yaklaşım

YaklaşımAvantajDezavantaj
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
Hocanın somut örneği ve dürüst itirafı Java örneği: 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

Tanım zinciri — üç adımda a) Principle of substitution: Bir dilde, bir sınıfın değişkeni atalarından birinin değişkeninin yerine herhangi bir durumda, tip hatası oluşturmadan ve programın davranışını değiştirmeden konabiliyorsa, o dil substitution ilkesini destekler.

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.)

Slaytın altın cümlesi — ezberle "Subclasses inherit implementation; subtypes inherit interface and behavior."
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

Hocanın açıkça sorduğu soru: "Neden Java'da multiple inheritance yok?" Amaç: Multiple inheritance, yeni bir sınıfın iki veya daha fazla sınıftan miras almasına izin verir.

İki dezavantajı (slaytta böyle, ezberle):
  1. Dil ve gerçekleme karmaşıklığı — kısmen isim çakışmaları (name collisions) yüzünden
  2. Potansiyel verimsizlik — multiple inheritance ile dynamic binding daha pahalıya gelir (slaytın kendi notu: "but not much" — çok değil)
Avantajı: "Sometimes it is quite convenient and valuable."

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'ı

Slaytın maddeleri + hocanın "object slicing" açıklaması Nesneler nereden ayrılır?
  • ADT gibi davranıyorlarsa her yerden ayrılabilirler: run-time stack'ten ya da new ile 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.
Object slicing nedir: Bir subclass nesnesi, parent tipinde stack'te ayrılmış bir yere kopyalandığında, subclass'a özgü fazlalık veri kesilir/budanır (truncation) — nesnenin bir kısmı kaybolur. Bu yüzden stack-dynamic nesneler, subtype'larla birlikte kullanıldığında veri alanına doğru erişim sorunları doğurur.

İ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 sorusuGerilimYaygın çözüm
BindingHiç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 classesBir 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?
InitializationNesneler 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

Genel özellikler — hepsi "saf"lığın sonucu
  • Her şey bir nesnedir5 bile 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
KonuSmalltalk'ta
InheritanceSubclass, 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 bindingMesajları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şkenlerTipsizdir; herhangi bir ad herhangi bir nesneye bağlanabilirdynamic polymorphism. Tüm Smalltalk kodu bu anlamda generic'tir
Evaluation of Smalltalk — slaytta madde madde, açık uçlu adayı
  • 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)
Hocanın eklediği: Tasarımcıları pratik kaygıları ve yürütme verimliliğini değil, dil zarafetini ve OOP ilkelerine sıkı bağlılığı seçtiler. Bu yüzden endüstride çok başarılı olmadı — ama Java, C# gibi dillerin varlığını ona borçluyuz.

Dil örneği: C++ — hibrit

Genel özellikler
  • 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
Terminoloji: C++ "parent class" demez, base class der. Sınıfta tanımlı veriye data member, fonksiyonlara member function denir.
⭐ İki katmanlı erişim denetimi — C++'ın en ayırt edici özelliği Katman 1 — üyelerin erişim denetimi:
BelirteçAnlamı
privateYalnızca sınıfta ve friend'lerde görünür — subclass'ların subtype olmasını engeller
publicSubclass'larda ve istemcilerde görünür
protectedSınıfta ve subclass'larda görünür, istemcilerde görünmez
Katman 2 — subclassing sürecinin kendisi de private/public işaretlenebilir:
DerivationEtkisi
Private derivationMiras alınan public ve protected üyeler subclass'ta private olur
Public derivationPublic ve protected üyeler subclass'ta da public ve protected kalır
Slayttaki örnek — sınavda birebir çıkabilir:
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
Reexportation — scope resolution operatörü (::) Private derivation yüzünden subclass'ta erişilemeyen bir üye, :: 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.
⭐ Multiple inheritance ve diamond problemi C++ multiple inheritance'ı destekler. Aynı adlı iki miras üye varsa ikisi de scope resolution operatörü (::) 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.
⭐⭐ C++'ta dynamic binding — 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 virtual tanı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 mi heap'ten mi — sonucu değiştiren fark Aynı kod, nesnelerin nereden ayrıldığına göre farklı metot çağırır. Bu tam bir sınav sorusu kalıbıdır:
// 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).
Nested classes ve Evaluation of C++ Nested class kuralı: C++'ta nested class'ların, nesting class'ın üyelerine özel bir erişimi yoktur. (Java'nın inner class'larının tersi — aşağıya bak.)

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ırstatic 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.

Genel özellikler
  • Primitive tipler hariç tüm veri nesnedir
  • Tüm primitive tiplerin bir veri değeri saklayan wrapper sınıfları vardır (intInteger). 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 new ile ayrılır
  • Tüm sınıflar Object kök sınıfının torunudur — bu sayede toString, equals gibi ortak metotlar bir kez tanımlanıp herkese miras kalır
  • Depolama geri kazanımı için garbage collection; finalize metodu, çöp toplayıcı bir nesnenin belleğini geri almak üzereyken örtük olarak çağrılır
⭐ Inheritance ve dynamic binding — Java vs C++ (en olası MC)
C++Java
Varsayılan bindingStatic — dynamic istiyorsan virtual yaz Dynamictüm mesajlar dinamik bağlanır
İstisnalarfinal (override edilemez → dynamic binding anlamsız), static ve private (ikisi de override'ı engeller) → static bağlanır
Multiple inheritanceVarYok — yerine interface
Parentless sınıfOlabilirOlamaz
Subclass = subtype?private üye/private derivation varsa hayırTü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.
Interface — multiple inheritance'ın Java'daki karşılığı Bir interface yalnızca metot bildirimleri ve isimlendirilmiş sabitler içerebilir.
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 vs Abstract class — slaytta İKİ sayfalık tablo, karşılaştırma sorusu adayı
INTERFACEABSTRACT CLASS
Kod içerebilir miHiç 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ç taneBir sınıf birden çok interface implemente edebilir Bir sınıf yalnızca bir abstract class'ı extend edebilir
Yeni metot eklemekEvrendeki 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
EsneklikMevcut 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
Java'da nested classes — C++'tan en keskin fark
  • 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
Slayttaki iki örnek — farkı bu ikisi anlatıyor:
// 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."
Evaluation of Java
  • 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#

C++ ile Java'nın birleşimi
  • 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 new ile 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
⭐ C#'ın dynamic binding'i — iki taraf da işaretlenmeli Java'dan ve C++'tan farkı: hem base metot hem türetilmiş metot özel olarak işaretlenmelidir.
  • Base sınıftaki metot → virtual
  • Türetilmiş sınıflardaki karşılıkları → override
  • Abstract metotlar abstract ile 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ı

Genel özellikler — Smalltalk gibi saf, ama esneklikte daha ileri
  • 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 new ile 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)
KonuRuby'de
InheritanceMiras 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 bindingTüm değişkenler tipsiz ve polymorphic'tir → tüm bağlamalar dinamiktir
EvaluationAbstract 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

İki ilginç ve zorlu parça Slaytın çerçevesi: OO yapıları gerçeklerken iki ilginç ve zorlayıcı kısım vardır:
  1. Instance değişkenleri için depolama yapıları — hocanın deyimiyle görece kolay olan
  2. Mesajların metotlara dinamik bağlanmasıasıl zorluk burada

Instance data storage — Class Instance Record (CIR)

ÖzellikAçıklama
Ne saklarClass instance record (CIR), bir nesnenin state'ini saklar
Ne zaman kurulurStaticderleme zamanında kurulur
InheritanceSınıfın bir parent'ı varsa, subclass'ın instance değişkenleri parent'ın CIR'ına eklenir
Erişim maliyetiCIR 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

Slaytın maddeleri — sınavda "nasıl gerçeklenir" sorusunun cevabı
  • 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_offset mantığı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.
Slayttaki Java örneği:
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'ı draw ve area kodlarını gösterir.
  • B'nin CIR'ı: A'nınkine c ve d eklenir. B'nin vtable'ında üç girdi olur: drawB'nin kendi draw'ı (override edildi); areaA'nın area'sı (override edilmedi, A'ya işaret eder); sift → B'nin sift'i.
Sınav cümlesi: "Override edilen metot için kendi koduna, edilmeyen için parent'ın koduna pointer tutulur."
Bölümün özeti (slaytın Summary'si) — açık uçlu cevabın iskeleti
  • 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).
Beş dil tek tabloda — son tekrar kartı
SmalltalkC++JavaC#Ruby
SaflıkSaf OOPHibritYalnızca OOPYalnızca OOPSaf OOP
Her şey nesne miEvetHayır (karma tip sistemi)Hayır (primitive'ler)Hayır (primitive + struct)Evet
Multiple inheritanceYokVarYok (interface)YokTam desteklemez
Binding varsayılanıTamamen dynamicStatic (virtual ile dynamic)Dynamic (final/static/private hariç)Static (virtual+override)Tamamen dynamic
Subclass = subtype?Her zamanHayır (private ile bozulur)Her zamanParent'ta private yoksaZorunlu değil
AllocationHep heap, implicit deallocStack / heap / staticHep heap + GCHeap + GC (struct stack)Heap
Nested classYokVar, özel erişim yokVar, inner erişebilirVar, yalnızca static gibiVar, özel erişim yok
Abstract class=0 pure virtualabstract + interfaceabstractDesteklemez
<final-deneme> ::= 20 * <çoktan-seçmeli> 6 * <açık-uçlu>

Final Deneme Sınavı

Hocanın teyit ettiği formatta (10–15 çoktan seçmeli + 3–5 açık uçlu), final kapsamından (Ch.6–12) — gerçek sınavdan geniş tutuldu ki daha çok konu taransın. Önce kendin çöz, sonra cevabı aç. Her cevabın altında kaynağı yazıyor.

Bölüm A — Çoktan seçmeli

Soru 1 · Lecture 5

C ve C++'ta static niteleyicisi olmadan bildirilen bir array hangi kategoridedir?

  1. Static
  2. Fixed stack-dynamic
  3. Fixed heap-dynamic
  4. Heap-dynamic
Cevabı göster
b) Subscript aralıkları statik bağlıdır ama depolama bildirim anında stack'ten ayrılır. Avantajı space efficiency. static eklenirse (a) olur; malloc/new ile (c) olur. Kaynak: L5 — array'in dört kategorisi tablosu.
Soru 2 · Lecture 5

Aşağıdakilerden hangisi lost heap-dynamic variable (garbage) durumunu tanımlar?

  1. Bir pointer, deallocate edilmiş bir heap değişkenini gösteriyor
  2. Ayrılmış bir heap değişkenine artık kullanıcı programından erişilemiyor
  3. İki pointer aynı heap hücresini gösteriyor
  4. Bir pointer nil değerine sahip
Cevabı göster
b) (a) şıkkı dangling pointer'ın tanımıdır. Slaytın formülü: nesne binding'den uzun yaşarsa → garbage; binding nesneden uzun yaşarsa → dangling reference. Garbage'ın oluşma sürecine memory leakage denir. Kaynak: L5 — Problems with Pointers.
Soru 3 · Lecture 5

Aşağıdaki dillerden hangisi union tipini hiç desteklemez?

  1. C
  2. Ada
  3. Java
  4. F#
Cevabı göster
c) Java ve C# union'ı hiç desteklemez — slaytın gerekçesi: "programlama dillerinde artan güvenlik kaygılarının yansıması." C free union, Ada/ML/Haskell/F# ise discriminated (güvenli) union sunar. Kaynak: L5 — Evaluation of Unions.
Soru 4 · Lecture 5

Mark-sweep çöp toplama yönteminin, reference counting'e göre en belirgin dezavantajı nedir?

  1. Dairesel bağlı hücreleri toplayamaz
  2. Her hücrede bir sayaç tutulması gerekir
  3. Çalıştığında uygulamanın yürütmesinde ciddi gecikmelere neden olur
  4. Yalnızca sabit boyutlu hücrelerde kullanılabilir
Cevabı göster
c) Mark-sweep lazy'dir: boş alan listesi bitene kadar bekler, sonra topluca çalışır → gecikme. (a) ve (b) reference counting'in dezavantajlarıdır. Modern çözüm: incremental mark-sweep. Kaynak: L5 — Heap Management.
Soru 5 · Lecture 5

C ve C++ neden strongly typed sayılmaz?

  1. Explicit type casting'e izin verdikleri için
  2. Parametre tip denetimi atlanabildiği ve union'lar type checked olmadığı için
  3. Coercion'a hiç izin vermedikleri için
  4. Değişkenlerin değil, nesnelerin tipi olduğu için
Cevabı göster
b) Slaytın iki gerekçesi tam olarak budur. (a) Java ve C#'ın "neredeyse strongly typed" olmasının gerekçesidir. (d) Python/Ruby içindir. Kaynak: L5 — Strong Typing.
Soru 6 · Lecture 6

Aşağıdaki C kodunda a'nın Java'daki çıktısı ne olur?

int a = 5;
int fun1() { a = 17; return 3; }
…
a = a + fun1();
  1. 8
  2. 17
  3. 20
  4. Tanımsız
Cevabı göster
a) 8. Java, operand'ların soldan sağa değerlendirilmiş görünmesini zorunlu kılar → soldaki a önce okunur (5), sonra fun1() 3 döndürür → 5+3=8. C/C++'ta sonuç tanımsızdır (derleyiciye bağlı; 8 ya da 20). Kaynak: L6 — hocanın sınıfa bıraktığı soru.
Soru 7 · Lecture 6

Bir programın referential transparency özelliğine sahip olması ne demektir?

  1. Tüm değişkenlerin tipi derleme zamanında bellidir
  2. Aynı değere sahip iki ifade, programın davranışını değiştirmeden birbirinin yerine konabilir
  3. Tüm fonksiyonlar aynı parametre profiline sahiptir
  4. Operand değerlendirme sırası soldan sağa sabitlenmiştir
Cevabı göster
b) Tanım birebir budur. Saf fonksiyonel diller her zaman referentially transparent'tır — çünkü 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. Kaynak: L6 — Referential Transparency.
Soru 8 · Lecture 6

C, C++ ve Java'da && ile & arasındaki fark nedir?

  1. && bitwise, & mantıksaldır
  2. && short-circuit değerlendirilir, & (bitwise) değerlendirilmez
  3. İkisi de short-circuit'tir, yalnızca öncelikleri farklıdır
  4. & yalnızca Java'da vardır
Cevabı göster
b) Bu diller olağan Boolean operatörlerini short-circuit yapar, ayrıca short-circuit olmayan bitwise Boolean operatörleri de sunar. Ruby, Perl, ML, F# ve Python'da tüm mantık operatörleri short-circuit'tir. Kaynak: L6 — Short Circuit Evaluation.
Soru 9 · Lecture 6

C#'ın switch deyimini C ve Java'nınkinden ayıran temel özellik nedir?

  1. Kontrol ifadesi yalnızca integer olabilir
  2. default clause zorunludur
  3. Birden fazla segmentin örtük çalışmasını yasaklar; her segment koşulsuz dallanmayla bitmelidir
  4. Case sabitleri yalnızca sabit ifadeler olabilir
Cevabı göster
c) C#'ın static semantics kuralı fall-through'u yasaklar; her segment break ya da goto ile bitmek zorundadır. Ayrıca C#'ta kontrol ifadesi ve case sabitleri string olabilir. Kaynak: L6 — Multiple-Way Selection.
Soru 10 · Lecture 7

Bir subprogram'ın protocol'ü neyi içerir?

  1. Yalnızca parametrelerin sayısı ve sırası
  2. Parametrelerin sayısı, sırası ve tipleri
  3. Parameter profile ve — fonksiyonsa — dönüş tipi
  4. Subprogram'ın gövdesi ve local değişkenleri
Cevabı göster
c) (b) parameter profile'ın (signature'ın) tanımıdır; protocol onu kapsar ve dönüş tipini de ekler. Overloaded subprogram'ların her versiyonu benzersiz bir protokole sahiptir. Kaynak: L7 — Basic Definitions.
Soru 11 · Lecture 7

Pass-by-reference'ın en belirgin avantajı nedir?

  1. İstenmeyen alias'ları engeller
  2. Formal parametrelere erişim en hızlıdır
  3. Kopyalama ve depolama tekrarı olmadığı için aktarım verimlidir
  4. Yalnızca tek yönlü veri aktarımına izin verir
Cevabı göster
c) Yalnızca bir access path (adres) geçirilir. (a) ve (b) tam tersidir: pass-by-reference alias yaratır ve indirect addressing yüzünden erişim pass-by-value'dan yavaştır. (d) in-mode'un özelliğidir. Kaynak: L7 — Pass-by-Reference.
Soru 12 · Lecture 7

Bir closure nedir?

  1. Birden çok girişi olan ve bunları kendisi yöneten subprogram
  2. Bir subprogram ve onun tanımlandığı referencing environment
  3. Farklı çağrılarda farklı tipte parametre alan subprogram
  4. Aynı referencing environment'ta aynı ada sahip subprogram
Cevabı göster
b) (a) coroutine, (c) generic/polymorphic subprogram, (d) overloaded subprogram tanımlarıdır. Kritik ek bilgi: nested subprogram'a izin vermeyen static-scoped bir dilin closure'a ihtiyacı yoktur. Kaynak: L7 — Closures.
Soru 13 · Lecture 8

Bir activation record hakkında aşağıdakilerden hangisi doğrudur?

  1. Biçimi dinamik, boyutu statiktir
  2. Biçimi statik, boyutu dinamik olabilir
  3. Hem biçimi hem boyutu her zaman statiktir
  4. Yalnızca recursive subprogram'lar için yaratılır
Cevabı göster
b) Slaytın birebir ifadesi: "The activation record format is static, but its size may be dynamic." (d) de yanlıştır: her subprogram etkinleşmesi — recursive olsun olmasın — yeni bir ARI yaratır. Kaynak: L8 — Activation Record.
Soru 14 · Lecture 8

Static chain yönteminin belirtilen problemlerinden biri nedir?

  1. Her activation record instance'ın değişken adlarını taşıması gerekir
  2. Zincirin uzunluğu statik olarak belirlenemez
  3. Kod değişiklikleri nesting derinliğini, dolayısıyla erişim maliyetini değiştirebilir
  4. Yalnızca dynamic-scoped dillerde kullanılabilir
Cevabı göster
c) İki problem: (1) nesting derinliği büyükse non-local referans yavaştır; (2) zaman-kritik kod zordur — maliyeti belirlemek zor ve kod değişikliği maliyeti değiştirir. Dikkat: (a) ve (b) deep access'in (dynamic scoping) problemleridir; (d) tam tersidir — static chain static scoping içindir. Kaynak: L8 — Evaluation of Static Chains.
Soru 15 · Lecture 9

Bir abstract data type'ın iki koşulundan birincisi (temsilin gizlenmesi) hangi avantajı doğrudan sağlar?

  1. Ayrı derleme (separate compilation)
  2. Reliability — temsil, kullanıcı kodunu etkilemeden değiştirilebilir
  3. Bir program organizasyonu yöntemi
  4. Parameterized ADT desteği
Cevabı göster
b) Birinci koşul (information hiding) → reliability + farkında olunması gereken kod/değişken aralığının azalması + isim çakışmasının azalması. (a) ve (c) ikinci koşulun (tek sözdizimsel birim) avantajlarıdır. Kaynak: L9 — Advantages of Data Abstraction.
Soru 16 · Lecture 10

Bir sınıfın subtype olması ne demektir?

  1. Ebeveyninden en az bir metodu override etmesi
  2. Ebeveyniyle is-a ilişkisi taşıması; nesnelerinin ebeveyn nesnesinin yerinde aynı davranışı göstermesi
  3. Ebeveyninin tüm private üyelerine erişebilmesi
  4. Birden çok sınıftan miras alabilmesi
Cevabı göster
b) Substitution ilkesinin tanımı. Subclass yalnızca ekleme yapabilir ve miras metotları uyumlu biçimde override edebilir; parent'ta public olan bir varlık subclass'ta public kalmalıdır. Slaytın ezber cümlesi: "Subclasses inherit implementation; subtypes inherit interface and behavior." Kaynak: L10 — Are Subclasses Subtypes?
Soru 17 · Lecture 10

C++ ve Java'nın dynamic binding yaklaşımı arasındaki temel fark nedir?

  1. C++'ta varsayılan dynamic'tir; Java'da virtual yazmak gerekir
  2. C++'ta varsayılan static'tir, dynamic için virtual gerekir; Java'da varsayılan dynamic'tir
  3. Java'da hiç static binding yoktur
  4. İkisinde de tüm bağlamalar çalışma zamanında yapılır
Cevabı göster
b) C++'ta programcı tasarım zamanında karar verir (static binding daha hızlıdır). Java'da tüm mesajlar dinamik bağlanır — istisnalar: final, static ve private metotlar (üçü de override'ı engeller, dolayısıyla statik bağlanır). Bu yüzden (c) de yanlıştır. Kaynak: L10 — Dynamic Binding in C++ / Java.
Soru 18 · Lecture 10

Aşağıdakilerden hangisi abstract class'ın tanımıdır?

  1. Hiç veri üyesi olmayan sınıf
  2. En az bir virtual (abstract) metot içeren ve örneklenemeyen sınıf
  3. Yalnızca metot bildirimleri ve sabitler içerebilen yapı
  4. Başka bir sınıfın içine nested edilmiş sınıf
Cevabı göster
b) Abstract method = tanımı olmayan, yalnızca protokol belirten metot; abstract class = en az bir tane böyle metodu olan sınıf; ve örneklenemez. (c) şıkkı interface'in tanımıdır — klasik çeldirici. C++'ta karşılığı virtual void draw() = 0; (pure virtual). Kaynak: L10 — Dynamic Binding Concepts.
Soru 19 · Lecture 10

Java'da static ve non-static (inner) nested class arasındaki fark nedir?

  1. Static olan nesting class'ın üyelerine erişebilir, inner erişemez
  2. Inner class nesting class'ın üyelerine (private dahil) erişebilir; static nested class erişemez ve dış sınıfın örneği olmadan örneklenebilir
  3. Inner class yalnızca bir metodun içinde tanımlanabilir
  4. İkisi arasında yalnızca sözdizimsel bir fark vardır
Cevabı göster
b) Nedeni: her inner class örneği, ait olduğu nesting class örneğine açık bir pointer taşır; static nested class bu pointer'ı taşımaz. Slaytın cümlesi: "a static inner class can be instantiated without first creating an instance of the outer class; a non-static inner class cannot." (c) local nested class'ın tanımıdır. Kaynak: L10 — Nested Classes in Java.
Soru 20 · Lecture 10

Bir sınıfta dinamik olarak bağlanacak metotlar için gerçekleme düzeyinde ne yapılır?

  1. Metot kodu her nesnenin CIR'ına kopyalanır
  2. CIR'da girdileri olmalıdır; çağrılar CIR'daki bir pointer üzerinden vtable'a bağlanır
  3. Metotlar activation record'un dynamic link alanında saklanır
  4. Hiçbir şey — dinamik bağlama tamamen derleyicinin symbol table'ıyla çözülür
Cevabı göster
b) Statik bağlanan metotların CIR'da yer alması gerekmez; dinamik bağlananların girdisi olmak zorundadır. Depolama yapısının adı virtual method table (vtable); çağrılar vtable'ın başına göre offset olarak temsil edilebilir. Override edilmeyen bir metot için vtable parent'ın koduna işaret eder. Kaynak: L10 — Dynamic Binding of Method Calls.

Bölüm B — Açık uçlu

Açık uçlu 1 · Lecture 5

Array ile record arasındaki farkları açıklayın. Erişim hızları neden farklıdır?

Cevabı göster
1. Homojenlik: Array homogeneous (tüm elemanlar aynı tipte); record possibly heterogeneous.
2. Tanımlama: Array elemanı konumuyla (subscript), record alanı adıyla (field name) tanımlanır.
3. Erişim 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. Dinamik subscript record alanlarında da kullanılabilirdi, ama o zaman type checking imkânsızlaşır ve erişim çok daha yavaşlar.
4. Kullanım: Record, veri değerleri topluluğu heterojen olduğunda kullanılır.
5. Gerçekleme: Record'da her alan için, record'un başlangıcına göre bir offset adres tutulur. Kaynak: L5 — Evaluation and Comparison to Arrays; hoca bunu "one of the fundamental differences" diye vurguladı.
Açık uçlu 2 · Lecture 5

Coercion nedir? Strong typing ile ilişkisini ve iki dilden örnekle açıklayın.

Cevabı göster
Coercion: derleyici ya da run-time sistem tarafından başlatılan örtük (implicit) tip dönüşümü. Mixed-mode ifadeler mümkün olsun diye gereklidir — çünkü bilgisayarlarda farklı tipte operand alan ikili işlem yoktur.

Dezavantajı: derleyicinin tip hatası yakalama yeteneğini azaltır.

Strong typing ile ilişkisi: Bir dil, tip hataları her zaman yakalanıyorsa strongly typed'dır. Coercion kuralları strong typing'i ciddi biçimde zayıflatır.

Örnekler: C++ bol coercion yapar → strong typing zayıf; ayrıca parametre denetimi atlanabilir ve union'lar denetlenmez, bu yüzden C/C++ strongly typed değildir. ML ve F#'ta ifadelerde hiç coercion yoktur → strongly typed. Java/C# "neredeyse" strongly typed'dır — explicit casting yüzünden. Java'nın atama coercion'ları C++'ın yarısı kadardır ama strong typing'i hâlâ Ada'nınkinden daha az etkilidir. Kaynak: L5 — Type Checking / Strong Typing.
Açık uçlu 3 · Lecture 6

Functional side effect nedir? Yol açtığı problemi ve dillerin sunduğu iki çözümü avantaj/dezavantajlarıyla anlatın.

Cevabı göster
Tanım: Bir fonksiyon bir two-way parametreyi ya da bir non-local (global) değişkeni değiştirdiğinde oluşur.

Problem: İfadede geçen fonksiyon, aynı ifadenin başka bir operand'ını değiştirirse ifadenin sonucu operand değerlendirme sırasına bağlı hâle gelir → aynı kod farklı derleyicilerde farklı sonuç verir.

Çözüm 1 — Yasakla: Dil tanımı functional side effect'e izin vermesin (fonksiyonlarda two-way parametre yok, non-local referans yok).
  Avantaj: "It works!" — sorun tamamen ortadan kalkar.
  Dezavantaj: tek yönlü parametrelerin esneksizliği ve non-local referansların yokluğu.

Çözüm 2 — Sırayı sabitle: Dil tanımı operand değerlendirme sırasını sabit kılsın.
  Avantaj: sonuç deterministik olur.
  Dezavantaj: bazı derleyici optimizasyonlarını kısıtlar.
  Örnek: Java bu yolu seçmiştir — operand'ların soldan sağa değerlendirilmiş görünmesini zorunlu kılar.

Bonus bağlantı: Matematikte ve saf fonksiyonel dillerde side effect yoktur, çünkü değişken kavramı yoktur; bu yüzden bu diller referentially transparent'tır. Kaynak: L6 — Potentials for Side Effects / Functional Side Effects.
Açık uçlu 4 · Lecture 7

Pass-by-value, pass-by-result, pass-by-value-result ve pass-by-reference yöntemlerini modları, çalışma biçimleri ve avantaj/dezavantajlarıyla karşılaştırın.

Cevabı göster
Pass-by-value (in mode): Actual'ın değeri formal'i initialize eder, normalde kopyalayarak.
  + Skalerler için hızlı (linkage ve erişim). − Kopyalıysa ek depolama ve büyük parametrelerde pahalı taşıma; access path ile yapılırsa write-protect gerekir ve indirect addressing yüzünden erişim pahalanır.

Pass-by-result (out mode): 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; actual parameter collision riski (sub(p1, p1) — hangi formal en son kopyalanırsa o kazanır; C#'ta f.Fixer(out a, out a) sonucu implementation dependent).

Pass-by-value-result (inout mode): İkisinin birleşimi, diğer adı pass-by-copy. Formal'lerin local depolaması vardır.
  − Hem pass-by-value'nun hem pass-by-result'ın dezavantajları.

Pass-by-reference (inout mode): Bir access path (adres) geçirilir, diğer adı pass-by-sharing.
  + Çok verimli — kopyalama ve depolama tekrarı yok.
  − Erişim yavaş (indirect addressing); istenmeyen side effect/collision; istenmeyen alias'lar → readability ↓ → reliability ↓ → verification zorlaşır.

Tasarım gerilimi (bitirici cümle): İki değerlendirme çatışır — iyi programlama tek yönlü erişimi önerir, ama büyük yapılar için pass-by-reference daha verimlidir. Pratik kural: parametrelerle veri dönmeyecekse in-mode, veri gitmeyecekse out-mode kullan. Kaynak: L7 — Parameter-Passing Methods + Design Considerations.
Açık uçlu 5 · Lecture 8 + 9

(a) Static-scoped bir dilde non-local bir değişkene erişmek neden iki adımlıdır ve hangi adım zordur? (b) Dynamic scoping'de kullanılan deep access ile shallow access yöntemlerini karşılaştırın.

Cevabı göster
(a) İki adım: (1) doğru activation record instance'ı bul, (2) o ARI içindeki doğru offset'i belirle. Zor olan birinci adımdır — offset bulmak kolaydır çünkü derleyici local_offset'i derleme zamanında hesaplar. Birinci adımın çalışacağını static semantics kuralları garanti eder: referans verilebilecek tüm non-local değişkenler, referans anında stack'te bulunan bir ARI'da ayrılmıştır.
Çözüm: static chain — static link'ler zinciri. Verimsiz yöntem zinciri arar; verimli yöntemde nesting derleme zamanında bilindiği için derleyici izlenecek zincir uzunluğunu önceden hesaplar ve referans (chain_offset, local_offset) çiftiyle temsil edilir.

(b) Deep access: non-local referanslar dynamic chain üzerindeki ARI'lar aranarak bulunur. Sorunları: zincirin uzunluğu statik olarak belirlenemez ve her ARI değişken adlarını taşımak zorundadır.
Shallow access: local'ler merkezî bir yere konur — ya her değişken adı için bir stack, ya da her değişken adı için bir girdisi olan merkezî tablo.

Ayrım uyarısı: static chain → static scoping; deep/shallow access → dynamic scoping. Ayrıca L7'deki deep/shallow binding bambaşka bir konudur (parametre olarak geçirilen subprogram'ın referencing environment'ı). Kaynak: L8 — Nested Subprograms, Static Scoping, Implementing Dynamic Scoping.
Açık uçlu 6 · Lecture 10

(a) Inheritance hangi iki problemi çözmek için ortaya çıktı? (b) Kendisi hangi yeni problemi getirir? (c) Multiple inheritance'ın iki dezavantajını yazın ve dillerin buna karşı geliştirdiği çözümü açıklayın.

Cevabı göster
(a) ADT'lerle software reuse'un iki problemi:
1. ADT'ler yeniden kullanılması zordur — her seferinde değişiklik gerekir, çünkü var olan tipin özellikleri yeni kullanım için hemen hiçbir zaman tam uygun değildir. Değiştiren kişi eski kodu anlamak zorundadır ve genellikle asıl yazar o değildir; üstelik değişiklik istemci programları da etkileyebilir.
2. Tüm ADT'ler bağımsızdır ve aynı düzeydedir — aralarında ata/torun ilişkisi kurulamaz, hepsi "kardeş"tir; bu yüzden programı problem uzayına benzer biçimde organize etmek çok zordur.
Inheritance yeni sınıfların var olanlar cinsinden tanımlanmasına izin vererek her ikisini birden çözer: küçük değişikliklerle reuse ve hiyerarşi.

(b) Getirdiği problem: hiyerarşideki sınıflar arasında karşılıklı bağımlılık (interdependency) yaratır ve bu bakımı zorlaştırır. İroni: ADT'lerin en güçlü olumlu özelliği birbirinden bağımsız olmalarıydı — inheritance tam da bunu bozar. Klasik trade-off: reuse kazanılır, bağımsızlık kaybedilir.

(c) Multiple inheritance'ın iki dezavantajı:
1. Dil ve gerçekleme karmaşıklığı — kısmen isim çakışmaları yüzünden. Somut örnek: diamond problemi (BC → D1, D2 → Z; x Z'ye iki kez gelir). C++'ın çözümü public virtual BC ile virtual inheritancex bir kez gelir.
2. Potansiyel verimsizlikdynamic binding multiple inheritance ile daha pahalıya gelir (slaytın notu: "but not much").
Avantajı: "sometimes it is quite convenient and valuable."
Dillerin çözümü — interface: Metotları bildirilir ama tanımlanmaz, örneklenemez; Java'da multiple inheritance yerine kullanılır. Bir sınıftan miras alıp ayrıca interface implemente ederek multiple inheritance simüle edilir (mixin). Bedeli: interface'e sonradan metot eklersen tüm gerçeklemeleri bulup her birine kod yazman gerekir — abstract class'ta varsayılan gerçekleme verip mevcut kodu bozmadan devam edebilirdin. Kaynak: L10 — Inheritance, Single and Multiple Inheritance, Abstract vs Interface.
<final-havuz> ::= { ⭐<yüksek-ihtimal> | <soru> } /* Ch.6–12 */

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?
C) Associating a property (like type or value) with a name. Diğer şıklar: A) çalışma anında bellek ayırma, B) değişkenin scope'ta olup olmadığını denetleme, D) bir değeri sabite bağlama. Ch.5 — binding'in temel tanımı.
Q2-2Which language first introduced the concept of structured programming?
C) ALGOL. (Şıklar: COBOL / Pascal / ALGOL / C++.) ALGOL 60 blok yapısı ve yapısal kontrol akışının atasıdır. Ch.2 — vize konusu, ama Quiz 2'de çıktı: birikimli sorma örneği.
Q2-3In static scoping, how is the binding of a variable determined?
C) By the layout of the code in the source program. Static scoping metinsel/sözdizimsel yerleşime bakar; D şıkkı (çağrı yığını) dynamic scoping'i tarif eder. Ch.5.
Q2-4Which of the following is NOT a benefit of syntax-directed translation?
B) It enables syntax error recovery. Hata kurtarma parser'ın ayrı bir işidir, syntax-directed translation'ın faydası değildir. Diğerleri fayda sayılır: syntax–semantics bağını basitleştirmesi, parse tree'lerin derleyicide doğrudan kullanımı, grammar'a dayalı çeviri kuralları tanımlaması. Ch.3 · Bu, Quiz 1'deki "NOT a reason" sorusuyla aynı kalıp — hoca bu kalıbı seviyor.
Q2-5Which of the following is true regarding strongly typed languages?
C) They strictly enforce type rules during both compile and run time. A (tip uyumluluğunu denetlemezler) ve B (her tip arasında otomatik dönüşüme izin verirler) strong typing'in tersidir; D (her zaman dynamic type binding) yanlıştır. Ch.6 — rehberdeki "strong typing" bölümüyle birebir.
Q2-6What is a key advantage of dynamic type binding?
D) Greater flexibility at the cost of reliability. Rehberdeki genel kuralın ta kendisi: static = verimli ama esnek değil; dynamic = esnek ama pahalı/riskli. A (performans artışı) ve B (bellek tasarrufu) tam tersidir. Ch.5.
Q2-7Which of the following is a non-primitive data type?
D) Array. Integer, Float ve Boolean primitive'dir (başka tipler cinsinden tanımlanmazlar); array başka tiplerden kurulur. Ch.6 — primitive tanımının doğrudan uygulaması.
Q2-8Which of the following best describes referential transparency?
B) An expression can be replaced by its value without changing behavior. Ch.7 — dikkat: bu konu 27 Temmuz'da işlendi, 28 Temmuz'da soruldu. Yani en taze konu da çıkabiliyor.
Q2-9Which of the following describes the job of a parser?
A) Ensuring syntactic correctness of source code. B (girdi akışını token'lara ayırma) lexical analyzer'ın işidir — klasik tuzak. Ch.3.
Q2-10Which of the following languages introduced object-oriented programming concepts like encapsulation and inheritance?
A) Smalltalk. (Şıklar: Smalltalk / Pascal / BASIC / Fortran.) Ch.2 — vize konusu, yine birikimli sorulmuş.

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?
readability ve modifiability. Sayının anlamı adından okunur; değeri değiştirmek gerektiğinde tek bir yerde değiştirilir. Ch.5 — Named Constants.
Q3-2What is the primary purpose of Backus-Naur Form (BNF)?
Bir programlama dilinin sözdizimini (syntax) biçimsel olarak tanımlamak. BNF bir context-free grammar gösterimidir; semantiği tanımlamaz. Ch.3 — vize konusu, yine çıktı.
Q3-3Which of the following best describes a side effect in an expression?
Bir fonksiyonun, değer döndürmenin yanında two-way bir parametreyi ya da non-local (global) bir değişkeni değiştirmesi — yani ifadenin dışındaki durumu değiştirmesi. Ch.7 — rehberdeki functional side effect bölümü.
Q3-4Which of the following types of loops is best when the number of iterations is known before execution?
Counter-controlled loop (sayaç kontrollü / 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?
Kısa devre değerlendirme McCarthy evaluation olarak da bilinir ve kökeni LISP'e (John McCarthy) dayanır; erken imperatif dillerde ALGOL 60 ile ilişkilendirilir. Bu sorunun şıkları elimizde yok, dolayısıyla hangisinin beklendiğinden emin olamıyorum. Şıklarda LISP varsa LISP, yoksa ALGOL en güçlü aday. Ch.7 — Short Circuit Evaluation.
Q3-6Which of the following language features most improves readability?
Ders çerçevesinde readability'yi artıran başlıca özellikler: simplicity (aşırı feature multiplicity'den kaçınma), orthogonality, uygun veri tipleri (özellikle enumeration ve boolean) ve named constants. Şıklar elimizde olmadığı için kesin cevabı veremiyorum — ama şıklarda enumeration/named constants/boolean geçiyorsa o. Ch.1 kriter tablosu + Ch.6.
Q3-7In dynamic scoping, how is a variable's binding resolved?
Çalışma zamanında, çağrı zinciri (call/dynamic chain) üzerinden — en son etkinleşmiş ve hâlâ aktif olan bildirime bağlanır. Static scoping'in tersi (o, kaynak koddaki metinsel yerleşime bakar). Ch.5 · Quiz 2'de static scoping sorulmuştu, Quiz 3'te dynamic — hoca ikiliyi ayrı ayrı yokluyor.
Q3-8Which of the following expression evaluation strategies guarantees that all operands are evaluated, regardless of short-circuit conditions?
Non-short-circuit (tam / eager) değerlendirme. C, C++ ve Java'da bunu bitwise Boolean operatörleri (& 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?
Bir veri nesneleri kümesi ve bu nesneler üzerinde önceden tanımlı işlemler kümesi. Slayttaki tanım birebir budur.
⭐2Descriptor nedir ve ne zaman compile-time, ne zaman run-time'da bulunur?
Bir değişkenin özniteliklerinin toplamı. Öznitelikler tamamen static ise descriptor yalnız compile time'da gerekir (symbol table'ın parçası); dynamic öznitelikler varsa descriptor'ın bir kısmı/tamamı run time boyunca korunur. Her hâlükârda type checking ve allocation kodu üretiminde kullanılır.
⭐3Bu derste object ne demektir? OOP'deki nesneden farkı nedir?
Burada object = kullanıcı tanımlı (abstract data) bir tipin örneği (instance). Hoca özellikle uyardı: bu, OOP derslerinde bildiğin nesne değildir.
⭐4Bir dilde tip sistemi neden vardır? Üç gerekçe.
(1) Error detection — en pratik gerekçe, hoca 1. sıraya koydu; type checking süreci tip sistemi tarafından yönetilir. (2) Modularization — cross-module tip denetimi modül arayüzlerinin tutarlılığını sağlar. (3) Documentation — tip bildirimleri verinin ve programın davranışının belgesidir.
5Primitive data type tanımı nedir?
Başka veri tipleri cinsinden tanımlanmayan tipler. Bazıları donanımın doğrudan yansımasıdır, bazıları küçük bir yazılım desteği ister.
⭐6Negatif tamsayılar için neden ones complement yerine two's complement kullanılır?
Ones complement'te iki tane sıfır olur — pozitif sıfır ve negatif sıfır. Hoca bunu "biggest problem" diye niteledi. Two's complement = ones complement + 1; toplama ve çıkarma için elverişlidir. Örnek: 00101101 → +1 → 1110.
7IEEE 754'te 32-bit bir floating point sayı hangi parçalara ayrılır?
1 bit sign + 8 bit exponent + 23 bit fraction. 64-bit'te: 1 + 11 + 52.
⭐8Precision ile range arasındaki fark nedir?
Precision: değerin kesir (fraction) kısmının doğruluğu, bit cinsinden ölçülür. Range: kesir aralığı ile üs aralığının birleşimi. Karıştırılması kolay, bu yüzden sorulmaya elverişli.
⭐9Decimal tipin avantajı ve dezavantajları nelerdir? Hangi dillerde vardır?
Avantaj: accuracy — ondalık değerleri kesin saklar. Dezavantajlar: sınırlı aralık (limited range) ve bellek israfı. COBOL için temeldir, C# da sunar. Sabit sayıda ondalık basamağı BCD (binary coded decimal) kodlu saklar. Hocanın somut örneği: 6 basamaklı BCD 24 bit tutar, saf ikilide 20 bit yeter.
10Boolean tipin en büyük avantajı nedir ve hangi dilde tanıtılmıştır?
En büyük avantaj readability. ALGOL 60'ta tanıtılmıştır. Bit ile gösterilebilir ama çoğunlukla byte kullanılır.
11C89'un boolean tipi konusundaki istisnası nedir? Java/C# nasıl davranır?
C89'un boolean tipi yoktur; 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?
ASCII: 0–127, 128 karakter. Unicode UCS-2: 16 bit, çoğu doğal dilin karakteri; orijinal olarak Java'da kullanıldı; ilk 128 karakteri ASCII ile birebir aynıdır. UCS-4: 32 bit; Fortran 2003'ten itibaren destekler.
⭐13Character string tipinin iki tasarım sorusu nedir?
(1) Primitive bir tip mi, yoksa sadece özel bir array mi? (2) String'in uzunluğu static mi dynamic mi? Hoca bu ikisini "the two important issues" diye nitelendirdi.
14String için tipik işlemler nelerdir?
Assignment ve copying · comparison (=, >) · catenation · substring reference · pattern matching. Substring reference, array bağlamında slice adını alır.
⭐15String uzunluğunun üç kategorisi nedir, hangi diller hangisini kullanır?
Static: COBOL, Java'nın String sınıfı. Limited dynamic length: C ve C++ — bildirilen bir maksimuma kadar değişebilir; sonu özel bir karakterle (null) işaretlenir, uzunluk tutulmaz. Dynamic (maksimum yok): SNOBOL4, Perl, JavaScript.
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?
SNOBOL4 — string'ler primitivedi ve gelişmiş pattern matching dahil çok sayıda işlem sunuyordu.
18Hangi diller yerleşik pattern matching (regular expression) sunar?
Perl, JavaScript, Ruby, PHP.
19Ordinal type nedir? Java'daki primitive ordinal örnekleri nelerdir?
Olası değerler kümesi pozitif tamsayılarla kolayca eşleştirilebilen tip. Java örnekleri: integer, char, boolean.
⭐20Enumeration type readability ve reliability'ye nasıl katkı yapar?
readability: rengi bir sayı olarak kodlamaya gerek kalmaz. reliability: derleyici (a) işlemleri denetler — renkler toplanamaz; (b) enum değişkenine tanımlı aralık dışında değer atanmasını engeller.
⭐21C#, F#, Swift ve Java 5.0 enumeration desteğinde C++'tan neden daha iyidir?
Çünkü bu dillerde enum tipi değişkenler integer tiplerine coerce edilmez — kendi başına bir tiptir. C++'ta coerce edilir, bu da aralık dışı değer riskini doğurur.
22Enumeration tiplerinin üç tasarım sorusu nedir?
(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: üçü de type checking ile ilgilidir.
⭐23Array tanımı nedir?
Bir homogeneous veri elemanı topluluğudur; her eleman, topluluk içindeki konumuyla, ilk elemana göre tanımlanır.
⭐24Array'in dört kategorisini, subscript bind'ı ve allocation'ı ile açıklayın.
Static: subscript aralığı statik bağlı, allocation statik ve run-time öncesi → avantaj efficiency. (C/C++ 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?
Allocation ve deallocation daha uzun sürer ve çalışma boyunca defalarca gerçekleşebilir.
26Hangi diller array indekslerinde range checking yapar, hangileri yapmaz?
Yapar: Java, ML, C#. Belirtmez/yapmaz: C, C++, Perl, Fortran.
27Hangi diller subscript olarak yalnız integer, hangileri ordinal tipleri kabul eder?
Yalnız integer: Fortran, Java. Ordinal tipler (integer, char, boolean, enum): C, C++.
28Ada neden array indekslemede parantez kullanır?
Çünkü array referansı da fonksiyon çağrısı da birer mapping'dir; Ada bu tekdüzeliği (uniformity) göstermek için bilinçli olarak parantez seçmiştir. Fortran/PL1'de ise gerekçe tarihseldi: delikli kartlarda köşeli parantez karakteri yoktu. Sakıncası: alt program çağrısıyla karışması.
29Heterogeneous array nedir, hangi diller destekler?
Elemanları aynı tipte olmak zorunda olmayan array. Perl, Python, JavaScript, Ruby.
30Rectangular ve jagged array farkı nedir? Hangi diller neyi destekler?
Rectangular: tüm satırlar eşit sayıda eleman, tüm sütunlar eşit sayıda eleman. Jagged (ragged): satırlar farklı sayıda eleman içerir — çok boyutlu array aslında array of arrays olduğunda mümkün. C, C++, Java jagged destekler; F# ve C# ikisini de destekler.
⭐31Slice nedir ve ne zaman anlamlıdır?
Bir array'in alt yapısıdır; "bir referanslama mekanizmasından başka bir şey değildir". Yalnızca array işlemleri olan dillerde kullanışlıdır. Python: vector[3:6] · Ruby: list.slice(2, 2).
⭐32Row major ve column major order nedir? Hangi dil hangisini kullanır?
1 2 3 / 4 5 6 / 7 8 9 matrisi için: Row major → 1 2 3 4 5 6 7 8 9 (çoğu dil). Column major → 1 4 7 2 5 8 3 6 9 (Fortran).
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?
Sırasız bir veri elemanı topluluğu; elemanlar key denen eşit sayıda değerle indekslenir. Kritik ayrım: kullanıcı tanımlı key'ler saklanmak zorundadır (normal array'de indeks saklanmaz). Yerleşik olduğu diller: Perl, Python, Ruby, Swift.
35Perl hash'lerinde ve Python dictionary'lerinde sözdizimi nasıldır?
Perl: isim % 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?
Tanım: possibly heterogeneous bir veri elemanı topluluğu; elemanlar isimleriyle tanımlanır. Farklar: (1) array homogeneous / record heterogeneous; (2) array konumla / record isimle; (3) array elemanına erişim record alanına erişimden çok daha yavaş — subscript'ler dinamik, field name'ler statik; (4) record alanları için offset adres tutulur.
37Fully qualified ve elliptical reference nedir?
Fully qualified: tüm record isimlerini içeren referans. Elliptical: belirsizlik olmadığı sürece record isimlerinin atlanmasına izin verir. COBOL örneği: FIRST, FIRST OF EMP-NAME ve FIRST OF EMP-REC üçü de aynı alana elliptical referanstır.
38COBOL record'ları nasıl tanımlar?
Seviye numaralarıyla (01, 02, 05…) iç içe record gösterir; diğer diller özyinelemeli tanım kullanır. Alan referansında COBOL OF, diğerleri dot notation kullanır.
⭐39Tuple nedir, record'dan farkı ne?
Record'a benzer, ama elemanları isimsizdir. Python, ML ve F#'ta fonksiyonların birden çok değer döndürmesini sağlar. Python'da listelere yakındır ama immutable'dır.
⭐40Scheme'de CAR, CDR, CONS, LIST ne yapar?
CAR: ilk eleman — (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?
Veri ve kod aynı biçimdedir. (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?
Python listeleri mutable'dır (Scheme, Common Lisp, ML, F# listeleri değil); array görevi de görür; elemanlar herhangi tipte olabilir; indeks 0'dan başlar; del ile eleman silinir.
43List comprehension nereden gelir, hangi dilde orijinaldir?
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].
⭐44Union tanımı nedir?
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.
⭐45Free union ile discriminated union arasındaki fark nedir?
Free union: dil desteği yok, type checking yokunsafe. C ve C++.
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?
Slaytın gerekçesi: programlama dillerinde artan güvenlik kaygılarının yansıması.
47Union'ların iki tasarım sorusu nedir?
(1) Type checking gerekli olmalı mı? (2) Union'lar record'ların içine gömülmeli mi?
⭐48Pointer tipi nedir ve neyi sağlar?
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; heap'te dinamik yaratılan alana erişimi mümkün kılar.
49Pointer'ların iki temel işlemi nedir?
Assignment (pointer'a yararlı bir adres atamak) ve dereferencing (pointer'ın gösterdiği yerdeki değeri almak). Dereferencing explicit (C++: *ptr) veya implicit olabilir.
⭐50Dangling pointer ile lost heap-dynamic variable arasındaki fark nedir?
Dangling pointer: pointer, deallocate edilmiş bir heap-dynamic değişkeni gösteriyor. Lost heap-dynamic variable (garbage): ayrılmış ama artık erişilemeyen heap değişkeni; bu sürece memory leakage denir.
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?
Tombstone: 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) ç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?
Herhangi bir tipi gösterebilir ve type checked edilebilir, ama dereference edilemez.
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?
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ı.
⭐55"Pointers are like goto's" ne demektir? Pointer'lardan vazgeçilebilir mi?
Her ikisi de bir değişkenin erişebileceği hücre aralığını genişletir (goto kontrolü savurur, pointer erişimi savurur) → readability ve reliability düşer. Ama vazgeçilemez: dinamik veri yapıları için pointer/reference zorunludur — "we can't design a language without them."
⭐56Reference counting ile mark-sweep arasındaki farklar nelerdir?
Reference counting (eager): her hücrede bir sayaç; geri kazanım kademeli. + Intrinsically incremental → büyük gecikme olmaz. − Alan ve zaman maliyeti, dairesel bağlı hücrelerde çuvallar.
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?
Bir değişkenin şu anda değeri olmadığını belirtmesi gerektiğinde kullanılır. C#, F#, Swift. 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;. Swift'te değersizlik nil'dir.
⭐58Type checking, compatible type, coercion ve type error tanımlarını verin.
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 çevrim. type error: bir operatörün uygunsuz tipte operand'a uygulanması.
⭐59Type binding'ler ile type checking arasındaki ilişki nedir?
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.
⭐60Strong typing tanımı nedir? Hangi diller strongly typed'dır?
Tanım: tip hataları her zaman yakalanıyorsa dil strongly typed'dır. Avantajı: tip hatasına yol açan değişken yanlış kullanımlarının saptanması.
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?
Coercion kuralları strong typing'i ciddi biçimde zayıflatır — C++ ↔ ML/F# karşıtlığı bunun örneğidir.
⭐62Name ve structure type equivalence arasındaki fark nedir?
Name: iki değişken aynı bildirimde ya da aynı tip adını kullanan bildirimlerdeyse eşdeğerdir. Kolay uygulanır ama çok kısıtlayıcıdır — integer'ın subrange'i integer'a eşdeğer değildir, formal parametre actual ile aynı tipte olmalıdır.
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?
Alan adları farklı ama yapısı aynı 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?

Lecture 6 · Expressions, Assignment & Control Structures (Ch.7–8)

⭐64Imperative dillerin "özü" nedir?
Assignment statement'ın baskın rolü. Expression'lar ise hesaplamayı belirtmenin temel aracıdır.
⭐65Aritmetik expression'ların altı tasarım sorusu nedir?
(1) Operator precedence kuralları (2) Operator associativity kuralları (3) Operand değerlendirme sırası (4) Operand değerlendirmesinin side effect'leri (5) Operator overloading (6) Expression'larda tip karışımı.
66Precedence ile associativity arasındaki fark nedir?
Precedence: farklı öncelik seviyesindeki komşu operatörlerin sırası. Associativity: aynı öncelik seviyesindeki komşu operatörlerin sırası. İkisi de parantezle ezilebilir.
⭐67APL'in operatör kuralları neden istisnadır?
APL'de tüm operatörlerin önceliği eşittir ve hepsi sağdan sola associate eder. Diğer dillerde tipik associativity soldan sağadır (istisna: ** sağdan sola).
68Hangi dillerde binary operatörler prefix'tir?
Scheme ve LISP (Perl'de de bazı prefix binary'ler var). Çoğu dilde binary operatörler infix'tir. Unary operatörler çoğunlukla prefix, ama C tabanlı dillerde ++/-- hem prefix hem postfix olabilir.
69Ruby ve Scheme'de operatörler nasıl gerçeklenmiştir?
Ruby: tüm aritmetik, ilişkisel, atama operatörleri, array indeksleme, shift ve bit işlemleri metot olarak gerçeklenmiştir → hepsi override edilebilir. Scheme/Common Lisp: tüm aritmetik ve mantık işlemleri açıkça çağrılan alt programlardır: a + b * c(+ a (* b c)).
⭐70Functional side effect nedir ve neden problem yaratır?
Bir fonksiyon two-way bir parametreyi ya da non-local (global) bir değişkeni değiştirdiğinde oluşur. Problem: 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.
⭐71Side effect problemine iki çözüm nedir, avantaj/dezavantajları?
(1) Yasakla: two-way parametre ve non-local referans yok. + "It works!" − Tek yönlü parametrelerin esneksizliği ve non-local referans yokluğu.
(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?
Tanım: aynı değere sahip iki ifade, programın davranışını değiştirmeden her yerde birbirinin yerine konabilir. Avantajı: programın semantiğini anlamak çok daha kolaydır.
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?
(1) 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. (2) Okunabilirlik kaybı. Örnek: & 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?
C++, C#, F# (ayrıca Ada, Python, Ruby). C++'ta overload edilemeyenler: sınıf/struct üye operatörü . ve scope resolution ::.
⭐75Operator overloading'in Java ile ilişkisi nedir?
C++'ın Java'ya kopyalanmayan özelliklerinden biridir — ama sonra C#'a girmiştir. Hoca bunu "very interesting" diye niteledi; dil tasarımcılarının bakış açısını gösterir.
⭐76Narrowing ve widening conversion tanımları nedir?
Narrowing: nesneyi, orijinal tipin tüm değerlerini içeremeyen bir tipe çevirir (float→int). Kayıplıdır. Widening: orijinal tipin tüm değerlerine en azından yaklaşık karşılık verebilen bir tipe çevirir (int→float). Neredeyse her zaman güvenlidir ama doğruluk azalabilir.
⭐77Mixed-mode expression ve coercion neden gereklidir? Dezavantajı nedir?
Mixed-mode: operand'ları farklı tipte olan ifade. Coercion: örtük tip dönüşümü. Neden gerekli: bilgisayarlarda farklı tipte operand alan ikili işlem yoktur. Dezavantaj: derleyicinin tip hatası yakalama yeteneğini azaltır. ML ve F#'ta ifadelerde hiç coercion yoktur.
⭐78PL/I'ın aşırı coercion örneği nedir ve bedeli neydi?
PL/I'da bir karakter dizisi, bir integer ile aritmetik operatörün operand'ı olabiliyordu; run-time'da string sayısal değer için taranıyor, ondalık nokta varsa floating point varsayılıyordu. Bedeli: hem tip denetimi hem dönüşüm run-time'da → çok pahalı; ayrıca ifadelerdeki programcı hatalarını saptama olanağı yok oluyor, çünkü her tip her tiple birleşebiliyor.
79Expression hatalarının iki kaynağı nedir?
(1) Aritmetiğin doğasındaki sınırlar — sıfıra bölme. (2) Bilgisayar aritmetiğinin sınırları — overflow/underflow. Bunlar run-time error'dır ve çoğu zaman run-time sistem tarafından görmezden gelinir; bazen exception denir.
⭐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?
Yasaldır ama beklenen anlamı vermez. (1) Soldaki operatör değerlendirilir → 0 veya 1 üretir. (2) Bu sonuç üçüncü operand (c) ile karşılaştırılır. Yani "b, a ile c arasında mı" anlamı çıkmaz.
⭐82Short-circuit evaluation nedir ve olmamasının problemi nedir?
Tanım: sonucun, tüm operand/operatörler değerlendirilmeden belirlendiği ifade. Problem (slayttaki kod): 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?
Short-circuit, ifadelerdeki side effect problemini açığa çıkarır: (a > b) || (b++ / 3)a > b doğruysa b++ hiç çalışmaz.
⭐84C tabanlı diller neden =='i ilişkisel operatör yaptı?
Çünkü ='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ı?
ALGOL'de tanıtıldı, C ve C tabanlı diller benimsedi. a += ba = 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?
C tabanlı diller, Perl ve JavaScript'te atama bir değer üretir ve operand olarak kullanılabilir: while ((ch = getchar()) != EOF) {…}. Dezavantajı: bir başka tür expression side effect'i.
88Perl/Ruby'de multiple assignment nasıl kullanılır?
Çok hedefli çok kaynaklı atama: ($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?
Fortran, C, Perl, C++: herhangi numeric değer herhangi numeric değişkene atanabilir. Java, C#: yalnızca widening atama coercion'ları. Ada: hiç atama coercion'ı yok.
90ML'in val'i ile F#'ın let'i arasındaki fark nedir?
İkisi de isimleri değere bağlar; F#'ın 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?
(1) İfadeler içinde (associativity/precedence) (2) Program birimleri arasında (subprogram) (3) Program deyimleri arasında (selection/iteration).
⭐921960'larda kontrol yapıları hakkında kanıtlanan "önemli sonuç" nedir?
Akış şemalarıyla temsil edilebilen tüm algoritmalar, yalnızca iki yönlü seçim (two-way selection) ve ön testli mantıksal döngüler (pretest logical loops) ile kodlanabilir.
93Control structure tanımı nedir?
Bir kontrol deyimi ve onun çalışmasını yönettiği deyimler. Tasarım sorusu: birden çok girişi olmalı mı?
⭐94Dangling else problemi nedir, Java nasıl çözer?
İç içe 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?
C89, C99, Python, C++. Diğer çoğu dilde Boolean olmak zorundadır.
⭐96C/C++/Java switch'inin dört tasarım tercihi nedir?
(1) Kontrol ifadesi ordinal tip (integer, karakter, enum); Java'da JDK 7+ ile string ve wrapper da. (2) Segmentler deyim dizisi, blok veya compound olabilir. (3) Bir yürütmede herhangi sayıda segment çalışabilir — segment sonunda örtük dallanma yoktur. (4) default temsil edilmeyen değerler içindir; yoksa deyim hiçbir şey yapmaz.
⭐97C#'ın switch'i C'den nasıl ayrılır?
Bir static semantics kuralıyla birden fazla segmentin örtük yürütülmesini yasaklar — her segment koşulsuz bir dallanmayla (goto veya break) bitmelidir. Ayrıca kontrol ifadesi ve case sabitleri string olabilir.
98Ruby'nin iki case biçimi nedir?
(1) when + Boolean ifadeler (case değeri yok). (2) Bir case değeri + when değerleri.
⭐99Counter-controlled loop'un üç tasarım sorusu nedir?
(1) Loop değişkeninin tipi ve scope'u? (2) Loop değişkeni/parametreleri gövdede değiştirilebilir mi, değiştirilirse kontrolü etkiler mi? (3) Loop parametreleri bir kez mi yoksa her iterasyonda mı değerlendirilir?
⭐100C'nin for'unun tasarım tercihleri nelerdir?
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 · gövdenin içine dallanmak yasaldır · ikinci ifade yoksa sonsuz döngü.
101C++ (ve C99) for'u C89'dan iki noktada nasıl ayrılır? Java/C#?
(1) Kontrol ifadesi Boolean da olabilir. (2) Başlangıç ifadesi değişken tanımı içerebilir (scope'u tanımdan gövde sonuna). Java ve C#'ta kontrol ifadesi zorunlu Boolean'dır.
102Python'ın for'undaki else clause'u ne zaman çalışır?
Döngü normal biçimde sonlanırsa (yani break ile kesilmezse). İsteğe bağlıdır.
103Logically-controlled loop'un iki tasarım sorusu nedir?
(1) Pretest mi posttest mi? (2) Mantıksal kontrollü döngü, sayma döngüsünün özel hâli mi olmalı yoksa ayrı bir deyim mi?
⭐104Java'nın döngüleri C/C++'tan nasıl ayrılır?
Kontrol ifadesi Boolean olmalı ve gövdeye yalnızca baştan girilebilir — çünkü Java'da 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?
Etiketsiz break: C, C++, Python, Ruby, C#. Etiketli: Java (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?
İterasyon 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ü sonlanır. Java: 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?
Temel kaygı readability. 1960 ve 70'lerin en hararetli tartışmalarından biri. Java'da 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?
Seçim ve mantıksal ön test döngüsünün ötesindeki kontrol deyimi seçimi, dil büyüklüğü ile writability arasında bir trade-off'tur. Hoca: "how much a language should be expanded to increase its writability at the expense of its simplicity, size, and portability."

Lecture 7 · Subprograms (Ch.9)

⭐109İki temel soyutlama nedir, ne zaman öne çıktılar?
Process abstraction — ilk günlerden beri vurgulandı (Ch.9). Data abstraction1980'lerde vurgulandı (Ch.11). Hocanın eklediği: bugün ikisi de eşit derecede önemli sayılır.
⭐110Subprogram'ların üç temel özelliği nedir?
(1) Her subprogram'ın tek bir giriş noktası vardır. (2) Çağıran program, çağrılan çalışırken askıya alınır. (3) Çağrılan bitince kontrol her zaman çağırana döner. Coroutine'ler 1. ve 3. maddeyi ihlal eder.
⭐111parameter profile ve protocol tanımları nedir?
parameter profile (= signature): parametrelerin sayısı, sırası ve tipleri. protocol: parameter profile + (fonksiyonsa) dönüş tipi.
112formal ve actual parametre nedir?
Formal: header'da listelenen ve subprogram içinde kullanılan dummy (kukla) değişken. Actual: çağrı deyiminde kullanılan bir değer veya adres.
113subprogram declaration nedir, C/C++'ta ne denir?
Protokolü verir ama gövdeyi vermez. C/C++'ta buna prototype denir.
114Python, Ruby ve Lua'nın fonksiyon tanımı konusundaki istisnaları nelerdir?
Python: fonksiyon tanımları çalıştırılabilirdir — diğer tüm dillerde değildir. Ruby: tanımlar sınıfın içinde veya dışında olabilir; dışındaysa Object'in metodudur ve nesnesiz çağrılabilir. Lua: tüm fonksiyonlar anonimdir.
⭐115Positional ve keyword parametre karşılığının avantaj/dezavantajları nelerdir?
Positional: bağlama konuma göre. + Safe and effective. − Liste uzunsa hata yapılır.
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?
Çünkü parametreler konumsal olarak eşleşir. Default değer sunan diller: C++, Python, Ruby, Ada, PHP.
117Python'da * ve ** parametreleri ne yapar?
Bir yıldız → tuple; iki yıldız → hash/dict. 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?
Procedure: parametreli hesaplamaları tanımlayan deyimler topluluğu. Function: yapısal olarak benzer ama semantik olarak matematiksel fonksiyonlara göre modellenmiştir; side effect üretmemesi beklenirama pratikte program fonksiyonlarının side effect'i vardır.
⭐119Stack-dynamic local değişkenlerin avantaj ve dezavantajları nelerdir?
Avantajlar: recursion desteği; depolamanın bazı subprogram'lar arasında paylaşılması. Dezavantajlar: allocation/deallocation ve initialization zamanı; indirect addressing; subprogram'lar history sensitive olamaz. Static local'lerin avantaj/dezavantajları bunun tam tersidir.
⭐120Static local değişkenlerin en büyük dezavantajı nedir?
Recursion'ı destekleyemezler. Ayrıca depolamaları, etkin olmayan subprogram'ların local'leriyle paylaşılamaz.
121Hangi dillerin metotlarında yalnızca stack-dynamic local'ler vardır?
C++, Java, Python ve C#. C tabanlı dillerde varsayılan stack-dynamic'tir ama static ile bildirilebilir — bu Java'da yasal değildir.
⭐122Parameter passing'in üç semantik modeli nedir?
In mode: subprogram actual'dan veri alır. Out mode: subprogram actual'a veri iletir. Inout mode: her ikisi. İki kavramsal aktarım modeli: değeri fiziksel taşı ya da bir access path taşı.
⭐123Pass-by-value'nun avantaj ve dezavantajları nelerdir?
Actual'ın değeri formal'i initialize eder, normalde kopyalayarak. + Skalerler için hızlı. − Fiziksel taşımada: ek depolama (iki kez saklanır) + büyük parametrelerde pahalı taşıma. − Access path yöntemiyle: write-protect gerekir (kolay değil) ve indirect addressing yüzünden erişim pahalanır.
⭐124Pass-by-result nasıl çalışır ve hangi problemi doğurur?
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. Problemler: ek depolama + kopyalama; actual parameter collisionsub(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ı?
Diğer adı pass-by-copy. Formal'lerin local depolaması vardır. Dezavantajı: hem pass-by-result'ın hem pass-by-value'nun dezavantajları.
⭐126Pass-by-reference'ın diğer adı nedir, avantaj ve dezavantajları?
Diğer adı pass-by-sharing; bir access path geçirilir. + Çok verimli — kopyalama ve depolama tekrarı yok. − Erişim daha yavaş (indirect addressing); istenmeyen side effect/collision; istenmeyen alias'lar. Tehlikeli çağrılar: fun(total,total), fun(list[i],list[j]), fun(list[i],i).
⭐127Aliasing hangi zinciri tetikler?
aliasing → readability düşer → reliability düşer → program verification zorlaşır.
⭐128Pass-by-name nasıl çalışır?
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 esneklik. − Gerçeklemesi karmaşık ve verimsiz, readability/reliability düşürür; caller'ın referencing environment'ının geçirilmesini gerektirir.
129Geçirilen referans çağrılan subprogram'da değiştirilebilir mi?
C'de mümkündür. Pascal ve C++'ta adres olan formal parametreler örtük olarak dereference edilir → bu tür değişiklikler engellenir.
⭐130Java'da parametreler nasıl geçirilir?
Tüm non-object parametreler by value → hiçbir metot bunları değiştiremez. Object parametreleri by reference.
⭐131Ada'nın üç parametre modu nasıl çalışır?
in, out, in out; 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?
C#: hem formal hem actual ref ile öncelenmelidir. PHP: yalnızca biri (actual veya formal) belirtebilir.
133Python ve Ruby hangi parameter passing yöntemini kullanır?
Pass-by-assignment — tüm veri değerleri nesnedir; actual, formal'e atanır.
⭐134Parametre tip denetimi hangi dillerde nasıldır?
Hiç yok: FORTRAN 77, orijinal C. Her zaman zorunlu: Pascal, Java. Seçim kullanıcıya ait (prototype): ANSI C, C++. Gerektirmez: Perl, JavaScript, PHP. Mümkün değil: Python, Ruby — değişkenlerin tipi yoktur, nesnelerin vardır.
⭐135Çok boyutlu bir array parametre olarak geçirilirken derleyicinin neyi bilmesi gerekir?
Sütun sayısını (row major order için) — satır sayısını değil. C/C++'ta bu yüzden 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?
Yoktur. Gerçek 2D array'de tüm elemanlar bitişik bir bellek bloğunda durur; Java'da durmaz — array of arrays'tir. Java/C#'ta array'ler nesnedir ve her biri length/Length sabitini miras alır.
⭐137Parameter passing tasarımındaki iki değerlendirme neden çatışır?
(1) Efficiency ve (2) tek yönlü mü çift yönlü mü aktarım. Çatışma: iyi programlama sınırlı erişimi (mümkünse tek yönlü) önerir, ama büyük yapılar için pass-by-reference daha verimlidir. Pratik kural: parametrelerle veri dönmeyecekse in-mode, veri gitmeyecekse out-mode.
⭐138Shallow, deep ve ad hoc binding nedir?
Shallow: geçirilen subprogram'ı çalıştıran çağrının ortamı → dynamic-scoped diller için doğal. Deep: geçirilen subprogram'ın tanımının ortamı → static-scoped diller için doğal. Ad hoc: subprogram'ı geçiren çağrının ortamı.
139C/C++ ve Java, subprogram'ları parametre olarak geçirme konusunda ne yapar?
C/C++: fonksiyonlar geçirilemez ama fonksiyon pointer'ları geçirilebilir ve tipleri parametre tiplerini içerdiği için tip denetimi yapılabilir. Java, metot adlarının parametre olarak geçirilmesine izin vermez.
⭐140Delegate nedir? Multicast delegate ne demektir?
C#'ta metot pointer'ları delegate denen nesneler olarak gerçeklenir: 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?
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.
⭐142Overloaded subprogram nedir? Ada'nın ayrıcalığı nedir?
Tanım: aynı referencing environment'ta başka bir subprogram'la aynı ada sahip subprogram; her versiyonun benzersiz bir protokolü vardır. Ada'da overloaded bir fonksiyonun dönüş tipi çağrıları ayırt etmek için kullanılabilir → iki overloaded fonksiyon aynı parametrelere sahip olabilir.
⭐143Polymorphism'in üç türü nedir?
Ad hoc: overloaded subprogram'lar. Subtype: T tipindeki değişken, T'den türetilmiş her nesneye erişebilir (OOP). Parametric: generic parametre alan subprogram — slaytın notu: dynamic binding'in ucuz bir compile-time ikamesi.
⭐144Java 5.0 generic'lerinin C++'tan dört farkı nedir?
(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<?>).
145C# 2005 generic'leri Java 5.0'dan nasıl ayrılır?
Derleyici çıkarabiliyorsa çağrıda tip parametreleri atlanabilir; C# wildcard desteklemez.
146F#'ın generic'leri neden daha az kullanışlıdır?
Parametreler aritmetik operatörlerle kullanılırsa, generic belirtilseler bile tipleri kısıtlanır; bu ve coercion yokluğu yüzünden F#'ın generic fonksiyonları C++/Java 5.0+/C# 2005+'ınkinden çok daha az kullanışlıdır. F# tipi belirleyemezse generic çıkarır — buna automatic generalization denir ('a gösterimi).
⭐147Closure nedir, ne zaman gerekir?
Tanım: bir subprogram ve onun tanımlandığı referencing environment. Gereklilik: subprogram her yerden çağrılabiliyorsa referencing environment gerekir; nested subprogram'a izin vermeyen static-scoped bir dilin closure'a ihtiyacı yoktur; gerçekleme bazı değişkenlere unlimited extent sağlamak zorunda kalabilir.
⭐148Coroutine nedir? Hangi dilde doğrudan desteklenir?
Tanım: birden çok girişi olan ve bu girişleri kendisi yöneten subprogram. Lua'da doğrudan desteklenir. Diğer adı symmetric control — caller ve callee daha eşit bir temeldedir. Çağrısının adı resume'dur; ilk resume başa gider, sonraki çağrılar en son çalıştırılan deyimin hemen ardından girer. Yürütme interleaved but not overlapped — quasi-concurrent.

Lecture 8 · Implementing Subprograms (Ch.10)

⭐149Subprogram linkage nedir?
Bir dilin subprogram çağrı ve dönüş işlemlerine birlikte verilen ad.
⭐150Bir subprogram çağrısının genel semantiği hangi beş şeyi içerir?
(1) Parameter passing yöntemleri (2) Local değişkenlerin stack-dynamic ayrılması (3) Çağıranın execution status'unun saklanması (4) Kontrolün aktarılması ve dönüşün ayarlanması (5) Nesting varsa non-local değişkenlere erişimin ayarlanması.
⭐151Activation record ile activation record instance arasındaki fark nedir?
Activation record: çalışan bir subprogram'ın kod-olmayan kısmının biçimi/yerleşimi — bir şablon. ARI: bu biçimin somut bir örneği; belirli bir etkinleşmeye ait veri topluluğu.
⭐152Activation record'un biçimi ve boyutu hakkında ne söylenebilir?
Biçimi static'tir ama boyutu dynamic olabilir.
⭐153Dynamic link ve EP (Environment Pointer) neyi gösterir?
Dynamic link: caller'ın ARI'sının tepesini. EP: o an çalışan program biriminin ARI'sının tabanını; run-time sistem tarafından korunur.
154Recursive olmayan bir subprogram çağrısı da ARI yaratır mı?
Evet — 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.
⭐155Prologue ve epilogue eylemleri nelerdir?
Prologue (giriş): eski EP'yi stack'e dynamic link olarak sakla ve yeni değeri kur; local değişkenleri ayır.
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?
Belirli bir andaki stack'teki dynamic link'lerin topluluğu. Diğer adı call chain.
⭐157local_offset nedir ve ne zaman belirlenir?
Local değişkenlere activation record'un başlangıcına göre erişim offset'i. Derleyici tarafından derleme zamanında belirlenebilir. Erişim: adres = EP + local_offset.
158Hangi diller nested subprogram'a izin verir ve stack-dynamic local kullanır?
Fortran 95+, Ada, Python, JavaScript, Ruby, Swift — C tabanlı olmayan static-scoped diller.
⭐159Non-local bir referansı bulmanın iki adımı nedir, hangisi zordur?
(1) Doğru ARI'yı bulzor olan budur. (2) O ARI içindeki doğru offset'i belirle ← kolay. Birinci adımın işleyeceğini static semantics kuralları garanti eder.
⭐160Static link, static chain, static_depth ve chain_offset tanımlarını verin.
static link: A'nın ARI'sındaki link, A'nın static parent'ının ARI'larından birini gösterir. static chain: bir ARI'yı tüm static ancestor'larına bağlayan static link zinciri. static_depth: bir static 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.
⭐161Non-local referans için verimli ve verimsiz yöntemler nelerdir?
Verimsiz: ARI, static chain aranarak bulunur. Verimli: nesting derleme zamanında bilindiği için derleyici izlenecek zincir uzunluğunu önceden hesaplar. Referans (chain_offset, local_offset) çiftiyle temsil edilir.
⭐162Static chain'in iki problemi nedir?
(1) Nesting derinliği büyükse non-local referans yavaştır. (2) Zaman-kritik kod zordur: (a) non-local referansların maliyetini belirlemek zor; (b) kod değişiklikleri nesting derinliğini, dolayısıyla maliyeti değiştirebilir.
163Çağrı anında static link nasıl kurulur?
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/tanımları gibi ele al.
164Block nedir ve nasıl gerçeklenir?
Tanım: değişkenler için kullanıcının belirlediği local scope'lar. Blok içindeki değişkenin lifetime'ı kontrol bloğa girdiğinde başlar; avantajı aynı adlı başka değişkenle çakışmamasıdır.
İ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?
Deep access: non-local referanslar dynamic chain üzerindeki ARI'lar aranarak bulunur. Sorunları: zincirin uzunluğu statik olarak belirlenemez ve her ARI değişken adlarını taşımak zorundadır.
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?
Static-scoped + nested subprogram: static chain'ler başlıca yöntemdir. Dynamic-scoped: dynamic chain ya da bir merkezî değişken tablosu yöntemi.

Lecture 9 · ADTs & Encapsulation (Ch.11)

⭐167Abstraction nedir?
Bir varlığın, yalnızca en anlamlı özniteliklerini içeren bir görünümü / temsili.
⭐168Diller process ve data abstraction'ı ne zamandan beri destekler?
Neredeyse tüm diller process abstractionsubprogram'larla destekler. Neredeyse 1980'den beri tasarlanan tüm diller data abstraction'ı destekler.
⭐169Abstract data type'ın iki koşulu nedir?
(1) Tipin nesnelerinin temsili, bu nesneleri kullanan program birimlerinden gizlidir; tek mümkün işlemler tipin tanımında sağlananlardır. (2) Tipin bildirimi ve işlemlerin protokolleri tek bir sözdizimsel birimde bulunur; diğer birimler bu tipten değişken yaratabilir.
⭐170ADT'nin birinci koşulunun avantajları nelerdir?
Reliability — veri temsili gizlendiği için kullanıcı kodu ne doğrudan erişebilir ne de temsile bağımlı olabilir; böylece temsil, kullanıcı kodunu etkilemeden değiştirilebilir. Ayrıca programcının farkında olması gereken kod ve değişken aralığını azaltır ve isim çakışmaları daha az olasıdır.
⭐171ADT'nin ikinci koşulunun avantajları nelerdir?
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) mümkün olur.
172Bir dilin ADT desteği için sağlaması gereken üç şey nedir?
(1) Tip tanımını kapsülleyecek bir sözdizimsel birim. (2) Tip adlarını ve subprogram header'larını istemcilere görünür kılan ama asıl tanımları gizleyen bir yöntem. (3) Bazı ilkel işlemlerin dil işlemcisine gömülü olması.
173ADT'lerin üç tasarım sorusu nedir?
(1) Abstract tipler parametreleştirilebilir mi? (2) Hangi erişim denetimleri sunuluyor? (3) Tipin spesifikasyonu gerçeklemesinden fiziksel olarak ayrı mı?
⭐174C++'ın sınıf yapısının temeli nedir ve örnekler neyi paylaşır?
Temeli: C'nin 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?
Constructor: örneklerin veri üyelerini başlatırnesneyi yaratmaz; heap-dynamic kısım varsa depolama da ayırabilir; sınıf adıyla aynı adı taşır; örnek yaratılınca örtük çağrılır. Destructor: örnek yok edildikten sonra temizlik (genelde heap depolamasını geri kazanma); adı sınıf adı + önünde tilde (~); lifetime bitince örtük çağrılır. İkisi de açıkça çağrılabilir.
⭐176Java'nın destructor'ı var mıdır?
Hayır. Java'nın destructor'ı yoktur; garbage collector'ı vardır. Slaytta ayrı bir kutuda vurgulanmıştır.
⭐177C++'ta friend ne işe yarar?
Bazı ilgisiz birim veya fonksiyonlara private üyelere erişim vermek için. Slaytın notu: C++'ta gereklidir ("Necessary in C++").
⭐178Java'nın ADT desteğini C++'tan ayıran beş nokta nedir?
(1) Tüm kullanıcı tanımlı tipler sınıftır. (2) Tüm nesneler heap'ten ayrılır ve reference değişkenlerle erişilir. (3) Tek tek varlıkların access control modifier'ı vardır (C++'ta clause). (4) Tüm nesneler için örtük garbage collection. (5) İkinci bir scoping mekanizması: package scopefriend'in yerine kullanılabilir; access modifier'ı olmayan varlıklar paket boyunca görünürdür.
⭐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?
Inheritance'ı desteklemeyen hafif sınıflar. C#'ta ayrıca tüm sınıf örnekleri heap dynamic'tir ve tüm sınıflar için varsayılan constructor vardır.
⭐181C#'ın property'si hangi sorunu çözer?
Veri üyelerine erişim için accessor metot (getter/setter) yazma zorunluluğunu. Property'ler, getter ve setter'ı açık metot çağrısı gerektirmeden gerçeklemenin yoludur — kullanım alan erişimi gibi görünür ama arkada metot çalışır.
⭐182Ruby'de instance ve class değişkenleri nasıl adlandırılır? Constructor nedir?
Instance: tek @ 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?
Herhangi tipte eleman saklayabilen ADT tasarlamayı sağlar; diğer adı generic classes. Yalnızca statik tipli diller için bir sorundur. Destekleyenler: C++, Java 5.0, C# 2005.
⭐184Java 5.0'ın parameterized sınıflarının kısıtları nelerdir?
Generic parametreler sınıf olmak zorunda; generic koleksiyon sınıfları primitive saklayamaz; indexing desteklenmez. Faydaları: çıkarılan nesneleri cast etme ihtiyacını ve yapıda birden çok tip bulunma sorununu ortadan kaldırır.
185C# 2005'in parameterized sınıfları Java 5.0'dan nasıl ayrılır?
Wildcard sınıflar yoktur; Array, List, Stack, Queue, Dictionary için önceden tanımlıdır; parameterized yapıların elemanlarına indexing ile erişilebilir (Java'nın tersi).
⭐186Encapsulation neden gereklidir?
Büyük programların iki ihtiyacı: (1) subprogram'lara bölmenin ötesinde bir organizasyon yolu; (2) bir kısmi derleme yolu — programın tamamından küçük derleme birimleri. Çözüm: mantıksal olarak ilişkili subprogram'ları ayrı derlenebilen bir birimde gruplamak; bunlar genellikle kütüphanelere konur.
187Hangi diller nested subprogram'ı destekler?
Python, JavaScript, Ruby.
⭐188C'de encapsulation'ın iki problemi nedir?
Problem 1: linker, header ile gerçekleme arasındaki tipleri denetlemez. Problem 2: pointer'ların doğasındaki sorunlar.
⭐189C# assembly nedir?
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.
⭐190Naming encapsulation nedir ve dillerde nasıl gerçeklenir?
Tanım: isimler için yeni bir scope yaratmak üzere kullanılır; büyük programların çok sayıda global ismini mantıksal gruplara ayırır. C++/C#: namespace. Java: packagebir paketteki sınıflar kısmî friend'dir; istemciler tam nitelenmiş ad ya da import kullanır. Ruby: module.
⭐191Ruby module'lerinin kısıtları nelerdir?
Örneklenemez ve alt sınıflanamazlar; değişken tanımlayamazlar. Tipik olarak sabit ve metot topluluklarını kapsüller. Modülde tanımlı metotlar modülün adını içermelidir; içeriğe erişim require metoduyla istenir.
⭐193Process abstraction'ı destekleyen ilk dil hangisidir? Data abstraction'ın evrimi ne zaman başladı?
Process abstraction: Plankalkül, 1940'lar — dil tasarımındaki en eski soyutlamadır. Data abstraction: evrimi 1960'larda COBOL'un ilk sürümleriyle, record veri yapısı üzerinden başladı; 1980'lerde yaygınlaştı. (Hocanın slayta eklediği tarihsel zincir.)
⭐194Data abstraction'ın yaygınlaşması neden process abstraction'ınkini izlemek zorundaydı?
Çünkü her data abstraction'ın ayrılmaz ve zorunlu bir parçası onun işlemleridir, ve işlemler zaten process abstraction olarak tanımlanır. Yani önce "yapılacak şeyler", sonra "üzerinde iş yapılan şeyler" soyutlandı — mantıksal sıra budur.
⭐195"Bütün yerleşik (built-in) veri tipleri aslında ADT'dir" ne demektir? Floating point üzerinden açıklayın.
ADT kavramı yeni değildir — Fortran I'inkiler dahil tüm built-in tipler ADT'dir, sadece öyle adlandırılmazlar.
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?
Temsil gizli olduğu için, aynı dilin farklı gerçeklemeleri veriyi farklı biçimde temsil etse bile program taşınabilir kalır.
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?
Kuş = iki kanat, iki bacak, kuyruk, tüy (en anlamlı öznitelikler). "Karga bir kuştur" dedikten sonra karganın kanatlarını tarif etmeye gerek kalmaz — onlar kuş soyutlamasından gelir. Kargayı artık siyah, gürültücü gibi kendine özgü özniteliklerle tarif ederiz.
"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?
İç temsil değişimi istemciyi ETKİLEMEZ. Slaytın örneği: stack'in gerçeklemesi linked list'ten array'e çevrilirse yalnızca stack tipini tanımlayan kod değişir, istemcilerin hiçbirinde değişiklik gerekmez.
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?
Java'da 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?
(1) Abstract data types (= encapsulation) · (2) Inheritance · (3) Polymorphism (= dynamic binding). Slaytın notu: "Inheritance is the central theme in OOP and languages that support it." Summary bu üçlüyü parantezli verir — cevabında her iki adı da yaz.
⭐200ADT'lerle software reuse'un iki problemi nedir? Inheritance bunları nasıl çözer?
(1) ADT'ler zor yeniden kullanılır — her zaman değişiklik gerekir; değiştiren kişi eski kodu anlamak zorundadır ve genellikle asıl yazar değildir; değişiklik istemcileri de etkileyebilir. (2) Tüm ADT'ler bağımsız ve aynı düzeydedir — hiyerarşi kurulamaz, programı problem uzayına benzetmek zorlaşır. Inheritance yeni sınıfların var olanlar cinsinden tanımlanmasına izin vererek ikisini birden çözer.
⭐201Inheritance'ın dezavantajı nedir? Neden ironiktir?
Hiyerarşideki sınıflar arasında karşılıklı bağımlılık yaratır ve bakımı zorlaştırır. İroni: ADT'lerin en güçlü olumlu özelliği birbirinden bağımsız olmalarıydı — inheritance tam da bunu bozar. Reuse kazanılır, bağımsızlık kaybedilir.
⭐202Message ile message protocol nedir? Bir message'ın kaç parçası vardır?
Message = metot çağrısı. Message protocol (= message interface) = bir nesnenin tüm metotlarının topluluğu. Bir message'ın iki parçası vardır: metot adı ve hedef nesne.
⭐203Bir message ile bir subprogram çağrısı arasındaki fark nedir?
Subprogram: kendisine parametreyle geçirilen ya da non-local/global erişilen veriyi işler — veri dışarıdan gelir. Message: nesneye gönderilen bir metot çalıştırma isteğidir ve işlenecek 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."
⭐204Bir subclass, ebeveyninden hangi üç şekilde farklılaşabilir?
(1) Miras aldıklarına değişken ve/veya metot ekleyebilir. (2) Miras aldığı metotların davranışını değiştirebilir (override — aynı ad, çoğu zaman aynı protokol). (3) Parent, bazı değişken/metotlarını private tanımlayabilir; bunlar subclass'ta görünmez.
⭐205Class variable ile instance variable farkı nedir? Class method ne zaman çağrılabilir?
Class variable: one/class — sınıfa aittir, tek kopyası vardır. Instance variable: 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 ve sınıfın hiç örneği olmasa bile çağrılabilir; instance method nesnelere gönderilen mesajları kabul eder.
206Single ve multiple inheritance'ta sınıf ilişkileri nasıl gösterilir?
Single inheritance → derivation tree. Multiple inheritance → derivation graph. (Tam bir MC ayrımı.)
⭐207Polymorphic variable nedir? Dynamic binding ne zaman devreye girer?
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. Hiyerarşi metot override eden sınıflar içeriyorsa ve bu metotlar polymorphic değişken üzerinden çağrılıyorsa bağlama dinamik olur. Faydası: yazılım sistemleri hem geliştirme hem bakım sırasında daha kolay genişletilir.
⭐208Abstract method ve abstract class nedir? Hangi kural kesindir?
Abstract method: tanım (gövde) içermeyen, yalnızca bir protokol tanımlayan metot. Abstract class: en az bir virtual/abstract metot içeren sınıf. Kesin kural: abstract class örneklenemez.
⭐209OOP dilleri için yedi tasarım sorusu nedir?
(1) Exclusivity of objects · (2) Are subclasses subtypes? · (3) Single ve multiple inheritance · (4) Object allocation ve deallocation · (5) Dynamic ve static binding · (6) Nested classes · (7) Initialization of objects. Bölümün iskeleti — liste sorusu olarak gelebilir.
⭐210Exclusivity of objects için üç yaklaşım ve avantaj/dezavantajları nedir?
(1) Her şey nesne: + zarafet ve saflık; − basit nesnelerde yavaş işlemler (her şey message passing ile). (2) Tam tip sistemine nesne eklemek: + basit nesnelerde hızlı işlemler; − kafa karıştırıcı tip sistemi (iki tür varlık). (3) Primitive'ler imperatif, gerisi nesne: + hızlı işlemler ve görece küçük tip sistemi; − iki tip sistemi yüzünden hâlâ karışıklık. Hocanın notu: bu karışıklığa zarif bir çözüm yoktur.
⭐⭐211Subclass ile subtype arasındaki fark nedir? "Principle of substitution" nedir?
Substitution ilkesi: 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. Subtype: ebeveyniyle is-a ilişkisi taşıyan türetilmiş sınıf; yalnızca ekleyebilir ve miras metotları uyumlu biçimde override edebilir. Tanım, parent'ta public olan bir varlığın subclass'ta public olmamasını yasaklar. Altın cümle: "Subclasses inherit implementation; subtypes inherit interface and behavior." Sonuç: her subclass subtype değildir, her subtype subclass değildir.
⭐⭐212Multiple inheritance'ın iki dezavantajı ve avantajı nedir? Diamond problemi nedir?
Dezavantajlar: (1) dil ve gerçekleme karmaşıklığı (kısmen isim çakışmaları yüzünden); (2) potansiyel verimsizlik — dynamic binding daha pahalıya gelir ("but not much"). Avantaj: "sometimes it is quite convenient and valuable." Diamond: BC → D1, D2 → Z; x Z'ye iki kez gelir. Çözüm: class D1 : public virtual BCx bir kez gelir.
⭐213Object slicing nedir ve ne zaman ortaya çıkar?
Nesneler stack dynamic olduğunda ve subtype'larla birlikte kullanıldığında çıkar: bir subclass nesnesi parent tipinde ayrılmış bir yere kopyalanınca subclass'a özgü fazlalık veri kesilir/budanır (truncation). C++ örneği: 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?
Motivasyon: information hiding — bir sınıfa yalnızca tek bir sınıf ihtiyaç duyuyorsa onu herkesin göreceği biçimde tanımlamak için neden yoktur. 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?
⭐215Smalltalk'ta inheritance ve dynamic binding nasıl çalışır?
Inheritance: subclass, superclass'ın tüm instance değişken, instance metot ve class metotlarını miras alır; tüm subclass'lar subtype'tır — çünkü hiçbir şey gizlenemez; tüm inheritance implementation inheritance'tır; multiple inheritance yoktur. Dynamic binding: tüm bağlamalar dinamiktir; metot önce nesnede aranır, bulunamazsa superclass'ta, en üstte superclass'ı olmayan system class'a kadar. Tek tip denetimi dynamic'tir ve tek tip hatası, bir nesneye eşleşen metodu olmayan bir mesaj gönderilmesidir.
⭐216Smalltalk'ın değerlendirmesi (avantaj/dezavantaj) nedir?
+ Sözdizimi basit ve düzenli; küçük bir dilin gücünün iyi örneği; GUI'yi tanıttı (pencere, fare, menüler); en büyük etkisi OOP'nin ilerlemesi. Geleneksel derlenen imperatif dillere göre yavaş (C++'tan ~10 kat); dynamic binding tip hatalarının çalışma zamanına kadar fark edilmemesine yol açar. Tasarımcıları verimlilik yerine zarafeti seçtiler — bu yüzden endüstride yaygınlaşmadı.
⭐217C++'ta private derivation ile public derivation farkı nedir? Private derivation neden kullanılır?
Private derivation: miras alınan public ve protected üyeler subclass'ta private olur. Public derivation: public ve protected üyeler public ve protected kalır. Motivasyon: bir sınıf görünmesi zorunlu üyeler sunar (public tanımlanmışlardır); türetilmiş sınıf yeni üyeler ekler ama kendi istemcilerinin parent'ın üyelerini görmesini istemez. Gerekirse scope resolution (::) ile tek tek yeniden görünür kılınabilir (reexportation).
⭐⭐218C++'ta virtual ve pure virtual ne demektir?
virtual: metot polymorphic değişkenler üzerinden çağrılabilir ve dinamik bağlanır. Pure virtual: hiç tanımı yoktur — sözdizimi 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ı)?
C++ kapsamlı erişim denetimleri sunar (Smalltalk sunmaz); multiple inheritance sunar; programcı tasarım zamanında hangi metotların static hangilerinin dynamic bağlanacağına kendisi karar vermek zorundadırstatic binding daha hızlıdır. Smalltalk'ın tip denetimi dynamic'tir: esnek ama bir miktar güvensiz; ve Smalltalk C++'tan ~10 kat yavaştır.
⭐⭐220Java'da hangi metotlar statik bağlanır?
Java'da tüm mesajlar dinamik bağlanır — üç istisna: 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?
Avantaj: sınıfta hiçbir değişikliğe izin verilmez (kararlılık/güvenlik). Dezavantaj: küçük değişiklik gerektiren yeniden kullanımları da engeller. Ek bilgi: final sınıftaki tüm metotlar örtük olarak final'dır, dolayısıyla hepsi statik bağlanır.
⭐⭐222Interface ile abstract class arasındaki farklar nelerdir?
Kod: interface hiç kod veremez (Java 8'den beri 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?
Inner (non-static): nesting class'ın üyelerine (private dahil) erişebilir — çünkü her örneği, ait olduğu nesting class örneğine açık bir pointer taşır; örneklenmesi için önce dış sınıf örneklenmelidir (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?
Java'da bir primitive değerin, wrapper sınıfının nesnesine örtük olarak dönüştürülmesi (intInteger). 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?
Kararlar C++'a 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 "normal" bağlama yoludur; multiple inheritance için interface'lerle basit bir destek sağlar.
⭐226C#'ta dynamic binding nasıl sağlanır? new ile override farkı nedir?
İki taraf da işaretlenmelidir: base metot 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?
struct: daha az güçlü, stack-dynamic yapılar; inheritance'ları yoktur. Nested class: 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. Ayrıca C#'ta single inheritance vardır ve parent'ın hiçbir üyesi private değilse subclass'lar subtype'tır.
⭐228Ruby'nin OOP desteğini ayırt eden özellikler nelerdir?
Sınıf tanımları çalıştırılabilirdir ve yürütme sırasında açık kalır → var olan tanıma ikincil tanımlarla üye eklenebilir; 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 → program, 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?
(1) Abstract class'ları desteklemez. (2) Multiple inheritance'ı tam desteklemez. (3) Erişim denetimleri, OOP destekleyen diğer dillerinkinden zayıftır. Ayrıca subclass'ları zorunlu olarak subtype değildir — Smalltalk'ın tam tersi.
⭐230Class instance record (CIR) nedir? Neden erişim verimlidir?
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. CIR static olduğu için tüm instance değişkenlerine erişim record'lardaki gibi yapılır → verimli.
⭐⭐231vtable nedir ve nasıl çalışır?
Statik bağlanan metotların CIR'da yer alması gerekmez; dinamik bağlanacakların girdisi olmak zorundadır. Çağrılar CIR'daki bir pointer üzerinden koda bağlanır; bu depolama yapısına virtual method table (vtable) denir ve çağrılar vtable'ın başına göre offset olarak temsil edilebilir. Bir ata sınıfın polymorphic değişkenleri her zaman doğru tipteki nesnenin CIR'ını gösterir.
Örnek (A → B extends A, draw override edilmiş): B'nin vtable'ında drawB'nin kendi kodu, areaA'nın kodu (override edilmedi), sift → B'nin kodu.
⭐232Beş dili saflık, multiple inheritance ve binding varsayılanı açısından sırala.
Smalltalk: saf OOP · MI yok · tamamen dynamic · tüm subclass'lar subtype · nested class yok.
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.
<sözlük> ::= { <terim> <açıklama> } /* metindeki ° işaretleri buraya gelir */

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 #include ve #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 — length bile 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: sum ve total lexeme'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ğersizlik null, Swift'te nil.
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 + nil olan 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 interface kavramı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 virtual ile 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 default hariç), 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 (intInteger). 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.