KABAFORCEGeliştirici KabaOS'u edinin
Önizleme · 0.6.0 — dil 1.0 öncesidir; sözdizimi ve kütüphane değişebilir. Buradaki her örnek derlenerek sınanır.

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

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

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

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

  1. Kurucunun adı kurdur ve ilk parametresi self olmalıdır. fonksiyon kur() (self'siz) sıradan bir metottur, kurucu değildir.
  2. self rezerve bir sözcük değildir: self = 5 yazan eski kodunuz çalışmaya devam eder. Tanıma bağlamsaldır — yalnız bir sınıf/yapı gövdesindeki fonksiyonun ilk parametresi olduğunda self anlamına gelir.
  3. ⚠️ Kurucuya baslat adı verilemezdi: baslat eş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. Metoda baslat adı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.

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

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

Derlenmez
sayilabilir Renk:
    KIRMIZI
    MAVI

r = Renk.MOR

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

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

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

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

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

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

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

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

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

KabaLang
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 metodu yapi dışına, sıradan bir fonksiyon olarak yazın.
  • yapi metoduna 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: -> sayi metodu 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 derleyici YAPI_UST_DUZEY_AD hatası 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:

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

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

KabaLang
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

  1. Sözdizimi parantezdir, sinif Turev: Temel DEĞİ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):).
  2. 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ı.
  3. 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 metodu self.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.
  4. 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.
  5. Taban sınıf kur tanımlıyorsa, alanı olan türev de kur yazıp ust.kur(...) çağırmalıdır — yoksa türev tabanı nasıl kuracağını bilemez ve derleyici bunu söyler.
  6. Kendi alanı ve kuru olmayan bir türev, tabanın kurucusunu devralır (Oniks() yukarıda böyle çalışıyor).
  7. 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.
  8. ust rezerve bir sözcük DEĞİLDİR. ust = 5 yazan kodunuz çalışmaya devam eder. Yapınızın ust adında bir alanı varsa alan kazanır ve üst sınıfa o adla erişilemez (derleyici bunu söyler). self.ust.x gibi 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 çıplak usttur.

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:

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

Sonraki adım

6. Hata yönetimi