3. DART PROGRAMLAMA DİLİ GELİŞMİŞ ÖZELLİKLER
Giriş
Bu bölümda Dart programlama dilindeki nesneye yönelimli programlama mantığı ve asenkron programlama ile ilgili özellikler anlatılacaktır. Başlamadan önce genel olarak sınıf (class), kalıtım (inheritance), asenkron programlama, multi-thread programlama gibi kavramları anımsayalım. Bu kavramlara diğer dillerden aşina değilseniz konu ile ilgili bildiğiniz bir dilde bu kavramları incelemeniz Dart ile diğer dillerdeki yapısal benzerlik ve farklılıkları anlamak adına yardımcı olacaktır.
3.1. Sınıf (Class)
Dart programlama dili nesne tabanlı bir programlama dilidir. Kalıtım modeli olarak sınıf (class) ve mixin tabanlı bir çözüm kullanmaktadır. Kod içerisindeki her bir obje (object), kendi sınıfından üretilen bir örnektir. Null haricindeki tüm sınıflar Object sınıfından türer. Dart dili Java, C# gibi dillerde olduğu gibi tek bir ana sınıftan miras almayı destekleri C++’da ise aynı anda birden fazla sınıftan miras alma yapılmaktadır. Dart tek sınıftan miras almayı desteklemesinin yanında C++ programlama dilindeki bu esnekliği de mixin tabanlı miras almayla sağlamaktadır. Dart programlama dilinde bir sınıf ancak tek bir sınıftan miras alırken bunun yanında birden fazla mixin tabanlı miras alma yapabilir. Şimdi kısaca dilin temel nesneye yönelimli programlama özelliklerinden bahsedeceğiz. Konu hakkında detaylı bilgiyi Dart.dev sitesindeki Dilin Özellikleri (Dart.dev->Guides->Language->Specification) sayfasından inceleyebilirsiniz.
Basit bir sınıf tanımlamasını yukarıdaki gibi yapabiliriz. Diğer nesneye yönelik programlama dillerinde olduğu gibi üye değişkenleri ve üye fonksiyonları bulunmaktadır. Bazı temel farklılıklara gelirsek;
Dart’ta public, protected ve private etiketleri kullanılmamaktadır. Alt çizgi (_) ile başlayan tanımlamalar private diğer tanımlamalar public olarak ele alınmaktadır. protected belirtecininse bir karşılığı Dart’ta mevcut değildir.
Üye değişkenlerin tanımlanmasında ilk değer ataması yapılabilir. Java gibi diller buna izin vermemektedir. Değer atanmayan değişken null değeri ile oluşturulur.
3.1.1. Sınıf Üyelerine Erişim
Sınıfın üyelerine erişim için sınıfın bir örneği üzerinden nokta(.) operatörü ile üye değişkenlere erişilir ve üye fonksiyonlar çağrılır.
Eğer sınıfın örneğinin null olma ihtimali varsa üyelerine erişimde hata oluşturulmaksızın kodun ilerlemesi için soru işareti-nokta (?.) operatörünü kullanabiliriz.
3.1.2. Yapıcı (Constructor) Fonksiyonlar
Dart’ta yapıcı fonksiyonlar normal tanımlanabileceği gibi isimlendirilmiş yapıcı fonksiyonlar da tanımlanabilir. Bu yapıcı fonksiyonun işlevini kodu okuyana aktarmada iyi bir yöntemdir.
Bu iki örnekte Point adındaki sınıftan p1 ve p2 örnekleri türetilmiştir. p1’ın oluşturulmasında klasik iki parametreli bir yapıcı fonksiyon kullanılırken, p2’nin oluşturulmasında fromJson şeklinde adlandırılmış bir yapıcı fonksiyon kullanılmıştır. Burada ek bilgi okumaksızın fromJson yapıcı fonksiyonunun bir Point objesi oluşturmak için girdiyi JSON formatında aldığını anlayabilmekteyiz.
Bazı sınıflarda const yapıcı fonksiyon tanımlama yapılabilmektedir. const bir yapıcı fonksiyon kullanımı kod içerisinde aynı parametre listesi ile çağrılan birden fazla örnek için tek bir sabit oluşturur.
Eğer sınıfın bir yapıcı fonksiyonu bulunmuyorsa varsayılan olarak parametre almayan yapıcı fonksiyonu oluşturulur.
Dart miras alma yoluyla yapıcı fonksiyonları alt sınıflara aktarmaz. Eğer bir türemiş sınıf kendi yapıcı fonksiyonunu içermezse sadece parametresi olmayan varsayılan yapıcı fonksiyonu olacaktır.
Dart üye değişkenlere veri yüklemeyi kolaylaştırmak için this anahtar kelimesini yapıcı fonksiyon parametre listesinde kullanır. Böylece sadece üye değişkenlere ilk değer vermek için yazılan yapıcı fonksiyonları gövdesiz hale getirebilmektedir.
Yukarıdaki yapıcı fonksiyon yerine;
şeklinde yazılabilir.
Yapıcı fonsiyonun gövdesinin işlenmesine başlamadan önce eğer yapılmasını istediğiniz işlemler varsa örneğin üst sınıfın yapıcı fonksiyonunun çağrılması , bazı üye değişkenlere ilk değer atanması gibi, bu durumda iki nokta üst üste(:) operatöründen sonra bu işlemler sıralanabilir.
Üst sınıf tanımlamasına erişmek için super anahtar kelimesi kullanılmaktadır.
Benzer kullanımı yapıcı fonksiyonlar arasında yönlendirme için de kullanabiliriz. Örneğin iki parametre alan yapıcı fonksiyon içerisinde parametre almayan yapıcıdaki işlemlerin yine aynen bulunması gerekiyorsa bu sefer super yerine this anahtar kelimesi ile kendi içindeki diğer yapıcı fonksiyonları çağırabilir.
Dart’ta bir diğer yapıcı fonksiyon özelliği factory anahtar kelimesi ile tek bir örnek üzerinde çalışan bir yapıcı oluşturmaya izin vermesidir. factory anahtar kelimesiyle tanımlanan yapıcı fonksiyon her çağrıldığında sınıfın yeni bir örneğini oluşturmaz. Bu kullanım özellikle tampon bellek olarak saklanacak bilgilerin yoksa oluştur varsa kullan formundaki kullanımı için kolaylık sağlar.
Aşağıdaki Logger sınıfının amacı log adlı üye fonksiyon çağrıldığında gönderilen mesajı belirtilen kütüğe yazmaktır. (Buradaki örnekte implemantasyonu yapılmamış sadece konsola mesajı geri basmaktadır.) Uygulama içindeki tüm kütükleri (log kayıt yerlerini) ifade etmek için _cache adında static final bir Map sınıf içerisinde tanımlanmıştır. Bu tanım static olduğu için bellekte bir kere oluşacak, final olduğu için oluşumu ilk yapıcı çağrısında gerçekleşecek ve altçizgi ile tanımlandığı için private olacak yanı Logger sınıfı dışında erişime kapalı olacaktır. Logger sınıfından yeni örnek türetecek tek yapıcı fonksiyon Logger._internal’dir. Bu da altçizgili tanımlandığı için sadece sınıf içerisinde erişilebilir. Bunu çağıran isimsiz factory yapıcı fonksiyona ( factory Logger(String name)) dikkat ederseniz _cache Map’i üzerinde eğer ilgili Logger kaydı yoksa bir yenisini oluşturur ve referansını döner ama varsa sadece referansını döner. Logger.fromJson yapıcı fonksiyonu da verilen JSON formundaki name-Logger eşleşmesine uyan kaydı bulmak için diğer factory yapıcı fonksiyonu çağırır. factory yapıcı fonksiyonu diğer dillerdeki static yapıcı fonksiyonu tanımlamaya benzer özel bir yaklaşımdır. factory yapıcılarla ilgili bilinmesi gereken diğer bir durum da this anahtar kelimesinin bu yapıcılar içerisinde kullanılamayacağıdır.
Yukarıdaki kod parçacığı aşağıdaki gibi çağrılır.
3.1.3. Operatörler
Sınıflar için operatör tanımlaması yapılabilir. Buna genellikle operatör aşırı yükleme (operator overloading) denmektedir. Bir sınıf için operatör tanımlanması o sınıfın temel veri türleri gibi bu operatörlerle kullanılmasına imkân sağlar.
Tanımlanabilecek operatörlerin bir listesi;
< | + | | | [] |
> | / | ^ | []= |
<= | ~/ | & | ~ |
>= | * | << | == |
– | % | >> |
Buradaki örnekte Vector adında oluşturulan sınıf içerisinde (+) ve (–) operatörleri tanımlanmıştır. Bu tanımlama sayesinde main içerisinde oluşturulan v ve w adındaki iki örnek üzerinde toplama ve çıkartma işlemleri gerçekleştirilir.
3.1.4. Getter ve Setter
get ve set anahtar kelimeleri C# ve Java gibi dillerde bir objenin özelliklerini (property) tanımlamak için kullanılırlar. Dart’ta da bu yaklaşımı görmekteyiz. Gerektiğinde bir özelliğin değerinin değiştirilmesi veya elde edilmesi için hesaplama gereken durumlarda get ve set anahtar kelimeleri ile getter ve setter tanımlaması yapılabilir.
Aşağıdaki örnekte right ve bottom özellikleri left-witdh ve top-height değer çiftlerine bağımlıdır. Bu nedenle right ve bottom üye bir değişken olarak değil bir özellik(property) olarak tanımlanmak durumundadır.
3.1.5. Abstract Sınıf ve Abstract Metod
Dart, soyut (abstract ) sınıf ve metod tanımlamaya izin vermektedir. Soyut sınıf tanımlamak için sınıf önüne abstract anahtar kelimesi yazılır. Soyut bir sınıfın örneği oluşturulamaz ancak miras alınarak kullanılması gerekir. Genelde soyut sınıflar içerisinde soyut fonksiyonlar barındırır. Soyut fonksiyon tanımı gövdesi yazılmamış sadece isimlendirilmiş fonksiyon manasındadır. Soyut fonksiyon tanımlamak için küme parantezleri dahil fonksiyon gövdesi çıkarılarak sadece noktalı virgül (;) sembolü ile fonksiyon tanımlaması bitirilir.
3.1.6. Implements ve Extends ile Miras
Nesneye yönelimli dillerde arayüz (interface) tanımlamak için özel bir kalıp vardır. Dart ise arayüz tanımlaması için yine sınıfları kullanır. Eğer bir sınıfın sadece davranışsal bir görüntüsü ile çalışılacaksa, yani üye değişkenleri alınmayacak sadece fonksiyonlarının prototipi alt sınıfa aktarılacaksa implements anahtar kelimesi ile üst sınıfı bir arayüz gibi kullanırız. Dart birden fazla sınıftan implements ile arayüz formunda miras almayı destekler.
Yukarıdaki kod parçasında Person adındaki sınıftan implements ile arayüz formunda miras alınmıştır. Arayüz olarak alınan miras olduğu için Person sınıfındaki _name ve greet() Impostor sınıfına aktarılmamıştır. Imposter’a sadece tek String parametre alan ve String dönüş değeri olan greet adındaki bir fonksiyonu yeniden gerçeklemesi gerektiği bilgisi aktarılmıştır. Imposter içerisinde _name tanımlı olmadığı için yeniden tanımlanabilmektedir. greet metodu ise Person arayüzünden aktarılan yapısına uygun şekilde yeniden tanımlanmalıdır.
Bu yapıdaki güzel taraf şudur. greetBob adındaki global fonksiyon Person türünde bir parametre almaktadır ve greet metodunu çağırmaktadır. main içerisindeki greetBob çağrılarında birinde Person diğerinde ise Imposter türünde yaptığımız parametre aktarımlarında farklı greet metotlarının çağrıldığı görülecektir.
Bir sınıfın birden fazla arayüzden miras alması mümkündür.
Bir sınıfın miras alırken tüm özellik ve davranışlarını devralmasını istiyorsak extends anahtar kelimesi ile miras alımı yapılmalıdır. extends ile miras alımlarında sadece tek bir sınıftan miras alımı yapılır. Extends ile miras alımında amaç miras alınan sınıfın özelliklerini genişletmek suretiyle aynı yapıda daha gelişmiş bir sınıf oluşturmaktır. Extends ile miras alındığında ebeveyndeki tüm her şey miras alınır. @override dipnotu (annotation) ile miras alınan fonksiyonlar bilinçli şekilde ezilebilir.
3.1.7. noSuchMethod()
Miras alma süreçlerinden kaynaklı dinamik oluşturulmuş bir objenin üye fonksiyonlarını çağırırken olmayan bir üye çağrısı durumunda uygulamanın hata vermesi yerine bunu düzenleyecek noSuchMethod() fonksiyonu kullanılmaktadır.
3.1.8 Mixin ile Sınıflara Özellik Ekleme
Dart ile birden fazla sınıftan(arayüzden) implements ile davranış alabileceğimizi ama sadece bir tane ana miras yolunu extends ile belirttiğimizi söylemiştik. Eğer birden fazla koldan sınıfın özellikler alması gerekiyorsa çözümümüz ne olmalıdır? C# ve Java dillerinde nesne yönelimli yaklaşımın bellek yönetimini zorlaştıracağı için bir çözüm sunulmamış C++’da ise tam aksine çok sayıda ana hattan miras alımına izin verilmiştir. Dart ise bu ikisinin arasında bir çözümü mixin adı verilen yan parçacıkların with anahtar kelimesi ile miras alımına eklenmesiyle sunmaktadır.
Burada Musician, Performer sınıfından miras almaktadır. Performer sınıfının yanında Musical adındaki mixim’in de belirttiği özellikleri bünyesine eklemiştir. Maestro, Musician’a göre daha donanımlıdır ve başka ek özellikleri olmalıdır ama bunları Performer’a ekleyemeyiz ve Maestro, Musician sınıfından da miras alamaz (Bunun kavramsal olarak neden olamayacağı nesne modelleri ve ilişkileri konusudur. Burada detaya inilmeyecektir.). Maestro’nun içermesi gereken bu ek özellikler farklı mixin’ler olarak eklenmiştir. Görüleceği üzere birden fazla mixin with anahtar kelimesi ile miras almada kullanılabilir.
Eğer bir mixin’in kullanımında belli bir sınıftan miras alınması gerekli ise mixin oluşturulurken on anahtar kelimesi ile bu durum belirtilebilir. Bazı fonksiyonaların çalışabilmesi için belli özelliklerin tanımlanması gereken durumlar için bu yaklaşım gerekebilir.
3.2. Kütüphaneler ve Görünürlük
Dart zengin bir kütüphane yapısına sahiptir ve bu topluluğun aktif katılımı ile giderek artmaktadır. Kütüphaneler package olarak pub.dev sayfasında paylaşılır. Kütüphaneler aynı zamanda altçizgi(_) ile başlayan objelerin kütüphane dışından erişimine izin vermediği için bir gizlilik de sağlarlar. Her uygulama aynı zamanda bir kütüphanedir.
Projenize bir kütüphane dahil etmek istediğinizde import anahtar kelimesi ile kütüphane yolunu (URI- Unique Resource Identifier) vermeniz yeterlidir.
Yukarıda Dart dağıtımı ile gelen html kütüphanesi ve paket olarak yazılmış test kütüphanesinin koda dahil edilmesi örnekleri verilmiştir. pub.dev üzerinden sağlanan paketlerin dahil edilmesinde package: ile yol belirtilmektedir.
Bir kütüphane projenize dahil ettiğinizde içerisindeki tüm tanımlamalar projenize dahil olurlar. Bazen farklı iki kütüphanede aynı isimlendirme kullanılabilir. Bu durumda ilk kütüphane içerisindeki tanımlama kabul görecektir. İkinci kütüphanenin takılanması sayesinde çakışma giderilir. Örnekte ikinci kütüphane as lib2 olarak takma isim verilerek import edilmiştir. Kod içerisinde de bu takma isim kullanılarak içerdiği elemanlara erişilmektedir.
Bazen de kütüphane içerisinde sadece belli tanımların görünmesi veya gizlenmesi istenebilir. Bunun için show ve hide anahtar kelimeleri kullanılır.
Kütüphanelerin paketler şeklinde İnternet üzerinden paylaşımı kod geliştirme süreçlerini kolaylaştırmıştır. Artık pek çok fonksiyon için yazılımcılar başkaları tarafından hazırlanmış paketler bulup açık kaynak dağıtımı sayesinde kullanabilmektedir. Siz de isterseniz kendi paketinizi üreterek pub.dev altında yayınlanmasını sağlayabilirsiniz. Bununla ilgili adımlar Creating packages sayfasından incelenebilir.
3.3. Genişleme Metotları (Extention Methods)
Dart 2.7 sürümünde eklenmiş olan bu özellik müdahale edemediğiniz sınıf tanımlamalarını genişletmek ve istediğiniz metotların bu sınıflar için tanımlanmasında kullanılır. Kod yazarken IDE’nin sunduğu otomatik tamamlama özelliğinde genişleme metotları da önerilmektedir. Dart’ta temel türler dahi birer obje oldukları için onlara hatta kod içerisindeki sabitlere de genişleme metotları uygulanır.
Örneğin bir String değerin tamsayı türüne döndürülmesi için int tanımlamasında parse fonksiyonu vardır. Fakat String tanımında bir fonksiyon bulunmamaktadır. Oysaki işlem yapılan veri String olduğu için String veriye bir metot uygulamak daha akla yatkın bir çözümdür. Bunun için aşağıda birinci satırdaki işlemi ikinci satırdaki gibi yazabiliriz.
String tanımlaması Dart’ın ana kodlamasında tanımlıdır ve parseInt adında bir metodu bulunmamaktadır. Dart geliştiricileri bu genişleme fonksiyonunu sisteme daha sonra bir kütüphane olarak dahil etmiştir. Bunun için aşağıdaki import işlemiş yapılır. Burada string_apis.dart dosyası parseInt metodunun String veri tipi için tanımlandığı yerdir.
Bu genişleme metodunun tanımlanması için aşağıdaki gibi extension anahtar kelimesi ile başlayan bir tanımlama bloğu açılır. Bu blok sayesinde String sınıfı genişletilmiş ve verilen yeni özelliklere sahip olmuş olur.
3.4 Jenerik (Generics)
Veri türlerini incelerken diziler için List veri türü kullanıldığını ve bunun aslında diğer dillerde koleksiyonlarla yapıldığını söylemiştik. Aslına bakarsanız her iki tanımlamada da kullanılan yöntem generics olarak adlanıdırılan ve List<E> (E burada jenerik olarak sonradan atanacak türü ifade etmektedir.) gösterimi ile tanımlanmıştır.
Jenerik tanımlaması kodun daha iyi derlenmesine katkı sağlar ve gereksiz kod tekrarlarını engeller. Bir dizide sadece String değerlerin saklanmasını istiyorsak List<String> şeklinde bir dizi tanımlaması yaparız. Bu sayede farklı türde verinin bu listede yer almayacağı beyan edilmiş olur.
Kod tekrarını azaltmak için geliştirdiğimiz yapıları jenerik formunda hazırlayabiliriz. Bu sayede aynı kod farklı yerlerde farklı veri türleri ile çalışabilir. Aşağıdaki örneği inceleyelim;
Burada Cache adındaki sınıf jenerik olarak tanımlanmıştır ve T adı altında henüz belirtilmemiş bir veri türü ile çalışabilir denmektedir. Bu T türü örneğin Cache<int> şeklinde bir kullanımda int, Cache<String> şeklinde bir kullanımda String veri türü olarak değiştirilecek ve buna göre sınıf içerisindeki fonksiyonların varyantları üretilecektir. Cache<int> için durumu düşünürsek getByKey metodunun dönüş değeri int türünde olacak ve setByKey metodunun ikinci parametresi de int türünde olacaktır. Sonuçta Cache sınıfının T:int olan varyasyonu için bir derleme yapılacaktır. Aynı süreç T yerine gelecek her veri türü için tekrarlanır ve tek bir kod bloğu farklı veri türlerinde tekrar tekrar farklı veri türüyle derlenir.
3.5. Asenkron Uygulama Geliştirme Desteği
Gelişmiş programlama dillerinde sunulan en önemli özellikler arasında asenkron kod çalıştırma desteği gelmektedir. Asenkron kodlama ihtiyacının çoğu dildeki temel çözümü multi-thread (çoklu işlemli) uygulama geliştirmektir. Multi-thread uygulama geliştirmek yazması ve bakımı açısından zor bir süreçtir. Birbirinden bağımsız iş parçalarının ortak alanları kullanımı için birçok düzenleme gerekmektedir. Yanlış yazılan bir kod parçası tüm iş parçalarının çalışmasını engelleyebilir.
Dart dili asenkron desteğini basit bir formda sunmaktadır. Multi-Thread kodlama gerektiren yerlerde cevabı sonradan dönecek fonksiyon çağrısı kullanmaktadır. Çünkü Multi-Thread kodlamadaki yegâne amaç CPU’nun I/O gecikmelerinden etkilenmemesi ve tam kullanılabilmesidir. Dart, bir fonksiyonun yüksek bir I/O gerektirmesi durumunda kodun bu fonksiyon sonucunu beklemeksizin çalışması için Future ve Stream adında iki veri türü kullanmaktadır.
Kod içerisinde sonradan gelecek veri kısmının asenkron çalıştırılması ve icap ettiğinde gelecek sonucun beklenmesi sırasıyla async ve await anahtar kelimeleri ile sağlanmaktadır. İçerisinde async ve await anahtar kelimeleri yer alan bir kod asenkron bir yapıdadır fakat senkron çalışan bir kod ile aynı görünümdedir.
Yukarıda checkVersion adında bir fonksiyon tanımlanmaktadır. Bu fonksiyonun çağrılacağı yerde asenkron çalışmasını istiyoruz. Yani ben main içerisinden checkVersion fonksiyonunu çalıştırayım ama sonucunu beklemeden bir sonraki komutu çalıştırmaya geçeyim. Bunu sağlamak için checkVersion fonksiyonunun tanımında async anahtar kelimesi kullanılır. async kullandığımız için fonksiyon geri dönüş değeri olarak Future veya Stream türü bir değer dönmelidir. checkVersion fonksiyonunun herhangi bir değer dönmesini istemesek de Future dönmesi gerekir. Bu nedenele Future<void> formunda boş bir Future dönülür.
Asenkron çalışan bir fonksiyon içerisinde başka asenkron veya senkron fonksiyonlar çağrılabilir. Asenkron fonksiyon çağrısında eğer devam eden komutlarda bu fonksiyonun işini bitirmesi gerekiyorsa bekletme için await komutu kullanılır. Yukarıdaki kodda lookUpVersion fonksiyonu da asenkron çalışan başka bir fonksiyon olsun. checkVersion fonkisyonunun devamında lookUpVersion’dan dönen version bilgisine ihtiyaç duyuyorsam lookUpVersion fonksiyonu önüne await koyularak çağrılır. await önüne geldiği fonksiyonunun işi bitmeden sonraki kodun icra edilmesini engeller. Bir nevi senkron çalışmaya zorlar. Böylece async blokları içerisinde senkron olarak yapılması gereken işlemler düzenlenirler. Bir asenkron (async) fonksiyon çağrısı içerisinde birden fazla await kullanımı olabilir.
Bazı yerlerde await kullanma ihtiyacınız olduğu halde hata alıyorsanız (örneğin main içerisinde asenkron bir fonksiyon çağıracaksanız ve senkron iş görmesi gerekiyorsa) await yazılan fonksiyon gövdesi async ile kuşatılır. Aşağıdaki örnekte lookUpVersion fonksiyonu main içerisinde konsola veri yazmak için çağrılmaktadır. Konsola yazan print metodu lookUpVersion sonucunu beklemelidir bu nedenle await kullanılır. await kullanımından dolayı main fonksiyonu async olmalı ve bundan dolayı da Future<void> geri dönüş değerine sahip olmalıdır.
Future dönüş değeri eğer asenkron çalışacak kod bloğu işlem sonunda tek seferde sonuç dönecekse kullanılmaktadır. Eğer asenkron kod bloğu işlem yaparken sürekli bir veri akışı olacak ve bu veri akışının eş zamanlı olarak işlenmesi gerekiyorsa Future yerine Stream türü jenerik bir dönüş değeri kullanılır. Future ve Stream kullanımı ile ilgili alıştırmaya Asynchronous programming: futures, async, await ve Asynchronous programming: Streams bağlantılarından erişilebilir.
async fonksiyon tanımlamak asenkron kod yazmanın kolay yoludur ve senkron bir kodlama yaklaşımı içerisinde asenkron çalışan uygulama geliştirmemizi sağlar. Bunun haricinde Dart multi-thread yaklaşımı için isolate olarak adlandırılan bir modeli desteklemektedir. Klasik multi-thread yaklaşımda tüm thread’ler ortak erişimli bir bellek bölgesi kullanırlar. Bu kodun kararsız olmasına neden olabilir ve uygulamanın çalışmasında çeşitli komplikasyonlar oluşturur. Dart isolate kullanarak ayrı koşacak her bir kod parçasını kendine ayrılmış bellek bölgesine erişimle çalıştırır. Böylece isolate’ler birbirini tutarsız hale getirme tehlikesine girmezler. Arkaplan işlemleri ile ilgili konu işlenirken isolate çalışma mantığı incelenecektir. Konu ile ilgili örneğe Dart asynchronous programming: Isolates and event loops | by Kathy Walrath sayfasından bakılabilir.
Bölüm Özeti
Bu bölümde Dart programlama dilinin nesneye yönelimli programlamadaki kullanım şekline diğer dillere göre farklı miras alma modeline implements, extends, with anahtar kelimeleri ile miras alma yaklaşımlarına bakılmıştır. C# ve Java ile C++ arasındaki çoklu miras alma modeli farklılığında Dart mixin-based bir yaklaşım sunarak ikisi arasında bir model kullanmaktadır. public, private ve protected gibi erişim belirteçleri Dart programlama dilinde kullanılmamıştır. Bunun yerine private ve protected manasına gelecek şekilde altçizgi(_) ile tanımlama yapılması benimsenmiştir. Asenkron uygulama geliştirmek için Dart basit fonksiyon tabanlı asenkron kod çalıştırmayı async ve await anahtar kelimeleri ile desteklemektedir. Bu fonksiyonlar Future veya Stream türü dönüş yapmaktadır ve dönülen değer daha sonra hazır hale gelmektedir. Genişletme metotları ile üzerinde değişiklik yapma imkanımız olmayan kütüphanelerdeki sınıfların davranışlarını zenginleştirme imkanımız vardır. Dilin bu özelliklerinin yanında tam bir içerik Dart.dev internet adresi üzerinden incelenebilir.
Kaynakça
https://dart.dev/guides/language/language-tour
https://dart.dev/guides/language/specifications/DartLangSpec-v2.10.pdf
https://dart.dev/guides/libraries/library-tour
Ünite Soruları
Soru-1 :
Aşağıdakilerden hangisi yanlıştır?
(Çoktan Seçmeli)
(•) – Dart programlama dilinde public, private, protected gibi erişim belirtici anahtar kelimeler kullanılmamaktadır.
(•) – Dart programlama dilinde bir sınıf içerisindeki üye değişkenlere ilk değer verilebilir.
(•) – ok (=>) operatörü ile oluşturulmuş tek satırlık fonksiyonlarda return yazmaya gerek yoktur.
(•) – Dart programlama dilinde bir sınıf(class) aynı anda birden fazla sınıftan extends anahtar kelimesi kullanarak miras alabilir.
(•) – Dart programlama dilinde bir sınıf(class) aynı anda birden fazla mixim’den with anahtar kelimesi kullanarak miras alabilir.
Cevap-1 :
Dart programlama dilinde bir sınıf(class) aynı anda birden fazla sınıftan extends anahtar kelimesi kullanarak miras alabilir.
Soru-2 :
Dart programlama dilinde soru işareti-nokta (?.) ile bir sınıfın üyelerine erişimin sağladığı özellik nedir? var deger = obj?.value;
(Çoktan Seçmeli)
(•) – Sınıfın örneğinin (obj), null olması durumunda kodun hata vermesini engeller.
(•) – Erişilen değerin (value) null olması durumunda kodun hata vermesini engeller.
(•) – Atama yapılan değişkenin (deger) kod içerisinde kopyasının oluşturulmasını engeller.
(•) – Başka bir paket içerisinde tanımlı alanlara erişim imkanı sağlar.
(•) – Erişilen alanın ebeveyn sınıfta olduğunu belirtir.
Cevap-2 :
Sınıfın örneğinin (obj), null olması durumunda kodun hata vermesini engeller.
Soru-3 :
Point adında bir sınıfım varsa Dart programlama dilinde aşağıdaki satırlardan hangisi isimlendirilmiş bir yapıcı fonksiyon (named-constructor) tanımıdır?
(Çoktan Seçmeli)
(•) – Point(this.x, this.y);
(•) – Point( { int x, int y } ) { ….. }
(•) – Point.fromText( int x, int y, String source) { ….}
(•) – Print(int x , int y) { …… }
(•) – Point() { …..}
Cevap-3 :
Point.fromText( int x, int y, String source) { ….}
Soru-4 :
Dart programlama dilinde implements anahtar kelimesi hangi amaçla kullanılır?
(Çoktan Seçmeli)
(•) – Bir sınıftan tüm özelliklerini alarak miras almak için.
(•) – Yeni bir mixin oluşturmak için.
(•) – Bir sınıftan arayüz (interface) olarak miras almak için.
(•) – Bir sınıfın sonradan genişletilmesinin sağlamak için
(•) – Bir sınıfın soyut (abstract) olduğunu ifade etmek için.
Cevap-4 :
Bir sınıftan arayüz (interface) olarak miras almak için.
Soru-5 :
noSuchMethod() fonksiyonunun kullanım amacı nedir?
(Çoktan Seçmeli)
(•) – Sınıfın yapıcı fonksiyonu olmadığını gösterir.
(•) – Dinamik oluşturulmuş bir objenin miras almadan gelmeyen(olmayan) bir üye fonksiyonu çağrıldığında hatayı engeller.
(•) – Sınıfın örneği oluşturulmaksızın bir fonksiyonunun kullanımını engeller.
(•) – Miras alınan sınıflarda aynı fonksiyonların tekrar yazılmasını engeller.
(•) – Mixin ile miras alma özelliği kullanılmayan bir sınıfı ayırt etmeyi sağlar.
Cevap-5 :
Dinamik oluşturulmuş bir objenin miras almadan gelmeyen(olmayan) bir üye fonksiyonu çağrıldığında hatayı engeller.
Soru-6 :
Bir sınıf oluşturulurken Mixin türü tanımladan miras alması için hangi anahtar kelime kullanılır?
(Çoktan Seçmeli)
(•) – extends
(•) – implements
(•) – with
(•) – perform
(•) – execute
Cevap-6 :
with
Soru-7 :
Flutter ve Dart içn hazırlanmış kütüphanelerin ortak paylaşımı için hazırlanmış özel İnternet sayfası hangisidir?
(Çoktan Seçmeli)
(•) – flutter.dev
(•) – dart.dev
(•) – developer.android.com
(•) – pub.dev
(•) – dartpad.dev
Cevap-7 :
pub.dev
Soru-8 :
Bir sınıfın kodlamasına müdahele etme şansımız olmasa da sınıfa ek üye fonksiyonlar tanımlamamızı sağlayan yaklaşıma verilen ad nedir?
(Çoktan Seçmeli)
(•) – İsimlendirilmiş Parametre (Named Parameter)
(•) – İsimlendirilmiş Yapıcı Fonksiyon (Named Constructor)
(•) – Genişletme Metodu (Extention Method)
(•) – Mixin Tabanlı Miras Alma (Mixin-Based Inheritance)
(•) – Jenerik (Generics)
Cevap-8 :
Genişletme Metodu (Extention Method)
Soru-9 :
Eğer bir metodun asenkron çalışmasını istiyorsak metot tanımlamasında gövdesinden önce hangi anahtar kelime gelmelidir?
(Çoktan Seçmeli)
(•) – thread
(•) – async
(•) – await
(•) – Future
(•) – Stream
Cevap-9 :
async
Comments