5. Yapı, sınıf ve sayılabilir
Kendi türlerinizi tanımlamanın üç yolu: veri kümesi için yapi, davranışı
olan nesne için sinif, kapalı değer kümesi için sayilabilir.
yapi — ilgili verileri bir arada tutmak
yapi Urun:
ad = ""
fiyat = 0
fonksiyon etiket():
don ad + " — " + metin(fiyat) + " TL"
k = Urun()
k.ad = "Klavye"
k.fiyat = 750
dogrula(k.etiket() == "Klavye — 750 TL", "yapı metodu")
yazdir(k.etiket())Alanlara varsayılan değer verirsiniz; tür bu değerden anlaşılır.
Yapı metotları alanlara çıplak adıyla erişir (ad, fiyat).
Alanları kurarken sırayla da verebilirsiniz:
yapi Nokta:
x = 0
y = 0
fonksiyon uzunluk_kare():
don x * x + y * y
n = Nokta(3, 4) # alan sırasına göre
dogrula(n.x == 3 ve n.y == 4, "sıralı kurma")
dogrula(n.uzunluk_kare() == 25, "metot")
yazdir("yapı tamam")sinif — selfli metotlar ve kurucu
sinif, yapi ile aynı üretim yolunu paylaşır; farkı metotların self
alabilmesi ve bir kurucu tanımlanabilmesidir.
sinif Sayac:
deger = 0
fonksiyon kur(self, baslangic): # KURUCU
self.deger = baslangic
fonksiyon artir(self):
self.deger = self.deger + 1
fonksiyon oku(self):
don self.deger
s = Sayac(10) # kur(...) çağrılır
s.artir()
s.artir()
dogrula(s.oku() == 12, "sınıf kurucu + metot")
yazdir(f"sayaç: {s.oku()}")Kurallar — üçü de ölçülmüştür:
- Kurucunun adı
kurdur ve ilk parametresiselfolmalıdır.fonksiyon kur()(self'siz) sıradan bir metottur, kurucu değildir. selfrezerve bir sözcük değildir:self = 5yazan eski kodunuz çalışmaya devam eder. Tanıma bağlamsaldır — yalnız bir sınıf/yapı gövdesindeki fonksiyonun ilk parametresi olduğundaselfanlamına gelir.- ⚠️ Kurucuya
baslatadı verilemezdi:baslateşzamanlılıkta rezerve bir anahtar sözcüktür (7. sayfa). Ölçülen bugünkü durum:fonksiyon baslat(self):yazımı derlenir — ama o bir kurucu DEĞİL, sıradan bir metottur ve dilin yeni ön yüzü (tip denetimi) onu reddeder. Metodabaslatadını vermeyin.
sayilabilir — kapalı değer kümesi
Bir değişkenin alabileceği değerler sayılıysa (durum, kip, tür) sayilabilir
kullanın. Kapalı olduğu için derleyici yanlış üyeyi yakalayabilir.
sayilabilir Durum:
BEKLIYOR = 0
CALISIYOR # değer yazılmazsa bir öncekinden devam eder
BITTI = 9
d = Durum.CALISIYOR
eger d == Durum.CALISIYOR:
yazdir("çalışıyor")
degilse:
yazdir("başka durum")Sayılabilir bir yapı alanı ya da liste öğesi de olabilir:
sayilabilir Tur:
kedi
kopek
yapi Hayvan:
tur = Tur.kedi # tipi varsayılandan: Tur
ad = ""
h = Hayvan(Tur.kopek, "Karabaş")
dogrula(h.tur == Tur.kopek, "sayılabilir alan")
turler = [Tur.kedi, Tur.kopek]
dogrula(turler[1] == Tur.kopek, "sayılabilir listesi")
yazdir(turler) # [kedi, kopek]⚠️ Sözlük değerleri dinamiktir ve sayılabilir tutamaz
({"a": Tur.kedi} derleme hatasıdır, SOZLUKTE_SAYILABILIR). Metnini
saklayın (metin(Tur.kedi)) ya da değeri bir yapı alanında tutun.
⚠️ Kendi türünüze çalışma anının kullandığı bir ad veremezsiniz: Hata,
Konum, Deger, Liste, Metin, Sonuc, Kanal, Gorev ve birkaç
benzeri ayrılmıştır (AYRILMIS_TUR_ADI). HataKaydi, KonumBilgisi gibi
bir ad seçin.
Tanımsız üye derleme hatasıdır — kapalılığın anlamı budur:
sayilabilir Renk:
KIRMIZI
MAVI
r = Renk.MORKendi yazımı — fonksiyon metin(self) -> metin
Yapı metin(self) metodu tanımlarsa metin(x), yazdir(x), f-metin
(f"{x}") ve liste yazımı onu kullanır (yoksa otomatik Nokta(x: 1, y: 2)):
yapi Nokta:
x = 0
y = 0
fonksiyon metin(self) -> metin:
don "(" + metin(self.x) + ", " + metin(self.y) + ")"
p = Nokta(1, 2)
dogrula(f"{p}" == "(1, 2)", "f-metin")
dogrula(metin([p]) == "[(1, 2)]", "liste yazımı")metin metodu yalnız self alır ve metin döndürür (YAZIM_METODU).
Hesaplanan özellik — alan: tip => ifade
Yapı gövdesinde => ile yazılan alan saklanmaz, her okunuşta alanlardan
hesaplanır (parantezsiz okunur, salt okunurdur, OZELLIK_SALT_OKUNUR):
yapi Dikdortgen:
en = 0
boy = 0
alan: sayi => en * boy
kare_mi: mantik => en == boy
d = Dikdortgen(3, 4)
dogrula(d.alan == 12, "hesaplanan")
d.en = 4
dogrula(d.alan == 16 ve d.kare_mi, "alan değişince yeniden hesaplanır")genislet — var olan türe metot eklemek
Yerleşik türe (metin, liste, sozluk, sayi, ondalik, mantik) ya da
kendi yapınıza sonradan metot eklenir. Var olan bir metodu gölgeleyemez
(GENISLET_GOLGE); çağrı statiktir (ek maliyet yok):
genislet metin:
fonksiyon bas_harf_buyuk(self) -> metin:
eger self.uzunluk() == 0:
don self
don self.dilim(0, 1).buyut() + self.dilim(1, self.uzunluk() - 1)
dogrula("ankara".bas_harf_buyuk() == "Ankara", "genislet")genislet gövdesinde yalnız fonksiyon ad(self, …) yazılır. genislet ve
esles bağlamsaldır: değişken adı olarak kullanmaya devam edebilirsiniz.
Değer taşıyan üyeler (toplam tür)
Bir üye parantez içinde ilişkili değer taşıyabilir. Üye, türün adıyla
kurulur; kendi türünü içeren alan (özyineleme) derleyicide kendiliğinden
kutulanır — kullanıcıya düz değer gibi görünür, kopyalanır, == ile
karşılaştırılır, yazdir Uye(değerler) biçiminde basar:
sayilabilir Ifade:
Sayi(deger: sayi)
Ad(ad: metin)
Ikili(islec: metin, sol: Ifade, sag: Ifade)
Bos
e = Ifade.Ikili("+", Ifade.Sayi(1), Ifade.Ad("x"))
yazdir(e) # Ikili(+, Sayi(1), Ad(x))
dogrula(Ifade.Sayi(3) == Ifade.Sayi(3), "değer eşitliği")Değer taşıyan üye ile = sayı değerli üye aynı türde karışamaz. Değerler
yalnız esles ile açılır.
esles — desen eşleme
Konuyu sırayla kolların desenleriyle karşılaştırır, ilk tutan kolun gövdesini
koşar. Sayilabilir, belki, sonuc ve mantik üzerinde bütün durumlar ele
alınmak zorundadır (yeni üye eklenince unutulan kol derleme hatasıdır,
ESLES_EKSIK); sayi/metin üzerinde _ kolu zorunludur.
sayilabilir Ifade:
Sayi(deger: sayi)
Ikili(islec: metin, sol: Ifade, sag: Ifade)
Bos
fonksiyon hesapla(e: Ifade) -> sayi:
esles e:
Sayi(d):
don d
Ikili("+", a, b): # sabit alt desen
don hesapla(a) + hesapla(b)
Ikili(op, _, _) eger op == "*": # koşullu kol
don 0
Ikili(_, _, _), Bos: # birden çok desen
don -1
don 0
dogrula(hesapla(Ifade.Ikili("+", Ifade.Sayi(2), Ifade.Sayi(3))) == 5, "esles")
fonksiyon durum(kod: sayi) -> metin:
esles kod:
200, 204:
don "tamam"
400..499: # aralık (dahil); 500..<600 hariç
don "istemci hatası"
_:
don "diğer"
don ""
dogrula(durum(404) == "istemci hatası", "aralık deseni")belki için dolu(x) / bos, sonuc için tamam(x) / hata(h) desenleri
yazılır. Birden çok desenli kolda ad bağlanamaz; _ kolundan sonra kol
yazılamaz (ESLES_ULASILMAZ). Kollar aynı değer üzerinde karşılaştırma zinciri
olarak üretilir; LLVM bunu switche (yoğunsa atlama tablosuna) çevirir.
arayuz — ortak davranış (statik gönderim)
arayuz uygulayan yapıların yazması gereken metotları (gövdesiz imza) ve
isteğe bağlı varsayılan metotları (gövdeli) tanımlar. Yapı arayüzü taban
yazımıyla bildirir; yazmadığı varsayılan metot kendisine kopyalanır, gövdesiz
imzayı yazmazsa derleme hatasıdır (ARAYUZ_EKSIK):
arayuz Sekil:
fonksiyon alan(self) -> ondalik
fonksiyon tanim(self) -> metin: # varsayılan
don "alan=" + metin(self.alan())
yapi Kare(Sekil):
kenar = 0.0
fonksiyon alan(self) -> ondalik:
don self.kenar * self.kenar
dogrula(Kare(2.0).tanim() == "alan=4.0", "varsayılan metot")Gönderim yalnız statiktir: liste<Sekil> gibi karışık türlü kap (sanal
gönderim) yoktur; ortak kodu jenerik işlevle yazın.
Jenerik — fonksiyon f<T: Arayuz>(…), yapi Yigin<T>:
Tip parametresi argümanlardan çıkarılır, her somut tip için ayrı kod üretilir
(tek biçimleme: çağrı doğrudan, ek maliyet yok). T: Arayuz kısıtı tipin o
arayüze uymasını ister:
arayuz Adli:
fonksiyon ad(self) -> metin
yapi Kedi(Adli):
isim = ""
fonksiyon ad(self) -> metin:
don "kedi " + self.isim
fonksiyon selam<T: Adli>(x: T) -> metin:
don "merhaba " + x.ad()
fonksiyon en_buyuk<T>(l: liste<T>) -> belki<T>:
eger l.uzunluk() == 0:
don bos
en = l[0]
dongu x icinde l:
eger x > en:
en = x
don dolu(en)
yapi Yigin<T>:
ogeler: liste<T> = []
fonksiyon it(self, x: T):
self.ogeler.ekle(x)
dogrula(selam(Kedi("tekir")) == "merhaba kedi tekir", "kısıtlı jenerik")
dogrula(en_buyuk([3, 9, 2]).deger_veya(0) == 9, "sayı listesi")
dogrula(en_buyuk(["a", "c", "b"]).deger_veya("") == "c", "metin listesi")
y = Yigin<sayi>()
y.it(5)
dogrula(y.ogeler == [5], "jenerik yapı")Jenerik yapı tip argümanıyla kurulur (Yigin<sayi>()); her tip parametresi
bir parametrenin tipinde geçmelidir (çıkarılamazsa derleme hatası).
Bugün olmayan: dekoratör (@property, @staticmethod)
Python'dan gelen kodda sık görülen @dekorator yazımı KabaLang'da yoktur.
Yazdığınızda anlaşılmaz bir hata değil, özelliğin adını ve bugün çalışan yolu
söyleyen bir teşhis alırsınız:
yapi Kisi:
ad = "Ali"
@property
fonksiyon etiket(self):
don self.ad
k = Kisi()
yazdir(k.etiket)⚠️ Bu yazımın eklenmemesi bir ölçüme dayanır, unutulmuş değil. Kcode'un
43 dosyası / 29.873 satırı tarandığında 27 dekoratör kullanımı bulundu ve
hepsi @staticmethod (13), @property (7), @<ad>.setter (3),
@classmethod (2), @dataclass (2) idi — fonksiyonu saran, kullanıcının
kendi yazdığı dekoratör sayısı 0. Yani beşinin de bugün çalışan bir
karşılığı var; genel bir "dekoratör protokolü" kimsenin işine yaramazdı.
| Python | KabaLang'da bugün | Nasıl |
|---|---|---|
@property |
metodu metot olarak çağırın | fonksiyon etiket(self) → k.etiket() |
@<ad>.setter |
alana doğrudan atayın | k.ad = "Ayşe" |
@staticmethod |
selfi hiç yazmayın |
fonksiyon varsayilan() → k.varsayilan() |
@classmethod |
modül düzeyinde üreteç fonksiyon | fonksiyon kisi_metinden(m) -> Kisi |
@dataclass |
gerek yok, yapi zaten öyle |
kurucu + == + yazdırma kendiliğinden |
Beşinin karşılığı tek programda:
yapi Kisi:
ad = "Ali"
# @property yerine: sıradan metot, çağrıda parantez var
fonksiyon etiket(self):
don "Sn. " + self.ad
# @staticmethod yerine: ilk parametre `self` DEĞİL
fonksiyon varsayilan():
don "isimsiz"
# @classmethod yerine: yapıyı kuran ve döndüren modül fonksiyonu
fonksiyon kisi_metinden(m: metin) -> Kisi:
don Kisi(m)
k = Kisi()
dogrula(k.etiket() == "Sn. Ali", "property yerine metot")
dogrula(k.varsayilan() == "isimsiz", "staticmethod yerine self'siz metot")
# @<ad>.setter yerine: alana doğrudan atama
k.ad = "Ayşe"
dogrula(k.ad == "Ayşe", "setter yerine doğrudan atama")
# @dataclass yerine: `yapi` kurucusu ve `==` zaten üretiliyor
dogrula(k == Kisi("Ayşe"), "dataclass yerine yapı eşitliği")
dogrula(kisi_metinden("Veli").ad == "Veli", "classmethod yerine üreteç")
yazdir("beş dekoratörün de karşılığı çalışıyor")⚠️ İki tuzak ölçüldü, ikisi de dekoratörden bağımsız ama porta çarpar:
selfsiz metot bir örnek üzerinden çağrılır.k.varsayilan()çalışır;Kisi.varsayilan()çalışmaz (tip adı üzerinden çağrı yok). Örneğe hiç ihtiyacınız yoksa metoduyapidışına, sıradan birfonksiyonolarak yazın.yapimetoduna dönüş tipi yazılabilir (fonksiyon etiket() -> metin:,-> sonuc<sayi, Hata>,-> hic). (2026-09-30'a kadar bu yazım metodu sessizce düşürüyordu; artık çalışıyor.) Tipsiz alan döndüren metot (don ad) alanın o anki türünü denetler:-> sayimetodu bir metin alanı döndürmeye kalkarsa konumlu bir çalışma hatası alırsınız.- Yapı metodu dosya düzeyinden şunları görür: yalnız bir kez sabit bir
değerle atanan değerler (
oran = 3), dosya düzeyindeki değişen bir değere ya da bir yapıya dokunmayan işlevler, sayılabilirler ve diğer yapılar. ⚠️ Değişen ya da hesaplanan bir dosya düzeyi değeri (veya ona dokunan bir işlevi) kullanırsa derleyiciYAPI_UST_DUZEY_ADhatası verir: değeri metoda parametre olarak geçin, alan yapın ya da işlevi metot yapın.
Kalıtım — sinif Turev(Temel):
Bir sınıf başka bir sınıfın alanlarını ve metotlarını devralabilir. Taban sınıfın adı, tanımlanan adın ardından parantez içinde yazılır:
sinif Varlik:
ad = "?"
can = 100
fonksiyon kur(self, ad_, can_):
self.ad = ad_
self.can = can_
fonksiyon tur(self):
don "Varlik"
fonksiyon tanim(self):
don self.ad + "/" + metin(self.can)
sinif Canli(Varlik): # Varlik'tan kalıtır
hiz = 5
fonksiyon kur(self, ad_, can_, hiz_):
ust.kur(ad_, can_) # ÜST SINIFIN KURUCUSU — ilk satır
self.hiz = hiz_
fonksiyon tur(self): # GEÇERSİZ KILMA
don "Canli"
c = Canli("kurt", 80, 12)
dogrula(c.ad == "kurt", "taban sınıfın alanı")
dogrula(c.hiz == 12, "kendi alanı")
dogrula(c.tanim() == "kurt/80", "devralınan metot")
dogrula(c.tur() == "Canli", "geçersiz kılma")
yazdir(c.tanim())Kalıtım çok düzeyli olabilir ve ust.<metot>() ile üst sınıfın
kendi sürümü çağrılabilir:
sinif Tas:
agirlik = 1
fonksiyon tur(self):
don "Tas"
sinif Mermer(Tas):
parlaklik = 5
fonksiyon tur(self):
don "Mermer<" + ust.tur() + ">"
sinif Oniks(Mermer):
fonksiyon tur(self):
don "Oniks<" + ust.tur() + ">"
o = Oniks()
dogrula(o.agirlik == 1, "üç basamak yukarıdaki alan")
dogrula(o.tur() == "Oniks<Mermer<Tas>>", "ust zinciri")
yazdir(o.tur())yapi da kalıtabilir. Sıralı kurucu taban alanlarını da kapsar
(taban alanları önce gelir):
yapi Nokta:
x = 0
y = 0
fonksiyon uzunluk_kare():
don x * x + y * y
yapi Nokta3(Nokta):
z = 0
fonksiyon hacim():
don x * y * z
n = Nokta3(1, 2, 3) # x, y TABANDAN · z kendi
dogrula(n.x == 1 ve n.y == 2 ve n.z == 3, "sıralı kurucu taban alanlarını da alır")
dogrula(n.uzunluk_kare() == 5, "devralınan metot")
dogrula(n.hacim() == 6, "kendi metodu taban alanlarını görür")
yazdir("hacim: " + metin(n.hacim()))Kurallar — hepsi ölçülmüştür
- Sözdizimi parantezdir,
sinif Turev: TemelDEĞİL. Nedeni:in dilde iki işi olması: blok açmak (sinif X:) ve tip bildirmek (sayac: sayi). Parantez ise zaten "bu bildirime ait virgüllü liste" demektir (fonksiyon f(a, b):). ust.kur(...)kurucunun İLK satırı olmalıdır. Taban sınıf her hâlde gövdeden önce kurulur; ortada yazılsa okuduğunuz sıra ile çalışan sıra ayrışırdı.- Geçersiz kılma STATİKTİR.
turev.metot()türevin sürümünü çağırır. Ama taban sınıfın bir metoduself.metot()derse TABANIN sürümü çağrılır — türevin değil. Derleyici tam bu durumda uyarır (KALITIM_STATIK). Nedeni aşağıda. - Taban sınıf bir KabaLang yapısı olmalıdır. Arayüz bileşenleri gibi dilin hazır türleri taban olarak kullanılamaz.
- Taban sınıf
kurtanımlıyorsa, alanı olan türev dekuryazıpust.kur(...)çağırmalıdır — yoksa türev tabanı nasıl kuracağını bilemez ve derleyici bunu söyler. - Kendi alanı ve
kuru olmayan bir türev, tabanın kurucusunu devralır (Oniks()yukarıda böyle çalışıyor). - Eşitlik ve
metin(nesne)taban alanlarını da kapsar: yapı bir değer kümesidir, taban alanı da o kümenin parçasıdır. ustrezerve bir sözcük DEĞİLDİR.ust = 5yazan kodunuz çalışmaya devam eder. Yapınızınustadında bir alanı varsa alan kazanır ve üst sınıfa o adla erişilemez (derleyici bunu söyler).self.ust.xgibi bir üye erişimi de hiçbir zaman üst sınıf çağrısı sayılmaz — üst sınıf çağrısı her zaman çıplakusttur.
Bugün olmayan: çok kalıtım, soyut metot, çokbiçimli gönderim
⚠️ Üçü de henüz yoktur ve derleyici her biri için ne yapacağınızı açıkça söyler (anlaşılmaz bir hata vermez):
| Yazım | Neden yok | Bugünkü yol |
|---|---|---|
sinif D(A, B): |
ÖLÇÜLDÜ: Kcode'un 181 sınıfından 0'ı çok kalıtım kullanıyor | TEK taban yazın; ikinci tabanı bir alan yapın |
soyut metot / arayuz |
ÖLÇÜLDÜ: Kcode'da ABC/abstractmethod kullanan sınıf 0 |
taban metodu gövdesiyle yazın; "yapılmadı" için firlat |
| taban tipli yuvadan türevin metodunu çağırmak | dilin ikili uyumluluk (ABI) kararına bağlı; v1.1'e bırakıldı | değişkeni türev tipiyle tutun; tür ayrımı için sayilabilir alan + eger |
Sanal gönderimin neden bugün olmadığı da bilinçli bir karardır: her nesneye fazladan bir alan ekler ve küçük yapıların değer olarak taşınma kuralını etkiler. Bu yüzden dilin ikili uyumluluk kararıyla birlikte ele alınacak.
Paylaşılan nesne — sayilan<T>
yapi/sinif değeri atamada ve işleve geçerken kopyalanır. Aynı nesneyi
birden çok yerden görmek (ağaç, çizge, gözlemci) için sayilan<T> kullanın;
geri yönü zayif<T> yapıp döngü kurmayın:
sinif Hesap:
bakiye = 0
fonksiyon yatir(self, n):
self.bakiye = self.bakiye + n
h = sayilan(Hesap())
ortak = h # aynı nesne, kopya değil
ortak.yatir(50)
dogrula(h.bakiye == 50, "sayilan<T> paylaşılır")Ayrıntı (zayif<T>, .al(), arena, döngü uyarısı):
14. sayfa, Bellek modeli.