- Lone Lisp,
libcolmadan doğrudan Linux sistem çağrıları üzerinde çalışan bir Lisp; Matheus Moreira bunu, yalnızca freestanding C ile eksiksiz bir dil ve kullanıcı alanı programı oluşturmanın mümkün olup olmadığını görmek için başlattı - Kararlı Linux kullanıcı alanı ABI’sini doğrudan kullanarak
errno, yerel ayar, örtük dosya tamponlama gibi C kütüphanesinin küresel durumlarını ve eski API’lerini ortadan kaldırıyor; çalışma zamanı, bellek ayırıcısı ve test araçlarını kendisi uyguluyor - FEXPR ve uygun kuyruk çağrısı optimizasyonunun yanı sıra üreteçler, sınırlandırılmış devamlar ve devam ettirilebilir hata işleme destekleniyor; vektörler, tablolar ve devamlar da aynı fonksiyon çağrısı biçimiyle ele alınıyor
- Başlangıcı hızlı olsa da geçici benchmark’larda Python’dan 10–100 kat yavaş liste düzeyinde bir yorumlayıcı; C yorumlayıcısını bootstrap ölçütü olarak bırakıp uzun vadede Lone’un kendi içinde bir JIT derleyici uygulamayı planlıyor
- Moreira, Claude’u kod inceleme ve proje yönetiminde kullanıyor; ancak Lone kodunu bizzat yazıp inceliyor ve statik site üretici, shell ve yardımcı araçlar geliştirerek geleneksel Linux kullanıcı alanını yeniden inşa etmeyi amaçlıyor
Oyunlardan C++, Ruby ve Lisp’e
- Programlamaya ilgi duymasının nedeni Mega Man Battle Network oldu; ilgili forumlarda iletişim kurmak için İngilizce öğrendi ve ilk dili olan C++’ı da öğrendi
- Brezilya’daki bir teknik lisede 13–14 yaşlarında bilişim programına başladı
- Dev-C++ ve cplusplus.com eğitimlerini kullandı
- 6 ay içinde okul müfredatının tamamını öğrendikten sonra diğer öğrencilere yardımcı olan asistan olarak işe alındı
- Oyun yapmayı da denedi, ancak gerekli fizik bilgisi eksik olduğu için başarılı olamadı
- C++’tan sonra Java, Ruby ve Python’dan geçerek Lisp ve Scheme ile tanıştı; Scheme’in dilsel zarafetine kapıldı
- Sun’ın Java eğitimlerinin neredeyse tamamını okuyarak nesne yönelimli programlamayı öğrendi
- Java Swing ve Nimbus tasarımını sevdiği için bir matematik profesörü için çember ve yay çizme uygulaması da yaptı
- Ruby’de, Git tarzı komut tabanlı argüman ayrıştırıcısı Acclaim dahil olmak üzere gem’ler yazdı
- Birçok dili keşfetmesini başta okul projeleri tetikledi; sonrasında ise merak ve kendisine uygun doğru dili bulma isteği belirleyici oldu
Ruby’nin ifade gücü ve C’nin şeffaflığı
- Ruby’de metot adını tahmin ettiğinde çoğu zaman doğru çıkması; tekil/çoğul biçimleri ve eş anlamlıları desteklemesi, onun düşünme biçimine çok uyuyordu
items.each.with_index.mapgibi shell pipeline’ına yakın bileşimlerle az kodda çok iş yapılabiliyor- Bugün de Ruby’yi her zaman kurulu tutuyor; yakın zamanda bir Rails projesine de başladı
- C’de fonksiyonların ELF sembollerine ve assembly koduna doğrudan karşılık gelmesi, derleme çıktısını anlamayı kolaylaştırıyordu
- Modern C++’ın geçmiştekinden fiilen başka bir dil haline geldiğini düşünüyor ve artık C++ bildiğini söylemiyor
- Rust’a geçmeyi denedi ama kalıcı olmadı; C’ye yeniden yazma gerekçesini hız ve ABI’de bulan Zig’e ve kurucusuna da ilgi duyuyor
- Gençliğinde CRuby VM kaynaklarını okuyarak Stack Overflow’daki “Ruby neden böyle çalışıyor?” sorularına uygulama üzerinden yanıt aradı
- Daha sonra CRuby, CPython, JVM, Guile ve V8 kodlarını inceledi; özellikle Linux çekirdeği kaynak kodunu profesyonel C programlamanın ölçütü olarak görüyor
Başkalarının kodunu okuma biçimi
- Kütüphane kullanmakla yetinmeyip iç uygulamayı, sürücülerle donanımın iletişimini ve gizli katmanları anlamak için düzenli olarak kaynak kod okudu
- Gerçek uygulamalar yaparken bile çoğu kez alttaki teknolojileri araştırmaya yöneldi; çözülmüş problemleri daha iyi biçimde yeniden yapma eğilimi de gelişti
- Bu eğilimin tipik yazılım geliştirme kariyeriyle uyuşmadığına karar vererek programlamayı meslek olarak seçmedi, hobi olarak sürdürdü
- Sürücü kodunu en baştan anlamadı; hayal kırıklığı yaşasa da okumayı sürdürerek bazı davranışları kavrayabilir hale geldi
RGB klavyeyi tersine mühendislik etmek
- Clevo barebone dizüstünün RGB klavyesini kontrol eden Windows uygulaması pencere açmak için bir dakikadan fazla bekletecek kadar yavaştı; bu yüzden kendisi bir alternatif yaptı
- Wireshark ile uygulamanın klavyeye gönderdiği USB paketlerini yakaladı, yapısını analiz etti ve Linux kullanıcı alanında C ile bir sürücü yazdı
- GitHub’a koyduktan sonra unutmuştu, ancak gerçek kullanıcılar ortaya çıktı; bir kullanıcı GUI bile yaptı
- Ardından ACPI güç yönetimi gibi dizüstünün diğer özelliklerini de tersine mühendislik etti, fakat tüm özellikleri çözemedi
libc’yi aşan liblinux
- Linux sistem çağrılarının kodu, sıradan fonksiyon çağrılarına benzeyecek kadar basittir;
libcüzerinden geçmeden doğrudan Linux’u hedeflemek mümkündür - Linux’un kullanıcı alanı ABI kararlılığıyla bilindiğini, ancak kullanıcı alanı bileşenlerinin aynı şekilde olmadığını düşünüyor
- Kılavuzlarda bazı sistem çağrılarının glibc tarafından desteklenmediğine dair ifadelerle karşılaştı
getrandom’ın glibc’ye girmesinin yaklaşık 2 yıl sürdüğünü anlatan LWN örneği de etkili oldu
- Yalnızca sistem çağrılarını içeren
liblinux.aoluşturup-llinuxile bağlama fikrinden yola çıkarak liblinux’u geliştirdi- Freestanding C için Linux sistem çağrısı sarmalayıcıları koleksiyonuydu
- C çalışma zamanı (CRT), glibc, musl, uclibc gibi standart C kütüphanelerini ifade ediyor
Freestanding C’de ortadan kalkan sorunlar
- Linux hataları normal dönüş değeri olarak döndürür; C kütüphanesi ise bunları küresel değişken olan
errnoya kaydeder libckaldırıldığında çeşitli küresel durumlar ve eski API’ler de birlikte önlenebilirerrno,rand/srand, yerel ayar durumu- Yeniden girilebilir olmayan
strtok - Beklenmedik sorunlara yol açabilen örtük dosya tamponlama
gets,atexit,signal,malloc- NaN ve
errnoile birleşince karmaşıklaşanmath.h
- Buna karşılık tamsayı yükseltme kuralları ve taşma denetimi eksikliği C’nin kendi sorunları olduğundan olduğu gibi kalır
- Taşmalar için derleyici yerleşik özelliklerini kullanıyor
- Kendisinin de yeni kusurlar üretme ihtimaline karşı dikkatli
- Standart kütüphane olmadan bayt kopyalamadan tamsayıdan dizgeye dönüştürmeye kadar her şeyi kendisi yazmak zorunda kaldı, ancak bu beklediği kadar imkânsız bir iş değildi
- glibc deposunu yorumlamak zordu; ancak
musl libckaynakları temiz ve gezinmesi kolay olduğu için çok yardımcı oldu - C kütüphanesi ve dinamik bellek ayırma olmadan yalnızca statik bellek kullanan otomatik test paketini de Lone’da uyguladı
- glibc deposunu yorumlamak zordu; ancak
nolibc keşfi ve Lone Lisp’in başlangıcı
- Greg Kroah-Hartman’a Linux’ta resmi bir C kütüphanesi neden olmadığını sordu; geçmişte klibc projesi olduğu yanıtını aldı
- Daha sonra Linux çekirdek geliştiricilerinin dahili araçlar için nolibc.h oluşturduğunu keşfetti
- Bunun kendi liblinux’undan daha tamamlanmış ve kullanışlı olduğuna karar vererek projeyi arşivledi
- Bugün
nolibc.h, çekirdek ağacı içinde geçici birlibcye yakın bir dizine dönüşecek kadar büyüdü; ancak dışarıya yönelik kararlılık garantisi net değil
- Bir sonraki proje olarak Lone Lisp’i başlattı
- Linux üzerinde doğrudan çalışan freestanding bir Lisp yapılabiliyorsa her programın aynı şekilde yazılabileceğini düşündü
- Karmaşık modern Linux kullanıcı alanını soyup atarak kararlı sistem çağrısı ikili arayüzü üzerinde yeniden başlama deneyi
- Cosmopolitan’a da kayan nokta ayrıştırma uygulaması gibi konularda yamalar gönderdi
- Birden çok platformun çalıştırılabilir dosya biçimi olarak aynı anda yorumlanabilen APE biçimini ve çalıştırılabilir dosya içindeki gömülü arşiv özelliğini değerli buluyor
Hata işleme ve sınırlandırılmış devamlar
- İlk Lone’da tüm hata yolları yorumlayıcıda
exit(255)ile sonlanıyordu; ancak Common Lisp çizgisinde devam ettirilebilir koşul sistemi uyguladı - Hata işlemenin temeli sınırlandırılmış devamlardır
- Devamı, stack frame’lerini kopyalayıp başka bir konumda yeniden oynatmak olarak anlıyor
- İstisnaları da değer yakalamayan bir devam biçimi olarak görüyor
- Hata türlerini
'not-foundgibi sembollerden lambda’lara eşliyor- Tek argümanlı
(lambda (error) ...), tipik bir istisna işleyici gibi davranıyor - İki argümanlı
(lambda (error continuation) ...), devamı çağırarak hataya düşen kodu bir değerle sürdürebiliyor
- Tek argümanlı
- Common Lisp’teki
use-valuegibi, sinyal üreten kodun yeniden başlatma seçeneklerini listelediği restart API’sini bilerek benimsemedisignal,throw,transferişlemlerinin sanki yalnızca değer döndürmüş gibi davranmasını sağlayan temel mekanizmayı değerlendiricinin içine kurdu
FEXPR ve çağrılabilir dil öğeleri
- Geleneksel Lisp değerlendiricisinin
ifgibi özel biçimleri doğrudan işlemesi yaklaşımından da kaçındı - Lone, değerlendirici eklentilerine karşılık gelen FEXPR’leri destekleyerek özel biçimleri değerlendiricinin dışına ayırıyor
- Bu tasarım sayesinde saf Lisp fonksiyonlarında kuyruk çağrısı optimizasyonu önce mümkün oldu; ancak primitive’lerde bir süre hata vardı
- Primitive’lerin kuyruk konumunda dönebilmesi için ayrı bir mekanizma ekleyerek bunu çözdü
- Vektörler ve tablolar da çağrılabilir
([1 2 3] 0),1döndürür([1 2 3] 0 4), vektörü[4 2 3]olarak değiştirir
- Devamlar ve üreteçler de aynı çağrı kuralını izler
control, devam destekleyenbegine benzertransfer, en yakıncontrolbloğundan çıkar ve askıya alma noktasını temsil eden çağrılabilir bir devam döndürür- Bu devam bir değerle çağrıldığında askıya alınmış hesaplama farklı bir dönüş değeriyle sürdürülebilir
Sistem çağrıları ve çalışma yapısı
- Lone başlamadan önce üst süreç
execveçağırır; Lone ise iç bellek yönetimi için yaklaşık 12 kezmmapyapar - Standart girdiden betiği okuyup çalıştırır ve ardından çıkar; çalışma sırasında ek
mmap,munmap,mremapçağrıları oluşabilir - Modül sistemi
openatveclosekullanır - Linux’taki 300’den fazla sistem çağrısının yalnızca bir kısmını kendi kullanır; ancak Lisp düzeyinde system-call primitive sağlayarak programların diğerlerini de çağırabilmesini sağlar
ioctlgibi çekirdek C yapıları gerektiren çağrılar için yapı oluşturma ve değiştirme özellikleri eklenmelidir- Terminal boyutunu sorgulamak da böyle desteğe ihtiyaç duyan bir örnektir
Lone ile kurmak istediği kullanıcı alanı
- Dil düzeyinde hata işleme, uygun kuyruk çağrısı optimizasyonu, üreteçler ve sınırlandırılmış devamları uyguladı; uzun vadede Erlang/BEAM fikirlerini de almak istiyor
- Birden çok yorumlayıcının Lisp kodunu paralel çalıştırabilmesi için yapıyı hazırlıyor
- Lone ile yapacağı ilk program, şu anda kullandığı PugJS fork’u tabanlı statik site üreticisinin yerine geçecek araç
- Ardından kendi shell’ini ve yardımcı araçlarını yazarak geleneksel Linux kullanıcı alanını kendi yöntemiyle yeniden kurmayı planlıyor
env’i Lone Lisp tablosu olarak dışa aktaran bir uygulama da yaptı; o sırada dolaşma özelliği yoktu, ancak artık üreteçleri destekliyor- Yorumlayıcının özel bir ELF segmentindeki Lisp kodunu okuyup çalıştırma özelliği de var
- Yorumlayıcı ikilisi kopyalanıp Lisp kodu yerleştirilirse bağımsız çalıştırılabilir program yapılabilir
Claude ile inceleme ve proje yönetimi
- Toplam iş yükünün sınırı yok, ancak dilin kendi özellik kümesinin tamamlanmaya yaklaştığını düşünüyor
- Claude’u bir tür yönetici gibi kullanıyor ve kod inceleme ile proje yönetiminde en büyük yardımı alıyor
- Tüm codebase üzerinde sorunları, geliştirilmemiş alanları ve gelecekteki yönleri sıkı biçimde bulmasını istiyor
- Reddettiği yaklaşımları ve daha sonra ele alınacak özellikleri dokümanlar ve proje belleğiyle yönetiyor
- Çöp toplayıcı ve bellek ayırıcısı, Claude’un daha iyi algoritmalar önermesiyle büyük ölçüde iyileşti
- Lone’a giren her satırı bizzat inceliyor; kod yazmanın kendisini de eğitici gördüğü için yapay zekanın Lone kodunu onun yerine yazmasına güvenmiyor
- Buna karşılık JavaScript statik site üreticisinde Claude’a tüm bir özelliği yazdırdığı oldu
- Planlanan özellikler arasında GCC/Clang derleyici API’si ve stack koruma fonksiyonları desteği var
Ruby ve Scheme’den alınan sözdizimi
- Ruby’nin ifade gücüyle Scheme’in sadeliğini birleştirmeye çalıştı; Lisp ayrıştırıcısı basit olduğu için kendisi yazabildi ve iç içe listeleri doğrudan ele alabildi
- Lisp’i gerçekten anlamasını sağlayan an, fonksiyonun değerlendirilmiş değerleri değil listenin kendisini aldığı FEXPR’i uygulamasıydı
- Diziler
[1 2 3], sözlükler{k v}sözdizimini kullanır- Yalnızca Clojure ve newLisp’e değil; Ruby, Python ve JavaScript kullanıcılarına da tanıdık olduğundan gereksiz giriş bariyerini azaltır
- C kodlama stilinde Linux çekirdeği stilini değiştirerek kullanıyor; ancak hizalama ve süslemeyi daha çok tercih ediyor
- Ruby’de
method('arg')yerinemethod 'arg'gibi noktalama işaretlerini azaltıp İngilizce cümleye daha yakın yazmayı seviyor - Lisp’te de sözdizimsel iç içeliği azaltıyor
- Lone’un
letbiçimi(let (a b c d ...) body...) - Geleneksel
(let ((a b) (c d) ...) body...)yerine adların ve değerlerin sırayla geldiği biçimin fonksiyon uygulama tarzına daha doğal uyduğunu düşünüyor
- Lone’un
Performans ve bootstrap planı
- Lone’un öne geçtiği benchmark başlangıç hızı; Ruby’nin Rubygems’i okumasından daha hızlı şekilde programı başlatıp bitirebiliyor
- Geçici ölçümlerde Python’dan yaklaşık 10–100 kat yavaş
- Lone, SICP 5.4. bölümdeki biçime benzeyen liste düzeyinde bir yorumlayıcı
- Python ve Ruby bytecode yorumlayıcıları olduğu için performans kategorileri farklı
- Listeleri bytecode’a dönüştürmenin Lisp’in özünü kaybettirdiğini hissettiği için bytecode derlemeden kaçınıyor
- Uzun vadede C yorumlayıcısını nihai bootstrap ölçütü olarak bırakıp Lone içinde JIT derleyici yazmayı planlıyor
mmapile çalıştırılabilir sayfalar ayırıp komut üretme yöntemi kullanılacak
- Bash ile özyinelemeli Fibonacci için yapılan geçici karşılaştırmada Lone çok daha hızlıydı; ancak Bash’in her yinelemede süreç oluşturmuş olma ihtimali gibi ölçüm sapmalarını kabul ediyor
- Betiklerde başlangıç süresi önemli olduğundan Lone’un hızlı bootstrap’ini kullanışlı görüyor
- Hash tabloları derleme aşamasında önceden hesaplanıp C başlatma verisine dönüştürülürse çalışma zamanı başlatma maliyeti daha da azaltılabilir
Bellek ve en küçük ortam
mmap, çekirdekten bellek sayfaları ister; yaygın sayfa boyutu 4.096 bayttır- Okuma, yazma ve çalıştırma izinleri belirtilebilir; JIT çalıştırılabilir sayfaları kullanır
- Yalnızca 16 bayt gerekse bile 4 KiB istenirse israf büyük olur; bu yüzden genel ayırıcılar 128 MB gibi büyük bir alan alıp bunu küçük parçalara böler
- Lone’un en üst düzey ortamında yalnızca iki sembol vardır:
importveexport- Listeler, literaller ve fonksiyon çağrısı mekanizması dışında
if,quotebile içe aktarılmalıdır - Kullanıcının ortamdaki tüm adları doğrudan kontrol etmesini sağlayan bir tasarımdır
- Listeler, literaller ve fonksiyon çağrısı mekanizması dışında
- Şu anda yaklaşık 50 fonksiyon var;
if,let,begin,control/transfer,intercept/signal,flattenbaşlıcaları
Standart kütüphane ve dokümantasyon
- Dil dokümantasyonu hâlâ eksik; ancak dil özelliklerinden çok standart kütüphane çalışmasına yaklaşıyor
- Ruby’nin standart kütüphanesini ve Scheme’in adlandırma biçimini referans almayı planlıyor
- Sıradaki iş dolaşma protokolü
(for (each collection) (lambda (item) ...))biçimini değerlendiriyor- Mevcut
eachfonksiyonlarının tamamını üreteç döndürecek şekilde yeniden tasarlamayı planlıyor
- Ardından dizge işleme ve verimli birleştirme için string builder uygulamak istiyor
- Dolaşma ve dizge özellikleri tamamlandığında Hiccup biçiminde bir web framework de yazabileceğini düşünüyor
- Düşük seviyeli özellikler bitip tekrarlı standart kütüphane işine geçildiğinde odağının dağılabileceğinden endişe ediyor ve Claude’un yönetim yardımını kullanmayı planlıyor
Tüm stack’e bizzat sahip olma hedefi
- Devamlar gibi gizemli görünen özellikler bile stack frame kopyalama olarak anlaşılınca sıradan uygulama problemlerine dönüşür; Lone’un amacı başkalarını da kendi sistemlerini yapıp keşfetmeye teşvik etmektir
- Kütüphane tüketicisi olarak kalmayıp kütüphane yapan kişi olmak istiyor; sıradan geliştiricilere yasakmış gibi muamele edilen sistem çağrılarını da doğrudan kullanmak istiyor
- Kendi sistemine sahip olmak, bozulduğunda kendin düzeltmek zorunda olmak demektir; ancak daha fazla kişinin bu sorumluluğu ve ödülü seçmesini umuyor
- Bilgisayar dünyasında birikmiş eski koddan korkmamak ve gereksiz katmanların kaldırılabileceğini düşünüyor
- Linux kullanıcı alanını yeniden yapan kişi kendisi değil de Rust veya Zig geliştiricileri olabilir
- Lone başarılı olmasa bile bu tür girişimleri teşvik ederse bundan memnun olabilir
Özgür yazılım ve Android
- Özgür yazılımın hedeflediği kullanıcıyı güçlendirmeyi önemsiyor; genel amaçlı bilgisayarların şirketlerin veya devletlerin yönettiği ev aletleri gibi daraltılmasından kaygı duyuyor
- systemd’yi, ağır yaklaşmış yönleri olsa da geleneksel Linux kullanıcı alanını yeniden hayal edip yeniden kuran başarılı bir örnek olarak değerlendiriyor
- Tüm katmanları bizzat yapmak yerine mücadeleleri seçmek gerektiğini düşünüyor
- Lone’u bare metal Lisp olarak yapsaydı önyükleme aşamasına bile ulaşamayabilirdi
- 512 bayttan küçük boot sector Lisp’i olan jart’ın Sector Lisp’ini örnek gösteriyor
- Lone Termux içinde başladı ve önemli bir bölümü telefonda yazıldı
- Android,
statxdahil bazı sistem çağrılarını engellese de Lone Android’de çalışıyor ve test paketi %100 geçiyor
Doktor ve profesyonel olmayan programcı
- Moreira 2019’da tıp fakültesinden mezun olmuş bir doktor
- Lisede sinir ağı programlaması okurken biyolojiye ilgi duymaya başladı
- Bazı günler 10–14 saat hasta bakıp diğer günler dinlenerek programlamaya zaman ayırıyor
- Elektronik sağlık kaydı kullanan hastanelerde şablonlar ve klavye becerisiyle işini ciddi ölçüde kısalttı
- Hastayla göz teması kurarken kayıt tutabiliyor
- Yakın zamanda başladığı Rails projesi, kendi ihtiyacını çözmeye yönelik bir elektronik hasta kaydı sistemi
- Profesyonel geliştiricilerin kişisel sorunları bizzat çözmemesinin nedenlerinden biri olarak bilgisayarın kendisine duyulan ilgi eksikliğini görüyor
- Yalnızca sonuç almak isteyen tutumdan ziyade merak olmalı ki uygulamanın içlerine girilebilsin; insanlarda bu merakı nasıl uyandıracağını ise henüz bilmiyor
1 yorum
Lobste.rs görüşleri
Bu röportaj serisini hiçbirini kaçırmadan okuyacak kadar seviyorum; herkesin bilişimle kurduğu kişisel ilişkiyi görmek çok keyifli
GBE+ GBA emülatörünün yazarı Shonumi de benim gibi Mega Man Battle Network oyunlarından etkilenmiş; bir gün onun röportajını da okumak isterim
Yeniden başlatılabilir istisnalar için birinci sınıf süreklilikler (first-class continuation) şart değil
Common Lisp, süreklilikler olmadan da yeniden başlatılabilir istisnalar sunuyor; kilit nokta, işleyiciyi çağırmadan önce stack'i geri sarmamak
Böylece istisnanın oluştuğu stack ve durum aynen korunuyor; işleyici normal şekilde dönebilir ya da Common Lisp'teki gibi stack'in bir yerindeki yeniden başlatma işleyicisine sıçrayabilir
Yine de Lone Lisp'te döndürülen süreklilik birden fazla kez çağrılabiliyor ve sinyal işleyicisinin dışına kaçabiliyor; bu yüzden gerçekten gerekli Generator'lar yinelemeli işlemenin temeli olduğu için performans daha önemli; bu nedenle sınırlı süreklilikler yerine kopyalamayı ortadan kaldırmak için ayrı bir stack kullandım
Hata işleme ise nispeten seyrek bir yol olduğu için işlevselliği tam sunmayı tercih ettim
Birçok insan için en önemli iş ya da proje, boş zamanda ücret almadan sırf eğlencesine yapılan şey olabilir
Benim doktorumun da gizlice kendi Lisp dilini yapan böyle bir çifte hayatı olabileceğini hayal ediyorum
Dr. Cameron Kaiser de büyük projeler yürütmüş; makine sahipliğine dair bir felsefeyi paylaşmanın yanında tamamen açık POWER9 workstation'ı günlük olarak kullanıyor
Lone Lisp'i bu vesileyle ilk kez duydum ve harika bir proje gibi görünüyor
Ben de 13-14 yaşlarındayken bilişim dersinde eski Dev-C++ ile C++ öğrenmeye başlamıştım; bunu hatırlamak uzun zaman sonra nostaljik geldi
Doktor olduğunu hiç beklemiyordum; aklıma Con Kolivas geldi
Görünüşe göre böyle doktor geliştiriciler beklenmedik derecede çok
https://en.wikipedia.org/wiki/Con_Kolivas