Tüm Yazılar
KategoriFlutter
Okuma Süresi
15 dk
Yayın Tarihi
2026-09-07
Kelime Sayısı
3.229kelime

Kahveni hazırla - bu içerikli bir makale!

Dart 3.13 Primary Constructor: Sınıfları Tek Satırda Yaz

Özet

Dart primary constructor nedir, nasıl kullanılır? var/final declaring parameter kuralları, in-body constructor kısıtı, const sınıflar ve Flutter widget'larında pratik kazanç — Dart 3.13 rehberi.

Dart 3.13 Primary Constructor: Sınıfları Tek Satırda Yaz

Dart 3.13, 12 Ağustos 2026'da yayınlandı ve dilin en köklü sözdizimi yeniliklerinden birini getirdi: primary constructor. Artık bir sınıfın alanlarını ve ana constructor'ını tek satırda tanımlayabiliyorsun — class Point(var int x, var int y); yazman yeterli. Bu rehberde primary constructor'ın gerçekte ne yaptığını, var/final koyunca neyin değiştiğini, hangi durumlarda derleyicinin seni durdurduğunu ve Flutter projelerinde ne zaman kullanıp ne zaman kullanmaman gerektiğini satır satır göreceksin.

💡 Pro Tip: Primary constructor sadece yazım şeklini değiştirir, çalışma zamanı davranışını değiştirmez — yani mevcut kodun mantığını bozmadan kademeli olarak geçiş yapabilirsin.

İçindekiler

Primary Constructor Nedir: Point Sınıfının İki Hali

Geleneksel Dart'ta bir Point sınıfı yazarken alanları sınıf gövdesinde bildirir, sonra constructor içinde this.x, this.y ile tekrar eşlersin:

dart
1// Dart 3.13 öncesi klasik yazım
2class Point {
3 final int x;
4 final int y;
5 Point(this.x, this.y);
6}

Dart 3.13 ile aynı sınıfı tek satırda yazabilirsin:

dart
1// Dart 3.13 primary constructor
2class Point(var int x, var int y);

Dart ekibinin resmi tanımı şöyle: "Primary constructors provide a concise way to declare a class's fields and its main constructor in a single line." Yani x ve y parametreleri hem constructor argümanı hem de sınıfın instance değişkeni oluyor — ayrı bir gövdeye, ayrı bir atamaya gerek kalmıyor. Kritik nokta şu: bu bir performans optimizasyonu değil, saf bir sözdizimi kısayolu. Dart dokümantasyonu bunu açıkça belirtiyor: "This shorthand changes how you write the declaration, but it doesn't change runtime behavior." Derlenen kodun çalışma zamanı davranışı, klasik yazımla üretilenle birebir aynı.

Boş gövdeli sınıflarda süslü parantezleri bile atabilirsin. Dokümantasyon şunu ekliyor: "An empty body of a class...can be replaced by a semicolon (;)...particularly useful when using a primary constructor to keep the entire declaration on a single line." Yukarıdaki Point örneğindeki noktalı virgül tam olarak bunun için var.

Declaring Parameter: var/final Koyunca Ne Oluyor, Koymayınca Ne Olmuyor

Primary constructor'ın kalbi "declaring parameter" kavramı. Kural net: parametreyi var veya final ile işaretlersen, bu parametre otomatik olarak bir instance değişkeni (field) üretir. Resmi ifadeyle: "Declaring a parameter in the primary constructor with var or final implicitly induces an instance variable." İşaretlemezsen hiçbir şey oluşmaz — parametre sadece geleneksel bir constructor parametresi gibi davranır: "If you omit the modifier, the parameter doesn't create a field. It behaves just like a parameter in a traditional constructor."

dart
1// var/final ile: x ve y birer alan olur
2class Point(var int x, var int y);
3 
4// modifier yok: delta alan OLUŞTURMAZ, field initializer'da parametredir
5class DeltaPoint(final int x, int delta) {
6 final int y = x + delta;
7}

Bu ayrım önemli çünkü çoğu geliştirici alışkanlıkla her parametreye var koymaya kalkabilir, ama bazen sadece geçici bir constructor argümanına (yukarıdaki delta gibi bir ara değere) ihtiyacın olur — o durumda modifier'ı bilinçli olarak atlarsın.

İki farklı "scope" kuralı da burada devreye giriyor. Primary initializer scope dokümantasyonun ifadesiyle "non-late field initializers in the class body and to the primary constructor's initializer list (after this :)" kapsamına uygulanır; orada parametre adı gelen argümanı temsil eder. Primary parameter scope ise yalnız "the body block of the primary constructor (inside { ... })" için geçerlidir; orada declaring parameter'ın adı üretilen instance değişkenine işaret eder. Bu ayrımı karıştırmak kolay; bir sonraki bölümde gövde bloğunun nasıl yazıldığını göreceksin.

In-Body Constructor Kuralı: Neden İkinci Generative Constructor Yasak

Primary constructor'ı olan bir sınıf, redirecting olmayan başka bir generative constructor tanımlayamaz. Dart dokümantasyonu bu kısıtı şöyle koyuyor: "a class...with a primary constructor can't have any other non-redirecting generative in-body constructors." Bu yasak ada bakmaz: Point.origin() : x = 0, y = 0; gibi adlı ama redirecting olmayan bir generative in-body constructor da aynı hataya düşer. Serbest kalanlar yalnızca primary constructor'a yönlendiren (redirecting) constructor'lar ve generative olmadıkları için factory constructor'lardır — dokümantasyonun private primary constructor deseni de tam buna dayanıyor: "forces callers to use factory methods or other constructors."

Peki initializer list veya assert gibi doğrulama mantığı nereye gidecek? Buna primary constructor gövdesi (this bloğu) çözüm getiriyor:

dart
1class Point(var int x, var int y) {
2 this : assert(x >= 0 && y >= 0) {
3 // ek doğrulama veya yan etki burada çalışabilir
4 }
5}

Bu gövde parçasının da kendi kısıtları var: "A primary constructor body part...can't use the async, async*, or sync* modifiers, and it can't use the expression body arrow (=>) syntax." Yani this : ... async { } ya da ok işareti (=>) ile kısaltma yazamazsın — sadece klasik süslü parantez gövdesi kullanılır.

Kısıtın gerekçesini dokümantasyon yazıyor: "To ensure the primary constructor executes on every new instance." Yani amaç, primary constructor'ın her yeni instance'ta mutlaka çalışması. Bu netlik, declaring parameter'ların güvenilir şekilde field üretmesini sağlıyor.

Named, Optional ve Süper Parametreler

Primary constructor named (adlandırılmış) constructor'ları da destekliyor — sadece sınıf adının ardına nokta ile ek isim yazıyorsun:

dart
1// Named primary constructor
2class Point.custom(var int x, var int y);
3 
4// Private named primary constructor
5class Point._(var int x, var int y);

Named/optional parametreler ve required anahtar kelimesi de klasik constructor'lardaki gibi çalışır. Özel (private) bir alanı named parametre ile başlatmak istersen:

dart
1class User({required var String _name});
2// Dışarıdan çağrı yine de public isimle yapılır:
3// User(name: 'John Doe')

Kalıtımda super parametreleri de primary constructor içinde doğrudan kullanılabiliyor — üst sınıfın alanlarını tekrar tanımlamana gerek kalmıyor:

dart
1class Person {
2 Person(this.name, this.age);
3 final String name;
4 final int age;
5}
6 
7class Employee(super.name, super.age, final String role) extends Person;

Burada role yeni bir declaring parameter, super.name ve super.age ise doğrudan üst sınıfın constructor'ına aktarılıyor. Bu, özellikle Flutter'da katmanlı model sınıfları (ör. bir BaseEntity üzerine kurulu domain modelleri) yazarken tekrarı belirgin şekilde azaltıyor.

Enum'larda da primary constructor kullanılabiliyor, hatta örtük olarak const:

dart
1enum Color(final String hex) {
2 red('#FF0000'),
3 green('#00FF00'),
4 blue('#0000FF');
5}

Dokümantasyon şunu netleştiriyor: "Primary constructors in enums are implicitly constant." Yani enum değerlerini oluştururken const anahtar kelimesini elle yazmana gerek yok.

Const Sınıflar ve Immutability

Değişmez (immutable) veri sınıfları için primary constructor'ı const ile birleştirebilirsin:

dart
1class const ConstPoint(final int x, final int y) {
2 final int z;
3 // Initializer list serbest, gövde bloğu değil.
4 this : z = x + y;
5 
6 int get squaredDistanceFromOrigin => x * x + y * y;
7}

Ama burada sıkı bir kural var: const bir primary constructor, süslü parantezli bir gövde bloğu (this : ... { }) barındıramaz — boş olsa bile. Dokümantasyon: "Having a { ... } body is a compile-time error, even if it's empty." Kısıt sınıf gövdesini değil, constructor'ın gövde bloğunu hedefliyor: örnekteki alan, getter ve initializer list serbest; this : z = x + y { } yazsaydın hata alırdın.

Const constructor'ın alanları için de ek kısıt var: "every instance variable must be final, can't be late, and must be definitely initialized." Yani var ile değil, mutlaka final ile bildirmen ve late kullanmaman gerekiyor. Bu, Dart'ın const nesnelerin derleme zamanında tamamen belirleniyor olması gerektiği ilkesiyle tutarlı — declaring parameter'lar bu ilkeyi otomatik olarak zorunlu kılıyor.

Widget Sınıflarında Pratik Kazanç

Flutter'da StatelessWidget ve StatefulWidget alt sınıfları neredeyse her zaman aynı kalıbı izler: bir grup final alan, hepsini this. ile atayan bir constructor, çoğu zaman bir de super.key. Bu, primary constructor'ın en doğal uygulama alanlarından biri çünkü Dart ekibinin de vurguladığı gibi bu sözdizimi çalışma zamanı davranışını değiştirmeden yalnızca yazımı kısaltıyor — yani mevcut widget'larının render davranışında hiçbir risk almadan satır sayısını azaltabilirsin:

dart
1import 'package:flutter/material.dart';
2 
3// key named parametre; super.key de named kalır.
4class ProfileCard({
5 super.key,
6 required final String name,
7 required final String avatarUrl,
8}) extends StatelessWidget {
9 @override
10 Widget build(BuildContext context) {
11 return Card(
12 child: ListTile(title: Text(name), leading: Image.network(avatarUrl)),
13 );
14 }
15}

Burada super.key üst sınıfa (StatelessWidget) doğrudan aktarılıyor, name ve avatarUrl ise final declaring parameter olarak alan üretiyor — klasik yazımda bunun için ayrı üç satır (final String name;, final String avatarUrl;, constructor gövdesi) gerekirdi. Ben kişisel olarak sade, tek sorumluluklu "dumb" widget'larda (parametreleri alıp sadece render eden bileşenlerde) primary constructor'ı tercih ediyorum; state mantığı, karmaşık initializer veya birden fazla named constructor barındıran sınıflarda ise klasik yazımda kalmayı daha okunabilir buluyorum — bir sonraki bölümde bu sınırın nereye çekildiğini göreceksin.

Extension Type'larda Tek Parametre Kuralı

Extension type'larda primary constructor kullanımı normal sınıflardan farklı bir kısıtla geliyor. Dart dokümantasyonu açık: "For extension types, the primary constructor must have exactly one parameter. This parameter is always a declaring parameter, even if you omit the modifier." Yani extension type'larda var/final yazmasan bile o tek parametre otomatik olarak declaring parameter sayılır — normal sınıflardaki "modifier yoksa field oluşmaz" kuralı burada geçerli değil.

dart
1extension type UserId(int value) {
2 bool get isValid => value > 0;
3}

Burada value parametresi modifier yazılmamış olmasına rağmen extension type'ın temsil ettiği alan oluyor. Bu kural, extension type'ların "tek bir temel tipi sarmalayan hafif wrapper" felsefesiyle örtüşüyor — zaten tek parametre alabildiklerinden, o parametrenin field olması dilin tasarımı gereği zorunlu.

Bir başka kısıt da mixin sınıflarla ilgili: "Mixin classes can only have a primary constructor with no parameters, body, or initializer list." Yani bir mixin sınıfının primary constructor'ı varsa, bu constructor parametresiz, gövdesiz ve initializer list'siz olmak zorunda.

Code-Gen Paketleriyle Uyum

Dart 3.13'ün ekosistemdeki code-gen paketleriyle uyumu, dilin resmi dokümantasyonunda henüz ayrıntılı olarak ele alınmıyor — bu konuda dart.dev veya flutter.dev üzerinde kapsamlı bir uyumluluk açıklaması bulunmuyor. Belgelenmiş bir uyumluluk kısıtı yok; ancak dilin kuralları gereği primary constructor'ın "modifier yoksa field oluşmaz" ve "declaring parameter const sınıfta final olmalı" kuralları, otomatik kod üreten paketlerin ürettiği constructor imzalarıyla çakışabilir çünkü bu paketler genelde kendi constructor'larını this. tabanlı klasik yazımla üretir. Pratik öneri: code-gen ile üretilen sınıflarda (ör. @freezed, @JsonSerializable ile işaretlenmiş modeller) şimdilik primary constructor'a geçiş yapmadan önce ilgili paketin sürüm notlarını kontrol et; bu yazının kaynakçasındaki dart.dev sayfası dışında ekosistem-spesifik bir garanti yok.

Aynı Sürümde Gelen Kardeş Özellik: Concise Constructor

Dart 3.13, primary constructor'la birlikte ilişkili ama farklı bir sözdizimi kısayolu daha getirdi: concise constructor. Dart'ın resmi constructor dokümantasyonu bunu şöyle özetliyor: "In Dart 3.13 and later, you can omit the class name when declaring a generative or factory constructor inside the class body by using the modifier new or factory directly." Yani concise constructor, sınıf gövdesindeki ek constructor'larda sınıf adını tekrar yazma zorunluluğunu kaldırıyor — LongClassName.name() {} yerine new name() {}, factory LongClassName.name() yerine factory name() yazıyorsun. Dikkat: dokümantasyon "concise named constructors don't use a dot between the keyword (modifier) and the name" diyor, yani new.name değil, noktasız new name. Odağımız primary constructor olduğu için detaya girmiyoruz, ama aynı sürümde geldiğini ve isim benzerliği yüzünden karıştırılabileceğini bilmen faydalı.

Ne Zaman Kullanma ve Göç Stratejisi

Primary constructor'ın getirdiği kısıtlar, aynı zamanda "ne zaman kullanmamalısın" sorusunun cevabını da veriyor:

  • Birden fazla generative constructor gerekiyorsa kullanma. Sınıfın birden çok "ana" oluşturma yolu varsa (örneğin Point.fromJson dışında Point.origin gibi tam teşekküllü bir ikinci generative constructor), primary constructor bunu engelliyor — ad vermek kuralı esnetmez; yalnızca redirecting constructor'lar ve factory constructor'lar serbest.
  • Async constructor mantığı gerekiyorsa kullanma. Primary constructor gövdesi async, async*, sync* modifikatörlerini veya => kısaltmasını desteklemiyor.
  • Parametreye sonradan atama yapman gerekiyorsa kullanma. Dokümantasyon: "Assigning to them (such as with x = 5 or x++) in a field initializer...is a compile-time error." Declaring parameter'lar salt-okunur girişler gibi davranır.
  • Aynı adı taşıyan bir metot veya alan varsa kullanma. "Declaring a parameter...with the same name as a method or another field...results in a compile-time error." İsim çakışması derleme zamanında patlıyor.
  • late veya external alan gerekiyorsa kullanma. "The late and external modifiers aren't allowed on parameters in the primary constructor header."

Göç için Dart ekibi somut bir yol öneriyor: 3.12 veya altındaysan, final/var modifikatörünü parametrelerde kullanan yerleri "ahead of upgrading to Dart 3.13" bulup temizlemek için avoid_final_parameters ve var_with_no_type_annotation lint kurallarını etkinleştirebilirsin. Ayrıca parametrelerde final kullanmak (void printValue(final int x) => print(x); gibi) artık extraneous_modifier hatası veriyor; dokümantasyonun çözümü net: "remove the modifier or run dart fix". Değişmez parametreler bir stil tercihiyse, parametrelerde final yerine parameter_assignments kuralı öneriliyor.

Modifier Davranışı Özet Tablosu

Yazım
Field Oluşur mu?
Notlar
var int x
Evet
Değiştirilebilir instance değişkeni
final int x
Evet
Salt-okunur instance değişkeni
int x (modifier yok)
Hayır (normal sınıfta)
Sadece constructor parametresi
int x (extension type'ta)
Evet (her zaman)
Extension type'ta modifier zorunlu değil, tek parametre her zaman declaring parameter
late var int x
Derleme hatası
late/external primary constructor parametresinde yasak

Yaygın Derleme Hataları Özet Tablosu

Senaryo
Sonuç
Kaynak Kural
Primary constructor + ikinci generative constructor
Derleme hatası
Non-redirecting in-body constructor yasak
const primary constructor + { } gövde bloğu
Derleme hatası
Const constructor'da gövde bloğu hata, boş olsa bile
Declaring parametreye x = 5 atama
Derleme hatası
Parametreye atama yasak
Declaring parametre adı mevcut metotla çakışıyor
Derleme hatası
İsim çakışması
Aynı alanı hem bildirip hem initializer list'te atama
Derleme hatası
Çift initialization yasak
Parametrede late/external
Derleme hatası
Bu modifikatörler header'da yasak

ALTIN İPUCU

Bu yazının en değerli bilgisi

Bu ipucu, yazının en önemli çıkarımını içeriyor.

Easter Egg

Gizli bir bilgi buldun!

Bu bölümde gizli bir bilgi var. Keşfetmek ister misin?

Okuyucu Ödülü

Primary constructor'a geçerken kontrol listesi sürekli aklından çıkabiliyor — özellikle mevcut bir kod tabanını kademeli göç ettirirken hangi sınıfın uygun aday olduğuna karar vermek zaman alıyor. Aşağıdaki checklist'i bir sınıfı primary constructor'a taşımadan önce sırayla kontrol ederek kullan; her madde işaretlendiğinde geçiş güvenli demektir.

SSS

Dart primary constructor nasıl yazılır?

Sınıf adının hemen ardından parantez içine parametre listesi yazarsın, örneğin class Point(var int x, var int y);. Bu tek satır hem alanları hem de constructor'ı tanımlar. Dart 3.13 ve üstünde bu sözdizimi varsayılan olarak etkindir, ekstra bir flag açman gerekmez; yalnız paketinin pubspec SDK kısıtının alt sınırının 3.13 veya üstü olması gerekir.

Primary constructor ile eski constructor arasındaki fark nedir?

Geleneksel yöntemde alanları sınıf gövdesinde ayrı bildirir, sonra Point(this.x, this.y) ile constructor içinde tekrar atarsın — primary constructor bu tekrarı tek satıra indirir. Önemli kısıt: primary constructor'ı olan bir sınıf, redirecting olmayan başka bir generative constructor tanımlayamaz; ek constructor'lar "in-body constructor" olarak adlandırılır ve bu kurala tabidir.

var/final olmadan yazılan parametre alan üretir mi?

Hayır. Yalnızca var veya final ile bildirilen parametreler ("declaring parameter") otomatik olarak instance değişkeni oluşturur; değiştirici olmadan yazılan parametre sadece constructor parametresi olarak kalır, field oluşturmaz. Tek istisna extension type'lar: orada tek parametre modifier eksik olsa bile her zaman declaring parameter sayılır.

Freezed ve json_serializable primary constructor ile çalışır mı?

Dart'ın resmi dokümantasyonu bu konuda ayrıntılı bir uyumluluk garantisi vermiyor. Pratik olarak, code-gen paketleri kendi constructor imzalarını klasik yazımla ürettiği için primary constructor'a geçmeden önce kullandığın paketin güncel sürüm notlarını kontrol etmen öneriliyor; bu makalenin kapsamında doğrulanabilen bir birincil kaynak bulunmuyor.

Const sınıflarda primary constructor nasıl kullanılır?

class const ClassName(final int x) şeklinde yazarsın. Yasak olan sınıf gövdesi değil, primary constructor'ın süslü parantezli gövde bloğu — boş olsa bile derleme hatası. Dokümantasyonun örneği sınıf gövdeli: class const ConstPoint(final int x, final int y) { final int z; this : z = x + y; }. Ayrıca const bir primary constructor'daki tüm alanların final olması, late olmaması ve kesin şekilde başlatılmış olması gerekir.

Hangi durumda primary constructor'a hiç geçmemeliyim?

Sınıfın birden fazla generative constructor'a ihtiyacı varsa, constructor gövdesinde async mantık çalıştırman gerekiyorsa veya parametreye sonradan atama yapman gerekiyorsa primary constructor uygun değil — bu senaryolarda derleyici seni doğrudan engelliyor.

Sonuç

Primary constructor, Dart 3.13 ile gelen ve günlük kod yazımını gerçekten kısaltan nadir dil özelliklerinden biri — ama "her yerde kullan" demiyoruz, çünkü kısıtları (tek generative constructor, async yasağı, const'ta body yasağı) belirli tasarım kararlarını zorunlu kılıyor. Basit veri sınıfları, immutable value object'ler ve sade Flutter widget'ları için net bir kazanım; karmaşık initializer mantığı veya birden fazla oluşturma yolu olan sınıflarda ise klasik yazımda kalmak daha güvenli. Dart'ın genel evrimini ve 3.13 öncesi temel yenilikleri daha derinden görmek istersen Dart 3 Yenilikleri ve Modern Özellikler yazısına bakabilirsin. Bu sözdizimini Flutter widget katmanına uygularken Flutter Clean Architecture rehberindeki katman ayrımını referans almanı öneririm; state yönetimi tarafında Flutter Riverpod ile State Management yazısı da benzer immutable model kalıplarını kullanıyor. Performans tarafında primary constructor'ın çalışma zamanını etkilemediğini gördün — asıl 60fps kazanımları için Flutter Performans Optimizasyonu yazısı daha kritik. Son olarak render motoru tarafındaki değişiklikleri merak ediyorsan Flutter 4 Impeller: Yeni Render Engine yazısına göz atabilirsin.

Kaynaklar

Etiketler

#Dart#Dart 3.13#Flutter#primary constructor#declaring parameter#immutability#extension type
Muhittin Çamdalı

Muhittin Çamdalı

Lead Mobile Engineer

12+ yıllık deneyime sahip Lead Mobile Engineer. Swift, SwiftUI, Kotlin ve Flutter ile iOS, Android ve cross-platform mimarilerde uzman. Performanslı ve kullanıcı dostu mobil uygulamalar geliştiriyorum.

iOS Geliştirme Haberleri

Haftalık Swift tips, SwiftUI tricks ve iOS best practices. Spam yok, sadece değerli içerik.

Gizliliğinize saygı duyuyoruz. İstediğiniz zaman abonelikten çıkabilirsiniz.

Paylaş

İlgili İçerik