Masukkan Password
41 Redirecting Constructor Dart | Constructor Redirection in Dart | Dart Tutorials #40
Transcript ini membahas redirecting constructor di Dart. Konsepnya sebenarnya cukup sederhana kalau kita pisahkan dari factory constructor.
Ada beberapa istilah di transcript yang salah karena hasil speech-to-text, misalnya:
- “generator constructor” → generative constructor
- “redirecting constructor” kadang terdengar seperti “rewriting constructor”
- “field initializer” perlu dibedakan dari initializer list
- “const redirecting constructor” juga punya aturan khusus
Saya akan jelaskan dari dasar sampai semua poin yang ada di transcript.
1. Apa itu redirecting constructor?
Redirecting constructor adalah constructor yang mengalihkan proses konstruksi ke constructor lain dalam class yang sama.
Kata kuncinya adalah:
this(...)
Contoh paling sederhana:
class Test {
Test() {
print("Constructor utama");
}
Test.callMe() : this();
}
Di sini ada dua constructor:
Test()
dan:
Test.callMe()
Ketika kita menjalankan:
Test.callMe();
yang terjadi adalah:
Test.callMe()
↓
this()
↓
Test()
↓
"Constructor utama"
Jadi:
Test.callMe()tidak melakukan initialization sendiri, tetapi menyerahkan proses konstruksi kepadaTest().
Itulah redirecting constructor.
2. Kenapa disebut “redirecting”?
Karena constructor tersebut mengalihkan/redirect proses pembuatan object ke constructor lain.
Bayangkan ada dua pintu:
Test.callMe()
|
| redirect
↓
Test()
Jadi kalau kamu masuk melalui:
Test.callMe();
sebenarnya proses construction akhirnya diarahkan ke:
Test();
3. Bentuk dasar syntax
Bentuk umumnya:
ClassName.namaConstructor() : this();
Contoh:
class Person {
Person() {
print("Person()");
}
Person.guest() : this();
}
Person.guest() adalah redirecting constructor.
Bagian:
: this()
adalah yang melakukan redirect.
4. Redirecting constructor bisa memiliki parameter
Tidak harus selalu:
this()
Kita bisa mengirim parameter.
Contoh:
class Person {
String name;
int age;
Person(this.name, this.age);
Person.guest(String name) : this(name, 0);
}
Sekarang:
Person.guest("Budi");
akan diarahkan ke:
Person("Budi", 0);
Alurnya:
Person.guest("Budi")
↓
this("Budi", 0)
↓
Person("Budi", 0)
↓
object selesai dibuat
Jadi parameter dari redirecting constructor bisa diteruskan ke constructor tujuan.
5. Redirecting constructor bisa mengarah ke named constructor
Ini juga penting.
Misalnya:
class Test {
Test() {
print("Default constructor");
}
Test.demo() {
print("Demo constructor");
}
Test.callMe() : this.demo();
}
Sekarang:
Test.callMe();
akan melakukan:
Test.callMe()
↓
this.demo()
↓
Test.demo()
Output:
Demo constructor
Jadi this(...) tidak hanya bisa mengarah ke constructor default.
Bisa juga:
this.demo()
untuk mengarah ke named constructor demo.
6. Perhatikan perbedaan this() dan this.field
Ini sering membingungkan pemula.
this.name
Berarti:
field
namemilik object saat ini.
Contoh:
this.name = "Budi";
this(...)
Berarti:
redirect ke constructor lain dalam class yang sama.
Contoh:
Person.guest() : this("Guest", 0);
Jadi:
this.name
→ instance field
this(...)
→ constructor lain
7. Kenapa redirecting constructor berguna?
Sekarang masuk ke alasan sebenarnya konsep ini dibuat.
Bayangkan kita punya banyak constructor:
class User {
User() {
// logic A
// logic B
// logic C
}
User.admin() {
// logic A
// logic B
// logic C
// tambahan logic admin
}
User.guest() {
// logic A
// logic B
// logic C
// tambahan logic guest
}
}
Ada masalah.
Logic:
A
B
C
diulang-ulang.
Ini buruk karena kalau logic A berubah, kita harus mengubah banyak tempat.
8. Gunakan redirecting constructor
Kita bisa membuat satu constructor sebagai pusat logic.
Misalnya:
class User {
String name;
int age;
String role;
User(this.name, this.age, this.role) {
print("Common initialization");
}
User.admin(String name)
: this(name, 30, "Admin");
User.guest(String name)
: this(name, 0, "Guest");
}
Sekarang:
User.admin("Budi");
akan diarahkan ke:
User("Budi", 30, "Admin");
Dan:
User.guest("Andi");
akan diarahkan ke:
User("Andi", 0, "Guest");
9. Manfaat utamanya: menghindari duplikasi
Tanpa redirect:
User()
├─ logic A
├─ logic B
└─ logic C
User.admin()
├─ logic A
├─ logic B
├─ logic C
└─ logic D
User.guest()
├─ logic A
├─ logic B
├─ logic C
└─ logic E
Dengan redirect:
User()
├─ logic A
├─ logic B
└─ logic C
↑
|
├── User.admin()
└── User.guest()
Jadi logic yang sama cukup ditulis sekali.
10. Redirecting constructor tidak boleh punya body
Ini salah satu aturan penting.
Misalnya:
class Test {
Test() {
print("Default");
}
Test.callMe() : this() {
print("Call me");
}
}
Ini tidak valid.
Kenapa?
Karena redirecting constructor:
Test.callMe() : this()
sudah mengatakan:
“Serahkan proses construction kepada constructor lain.”
Jadi tidak boleh memiliki body sendiri.
Bentuk yang benar:
class Test {
Test() {
print("Default");
}
Test.callMe() : this();
}
11. Tidak boleh punya initializer list sendiri
Ini juga aturan penting.
Misalnya:
class Test {
int x = 10;
Test();
Test.callMe() : this(), x = 20; // ❌
}
Tidak boleh.
Kenapa?
Karena:
this()
sudah melakukan redirect ke constructor lain.
Redirecting constructor tidak boleh memiliki initializer list tambahan.
Jadi formatnya pada dasarnya:
Test.callMe(...) : this(...);
dan selesai.
12. Tapi parameter biasa boleh
Ini yang perlu dibedakan.
Redirecting constructor boleh menerima parameter biasa.
Contoh:
class Test {
int x;
int y;
Test(this.x, this.y);
Test.callMe(int x, int y) : this(x, y);
}
Ini valid.
x dan y di:
Test.callMe(int x, int y)
adalah parameter biasa.
Kemudian diteruskan:
this(x, y)
ke constructor:
Test(this.x, this.y)
13. Parameter biasa vs initializing formal
Ini bagian yang sering bikin bingung.
Lihat:
Test.callMe(int x, int y) : this(x, y);
x dan y adalah parameter biasa.
Sedangkan:
Test.callMe(this.x, this.y);
adalah initializing formal parameter.
Dalam redirecting constructor, kamu tidak bisa melakukan initialization langsung seperti:
Test.callMe(this.x, this.y) : this(); // ❌
karena redirecting constructor tidak boleh memiliki field initialization sendiri.
Tetapi kamu bisa:
Test.callMe(int x, int y) : this(x, y);
karena x dan y hanya parameter yang diteruskan.
14. Kenapa redirecting constructor tidak boleh menggunakan this.x?
Karena:
this.x
adalah bentuk initialization/access ke instance field.
Sedangkan redirecting constructor mengatakan:
“Jangan saya yang melakukan initialization. Constructor lain yang melakukannya.”
Contoh:
class Test {
int x;
int y;
Test(this.x, this.y);
Test.callMe(this.x, this.y) : this(); // ❌
}
Jangan seperti ini.
Lebih tepat:
class Test {
int x;
int y;
Test(this.x, this.y);
Test.callMe(int x, int y) : this(x, y);
}
15. Redirecting constructor harus generative
Ini poin penting berikutnya.
Redirecting constructor harus merupakan generative constructor.
Contoh valid:
class Test {
Test();
Test.callMe() : this();
}
Tetapi kalau:
class Test {
Test();
factory Test.callMe() : this(); // ❌
}
tidak valid.
16. Kenapa factory tidak bisa menjadi redirecting constructor?
Karena mekanismenya berbeda.
Redirecting constructor
Menggunakan:
this(...)
dan merupakan bagian dari proses generative construction.
Factory
Menghasilkan instance menggunakan:
return
Contoh:
factory Test.callMe() {
return Test();
}
Ini bukan redirecting constructor.
Ini adalah factory constructor yang memanggil constructor lain secara langsung.
Perbedaannya sangat penting.
17. Ini yang sering membingungkan
Bandingkan:
Redirecting
Test.callMe() : this();
dengan:
Factory
factory Test.callMe() {
return Test();
}
Kelihatannya mirip.
Tetapi secara konsep berbeda.
Redirecting
Test.callMe()
↓
this()
↓
Test()
Tidak ada body.
Factory
Test.callMe()
↓
factory body
↓
return Test()
Ada body.
Factory bisa melakukan logic sebelum return:
factory Test.callMe(int value) {
if (value > 10) {
return Test();
}
return Test.other();
}
Redirecting tidak bisa melakukan logic seperti itu.
18. Redirecting constructor hanya boleh redirect ke satu constructor
Misalnya:
class Test {
Test();
Test.demo();
Test.callMe() : this(), this.demo(); // ❌
}
Tidak boleh.
Satu redirecting constructor hanya bisa mengarah ke satu constructor.
Jadi:
Test.callMe() : this();
atau:
Test.callMe() : this.demo();
Tetapi tidak keduanya.
19. Tapi bisa dibuat chain
Nah, transcript memberikan contoh menarik.
Misalnya:
class Test {
Test() : this.demo();
Test.demo() {
print("Demo");
}
Test.callMe() : this();
}
Sekarang:
Test.callMe();
alur:
Test.callMe()
↓
this()
↓
Test()
↓
this.demo()
↓
Test.demo()
Jadi bisa terjadi rantai constructor.
Tetapi masing-masing constructor hanya melakukan satu redirect.
20. Visualisasinya
callMe()
│
▼
Test()
│
▼
demo()
Boleh.
Tetapi:
callMe()
├──→ Test()
│
└──→ demo()
tidak boleh secara langsung.
21. Tidak boleh recursive redirection
Ini aturan yang sangat penting.
Kita tidak boleh membuat constructor memanggil dirinya sendiri secara langsung.
Misalnya:
class Test {
Test() : this();
}
Ini tidak boleh.
Karena:
Test()
↓
this()
↓
Test()
↓
this()
↓
Test()
↓
...
Tidak pernah selesai.
22. Tidak boleh juga secara tidak langsung
Misalnya:
class Test {
Test() : this.callMe();
Test.callMe() : this();
}
Perhatikan:
Test()
↓
callMe()
↓
Test()
↓
callMe()
↓
Test()
↓
...
Ini juga tidak boleh.
Jadi Dart melarang recursive constructor redirection, baik:
Direct
A → A
maupun:
Indirect
A → B → A
atau bahkan:
A → B → C → A
23. Kenapa dilarang?
Karena construction tidak pernah selesai.
Contoh:
A
↓
B
↓
A
↓
B
↓
A
↓
...
Tidak ada titik akhir.
Jadi Dart harus memastikan rantai constructor akhirnya berhenti pada constructor yang benar-benar melakukan construction.
24. Redirecting constructor dan const
Ini bagian berikutnya dari transcript.
Misalnya kita punya:
class Point {
final int x;
final int y;
const Point(this.x, this.y);
const Point.origin() : this(0, 0);
}
Ini valid.
Karena:
Point.origin()
redirect ke:
Point(0, 0)
dan constructor tujuan juga const.
25. Kalau redirecting constructor const, tujuan juga harus const
Misalnya:
class Point {
final int x;
final int y;
Point(this.x, this.y);
const Point.origin() : this(0, 0); // ❌
}
Masalahnya:
Point(this.x, this.y)
bukan const.
Sedangkan:
const Point.origin()
ingin menghasilkan construction yang constant.
Maka Dart menolak.
26. Perbaikannya
Buat constructor tujuan menjadi const:
class Point {
final int x;
final int y;
const Point(this.x, this.y);
const Point.origin() : this(0, 0);
}
Sekarang valid.
27. Kenapa harus begitu?
Karena kalau:
const Point.origin()
redirect ke constructor yang bukan const:
Point(...)
maka proses constant construction tidak bisa dijamin.
Jadi:
const redirecting constructor
↓
harus redirect
↓
const constructor
28. Constructor tujuan harus berada di class yang sama
Ini juga inti dari redirecting constructor.
Misalnya:
class Person {
Person();
Person.guest() : this();
}
Valid.
Tetapi konsepnya bukan:
Person.guest() : this(otherClassConstructor());
untuk redirect ke constructor class lain.
this(...) digunakan untuk constructor lain pada class yang sama.
Kalau ingin memanggil superclass constructor, itu konsep lain:
super(...)
29. Bedakan this(...) dan super(...)
Ini sangat penting karena kamu sudah belajar inheritance.
this(...)
Memanggil/redirect ke constructor class yang sama.
class Person {
Person();
Person.guest() : this();
}
Visual:
Person.guest()
↓
Person()
super(...)
Memanggil constructor superclass.
class Father {
Father(int age);
}
class Son extends Father {
Son() : super(20);
}
Visual:
Son()
↓
Father(20)
30. Redirecting constructor vs superclass constructor
Jadi:
| Syntax | Tujuan |
|---|---|
this(...) | constructor lain di class yang sama |
super(...) | constructor superclass |
return SomeClass(...) | mengembalikan instance, biasanya dari factory |
Contoh:
class Father {
Father(int age);
}
class Son extends Father {
Son() : super(20);
}
Ini bukan redirecting constructor.
Ini adalah superclass constructor invocation.
31. Redirecting vs factory: bagian yang sangat penting
Mari kita bandingkan tiga bentuk berikut.
A. Generative biasa
class Person {
Person();
}
Artinya:
buat Person baru
B. Redirecting generative
class Person {
Person();
Person.guest() : this();
}
Artinya:
Person.guest()
↓
redirect
↓
Person()
↓
buat Person
C. Factory
class Person {
Person();
factory Person.guest() {
return Person();
}
}
Artinya:
Person.guest()
↓
factory body
↓
return Person()
Kelihatannya sama, tetapi mekanismenya berbeda.
32. Factory bisa melakukan logic, redirecting tidak
Misalnya:
factory Person.create(int age) {
if (age < 18) {
return Person.child();
}
return Person.adult();
}
Factory bisa melakukan:
if
else
perhitungan
cache
pemilihan subclass
dan lain-lain
Redirecting tidak.
Redirecting hanya:
Person.create(...) : this(...);
33. Redirecting constructor sebenarnya sangat sederhana
Kalau disederhanakan:
class User {
User(String name, int age) {
print("User dibuat");
}
User.guest(String name) : this(name, 0);
}
Saat:
User.guest("Budi");
jangan membayangkan:
guest constructor membuat object
↓
memanggil constructor lain
Lebih tepat:
User.guest("Budi")
↓
mengalihkan proses construction
↓
User("Budi", 0)
↓
User object selesai dibuat
34. Analogi yang mudah
Bayangkan kamu memiliki formulir pembuatan akun.
Ada dua cara membuat akun:
Buat akun lengkap
Buat akun guest
Daripada menulis semua proses dua kali:
Guest
├── validasi
├── simpan nama
├── simpan umur
├── buat object
└── dst.
Normal
├── validasi
├── simpan nama
├── simpan umur
├── buat object
└── dst.
Kita bisa mengatakan:
“Guest sebenarnya sama saja dengan akun normal, hanya nilai default-nya berbeda.”
Maka:
User.guest(String name) : this(name, 0);
Artinya:
“Kalau membuat guest, gunakan constructor utama dengan
namedanage = 0.”
Ini membuat kode lebih bersih.
35. Contoh yang lebih realistis
Misalnya aplikasi Flutter memiliki model User:
class User {
final String name;
final int age;
final String role;
User(this.name, this.age, this.role);
User.guest(String name)
: this(name, 0, "Guest");
User.admin(String name)
: this(name, 30, "Admin");
}
Sekarang:
final user1 = User("Budi", 25, "User");
final user2 = User.guest("Andi");
final user3 = User.admin("Citra");
Hasilnya:
user1
name = Budi
age = 25
role = User
user2
name = Andi
age = 0
role = Guest
user3
name = Citra
age = 30
role = Admin
Tetapi logic initialization hanya berada di:
User(this.name, this.age, this.role);
Constructor lainnya hanya menentukan nilai yang ingin digunakan.
36. Ini berbeda dengan named constructor biasa
Perhatikan:
class User {
User(this.name);
User.guest(String name) {
this.name = name;
}
}
User.guest() di sini bukan redirecting constructor, karena tidak menggunakan:
: this(...)
Dia adalah named generative constructor biasa yang punya body sendiri.
Sedangkan:
User.guest(String name) : this(name);
adalah redirecting constructor.
Jadi tanda pengenalnya adalah:
Ada
: this(...)→ redirecting constructor.
37. Ciri-ciri redirecting constructor
Kalau kamu melihat:
SomeClass.something(...) : this(...);
kemungkinan besar kamu sedang melihat redirecting constructor.
Ciri-cirinya:
- menggunakan
this(...), - mengarah ke constructor lain pada class yang sama,
- harus berupa generative constructor,
- tidak boleh memiliki body,
- tidak boleh memiliki initializer list tambahan,
- boleh menerima parameter biasa,
- hanya redirect ke satu constructor,
- tidak boleh terjadi recursive redirection,
- jika
const, constructor tujuan juga harusconst.
38. Ringkasan aturan syntax
Redirect ke default constructor
class Test {
Test();
Test.callMe() : this();
}
Redirect dengan parameter
class Test {
Test(int x, int y);
Test.callMe(int x, int y) : this(x, y);
}
Redirect ke named constructor
class Test {
Test();
Test.demo();
Test.callMe() : this.demo();
}
const
class Point {
final int x;
final int y;
const Point(this.x, this.y);
const Point.origin() : this(0, 0);
}
Yang tidak boleh
Test.callMe() : this() {
print("Hello"); // ❌
}
Tidak boleh body.
Test.callMe() : this(), x = 10; // ❌
Tidak boleh initializer list tambahan.
factory Test.callMe() : this(); // ❌
Tidak bisa menjadikan factory sebagai redirecting constructor.
Test.callMe() : this(), this.demo(); // ❌
Tidak boleh redirect ke dua constructor.
Test() : this(); // ❌
Recursive.
39. Hubungannya dengan pembahasan factory sebelumnya
Karena sebelumnya kamu sudah belajar factory constructor, ini bagian yang wajib benar-benar dibedakan.
Generative constructor
Person();
Saya membuat instance.
Redirecting constructor
Person.guest() : this();
Saya mengalihkan proses pembuatan ke constructor lain di class yang sama.
Factory constructor
factory Person.guest() {
return Person();
}
Saya menentukan instance mana yang harus dikembalikan.
40. Visualisasi tiga konsep
┌──────────────────────────┐
│ Generative Constructor │
└──────────────────────────┘
│
▼
buat object baru
│
▼
Person
┌──────────────────────────┐
│ Redirecting Constructor │
└──────────────────────────┘
│
▼
this(...)
│
▼
constructor lain
dalam class yang sama
│
▼
Person
┌──────────────────────────┐
│ Factory Constructor │
└──────────────────────────┘
│
▼
logic/decision
│
┌────┴────┐
▼ ▼
object baru object lama
│ │
└────┬────┘
▼
return
41. Cara mengingat paling gampang
Saya sarankan kamu menghafalkan tiga kata ini:
this(...) → redirect
Person.guest() : this("Guest");
Artinya:
“Lempar proses construction ke constructor lain.”
super(...) → parent
Son() : super(20);
Artinya:
“Panggil constructor superclass.”
return → factory
factory Person.create() {
return Person();
}
Artinya:
“Saya tentukan instance yang akan dikembalikan.”
42. Kesimpulan
Jadi inti dari transcript ini sebenarnya hanya satu konsep utama:
Redirecting constructor adalah constructor yang mengalihkan proses construction ke constructor lain dalam class yang sama menggunakan
this(...).
Contoh paling sederhana:
class Person {
Person(String name, int age) {
print("$name - $age");
}
Person.guest(String name) : this(name, 0);
}
Ketika:
Person.guest("Budi");
alur yang terjadi:
Person.guest("Budi")
↓
this("Budi", 0)
↓
Person("Budi", 0)
↓
"Budi - 0"
Dan jangan tertukar:
this(...) → redirect ke constructor class yang sama
super(...) → panggil constructor superclass
return ... → mengembalikan instance, biasanya dalam factory
Kalimat kunci untuk dihafal:
🔵 Generative constructor: membuat dan menginisialisasi object. 🟢 Redirecting constructor: mengalihkan construction ke constructor lain dalam class yang sama. 🟠 Factory constructor: menentukan instance mana yang akan dikembalikan.
Satu koreksi penting dari transcript: factory memang tidak bisa menggunakan this(...) sebagai redirecting constructor, tetapi factory tetap bisa memanggil constructor lain di dalam body dan return hasilnya. Itu terlihat mirip, tetapi secara bahasa Dart bukan redirecting constructor.