Berapa banyak parameter yang dapat dimiliki suatu fungsi

Di artikel sebelumnya, kita telah mengeksplorai fungsi-fungsi dasar di Swift. Tetapi fungsi-fungsi memiliki lebih banyak lagi. Di artikel ini, kami akan melanjutkan penjelajahan tentang fungsi dan melihat ke dalam parameter-parameter, nesting, dan tipe-tipe fungsi.

1. Nama-Nama Parameter Lokal & Eksternal

Nama Parameter Lokal

Mari melihat kembali salah satu contoh di artikel sebelumnnya. Fungsi printMessage mendefinisikan satu parameter, message.

func printMessage(message: String) { println(message) }

Meskipun kita memberikan nama pada parameter, message, kita tidak menggunakan nama itu ketika memanggil fungsinya. Kita memasukkan nilai untuk parameter message.

printMessage("Hello, world!")

Nama yang kita definisikan untuk definisi fungsi adalah nama parameter lokal. Nilai parameter hanya bisa direferensikan dengan nama ini dalam tubuh fungsi. Parameter-parameter fungsi sedikit lebih fleksibel daripada itu. Mari saya jelaskan apa yang saya maksudkan dengan itu.

Objective-C dikenal dengan metodenya yang panjang terkait nama. Meskipun terlihat ribet dan tidak elegan bagi orang luar, hal ini menjadikan metodenya mudah dipahami dan jika dipilih dengan baik akan sangat menjelaskan. Jika Anda pikir Anda kehilangan manfaat ketika berpindah ke Swift, maka Anda bersiap untuk terkejut.

Nama-Nama Parameter Eksternal

Apabila suatu fungsi menerima sejumlah parameter, tidak selalu jelas argumen mana yang berhubungan dengan parameter mana. Lihatlah contoh berikut untuk memahami permasalahannya lebih baik.

func power(a: Int, b: Int) -> Int { var result = a for _ in 1..<b { result = result * a } return result }

Fungsi power memunculkan nilai a dengan eksponen b. Kedua parameter tersebut bertipe Int. Meskipun kebanyakan orang akan secara intuitif memasukkan nilai dasar sebagai argumen pertama dan eksponennya sebagai argumen kedua, ini tidak jelas dari tipe, nama, dan tanda tangan fungsi. Sebagaimana yang kita lihat di artikel sebelumnya, cara memanggil fungsinya cukup langsung ke tujuan.

power(2, 3)

Untuk menghindari kebingungan, kita bisa memberi parameter fungsi nama eksternal. Kita bisa menggunakan nama-nama eksternal ini apabila fungsinya dipanggil untuk secara jelas mengindikasikan argumen mana yang berhubungan dengan parameter mana. Lihat pada contoh yang telah diperbarui di bawah ini.

func power(base a: Int, exponent b: Int) -> Int { var result = a for _ in 1..<b { result = result * a } return result }

Perhatikan bahwa tubuh fungsi tidak berubah karena nama lokal tidak berubah. Kendatipun demikian, apabila kami memanggil fungsi yang sudah diperbarui, perbedaannya jelas dan hasilnya lebih tidak membingungkan.

power(base: 2, exponent: 3)

Apabila kedua tipe fungsi sama, (Int, Int) -> Int, fungsi-fungsinya berbeda. Dengan kata lain, fungsi kedua bukanlah deklarasi ulang fungsi pertama. Sintaks untuk memanggil fungsi kedua mungkin mengingatkan sebagian dari Anda akan Objective-C. Tidak hanya argumennya yang dijelaskan dengan terang, kombinasi nama fungsi dan parameter menjelaskan tujuan fungsinya.

Dalam sejumlah hal, Anda mungkin ingin menggunakan nama yang sama unuk nama parameter lokal dan eksternal. Ini dimungkinkan dan tidak ada perlunya mengetikkan nama parameter dua kali. Di contoh berikut, kita menggunakan base dan exponent sebagai nama parameter eksternal dan lokal.

func power(#base: Int, #exponent: Int) -> Int { var result = base for _ in 1..<exponent { result = result * base } return result }

Dengan menuliskan prefiks nama parameter dengan simbol #, nama parameter berfungsi sebaagai nama lokal dan eksternal parameter. Ini juga berarti kita harus memperbarui tubuh fungsinya.

Penting untuk dicatat bahwa dengan menyediakan nama eksternal untuk suatu parameter, berarti Anda diminta untuk menggunakan nama tersebut ketika memanggil fungsinya. Ini akan membawa kita ke nilai-nilai default.

Nilai-Nilai Default

Kami membahas nilai-nilai parameter default di artikel sebelumnya, tetapi ada perilaku default yang harus Anda sadari. Jika Anda mendefinisikan nilai default suatu parameter, Swift akan secara otomatis menugaskkan suatu nama parameter eksternal ke parameter tersebut. Silakan menyaksikan contohnya dari artikel sebelumnya.

func printDate(date: NSDate, format: String = "YY/MM/dd") -> String { let dateFormatter = NSDateFormatter() dateFormatter.dateFormat = format return dateFormatter.stringFromDate(date) }

Karena parameter kedua, format memiliki nilai default, Swift akan secara otomatis mengatur nama parameter eksternal format menjadi format. Dengan kata lain, hasilnya sama seakan kita menuliskan prefiks format dengan simbol #. Anda bisa mengujinya dengan memanggil fungsi di atas di taman bermain Anda. Apa yang terjadi jika Anda memasukkan format tanpa menggunakan nama parameter eksternal dari parameter kedua? Jawabannya ditunjukkan di bawah ini.

Berapa banyak parameter yang dapat dimiliki suatu fungsi
Berapa banyak parameter yang dapat dimiliki suatu fungsi
Berapa banyak parameter yang dapat dimiliki suatu fungsi

Swift sangat jelas tentang apa yang harus dilakukan. Secara ringkas, apabila Anda mendefinisikan parameternya opsional, Swift secara otomatis mengatur nama parameter eksternal ke nama parameter lokal. Ide di balik perilaku ini adalah untuk menghindari kebingungan dan ambiguitas.

Kendatipun perilaku ini adalah praktek yang baik, dimungkinkan untuk menonaktifkannya. Di definisi fungsi yang telah diperbarui berikut, kita tambahkan garis bawah, biasanya yang ditambahkan adalah nama parameter eksternalnya. Ini akan memberitahu Swift bahwa kita tidak ingin menentukan nama parameter eksternal untuk parameter khusus tersebut, meskipun memiliki nilai default.

func formatDate(date: NSDate, _ format: String = "YY/MM/dd") -> String { let dateFormatter = NSDateFormatter() dateFormatter.dateFormat = format return dateFormatter.stringFromDate(date) }

Sekarang kita bisa memanggil fungsi formatDate tanpa menyediakan nama untuk argumen kedua.

formatDate(NSDate(), "dd/MM/YY")

Parameter & Mutabilitas

Mari mengunjungi kembali contoh pertama di tutorial ini, fungsi printMessage. Apa yang terjadi apabila kita mengubah nilai parameter message di dalam tubuh fungsi?

func printMessage(message: String) { message = "Print: \(message)" println(message) }

Tidak butuh waktu lama bagi Swift untuk mulai mengeluh.

Berapa banyak parameter yang dapat dimiliki suatu fungsi
Berapa banyak parameter yang dapat dimiliki suatu fungsi
Berapa banyak parameter yang dapat dimiliki suatu fungsi

Secara default, parameter-parameter fungsi bersifat konstan. Dengan kata lain, meskipun kita bisa mengakses nilai-nilai parameter fungsi, kita tidak bisa mengubah nilainya. Untuk mengubah perilaku default ini, tambahkan kata kunci var ke nama parameter di definisi fungsi. Maka Swift akan membuat variabel salinan nilai parameter untuk Anda kerjakan di dalam tubuh fungsi.

func printMessage(var message: String) { message = "Print: \(message)" println(message) }

Perhatikan bahwa ini tidak berarti Anda bisa memasukkan suatu nilai, memodifikasinya dalam fungsi, dan menggunakan nilai yang sudah dimodifikasi setelah fungsi menyelesaikan pekerjaannya. Swift membuat salinan nilai parameter yang hanya ada selama masa pemanggilan fungsi. Ini juga diilustrasikan di blok kode berikut yang di situ kita memasukkan suatu konstanta ke fungsi printMessage.

func printMessage(var message: String) { message = "Print: \(message)" println(message) } let myMessage = "test" printMessage(myMessage)

3. Parameter-Parameter Variadic

Istilahnya mungkin terdengar ganjil di awal, parameter variadic adalah istilah yang umum dalam pemrograman. Suatu parameter variadic adalah parameter yang menerima nilai nol atau lebih. Nilainya harus berada dalam tipe yang sama. Menggunakan parameter variadic di Swift cukup sepele, bisa dilihat di ilustrasi pada contoh berikut.

func sum(args: Int...) -> Int { var result = 0 for a in args { result += a } return result }

Sintaksnya mudah dipahami. Untuk menandai suatu parameter sebagai variadic, Anda menambahkan tiga titik ke tipe parameternya. Dalam tubuh fungsi, parameter variadic bisa diakses sebagai suatu array. Pada contoh di atas, args adalah array dari nilai Int.

Karena Swift harus tahu argumen mana yang berhubungan dengan parameter mana, parameter variadic dibutuhkan sebagai parameter terakhir. Implikasinya adalah suatu fungs bisa memiliki maksimal satu parameter variadic.

Hal di atas juga berlaku jika fungsinya memiliki parameter dengan nilai-nilai default. Parameter variadic harus selalu menjadi parameter terakhir.

4. Parameter In-Out

Di bagian lebih awal tutorial ini, Anda belajar bagaimana mendefinisikan mutabilitas suatu parameter dengan menggunakan kata kunci var. Di bagian itu, saya menekankan bahwa nilai suatu parameter variabel hanya bisa diakses dari dalam tubuh fungsi. Jika Anda ingin memasukkan suatu nilai ke dalam fungsi, modifikasilah di dalam fungsinya, dan lewatkan kembali di luar fungsinya, parameter in-out yang Anda cari.

Contoh berikut menunjukkan permisalan bagaimana parameter in-out bekerja di Swift dan bagaimana sintaksnya terlihat.

func prependString(inout a: String, withString b: String) { a = b + a }

Kita telah mendefinisikan parameter pertama sebagai parameter in-out dengan menambahkan kata kunci inout. Parameter kedua adalah parameter reguler dengan nama eksternal withString dan nama lokal b. Mari kita lihat bagaimana cara memanggil fungsi ini.

var world = "world" prependString(&world, withString: "Hello, ")

Kita mendeklarasikan variabel, world, dari tipe string dan memasukkannya ke fungsi perpendString. Parameter kedua adalah string literal. Dengan memanggil fungsi ini, nilai variabel world menjadi Hello, world. Perhatikan bahwa argumen pertama diberi prefiks & untuk mengindikasikan ini suatu parameter in-out.

Jelas bahwa konstanta dan literal tidak bisa dimasukkan sebagai parameter in-out. Swift akan melempar pesan kesalahan pada Anda sebagaimana diilustrasikan dalam screnshot berikut.

Berapa banyak parameter yang dapat dimiliki suatu fungsi
Berapa banyak parameter yang dapat dimiliki suatu fungsi
Berapa banyak parameter yang dapat dimiliki suatu fungsi

Ini adalah bukti bahwa parameter in-out tidak bisa memiliki nilai default, baik itu variadic, atau didefinisikan sebagai var atau let. Jika Anda melupakan detail-detail ini, Swift akan berbaik hati dengan memberikan Anda pesan kesalahan.

5. Nesting

Di C dan Objective-C, fungsi dan metode tidak bisa nested. Meskipun demikian, di Swift fungsi yang nested lumayan biasa. Fungsi-fungsi yang telah kita lihat di sini dan artikel sebelumnya adalah contoh-contoh fungsi global, yang didefinisikan dalam ruang lingkup global.

Ketika kita mendefinisikan suatu fungsi di dalam fungsi global, itulah yang dimaksudkan sebagai fungsi nested. Fungsi nested mempunyai akses ke nilai yang didefinisikan dalam fungsi yang melingkupinya. Lihatlah contoh berikut untuk memahami hal ini dengan lebih baik.

func printMessage(message: String) { let a = "hello world" func printHelloWorld() { println(a) } }

Meskipun fungsi-fungsi dalam contoh ini tidaklah benar-benar sangat bermanfaat, contoh itu mengilustrasikan ide fungsi nested dan menangkap nilai. Fungsi printHelloWorld hanya bisa diakses dari dalam fungsi printMessage. Sebagaimana diilustrasikan di contoh tersebut, fungsi printHelloWorld memiliki akses ke konstanta a. Nilainya ditangkap dengan fungsi nested dan oleh karenanya bisa diakses dalam fungsi tersebut. Swift menangani penangkapan nilai, termasuk mengelola memori nilai-nilai tersebut.

6. Tipe-Tipe Fungsi

Di artikel sebelumnya, kita menyentuh tipe-tipe fungsi secara singkat. Suatu fungsi punya tipe khusus, yang disusun atas tipe-yipe parameter fungsi dan tipe kembaliannya. Misalnya fungsi printMessage, adalah dari tipe (String) -> (). Ingatlah bahwa () menyimbolkan Void, yang setara dengan tupel kosong.

Karena tiap fungsi memiliki tipe, adalah mungkin untuk mendefinisikan suatu fungsi yang menerima fungsi lain sebagai parameternya. Contoh berikut menunjukkan bagaimana cara kerjanya.

func printMessageWithFunction(message: String, printFunction: (String) -> ()) { printFunction(message) } let myMessage = "Hello, world!" printMessageWithFunction(myMessage, printMessage)

Fungsi printMessageWithFunction menerima string sebagai parameter pertamanya dan fungsi tipe (String) -> () sebagai parameter keduanya. Di badan fungsi, fungsi yang kita masukkan dipanggil dengan argumen message.

Contoh berikut juga mengilustrasikan bagaimana kita memanggil fungsi printMessageWithFunction. Konstanta myMesssage dimasukkan sebagai argumen pertama dan fungsi printMessage, yang kita definisikan sebelumnya, sebagai argumen kedua. Keren sekali bukan?

Sebagaimana yang saya sebutkan sebelumnya, dimungkinkan untuk mengembalikan suatu fungsi dari fungsi lainnya. Contoh berikutnya sedikit direka-reka, tetapi mengilustrasikan seperti apa penampakan sintaksnya.

func compute(addition: Bool) -> (Int, Int) -> Int { func add(a: Int, b: Int) -> Int { return a + b } func subtract(a: Int, b: Int) -> Int { return a - b } if addition { return add } else { return subtract } } let computeFunction = compute(true) let result = computeFunction(1, 2) println(result)

Fungsi compute menerima suatu boolean dan mengembalikan fungsi type (Int, Int) -> Int. Fungsi compute mengandung dua fungsi nested yang juga merupakan tipe (Int, Int) -> Int, add dan subtract.

Fungsi compute mengembalikan referensi ke salah satu dari fungsi add atau subtract, berdasarkan nilai parameter addition. Contoh berikut juga menunjukkan cara menggunakan fungsi compute. Kita menyimpan referensi ke fungsi yang dikembalikan oleh fungsi compute dalam konstanta computeFunction. Lalu kita memanggil fungsi yang disimpan dalam computeFunction, memasukkan 1 dan 2, menyimpan hasilnya dalam result, dan mencetak nilai result dalam keluaran standar. Contoh tadi mungkin terlihat kompleks, tetapi sebenarnya mudah dipahami jika Anda tahu apa yang terjadi.

Kesimpulan

Seharusnya Anda sekarang sudah memiliki pemahaman yang bagus mengenai bagaimana cara kerja fungsi di Swift dan apa yang bisa Anda lakukan terhadapnya. Fungsi-fungsi adalah tema yang umum di Swift dan Anda akan menggunakannya secara luas ketika bekerja dengan Swift.

Di artikel berikutnya kita akan menyelami dengan teliti konstruksi hebat yang sangat mirip dengan blok di C dan Objective-C, closure fi JavaScript, dan lambda di Ruby.