CLICK HERE FOR BLOGGER TEMPLATES AND MYSPACE LAYOUTS »

Rabu, 13 Februari 2008

Procedure Dan Function

PROCEDURE DAN FUNCTION
Suatu Ide penting lain yang ditekankan oleh Delphi adalah konsep rutin, secara dasar merupakan sekumpulan perintah dengan nama yang unik, yang dapat diaktifkan banyak kali dengan menggunakan nama mereka. Dengan cara ini Anda menghindari pengulangan perintah yang sama berkali-kali, dan mempunyai hanya satu versi kode yang dapat Anda rubah yang berakibat pada seluruh aplikasi. Dari sudut pandang ini, Anda dapat berpikir rutin merupakan mekanisme dasar dari code encapsulation. Saya akan kembali ke topik ini dengan suatu contoh setelah saya memperkenalkan cara penulisan rutin dalam Pascal.
Procedure dan Function dalam Delphi
Dalam Pascal, sebuah rutin dapat diasumsikan dalam dua bentuk: suatu procedure dan suatu function. Secara teori, suatu procedure adalah operasi yang Anda minta untuk dikerjakan oleh komputer, sedangkan suatu function merupakan proses perhitungan yang menghasilkan suatu nilai. Perbedaan ini ditekankan pada kenyataan bahwa suatu function mempunyai return value, sedangkan sebuah procedure tidak. Kedua jenis rutin ini dapat mempunyai beberapa parameter, dengan data type yang ditentukan sebelumnya.
Walau demikian, dalam kenyataannya, perbedaan antara function dan procedure sangatlah terbatas: Anda dapat memanggil suatu function untuk melakukan suatu tugas dan melewati hasilnya (yang mungkin merupakan suatu error code yang optional atau semacam itu) atau Anda dapat memanggil suatu procedure yang menghasilkan nilai melalui parameter (reference parameter akan dibahas lebih lanjut pada bab ini).


Berikut ini adalah definisi procedure dan dua macam versi dari fungsi yang sama, menggunakan cara penulisan yang sedikit berbeda:
procedure Hello;
begin
ShowMessage ('Hello world!');
end;

function Double (Value: Integer) : Integer;
begin
Double := Value * 2;
end;

// or, as an alternative
function Double2 (Value: Integer) : Integer;
begin
Result := Value * 2;
end;
Penggunaan Result daripada nama function untuk mengisi nilai hasil suatu function menjadi cukup populer, dan dalam pandangan saya, cenderung membuat code lebih mudah dipahami.
Setelah rutin ini didefinisikan, Anda dapat memanggil mereka satu kali atau lebih. Anda memanggil procedure untuk menjalankan tugasnya, dan memanggil function untuk menghitung suatu nilai:
procedure TForm1.Button1Click (Sender: TObject);
begin
Hello;
end;

procedure TForm1.Button2Click (Sender: TObject);
var
X, Y: Integer;
begin
X := Double (StrToInt (Edit1.Text));
Y := Double (X);
ShowMessage (IntToStr (Y));
end;
Note: Untuk sementara, jangan hiraukan cara penulisan kedua procedure diatas, yang sebenarnya hanyalah merupakan method. Letakkan saja dua button dalam suatu form Delphi, click button tersebut saat design, dan IDE Delphi akan menghasilkan code pendukung yang tepat: Sekarang Anda cukup mengisikan perintah di antara begin dan end. Untuk mengkompilasi code diatas Anda perlu juga untuk menambahkan sebuah kontrol Edit pada form ini.
Nah sekarang kita dapat kembali pada konsep code encapsulation yang telah saya perkenalkan sebelumnya. Jika Anda memanggil function Double, Anda tidak perlu mengetahui algoritma yang digunakan untuk mengimplementasi itu. Jika Anda kemudian menemukan suatu cara yang lebih baik untuk menggandakan nilai suatu angka, Anda dapat dengan mudah mengganti code function, namun code yang memanggil tidaklah perlu dirubah (meskipun program akan berjalan lebih cepat!). Prinsip yang sama dapat diaplikasikan pada procedure Hello: Kita dapat memodifikasi hasi keluaran program dengan mengganti code procedure ini, dan method Button2Click akan secara otomatis merubah efek yang dihasilkan. Berikut ini adalah cara bagaimana kita dapat mengganti code:
procedure Hello;
begin
MessageDlg ('Hello world!', mtInformation, [mbOK]);
end;
Tip: Ketika Anda memanggil suatu function atau procedure Delphi yang sudah ada, atau method VCL apapun, Anda harus mengingat jumlah dan type parameter yang ada. Editor Delphi membantu Anda dengan memberikan daftar parameter dari suatu function atau procedure dengan suatu hint segera setelah Anda mengetikkan nama dan tanda kurung buka. Fitur ini dinamakan Code Parameter dan merupakan bagian dari teknologi Code Insight.
Reference Parameter
Rutin Pascal memperbolehkan parameter dilewatkan secara nilai atau reference. Secara default, Pascal menggunakan metode pelewatan parameter dengan nilai: yaitu nilai akan di-copy dalam stack dan rutin menggunakan dan memanipulasi hasil copy, bukan nilai original.
Melewatkan suatu parameter dengan reference berarti nilainya tidak akan di-copy dalam stack dalam parameter formal dari suatu rutin (menghindari proses copy seringkali berarti bahwa program akan berjalan lebih cepat). Sebaliknya, program akan menunjuk pada nilai original, juga code dalam rutin tersebut.
Hal ini memungkinkan procedure atau function mengganti nilai dari parameter. Melewatkan parameter dengan reference ditandai dengan penggunaan keyword var.
Teknik ini tersedia pada kebanyakan bahasa pemrograman. Hal ini tidak ditemukan dalam C, namun diperkenalkan dalam C++, dimana Anda menggunakan tanda & (pass by reference). Dalam Visual Basic semua parameter yang tidak menggunakan keyword ByVal akan dilewatkan secara reference.
Berikut ini adalah contoh melewatkan parameter secara reference menggunakan keyword var:
procedure DoubleTheValue (var Value: Integer);
begin
Value := Value * 2;
end;
Pada kasus ini, parameter digunakan untuk melewatkan nilai ke procedure dan juga untuk mengembalikan nilai ke code yang memanggil. Jika Anda menulis:
var
X: Integer;
begin
X := 10;
DoubleTheValue (X);
Nilai dari variable X menjadi 20, karena function tersebut menggunakan reference ke lokasi memory original dari X, yang mempengaruhi nilai awalnya.
Melewatkan parameter dengan reference merupakan hal yang masuk akal untuk ordinal types, untuk strings jaman kuno, dan untuk record berukuran besar. Sesungguhnya, Object Delphi selalu dilewatkan dengan nilai, karena mereka adalah reference ke diri mereka sendiri. Untuk alasan inilah, melewatkan object dengan reference tidak masuk akal (selain kasus khusus tertentu), karena hal ini berarti melewatkan reference kepada suatu reference.
Long string dalam Delphi mempunyai perilaku yang sedikit berbeda: mereka berlaku seperti reference, tapi jika Anda mengganti salah satu string variable yang menunjuk pada string yang sama dalam memory, maka string ini akan di-copy sebelum diperbaharui. Suatu long string digunakan sebagai parameter value akan berlaku seperti reference dalam istilah penggunaan memory dan kecepatan operasi. Namun jika Anda mengubah nilai string tersebut, maka nilai original tidaklah terpengaruh. Sebaliknya, jika Anda melewatkan long string itu secara reference, maka Anda dapat mengubah nilai original.
Delphi 3 memperkenalkan suatu jenis parameter yang baru, yaitu out. Suatu parameter out tidak mempunyai nilai awal dan hanya digunakan untuk mengembalikan nilai. Parameter ini sebaiknya hanya digunakan untuk procedure dan function COM; secara umum, lebih baik tetap menggunakan parameter var yang lebih efisien. Kecuali perbedaan bahwa dia tidak mempunyai nilai awal, parameter out berlaku sama seperti parameter var.
Constant Parameter
Sebagai alternatif dari parameter reference, Anda dapat menggunakan parameter const. Karena Anda tidak dapat memberikan nilai baru pada parameter const dalam suatu rutin, maka compiler dapat mengoptimalkan cara pelewatan parameter. Compiler dapat memilih suatu pendekatan yang mirip dengan paremeter reference (atau suatu const reference dalam istilah C++), tapi perilakunya akan tetap sama dengan parameter value, karena nilai original tidaklah terpengaruh oleh rutin tersebut.
Sesungguhnya, jika Anda mencoba untuk meng-compile code berikut ini, Delphi akan memberikan pesan kesalahan:
function DoubleTheValue (const Value: Integer): Integer;
begin
Value := Value * 2; // compiler error
Result := Value;
end;



Open Array Parameter
Tidak seperti C, suatu function atau procedure dalam Pascal selalu mempunyai jumlah parameter yang tetap. Namun demikian, ada suatu cara untuk melewatkan parameter dengan jumlah yang bervariasi kepada suatu rutin dengan menggunakan open array.
Definisi dasar dari suatu parameter open array adalah typed open array. Hal ini berarti Anda mengindikasikan type parameter namun tidak mengetahui berapa banyak elemen yang akan disimpan ke array tersebut. Berikut ini adalah contoh dari definisi tersebut:
function Sum (const A: array of Integer): Integer;
var
I: Integer;
begin
Result := 0;
for I := Low(A) to High(A) do
Result := Result + A[I];
end;
Dengan menggunakan High(A) kita dapat memperoleh ukuran array tersebut. Perhatikan juga penggunaan nilai kembali dari function, yaitu Result, untuk menyimpan nilai sementara. Anda dapat memanggil function ini dengan melewatkan array bertype Integer:
X := Sum ([10, Y, 27*I]);
Dengan adanya array Integer tersebut, berapapun besarnya, Anda dapat melewatkannya secara langsung pada suatu rutin yang memerlukan parameter open array, atau Anda dapat menggunakan function Slice untuk melewatkan hanya sebagian array (yang diindikasikan oleh parameter kedua). Berikut ini adalah contoh, dimana array secara lengkap dilewatkan sebagai suatu parameter:

var
List: array [1..10] of Integer;
X, I: Integer;
begin
// initialize the array
for I := Low (List) to High (List) do
List [I] := I * 2;
// call
X := Sum (List);
Jika Anda ingin melewatkan sebagian array ke function Slice, cukup menggunakan contoh seperti ini:
X := Sum (Slice (List, 5));
Anda dapat menemukan semua cuplikan code yang diberikan pada bagian ini di contoh OpenArr (lihat Gambar 6.1, selanjutnya, untuk form).
Gambar 6.1: Contoh OpenArr ketika tombol Partial Slice ditekan

Typed open array dalam Delphi 4 kompatibel sepenuhnya dengan dynamic array (diperkenalkan dalam Delphi 4 dan dibahas dalam Bab 8). Dynamic array menggunakan syntax yang sama seperti open array, dengan perbedaan bahwa Anda dapat menggunakan notasi seperti array of Integer untuk mendeklarasikan suatu variabel, tidak hanya untuk melewatkan parameter.




Type-Variant Open Array Parameter
Disamping typed open array, Delphi juga memperbolehkan Anda mendefinisikan type-variant atau untyped open array. Jenis Array khusus seperti ini mempunyai jumlah nilai yang belum terdefinisi, yang cukup memudahkan kita dalam melewatkan parameter.
Secara teknis, struktur const array memungkinkan Anda untuk melewatkan suatu array dengan jumlah elemen yang belum terdefinisi dengan type yang berbeda untuk suatu rutin secara berbarengan. Sebagai contoh, ini adalah definisi function Format (kita akan melihat cara penggunaan function ini dalam Bab 7, yang akan membahas mengenai string):
function Format (const Format: string;
const Args: array of const): string;
Parameter kedua merupakan open array, yang berisi sejumlah nilai. Sebenarnya Anda dapat memanggil function ini dengan cara seperti ini:
N := 20;
S := 'Total:';
Label1.Caption := Format ('Total: %d', [N]);
Label2.Caption := Format ('Int: %d, Float: %f', [N, 12.4]);
Label3.Caption := Format ('%s %d', [S, N * 2]);
Perhatikan bahwa Anda dapat melewatkan parameter sebagai nilai konstanta, nilai suatu variabel, atau suatu ekspresi. Mendeklarasikan suatu function seperti ini adalah mudah, tapi bagaimana Anda melakukan pemrogramannya? Bagaimana Anda tahu type dari parameter yang ada? Nilai dari open array parameter yang bervariasi jenisnya adalah kompatibel dengan elemen dari type TVarRec.
Note: Jangan bingung antara record TVarRec dengan record TVarData yang digunakan oleh Variant type sendiri. Kedua struktur ini mempunyai tujuan yang berbeda dan tidaklah kompatibel. Bahkan daftar dari type yang diperbolehkan juga berbeda, karena TVarRec dapat menampung data type Delphi, sedangkan TVarData dapat menampung data type OLE.
Record TVarRec mempunyai struktur seperti berikut:
type
TVarRec = record
case Byte of
vtInteger: (VInteger: Integer; VType: Byte);
vtBoolean: (VBoolean: Boolean);
vtChar: (VChar: Char);
vtExtended: (VExtended: PExtended);
vtString: (VString: PShortString);
vtPointer: (VPointer: Pointer);
vtPChar: (VPChar: PChar);
vtObject: (VObject: TObject);
vtClass: (VClass: TClass);
vtWideChar: (VWideChar: WideChar);
vtPWideChar: (VPWideChar: PWideChar);
vtAnsiString: (VAnsiString: Pointer);
vtCurrency: (VCurrency: PCurrency);
vtVariant: (VVariant: PVariant);
vtInterface: (VInterface: Pointer);
end;
Tiap record yang memungkinkan akan mempunyai field VType, mestipun hal ini tidaklh mudah untuk awalnya karena hanya dideklarasikan sekali saja, beserta data aktual berukuran Integer (yang umumnya merupakan suatu reference atau pointer).
Dengan informasi ini, kita dapat menulis suatu function yang mampu beroperasi pada data type yang berbeda. Dalam contoh function SumAll, saya ingin menjumlahkan semua nilai dengan type yang berbeda, mengubah string menjadi integer, karakter menjadi nilai urutan yang bersesuaian, dan menambah 1 untuk nilai Boolean True. Code didasarkan pada statement case, dan cukup sederhana, meskipun kita harus membalik reference pointer secara cukup sering:


function SumAll (const Args: array of const): Extended;
var
I: Integer;
begin
Result := 0;
for I := Low(Args) to High (Args) do
case Args [I].VType of
vtInteger: Result :=
Result + Args [I].VInteger;
vtBoolean:
if Args [I].VBoolean then
Result := Result + 1;
vtChar:
Result := Result + Ord (Args [I].VChar);
vtExtended:
Result := Result + Args [I].VExtended^;
vtString, vtAnsiString:
Result := Result + StrToIntDef ((Args [I].VString^), 0);
vtWideChar:
Result := Result + Ord (Args [I].VWideChar);
vtCurrency:
Result := Result + Args [I].VCurrency^;
end; // case
end;
Saya telah menambahkan code ini pada contoh OpenArr, yang memanggil function SumAll ketika suatu tombol ditekan:
procedure TForm1.Button4Click(Sender: TObject);
var
X: Extended;
Y: Integer;
begin
Y := 10;
X := SumAll ([Y * Y, 'k', True, 10.34, '99999']);
ShowMessage (Format (
'SumAll ([Y*Y, ''k'', True, 10.34, ''99999'']) => %n', [X]));
end;
Anda dapat melihat hasil keluaran dari pemanggilan code ini, dan form pada contoh OpenArr, pada Gambar 6.2.
Gambar 6.2: Form dari contoh OpenArr, dengan message box yang ditampilkan ketika tombol Untyped ditekan.

Delphi Calling Conventions
Delphi versi 32-bit telah memperkenalkan suatu pendekatan baru untuk melewatkan parameter, yang dikenal dengan fastcall: bilamana memungkinkan, sampai tiga parameter dapat dilewatkan dengan register CPU yang membuat pemanggilan function menjadi jauh lebih cepat. Fast calling convention (digunakan secara default pada Delphi 3) diindikasikan dengan register keyword.
Masalahnya hal ini merupakan default convention, dan function yang menggunakannya tidaklah kompatibel dengan Windows: fungsi dari Win32 API harus dideklarasikan menggunakan stdcall calling convention, suatu perpaduan dari original Pascal calling convention dari Win16 API dan cdecl calling convention dari bahasa C.
Secara umum tidak ada alasan untuk tidak menggunakan fast calling convention yang baru, kecuali Anda membuat suatu external Windows call atau mendefinisikan Windows callback function. Kita akan melihat suatu contoh penggunaan stdcall convention sebelum akhir bab ini. Anda dapat menemukan suatu ringkasan dari Delphi calling convention dalam Help Delphi di topik Calling Convention.
Apakah suatu Method itu?
Jika Anda telah bekerja dengan Delphi atau membaca buku manualnya, Anda mungkin telah mendengar istilah "method". Suatu method merupakan function atau procedure yang khusus yang berkaitan dengan suatu data type, suatu class. Dalam Delphi, tiap kali kita menangani suatu event, kita harus mendefinisikan suatu method, yang umumnya adalah suatu procedure. Meskipun demikian, secara umum istilah method digunakan untuk mengindikasikan baik function maupun procedure yang berkaitan dengan suatu class.
Kita telah melihat sejumlah method dalam contoh pada bab ini dan bab sebelumnya. Berikut ini adalah suatu method kosong yang secara otomatis ditambahkan oleh Delphi untuk suatu source code pada suatu form:
procedure TForm1.Button1Click(Sender: TObject);
begin
{here goes your code}
end;
Forward Declarations
Ketika Anda harus menggunakan suatu identifier (dengan jenis apapun), kompiler harus telah melihat semacam deklarasi sebelumnya untuk mengetahui apa yang ditunjuk oleh identifier tersebut. Untuk alasan inilah, Anda biasanya memberikan suatu full declaration sebelum menggunakan suatu rutin. Namun demikian, ada kasus tertentu yang tidak bisa menggunakan pendekatan semacam ini. Jika procedure A memanggil procedure B, dan procedure B memanggil procedure A, ketika Anda mulai menulis code, Anda harus melakukan pemanggilan rutin dimana kompiler masih belum melihat suatu deklarasi.
Jika Anda ingin mendeklarasikan keberadaan suatu procedure atau function dengan nama dan parameter tertentu, tanpa memberikan code sesungguhnya, Anda dapat menuliskan procedure atau function diikuti dengan keyword forward:
procedure Hello; forward;
Selanjutnya, code harus menyediakan definisi lengkap dari procedure tersebut, tapi procedure ini dapat dipanggil sebelum dia didefinisikan secara lengkap. Berikut ini adalah contoh untuk memberikan ide kepada Anda:
procedure DoubleHello; forward;

procedure Hello;
begin
if MessageDlg ('Do you want a double message?',
mtConfirmation, [mbYes, mbNo], 0) = mrYes then
DoubleHello
else
ShowMessage ('Hello');
end;

procedure DoubleHello;
begin
Hello;
Hello;
end;
Pendekatan ini memungkinkan Anda menulis mutual recursion: DoubleHello memanggil Hello, tapi Hello mungkin memanggil DoubleHello juga. Tentu saja harus ada suatu kondisi untuk menghentikan rekursi ini, untuk menghindari stack overflow. Anda dapat melihat code ini, dengan sedikit perubahan, dalam contoh DoubleH.
Meskipun suatu forward procedure declaration tidaklah umum dalam Delphi, tapi ada suatu kasus serupa yang lebih sering. Ketika Anda mendeklarasikan suatu procedure atau function dalam bagian interface dari suatu unit (pembahasan lebih lanjut tentang unit akan Anda temui pada bab selanjutnya), hal ini diperhitungkan sebagai forward declaration, bahkan bila kata kunci forward tidak dijumpai. Sebenarnya Anda tidak dapat menulis badan suatu rutin pada bagian interface dari suatu unit. Pada waktu yang sama, Anda harus menyediakan implementasi aktual dari tiap rutin yang telah Anda deklarasikan.

Hal yang sama juga berlaku untuk deklarasi suatu method didalam suatu class type yang secara otomatis dihasilkan oleh Delphi (saat Anda menambahkan suatu event pada suatu form atau komponen didalamnya). Event handler yang dideklarasikan dalam suatu class TForm merupakan forward declaration: code akan disediakan pada bagian implementation dari suatu unit. Berikut ini adalah cuplikan code dari contoh sebelumnya, dengan deklarasi method Button1Click:
type
TForm1 = class(TForm)
ListBox1: TListBox;
Button1: TButton;
procedure Button1Click(Sender: TObject);
end;
Procedural Types
Suatu fitur unik lainnya dari Object Pascal adalah adanya procedural type. Ini merupakan suatu topik pemrograman tingkat lanjut, yang hanya digunakan secara teratur oleh sedikit pemrogram Delphi. Namun demikian, karena kita akan mendiskusikan topik yang terkait pada bab-bab selanjutnya (secara spesifik, method pointer, suatu teknik yang sangat sering dipakai oleh Delphi sendiri), maka cukup berharga untuk melihat secara sepintas disini. Jika Anda adalah pemrogram tingkat sedang, Anda dapat melewati bagian ini sekarang, dan kembali lagi saat Anda merasa sudah siap.
Dalam Pascal, terdapat konsep prosedural type (yang mirip dengan konsep function pointer dalam bahasa pemrograman C). Deklarasi procedural type mengindikasikan daftar parameter dan, untuk kasus function, jenis nilai yang dikembalikan. Misalnya, Anda dapat mendeklarasikan sebuah procedural type yang baru, dengan parameter Integer yang dilewatkan secara reference, dengan code berikut ini:


type
IntProc = procedure (var Num: Integer);
Procedural type ini kompatibel dengan rutin apapun yang mempunyai parameter yang persis sama (atau function signature yang sama, dalam istilah C). Berikut ini adalah contoh dari suatu rutin yang kompatibel:
procedure DoubleTheValue (var Value: Integer);
begin
Value := Value * 2;
end;
Note: Dalam Delphi versi 16-bit, rutin harus dideklarasikan menggunakan direktif far agar bisa digunakan sebagai nilai aktual dari suatu procedural type.
Procedural type dapat digunakan untuk dua kegunaan yang berbeda: Anda dapat mendeklarasikan variabel dari suatu procedural type atau melewatkan suatu procedural type (yaitu suatu function pointer) sebagai parameter ke rutin yang lain. Dengan deklarasi type dan procedure sebelumnya, Anda dapat menuliskan code seperti ini:
var
IP: IntProc;
X: Integer;
begin
IP := DoubleTheValue;
X := 5;
IP (X);
end;
Code ini mempunyai efek yang sama dengan versi yang lebih pendek berikut:
var
X: Integer;
begin
X := 5;
DoubleTheValue (X);
end;
Versi pertama jelas lebih rumit, jadi kenapa kita harus memakainya? Dalam beberapa kasus, kemampuan untuk memutuskan fungsi mana yang akan dipanggil dan pemanggilan fungsi pada saat berikutnya sangatlah berguna. Sangatlah memungkinkan untuk membuat suatu contoh rumit yang menunjukkan pendekatan ini. Namun demikian, saya cenderung membiarkan Anda menjelajahi yang lebih sederhana, yaitu ProcType. Contoh ini lebih rumit daripada berbagai contoh yang telah kita lihat sejauh ini, untuk membuat situasi menjadi lebih realistik.
Anda cukup membuat suatu project baru dan meletakkan dua buah radio button dan sebuah push button, seperti yang terlihat pada Gambar 6.3. Contoh ini didasarkan pada dua procedure. Sebuah procedure digunakan untuk menghitung nilai dua kali dari parameter. Procedure ini serupa dengan versi yang telah saya tunjukkan sebelumnya pada bagian ini. Procedure kedua digunakan untuk menghitung nilai tiga kali dari parameter, dan karenanya diberi nama TripleTheValue:
Gambar 6.3: Form dari contoh ProcType.

procedure TripleTheValue (var Value: Integer);
begin
Value := Value * 3;
ShowMessage ('Value tripled: ' + IntToStr (Value));
end;
Kedua procedure ini menampilkan apa yang sedang berjalan, untuk memberitahu kita bahwa mereka sedang dijalankan. Ini merupakan suatu fitur pelacakan sederhana yang dapat Anda gunakan untuk memeriksa apakah atau kapan suatu bagian code dijalankan, daripada menambahkan suatu breakpoint disana.
Tiap kali seorang user menekan tombol Apply, salah satu dari kedua procedure ini akan dijalankan, tergantung pada status radio button. Sebenarnya, ketika Anda mempunyai dua buah radio button dalam satu form, hanya salah satu yang dapat dipilih pada suatu waktu. Code ini sebenarnya dapat diimplementasikan dengan memeriksa nilai radio button dalam code event Click dari button Apply. Untuk mendemonstrasikan penggunaan procedural type, saya menggunakan pendekatan yang lebih panjang tapi menarik. Tiap kali seorang user meng-klik salah satu dari radio button, satu dari procedure akan disimpan pada satu variabel:
procedure TForm1.DoubleRadioButtonClick(Sender: TObject);
begin
IP := DoubleTheValue;
end;
Ketika sang user meng-klik push button, procedure yang telah kita simpan akan dijalankan:
procedure TForm1.ApplyButtonClick(Sender: TObject);
begin
IP (X);
end;
Untuk memungkinkan tiga fungsi yang berbeda untuk mengakses variabel IP dan X, kita perlu membuat mereka terlihat pada semua form; mereka tidak dapat dideklarasikan secara local (dalam salah satu method). Solusi untuk permasalahan ini adalah menempatkan variabel ini pada deklarasi form:
type
TForm1 = class(TForm)
...
private
{ Private declarations }
IP: IntProc;
X: Integer;
end;
Kita akan melihat secara persis apakah arti hal ini pada bab selanjutnya, tapi untuk saat ini, Anda perlu mengubah code yang dihasilkan oleh Delphi untuk class type seperti yang diindikasikan diatas, dan menambahkan definisi procedural type seperti yang telah saya tunjukkan sebelumnya. Untuk menginisialisasi variabel ini dengan nilai yang sesuai, kita dapat menangani event OnCreate pada form (pilih event ini pada Object Inspector setelah Anda mengaktifkan form, atau cukup melakukan double-click pada form). Saya sarankan Anda membaca listing code ini untuk mempelajari detil source code pada contoh ini.
Anda dapat melihath suatu contoh praktis dari penggunaan procedural type di Bab 9, pada bagian A Windows Callback Function.
Function Overloading
Ide untuk melakukan overloading sangatlah sederhana: compiler memperbolehkan Anda untuk mendefinisikan dua function atau procedure dengan nama yang sama, asalkan parameternya berbeda. Dengan memeriksa parameter, sebenarnya, compiler dapat menentukan rutin versi mana yang ingin Anda jalankan.
Coba lihat sekian function yang diambil dari unit Math dari VCL:
function Min (A,B: Integer): Integer; overload;
function Min (A,B: Int64): Int64; overload;
function Min (A,B: Single): Single; overload;
function Min (A,B: Double): Double; overload;
function Min (A,B: Extended): Extended; overload;
Ketika Anda memanggil Min (10, 20), compiler dengan mudah menentukan bahwa Anda bermaksud untuk menjalankan function pertama dari grup diatas, sehingga return value adalah sebuah Integer.




Ada dua buah aturan dasar, yaitu:
Tiap versi rutin harus diikuti dengan kata kunci overload.
Haruslah ada perbedaan pada jumlah maupun type parameter, atau keduanya. Namun demikian, Return type tidak dapat digunakan untuk membedakan kedua rutin.
Berikut ini adalah tiga versi overload dari suatu procedure ShowMsg yang saya tambahkan pada contoh OverDef (suatu aplikasi yang mendemonstrasikan overload dan default parameter):
procedure ShowMsg (str: string); overload;
begin
MessageDlg (str, mtInformation, [mbOK], 0);
end;

procedure ShowMsg (FormatStr: string;
Params: array of const); overload;
begin
MessageDlg (Format (FormatStr, Params),
mtInformation, [mbOK], 0);
end;

procedure ShowMsg (I: Integer; Str: string); overload;
begin
ShowMsg (IntToStr (I) + ' ' + Str);
end;
Ketiga function ini menunjukkan suatu message box dengan sebuah string, setelah secara optional melakukan format string dalam cara yang berlainan. Berikut ini adalah tiga macam pemanggilan dari program:
ShowMsg ('Hello');
ShowMsg ('Total = %d.', [100]);
ShowMsg (10, 'MBytes');
Apa yang mengejutkan saya dalam konotasi positif, adalah teknologi Code Parameter dari Delphi bekerja dengan baik untuk procedure dan function yang di-overload. Sesaat setelah Anda mengetik tanda kurung buka setelah nama rutin, semua alternatif yang memungkinkan akan ditampilkan. Setelah Anda memasukkan parameter, Delphi menggunakan type mereka untuk menentukan alternatif mana yang masih memungkinkan. Dalam Gambar 6.4 Anda dapat melihat bahwa setelah mengetik suatu string constant, Delphi hanya menampilkan versi yang kompatibel (menghilangkan versi procedure ShowMsg yang mempunyai parameter pertama berupa Integer).
Gambar 6.4: Berbagai alternatif yang ditawarkan Code Parameters untuk rutin yang di-overload yang disaring berdasarkan parameter yang tersedia.

Kenyataan bahwa tiap versi dari rutin yang di-overload haruslah ditandai secara benar membawa implikasi bahwa Anda tidak dapat melakukan overload atas suatu rutin yang sudah ada pada unit yang sama yang tidak ditandai dengan kata kunci overload. (Pesan kesalahan yang Anda terima saat mencobanya adalah: "Previous declaration of '' was not marked with the 'overload' directive.") Namun demikian, Anda dapat melakukan overload suatu rutin yang dideklarasikan pada unit yang berbeda. Hal ini diperlukan untuk kompatibilitas dengan versi Delphi sebelumnya, yang memperbolehkan unit yang berbeda untuk menggunakan nama rutin yang sama. Namun demikian, perhatikan bahwa kasus khusus seperti ini bukanlah suatu fitur tambahan untuk overloading, tapi suatu indikasi permasalahan yang mungkin Anda hadapi.
Misalnya, Anda dapat menambahkan code berikut pada suatu unit:
procedure MessageDlg (str: string); overload;
begin
Dialogs.MessageDlg (str, mtInformation, [mbOK], 0);
end;
Code ini tidaklah meng-overload rutin MessageDlg yang sesungguhnya. Sebenarnya jika Anda mengetikkan:
MessageDlg ('Hello');
Anda akan mendapatkan suatu pesan kesalahan yang mengindikasikan bahwa beberapa parameter tidak dijumpai. Satu-satunya cara untuk memanggil versi lokal daripada versi dari VCL adalah merujuk secara eksplisit pada unit lokal, sesuatu yang bertentangan dengan ide overloading:
OverDefF.MessageDlg ('Hello');
Default Parameters
Sebuah fitur baru dari Delphi 4 adalah Anda dapat memberikan sebuah nilai default untuk parameter suatu function, dan Anda dapat menjalankan function tersebut dengan atau tanpa parameter.
procedure MessBox (Msg: string;
Caption: string = 'Warning';
Flags: LongInt = mb_OK or mb_IconHand);
begin
Application.MessageBox (PChar (Msg),
PChar (Caption), Flags);
end;
Dengan definisi ini, kita dapat menjalankan procedure dengan berbagai cara seperti berikut:
MessBox ('Something wrong here!');
MessBox ('Something wrong here!', 'Attention');
MessBox ('Hello', 'Message', mb_OK);
Pada Gambar Figure 6.5 Anda dapat melihat bahwa Code Parameters dari Delphi secara benar menggunakan style yang berbeda untuk mengindikasikan parameter yang mempunyai nilai default, sehingga Anda dapat dengan mudah menentukan parameter mana yang dapat dilewatkan.
Gambar 6.5: Code Parameters dari Delphi menandai parameter yang mempunyai nilai default dengan tanda kurung siku; Anda dapat melewatkan parameter ini saat menjalankan rutin tersebut.

Perhatikan bahwa Delphi tidak menghasilkan suatu code khusus untuk mendukung default parameter; atau membuat beberapa salinan rutin tersebut. Parameter yang tidak dilewatkan akan ditambahkan oleh compiler ke code pemanggil.
Ada juga satu pembatasan penting yang mempengaruhi penggunaan default parameters: Anda tidak dapat "melewati" parameter. Misalnya, Anda tidak melewatkan parameter ketiga walaupun Anda melewatkan parameter kedua:
MessBox ('Hello', mb_OK); // error
Ini merupakan aturan utama untuk default parameters: Dalam suatu pemanggilan, Anda dapat melewatkan parameter dimulai dari yang paling akhir. Dengan kata lain, jika Anda melewatkan suatu parameter, Anda juga harus melewatkan semua parameter setelah itu.
Ada beberapa aturan lain untuk default parameter, seperti berikut:
Parameter dengan nilai default haruslah diletakkan pada akhir daftar parameter.
Nilai default haruslah berupa konstanta. Hal ini terlihat membatasi type yang Anda dapat pakai dengan default parameter. Misalnya, suatu array dinamis atau suatu interface type tidak dapat mempunyai default parameter selain nil; record tidak dapat digunakan sama sekali.
Default parameter harus dilewatkan secara nilai (passed by value) atau sebagai const. Suatu parameter reference (var) tidak dapat mempunyai nilai default.
Menggunakan default parameters dan overloading pada waktu yang bersamaan dapat menyebabkan munculnya beberapa masalah, karena kedua fitur yang bisa bertabrakan/konflik. Misalnya, bila saya menambahkan versi baru untuk procedure ShowMsg pada contoh sebelumnya:
procedure ShowMsg (Str: string; I: Integer = 0); overload;
begin
MessageDlg (Str + ': ' + IntToStr (I),
mtInformation, [mbOK], 0);
end;
maka compiler tidak akan menampilkan pesan kesalahan - hal ini adalah definisi yang legal. Namun demikian, pemanggilan:
ShowMsg ('Hello');
ditandai oleh compiler sebagai Ambiguous overloaded call to 'ShowMsg'. Perhatikan bahwa error ini muncul pada suatu baris code yang dikompilasi dengan benar sebelum definisi baru yang ter-overload. Pada prakteknya, kita tidak mempunyai cara untuk menjalankan procedure ShowMsg dengan satu parameter berupa String, karena compiler tidak tahu apakah kita ingin menjalankan versi dengan hanya satu parameter String atau versi dengan parameter String dan parameter Integer dengan nilai default. Ketika compiler mengalami kebingungan, dia akan berhenti dan meminta pemrogram untuk menyatakan maksudnya dengan lebih jelas.
Kesimpulan
Menulis procedure dan function merupakan elemen penting dari pemrograman, meskipun dalam Delphi Anda akan cenderung menulis method -- procedure dan function terhubung dengan class dan object.
Ketimbang beralih ke fitur object-oriented, beberapa bab berikut ini akan memberikan Anda beberapa detil pada elemen pemrograman Pascal lainnya, mulai dari string.

0 comments: