Dart Fonksiyonlarında Parametre Kullanım Türleri

Dart ile bir fonksiyon oluşturmak için, fonksiyon adı ve geri dönüş tipini belirledikten sonra parantez içerisinde veri türünü belirttiğiniz bir parametre adı ile birlikte virgülle ayırarak istediğiniz sayıda parametre ekleyebilirsiniz.

Bu söz kalabalığını şu şekilde özetleyebiliriz.

void functionName(String parameter1, int parameter2 ...){...}

İstediğiniz sayıda dedik ama doğrusu bir sınırı var mı gerçekten bilmiyorum. İşin doğrusu önemli de değil.

Zira iyi yazılmış bir fonksiyonun özelliklerini Robert C. Martin, "Clean Code: A Handbook of Agile Software Craftsmanship" kitabında fonksiyonlara ait clean code prensipleri ile şu şekilde açıklıyor;

  1. Function should do one thing. They should do it well. They should do it only.

  2. If a function does only those steps that are one level below the stated name of the function, then the function is doing one thing.

  3. The smaller and more focus a function is, the easier it is to choose a descriptive name.

  4. Another way to know that a function is doing more than "one thing" is if you can extract another function from it with a name that is not merely a restatement of its implementation.

  5. A long descriptive name is better than a long descriptive comment.

  6. The ideal number of arguments for a function is zero (niladic). Next comes one (monadic), followed closely by two (dyadic). Three arguments (triadic) should be avoided where possible. More than three (polyadic) requires very special justification-- and they shouldn't be used anyway.

  7. Function should either do something or answer something, but not both. either your function should change the state of an object, or it should return some information about that object. doing both often leads to confusion.

Sınırlar konusundaki doğru tercihleri 6. madde de net olarak belirtmiş.

Konumuza geri dönelim..

Yukarıda belirtmiş olduğumuz fonksiyon yapısında "String parameter1, int parameter2" olarak belirttiğimiz alandaki tüm parametrelerin girişi zorunludur. Eğer eksik ya da fazla girerseniz hata alırsınız.

Bu şekilde olan kullanım şekline de literatürde Positional Parameters/Konumsal Parametreler adı veriliyor.

Peki bazı parametrelerin opsiyonel olmasını istesek?

Bu durumda yazım şeklimizi aşağıdaki gibi değiştirmek gerekiyor.

void functionName(String parameter1, [int parameter2]){...}

Köşeli parantezlerle belirtitğimiz alandaki parametreler artık isteğe bağlı olarak kullanılabilecektir.

Hadi deneyelim! Örneğimizi aşağıdaki gibi hazırladım.

void functionName(String name, [int age]){
  print("Name: $name - Yaş: ${age.toString()}");
}

main() {
  functionName("Egemen");
}

Ancak şöyle bir hata alıyorum.

Error: The parameter 'age' can't have a value of 'null' because of its type 'int', but the implicit default value is 'null'.

Yani "age" parametresi, "int" türünden dolayı 'null' değerine sahip olamaz. Fakat, örtük (implicit) varsayılan değer "null"dur. (Bkz. Potentially non-nullable)

Bu durumu ortadan kaldırmak için birkaç çözüm uygulayabiliriz.

1. Madem "age" parametresi örtük (implicit) varsayılan değer olarak "null" ise, bunu kullanmasına izin vermeliyiz. Bu sebeple "age" parametresini aşağıdaki gibi null yapılabilir hale getirmeniz gerekir.

void functionName(String name, [int? age]){
  print("Name: $name - Yaş: ${age.toString()}");
}

main() {
  functionName("Egemen");
}

Bu durumda hata ortadan kalkacak, ancak çıktı şu şekilde oluşacaktır.

Name: Egemen - Yaş: null

2. Eğer ilk örnek çözümümüzde olduğu gibi parametrenizin null olmasını istemiyorsanız, varsayılan bir değer atamalısınız.

void functionName(String name, [int age = 18]){
  print("Name: $name - Yaş: ${age.toString()}");
}

main() {
  functionName("Egemen");
}

Bu durumda hata yine ortadan kalkacak ve çıktı şu şekilde oluşacaktır.

Name: Egemen - Yaş: 18

Devam edelim..

Aslında yukarıdaki çözümlere bir tane daha ekleyebilirdik. Bu durumda age parametresini zorunlu olarak kullanıcıdan girmesini istememiz gerekirdi.

Bunun için örneğimizi aşağıdaki gibi güncelleyelim.

void functionName(String name, {required int age}){
  print("Name: $name - Yaş: ${age.toString()}");
}

Eğer istediğimiz bir parametrenin zorunlu olarak girilmesini istiyorsak süslü parantezler içerisinde bunu required olarak, aynen yukarıdaki gibi belirtmemiz gerekir.

Bunu da aşağıdaki gibi çağıralım.

main() {
  functionName("Egemen", 43);
}

Fakat aşağıdaki hatayı aldık..

Error: Too many positional arguments: 1 allowed, but 2 found.

İşte tam da bu noktada ikinci paramtreyi çağırma şeklimizin faklı olduğunu anlıyoruz. Zira zaten herhangi bir şey yazmadan (required gibi) ve süslü parantezler kullanmadan zorunlu olarak bu parametreleri belirtebiliyorduk. O halde bu yapıyı neden kullanayım?

Bu sorunun cevabı birazda kullanma şeklinde saklı.

Aynı constructor'larda nasıl ki **named constructorlar **tanımlanabiliyorsa, Dart dilinde fonksiyon tanımlamalarında zorunlu alanlarda da named olarak tanımlama yapılabiliyor.

Buna göre örneğimizi aşağıdaki gibi değiştirirsek,

void functionName(String name, {required int age}){
  print("Name: $name - Yaş: ${age.toString()}");
}

main() {
  functionName("Egemen", age: 20);
}

hata ortadan kalkacak ve aşağıdaki çıktıyı elde edebileceğiz.

Name: Egemen - Yaş: 20

Egemen MEDE - 23.09.2022