Programlama Dillerinin Gelişimi – I

Giriş

Programlama dillerini, sadece belli söz dizimi yapılarına sahip, bilgisayara iş yaptıran soyutlamalar bütünü olarak görmek eksik bir bakış açısı olacaktır. Programlama dilleri, programlamaya belli yaklaşımları ifade ederler. Hatta tarihi gelişimlerine bakıldığında programlama dilleri, zamanının yazılım yaklaşımlarını, problem uzaylarını ve problemleri çözme tekniklerini yansıtan özelliklere sahip olmuşlardır. Her yeni programlama dili bazen devrim niteliğinde bazen de ilerleme anlamında yepyeni özellikler getirmiş, karmaşık olan yazılım geliştirme projelerinin yine karmaşık olan programlama faaliyetlerini daha basit ve üretken yapma konusunda iddalara sahip olmuşlardır.

Bu arada dillerin değişik uygulama alanlarına dolayısıyla da değişik problemlere yönelik olarak tasarlandıkları gerçeğini de gözardı etmememek gerekmektedir. Örneğin bilimsel uygulamalar, iş uygulamaları, yapay zeka, sistem geliştirme ve tamamen teknolojik bir ayrım olsa bile web, pek çok programlama dilinin kendisi için özel yapılar içerdiği alanlardandır.  Bu konuya daha ileride yine döneceğiz.

Her dili ayrı ayrı ele alıp özelliklerini incelemek bu yazının konusu olmamakla beraber belli başlı dillerden yola çıkarak 20. yüzyılın ortalarında başlayan programlama ve yazılım projesi geliştirmenin ne gibi safhalardan geçtiğini anlamakta fayda vardır.

İlk Yaklaşım: Makina ve Assembly Kodları

Programlamanın ilk yıllarında, 1950’lerde yani, programlama doğrudan makina dilinde yapılıyordu ve ortaya çıkan koda da makina kodu deniyordu. Zaten yazılan programlar da yeterince küçüktü ve üzerinde çalışılan bilgisayarlar, şu ankilerle kıyaslanamayacak derece ilkeldiler. Dolayısıyla programların etkin çalışması da önemliydi. Bu yüzden makina dili çok zaman yeterli olabiliyordu. Makina kodu, 0 ve 1’lerden oluşmakta olup, ilk nesil kod (first-generation code) olarak adlandırılmaktadır.

Daha sonraları, makina koduna çevrilebilen, 2.nesil yapılar ortaya çıktı: Assembly dilleri. Bu diller, içinde ADD, PUSH, PULL gibi kelimeler barındıran ve assembler denen çevirici programlar tarafından makina koduna çevrilebilen bir üst seviyeli dillerdi.

İlk Yüksek Seviyeli Yaklaşım: Komut-merkezli Programlama

1950’lerde makina dilinin komutlarını daha basit bir şekilde çağırmayı sağlayacak, üçüncü nesil, ilk programlama dilleri geliştirildi. Genel kabule göre ilk yüksek seviyeli dil Fortran‘dır. İsmi, “FORmula TRANslating”den türetilen ve o tarihte bir IBM çalışanı olan John Backus liderliğindeki bir takım tarafından geliştirilen bu dil, 1957 yılında ticari olarak piyasaya sürüldü. Fortran’ın en temel özelliği, matematiksel problemleri kolayca çözmeye yarayacak yapıları içermesiydi. Bu yapılar, makina dili seviyesindeki pek çok komutu daha yukarı seviyede ve daha basit şekilde yerine getiren soyut komutlardı. Bu açıdan bakıldığında programlama dilleri,  donanımdan ne kadar uzaksa, o denli soyut (abstract) yapılar içerir ve yüksek seviyeli olurlar.

Fortran bilimsel programlama amacıyla geliştirildiği için daha çok algoritmik yapıları ifade etmede yetkindi. Fortran’da verileri tutmak için değişkenler ve bu değişkenlerin tutabileceği verilerin yapılarını ifade eden tipler vardı. Fortran’ın ilk versiyonunda I, J, K, L, M, N ile başlayan değişkenler tamsayı (integer), diğerleri kayan noktalı (floating-point) verilerdi. Ayrıca, Fortran’ın ilk sürümlerinde  kıyaslama için if , döngü için de do yapıları vardı. Her ne kadar Fortran, makina diline göre daha soyut bir yapıda olsa da öngördüğü programlama yaklaşımı alt taraftaki makina dilinin çalışmasından çok da farklı değildi: Arka arkaya çalıştırılan ifadeler. İfadeler ise komutların farklı dizilişleriyle oluşuyordu. Bu şekilde bir programlama anlayışı gelişti: Komut-merkezli programlama (imperative programming).

Her programlama dilinde komutlar vardır ve komutlar bir araya gelerek ifadeleri (statement) oluştururlar. İfadeler, bir programın cümleleri gibidir. Komut-merkezli programlamada ise en önemli şey ifadelerin sırayla çalıştırılmasıdır. Bu sırayı programcı belirler ve kodunu bu şekilde yazar. Yazılan kod, bir derleyici (compiler) tarafından makina diline çevrilir ve üretilen kod da çalışma zamanında makina üzerinde çalıştırılır. Komut-merkezli programlama, en eski ve en oturmuş yaklaşımdır. Yapısı, makina diline ve yapısına çok benzediği için, genelde performansı en yüksek diller komut-merkezli dillerdir.

İlerleme: Yordamsal Programlama

Fortran’ın alt yordam (subroutine) yapısına sahip olmasına rağmen, yordamların, programlarda yoğun olarak kullanılması ve merkezi bir önem kazanması için biraz geçmesi gerekti. 1960’larda popüler olan yapısal programlama (structured programming), programı, alt parçalara bölmeyi tavsiye ediyordu. Bu yaklaşımda, akışı kontrol eden ana parça dışında, adına birim (module) denen irili ufaklı pek çok program parçası vardı.  Birimler, ana birimden ya da diğer birimlerden değer alıp onlara değer döndürebiliyorlardı. Bu birimler, kendi yerel değişkenlerine (local variables) ve yerel ifadelere sahiptiler. Bu şekilde, ayrık işler/görevler birimlerde yazılıyor ve ana birimden tekrar tekrar çağrılabiliyordu. Böylece birimsel (modular) ya da başka bir deyişle yordamsal (procedural) programlama ortaya çıktı.

Yordamlar, farklı dillerde subroutine, procedure, operation, function, method gibi adlarla anılsa da aslen karmaşıklığı, böl-parçala yöntemiyle yönetmeyi hedefleyen, tekrar kullanımı öne çıkaran ve bu şekilde hataya daha az yer veren yordamsal programlamanın en temel aracıdır. Pek çok kişi, yordamsal programlama, komut-merkezli programlama ve yapısal programlamayı aynı anlamda, birbirleri yerine kullanır çünkü bu yaklaşımlar birbirlerinin tabi devamı olarak gelişmişlerdir. Bu yüzden, komut-merkezli programlama kısmında bahsettiğimiz gibi bir programda yazılan ifadelerin ardışıl olarak çalışması, yordamsal dillerde de en temel özelliklerdendir. Bu yaklaşımın farkı, sıklıkla tekrarlanan ve ayrı görevleri ifade eden yapıların yordam ya da fonksiyonlarda saklanmasıdır. Bu konuyu biraz daha açıklayalım.

Yordamsal dillerdeki fonksiyonlar bir işi yerine getirirler ve zorunlu olmamakla birlikte, bu işi yerine getirmek için çoğu zaman girdiye ihtiyaçları olur. Fonksiyonlar, girdi üzerinde çalışıp bir çıktı üretirler. Bir yazılımdaki bir iş ihtiyacı ise, bir ya da birden fazla fonksiyonun sırayla çalışmasıyla yerine getirilir. Buna “fonksiyonel ayrışma” (functional decomposition) denir. Yani, projedeki ihtiyaç analizi (requirements analysis) safhasında ortaya çıkarılan iş ihtiyaçları daha sonra bir ya da birden fazla fonksiyonla yerine getirilecek hale dönüştürülür. Bu dönüşüme tasarım (design) denir. Tasarımda bulunan fonksiyonlar da kodlama safhasında kodlanırlar. Kodlanma sırasında programcı, fonksiyonun yerine getireceği görevi (task), ardışıl ufak adımlara böler (stepwise refinement) ve bu adımları da tek tek kodlar. Dolayısıyla yordamsal yaklaşım, önce iş ihtiyaçlarının fonksiyonel ayrışma ile fonksiyonlara dönüştürülmesi, daha sonra da her bir fonksiyonun, ufak adımlarla kodlanması prensibi üzerine çalışır. Bu sırada birden fazla fonksiyonun üzerinde çalışacağı ortak veri alanları da bulunur ve bu veriler, fonksiyonların dışındaki genel değişkenlerde (global variable) ifade edilir.

Komut-merkezli ya da yordamsal dillerin, yazılım dünyasında en erken geliştirilen ve en yaygın diller olmasının, yazılımın ilk dönemlerinde ele alınan problemlerin, bilimsel ve mühendislik problemleri olup daha çok algoritmik tabiatta olmasıyla yakından alakası vardır. İlk yüksek seviyeli dil olan Fortran ile 1958’lerin sonunda geliştirilmeye başlanan ve 1960’ların popüler dili olan Algol’un (ALGOrithmic Language) isimlendirilmesi, bu yaklaşımın tipik bir sonucudur. Öte taraftan ilk programcıların aynı zamanda birer donanımcı olup, programın üzerinde çalışacağı donanımın çalışmasından etkilendikleri de bir gerçektir. Çünkü bilgisayarların donanım yapıları da zaten ardışık emirleri CPU üzerinde yerine getirecek şekilde geliştirilmektedir. Bilgisayarların ilk çıktığı günden bu yana hakim olan mimari yaklaşım olan Van Neumann mimarisi bize zaten böyle komut tabanlı bir dünya oluşturmuştur. Yordamsal diller de ilk temsilcilerinin ortaya çıktığı 1950’li yıllardan bu yana Van Neumann yaklaşımını tekrarlamaktadırlar.

Yordamsal dünyada, ilk temsilcileri olan Fortran ve Algol’dan bu yana pek çok dil geliştirildi. COBOL (COmmon Business-Oriented Language), Fortran ve Algol’un tam aksine, tamamen iş uygulamaları (business application) geliştirmek amacıyla 1950’lerin sonunda, Algol’de olduğu gibi, bir komite tarafından tasarlandı. COBOL, dönemin diğer dilleri gibi komut-merkezli bir yapıya sahipti ve ADD VAT TO NET-PRICE gibi tamamen iş mantığı ifadelerinin kullanımına izin veriyordu. Kendinden sonra gelen diller üzerinde çok etkisi olmayan bu dil, ilk çıktığından itibaren iş uygulamalarında yaygın kullanım alanı buldu. Özellikle, 1960’lı yıllarda ABD Savunma Bakanlığı’nın (Department of Defense, DoD), projelerinde COBOL kullanımını zorunlu hale getirmesi, COBOL’un bu denli yaygın olmasının en temel sebebi olarak gösterilmektedir. Gartner Group’un 1997 yılındaki bir araştırmasına göre iş dünyasının yazılımlarının %80’ı COBOL üzerinde çalışıyordu.

Komut-merkezli diller

Öte taraftan 1960’ların sonlarında, daha sonra en yaygın işletim sistemlerinden olacak olan UNIX üzerine çalışmalar başlamıştı. UNIX’i AT&T’nin Bell Laboratuvar’larında geliştirenler, Ken Thompson, Dennis Ritchie, Brian Kernighan, bu platformda kullanmak yüksek seviyeli bir sistem diline ihtiyaç duydular. Farklı girişimler sonunda, Dennis Ritchie 1972’de C dilini geliştirdi.

C, önceleri bir sistem dili olarak görülmesine rağmen, hem sistem hem de uygulama geliştirmekte yaygın bir şekilde kullanıldı. Yordamsal bir dil olan Algol’un ileri bir sürümü olan Algol68’den ciddi bir şekilde etkilenen C ile yazılan kodlar çok rahat bir şekilde makina diline çevrilebilmektedir. C, bir sistem dili olarak ortaya çıkmasından dolayı alt seviyeli yapılara sahiptir. Örneğin C’de makina belleğini doğrudan yönetmek için yapılar mevcuttur.

Farklı kişi ve kurumlarca geliştirilen C’nin orjinal tanımı, ünlü 1978 baskılı, Beyaz Kitap, (“the White Book”), The C Programming Language’de Brian Kernighan ve Dennis M. Ritchie tarafından yapıldı. C, 1989 yılında Amerikan Ulusal Standarlar Kurumu (American National Standards Institute (ANSI)) tarafından standart hale getirildi.

C’nin yaygınlık kazanmasının en temel sebeplerinden birisi, diğer pek çok dilin C ile yazılmasıdır. Bu şekilde C, platform ile yeni dil arasında bir ara dil haline gelmiştir. Pek çok dilin derleyici ve yorumlayıcıları C ile geliştirilmektedir.

Programlama dillerinin soy ağacı (Concepts of Programming Languages 7. baskı, Sebesta, Robert W.)

Programlama dillerinin soy ağacı

(Sabesta, Robert W., Concepts of Programming Languages 7. baskı)

Yordamsal Yaklaşımın Değerlendirilmesi

Diller, karmaşık olan problem alanını (problem domain), yine karmaşık olan bilgisayar alanı (computing domain) ile çözmeye yarayan araçlardır. Diller, birbirlerinden çok farklı yapıya sahip bu iki alan arasında tercuman rolündeki aracılardır. Lakin yordamsal yaklaşımın en temel problemi, yordamsal dillerin, problem alanını modellemek yerine bilgisayar alanını modellemelerindedir. Bir başka değişle, program yazarken programcılar, problem alanını ya da daha açık bir ifadeyle, önlerine gelen bir iş ihtiyacını, yordamsal dillerin yapılarıyla ifade etmek zorundadırlar. Yordamsal diller de alttaki makina platformunu ciddi bir şekilde taklit ettiklerinden, ortaya çıkan programlar, makinaların çalışmasına çok benzer bir yapıya sahip olmaktadırlar. Eğer uygulamalarımız, matematiksel yapılarda olsaydı ve algoritmalar yardımıyla kolayca ifade edilebilselerdi, problem olmazdı. Ama her ne kadar uygulamalarımızda algoritmalar ve matematiksel ifadeler kullanılıyor da olsak, programlarda ifade ettiğimiz şeyler genelde, çok daha karmaşık ilişkilere sahip olgular. Dolayısıyla, yordamsal diller, makina ve assembly dillerine göre çok daha soyut yapılar olmalarına rağmen, programlama dünyamızı, bilgisayar yapılarıyla ifade etmemize sebep oluyorlar. Halbuki, dillerin soyutlamaları bilgisayarınkiler yerine çok daha tabi yapıları ifade etmelidir. Bu durum, konuşurken kullandığımız dillerin, hayatı resmetmekte başarılı olmak için sahip olması gereken kavramlara değil de çok daha özel bir alanın kavramlarına sahip olması halinde ortaya çıkacak zorluklardan farklı değil.  Dolayısıyla bir programlama dili, nihai olarak alttaki makinanın diline çevrilebilmeli ama bir programcıya da hayattaki bir olayı, aslına olabildiğince uygun ifade edebilme gücü de tanımalı. Yordamsal diller, bu noktada yeterince başarılı olamadıkları için eleştirilmektedirler. Çözüm nedir? Bir sonraki yazıda, muhtemel bir çözüm ele alacağım.

Toplam görüntülenme sayısı: 5074