Saturday, December 24, 2016

Bab 2. Pemrograman C# Belajar Dari Contoh



2. Tipe Data, Literal, dan Variabel







Mengapa Tipe Data Penting

Tipe data sangat penting dalam C# karena semua operasi diperiksa oleh kompiler tentang kompatibilitas tipenya. Operasi yang ilegal tidak dapat dikompilasi. Hal ini mendukung kehandalan dalam pencegahan error. Untuk mendukung kehandalan pemrograman, semua variabel, ekspresi, dan nilai harus memiliki sebuah tipe data. Tipe data suatu variabel menentukan operasi apa saja yang diijinkan untuk diterapkan pada nilai variabel. Operasi yang dapat diterapkan pada suatu tipe bisa jadi tidak dapat diterapkan pada tipe data lain.


Tipe Data Dalam C#
C# memuat dua kategori umum dari tipe data built-in: tipe nilai dan tipe referensi. Perbedaan antara dua tipe itu adalah apa yang dimuat oleh suatu variabel. Untuk tipe nilai, variabel dapat menampung suatu nilai, seperti 3.1416 atau 212. Untuk tipe referensi, variabel dapat memuat sebuah referensi ke suatu nilai. Tipe referensi yang paling umum dipakai adalah kelas, dan diskusi tentang kelas dan tipe referensi akan dilakukan secara detil pada buku ini. Yang dibahas pada bab ini hanya tipe nilai.

Tipe
Arti
bool
Merepresentasikan nilai true/false
byte
Integer tak-bertanda 8-bit
char
Karakter
decimal
Nilai numerik untuk perhitungan keuangan
double
Titik mengambang kepresisian ganda
float
Titik mengambang kepresisian tunggal
int
Integer
long
Long integer
sbyte
Integer bertanda 8-bit
short
Integer short
uint
Integer tak-bertanda
ulong
Long tak-bertanda
ushort
Short tak-bertanda
Tabel 2.1 Tipe-tipe nilai dalam C#

Dalam C#, terdapat 13 tipe nilai seperti ditampilkan pada Tabel 2.1. Secara kolektif, tipe nilai disebut pula dengan tipe sederhana atau tipe primitif. Disebut dengan tipe sederhana karena hanya memuat satu nilai.


Integer
C# mendefinisikan sembilan tiga integer: char, byte, sbyte, short, ushort, int, uint, long, dan ulong. Tetapi, tipe char secara umum dipakai untuk merepresentasikan karakter, dan akan didiskusikan nanti pada akhir bab ini. Delapan tipe integer lainnya dipakai untuk perhitungan numerik. Lebar-bidang dan rentang dari delapan tipe integer tersebut ditampilkan di sini:


Seperti ditunjukkan pada tabel, C# mendefinisikan versi bertanda dan tak-bertanda dari berbagai tipe integer. Perbedaan antara integer bertanda dan tak-bertanda adalah bagaiman bit paling signifikan (MSB, most significant bit) diinterpretasikan. Jika integer bertanda dispesifikasi, maka kompiler C# akan menghasilkan kode yang mengasumsikan bahwa bit paling signifikan dari suatu integer dipakai sebagai flag. Jika tanda flag adalah 0, maka angka tersebut positif; jika flag adalah 1, maka angka tersebut negatif. Angka negatif direpresentasikan menggunakan pendekatan komplemen dua. Dengan metode ini, semua bit dalam angka negatif dibalik, kemudian ditambahkan 1.

Integer bertanda penting untuk banyak algoritma, tetapi hanya memiliki magnitudo setengah dari versi integer tak-bertanda. Sebagai contoh, sebuah short, di sini adalah 32,767:

0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

Untuk nilai tak-bertanda, jika bit paling signifikan ditetapkan 1, maka angka tersebut akan diinterpretasikan sebagai -1 (dalam format komplemen dua). Namun, jika Anda mendeklarasikannya sebagai ushort, maka ketika bit paling signifikan ditetapkan 1, angka tersebut akan menjadi 65,535.

Yang paling umum dipakai dari tipe integer adalah int. Variabel bertipe int seringkali dipakai untuk mengendalikan loop, untuk mengindeks array, dan untuk kepentingan matematika. Ketika Anda membutuhkan sebuah integer yang memiliki rentang nilai lebih dari int, maka Anda mempunyai banyak opsi. Jika nilai yang ingin disimpan adalah tak-bertanda, maka Anda bisa memakai uint. Untuk nilai bertanda yang besar, gunakan long. Untuk nilai tak-bertanda yang besar, gunakan ulong. Sebagai contoh, berikut adalah sebuah program yang menghitung jarak dari Bumi ke Matahari, dalam inci. Karena nilai ini terlalu besar, program menggunakan variabel long untuk menampungnya.

// Menghitung jarak dari Bumi ke Matahari dalam inci.
using System;

class Inci
{
    static void Main() {
        long inci;
        long mile;
       
        mile = 93000000; // 93,000,000 mile ke matahari
       
        // 5,280 kaki dalam satu mile, 12 inci dalam satu kaki.
        inci = mile * 5280 * 12;
       
        Console.WriteLine("Jarak ke matahari : " +
        inci + " inci.");
    }
}

Berikut adalah keluaran program:

Jarak ke matahari : 5892480000000 inci.

Jelaslah, hasil yang diperoleh tidak mungkin ditampung oleh variabel bertipe int atau uint.

Tipe integer terkecil adalah byte dan sbyte. Tipe byte merupakan nilai tak-bertanda dalam rentang 0 dan 255. Variabel bertipe byte berguna ketika bekerja dengan data biner, seperti aliran byte yang dihasilkan oleh divais tertentu. Untuk integer kecil tak-bertanda, gunakan sbyte.  Berikut disajikan contoh penggunaan variabel bertipe byte untuk mengendalikan sebuah loop for yang menghasilkan penjumlahan angka 0 sampai 100.

// Menggunakan byte.
using System;

class Menggunakan_byte {
    static void Main() {
        byte x;
        int jum;

        jum = 0;
        for (x = 1; x <= 100; x++)
            jum = jum + x;
       
        Console.WriteLine("Penjumlahan dari 0-100 adalah " + jum);
    }
}

Keluaran program ditampilkan di sini:

Penjumlahan dari 0-100 adalah 5050

Karena loop for hanya dijalankan dari 0 sampai 100, yang berada dalam rentang suatu byte, maka tidak diperlukan variabel bertipe yang lebih besar untuk mengendalikannya.

Ketika Anda memerlukan sebuah integer yang lebih besar dari byte atau sbyte, tetapi lebih kecil dari int atau uint, Anda bisa menggunakan short atau ushort.


Tipe Titik-Mengambang
Tipe titik-mengambang (floating-point) dapat merepresentasikan angka dengan komponen fraksional. Ada dua jenis tipe titik-mengambang, float dan double, yang merepresentasikan angka kepresisian tunggal dan kepresisian ganda. Tipe float berlebar 32 bit dan memiliki rentang berkisar 1.5E-45 sampai 3.4E+38. Tipe double berlebar 64 bit dan memiliki rentang berkisar 5E-324 sampai 1.7E308.

Dari keduanya, double adalah yang paling umum digunakan. Alasannya adalah bahwa banyak fungsi matematika dalam pustaka kelas C# (yang merupakan pustaka Framework .NET) menggunakan nilai-nilai double. Sebagai contoh, metode Sqrt() (yang didefinisikan oleh kelas System.Math) menghasilkan nilai balik bertipe double, yang merupakan akar kuadrat dari argumen bertipe double. Berikut disajikan Sqrt() yang dipakai untuk menghitung radius suatu lingkaran bila diberikan luas lingkaran.

// Menemukan radius dari luas suatu lingkaran.
using System;

class FindRadius {
  static void Main() {
      Double r;
      Double luas;

      luas = 10.0;

      r = Math.Sqrt(luas / 3.1416);
      Console.WriteLine("Radius adalah " + r);
  }
}

Keluaran program ditampilkan di sini:

Radius adalah 1.78412203012729

Seperti disebutkan sebelumnya, Sqrt() adalah anggota dari kelas Math. Perhatikan bagaimana Sqrt() dipanggil; diawali dengan nama Math. Sama dengan Console yang mengawali WriteLine().

Program berikut mendemonstrasikan beberapa fungsi trigonometrik C#, yang juga merupakan bagian dari pustaka matematika C#. Semua fungsi tersebut diterapkan pada data double. Program menampilkan sinus, kosinus, dan tangent untuk sudut (dalam radian) dari 0.1 sampai 1.0.

// Mendemonstrasikan Math.Sin(), Math.Cos(), dan Math.Tan().
using System;

class Trigonometri {
    static void Main() {
        Double theta; // sudut dalam radian
       
        for (theta = 0.1; theta <= 1.0; theta = theta + 0.1) {
            Console.WriteLine("Sinus dari " + theta + " adalah " +
                               Math.Sin(theta));
           
            Console.WriteLine("Kosinus dari " + theta + " adalah " +
                               Math.Cos(theta));
           
            Console.WriteLine("Tangent dari " + theta + " adalah " +
                               Math.Tan(theta));
           
            Console.WriteLine();
        }
    }
}

Berikut adalah keluaran program:

Sinus dari 0.1 adalah 0.0998334166468282
Kosinus dari 0.1 adalah 0.995004165278026
Tangent dari 0.1 adalah 0.100334672085451

Sinus dari 0.2 adalah 0.198669330795061
Kosinus dari 0.2 adalah 0.980066577841242
Tangent dari 0.2 adalah 0.202710035508673

Sinus dari 0.3 adalah 0.29552020666134
Kosinus dari 0.3 adalah 0.955336489125606
Tangent dari 0.3 adalah 0.309336249609623

Sinus dari 0.4 adalah 0.389418342308651
Kosinus dari 0.4 adalah 0.921060994002885
Tangent dari 0.4 adalah 0.422793218738162

Sinus dari 0.5 adalah 0.479425538604203
Kosinus dari 0.5 adalah 0.877582561890373
Tangent dari 0.5 adalah 0.54630248984379

Sinus dari 0.6 adalah 0.564642473395035
Kosinus dari 0.6 adalah 0.825335614909678
Tangent dari 0.6 adalah 0.684136808341692

Sinus dari 0.7 adalah 0.644217687237691
Kosinus dari 0.7 adalah 0.764842187284489
Tangent dari 0.7 adalah 0.842288380463079

Sinus dari 0.8 adalah 0.717356090899523
Kosinus dari 0.8 adalah 0.696706709347166
Tangent dari 0.8 adalah 1.02963855705036

Sinus dari 0.9 adalah 0.783326909627483
Kosinus dari 0.9 adalah 0.621609968270665
Tangent dari 0.9 adalah 1.26015821755034

Sinus dari 1 adalah 0.841470984807896
Kosinus dari 1 adalah 0.54030230586814
Tangent dari 1 adalah 1.5574077246549

Untuk menghitung sinus, kosinus, dan tangent, gunakan metode-metode pustaka standar Math.Sine(), Math.Cos(), dan Math.Tan(). Seperti Math.Sqrt(), semua metode trigonometrik dipanggil dengan sebuah argumen double dan menghasilkan nilai balik bertipe double. Sudut harus dalam radian.


Tipe Desimal
Yang paling menarik dari tipe data numerik dalam C# adalah tipe decimal, yang dimaksudkan untuk digunakan dalam kalkulasi moneter. Tipe decimal menggunakan 128 bit untuk merepresentasikan nilai di dalam rentang 1E-28 sampai 7.9E+28. Seperti Anda ketahui, aritmatika titik-mengambang sangat rentan terhadap berbagai error pembulatan ketika diterapkan pada nilai desimal. Tipe decimal mengeliminasi error tersebut dan dapat secara akurat merepresentasikan sampai dengan 28 posisi desimal. Kemampuan ini dipakai untuk merepresentasikan nilai desimal tanpa error pembulatan sehingga cocok untuk komputasi yang melibatkan uang.

Berikut disajikan suatu program yang menggunakan tipe decimal dalam kalkulasi finansial. Program ini menghitung harga yang telah didiskon dari harga awal dan persentase diskon.

// Menggunakan tipe decimal untuk menghitung diskon.
using System;

class GunakanDecimal {
    static void Main() {
        decimal harga;
        decimal diskon;
        decimal harga_diskon;
       
        // menghitung harga setelah diskon.
        harga = 19000.95m;
        diskon = 0.15m; // persen diskon adalah 15%

        harga_diskon = harga - (harga * diskon);
        Console.WriteLine("Harga Setelah Diskon: Rp." + harga_diskon);
    }
}

Keluaran program ditunjukkan di sini:

Harga Setelah Diskon: Rp.16150.8075

Di dalam program, perhatikan bahwa konstanta desimal diikuti dengan sufiks m. Ini perlu karena tanpa sufiks, nilai ini akan diinterpretasikan sebagai konstanta titik-mengambang standar, yang tidak kompatibel dengan tipe data decimal. Anda dapat menugaskan sebuah nilai integer, seperti 10, kepada variabel decimal tanpa menggunakan sufiks m. (Diskusi detil tentang konstanta numerik diberikan di akhir bab).

Berikut adalah contoh lain yang menggunakan tipe decimal. Program ini menghitung nilai masa depan dari sebuah investasi yang memiliki laju bunga tetap pada suatu periode (beberapa tahun).

/*
Menggunakan tipe decimal untuk menghitung
nilai masa depan dari suatu investasi.
*/
using System;

class NilaiMasaDepan {
    static void Main() {
        decimal investasi;
        decimal laju_bunga;
        int tahun, i;

        investasi = 1000.0M;
        laju_bunga = 0.07M;
        tahun = 10;
       
        Console.WriteLine("Investasi awal: Rp." + investasi);
        Console.WriteLine("Laju bunga: " + laju_bunga);
        Console.WriteLine("Selama " + tahun + " tahun");
       
        for (i = 0; i < tahun; i++)
            investasi = investasi + (investasi * laju_bunga);
        Console.WriteLine("Nilai masa depan adalah Rp." + investasi);
    }
}

Keluaran program ditampilkan di sini:

Investasi awal: Rp.1000.0
Laju bunga: 0.07
Selama 10 tahun
Nilai masa depan adalah Rp.1967.151357289565322490000

Perhatikan bahwa hasil yang didapatkan akurat dengan 21 dijit di belakang titik desimal, mungkin lebih dari yang Anda perlukan.


Karakter
Dalam C#, karakter bukan suatu kuantitas 8-bit seperti di dalam banyak bahasa pemrograman lainnya, seperti C++. C# menggunakan tipe karakter 16-bit yang dikenal dengan Unicode. Unicode mendefinisikan himpunan karakter yang cukup besar dalam merepresentasikan karakter dalam semua bahasa manusia. Meskipun banyak bahasa seperti, Indonesia, English, dan French menggunakan alfabet yang relatif sedikit, beberapa bahasa, seperti Chinese, menggunakan himpunan karakter yang tidak bida direpresentasikan hanya dengan 8 bit. Untuk mengatasi situasi ini, dalam C#, diberikan tipe char yang merupakan sebuah tipe tak-bertanda 16-bit dengan rentang 0 sampai 65,535. Himpunan karakter ASCII 8-bit standar adalah subhimpunan dari Unicode dengan rentang 0 sampai 127. Jadi, karakter-karakter ASCII masih merupakan karaker C# yang valid.

Variabel karakter dapat ditugasi sebuah nilai dengan mengapit karakter dengan dua kutip tunggal. Sebagai contoh, hal ini menugaskan X kepada variabel ch:

char ch;
ch = 'X';

Anda dapat menampilkan nilai char menggunakan statemen WriteLine(). Sebagai contoh, baris ini menampilkan nilai di dalam ch:

Console.WriteLine("Ini adalah ch: " + ch);

Meskipun char didefinisikan oleh C# sebagai sebuah tipe integer, tipe ini tidak dapat dengan bebas dicampur dengan integer pada semua kasus. Ini karena tidak adanya konversi tipe otomatis dari integer menjadi char. Sebagai contoh, fragmen berikut adalah tak-valid:

char ch;
ch = 88; // error, tak-valid

Alasannya adalah bahwa 88 adalah sebuah nilai integer, dan nilai itu tidak secara otomatis dikonversi menjadi sebuah char. Jika Anda mencoba mengkompilasi kode ini, Anda akan mendapatkan pesan error. Untuk membuat penugasan ini menjadi legal, Anda perlu menerapkan cast, yang akan didiskusikan nanti pada bab ini.


Tipe bool
Tipe bool merepresentasikan nilai true/false. C# mendefinisikan nilai true dan false menggunakan katakunci reservasi true dan false. Jadi, sebuah variabel atau ekspresi bertipe bool akan bernilai salah satu dari dua nilai tersebut. Di samping itu, tidak ada konversi yang didefinisikan antara bool dan nilai integer. Misalnya, 1 tidak dikonversi menjadi true, dan 0 tidak dikonversi menjadi false.

Berikut adalah sebuah program yang mendemonstrasikan tipe bool:

// Menggunakan nilai bool.
using System;

class DemoBool
{
    static void Main() {
        bool b;
       
        b = false;
        Console.WriteLine("b adalah " + b);
        b = true;
        Console.WriteLine("b adalah " + b);
       
        // Nilai bool dapat mengendalikan statemen if.
        if (b) Console.WriteLine("Ini dieksekusi.");
       
        b = false;
        if (b) Console.WriteLine("Ini tidak dieksekusi.");
       
        // Keluaran dari operator relasional adalah nilai bool.
        Console.WriteLine("10 > 9 adalah " + (10 > 9));
    }
}

Keluaran program ditampilkan di sini:

b adalah False
b adalah True
Ini dieksekusi.
10 > 9 adalah True

Ada tiga hal menarik yang perlu diperhatikan. Pertama, seperti Anda lihat, ketika suatu nilai bool ditampilkan dengan WriteLine(), “True” atau “False” ditampilkan. Kedua, nilai suatu variabel bool dapat dipakai untuk mengendalikan statemen if. Tidak diperlukan statemen if seperti ini:

if(b == true) ...

Ketiga, keluaran dari suatu operator relasional, seperti <, adalah sebuah nilai bool.  Ini mengapa ekspresi 10>9 menampilkan nilai “True”. Di samping itu, sepasang kurung untuk mengapit ekspresi 10>9 diperlukan karena operator + mempunyai derajat keutamaan yang lebih dari >.


Beberapa opsi Keluaran
Sampai di titik ini, ketika data ditampilkan menggunakan statemen WriteLine(), keluarannya ditampilkan menggunakan format default. Tetapi, Framework .NET mendefinisikan mekanisme pemformatan yang memberikan Anda kendali untuk bagaimana data ditampilkan. Meskipun I/O terformat dirangkum secara detil dalam buku ini, adalah hal yang bermanfaat untuk mengenalkan beberapa opsi pemformatan. Dengan opsi ini, Anda akan mampu menetapkan bagaimana tampilan keluaran menggunakan statemen WriteLine().

Ketika menampilkan runtun data, Anda dapat memisahkan setiap bagian data dengan tanda plus, seperti ditampilkan di sini:

Console.WriteLine("Anda memesan " + 2 + " item harga Rp." + 3 + " masing-masing.");

Meskipun cukup nyaman, penampilan informasi numerik dengan cara ini tidak memberikan Anda kendali dalam bagaimana menampilkan informasi. Sebagai contoh, untuk nilai titik-mengambang, Anda tidak dapat mengendalikan jumlah desimal yang akan ditampilkan. Perhatikan statemen berikut:

Console.WriteLine("Berikut adalah 10/3: " + 10.0/3.0);

menghasilkan keluaran ini:

Berikut adalah 10/3: 3.33333333333333

Meskipun ini baik untuk beberapa tujuan, menampilkan begitu banyak desimal di belakang titik desimal bisa jadi tidak cocok untuk tujuan tertentu. Sebagai contoh, dalam kalkulasi finansial, Anda biasanya hanya ingin menampilkan dua titik desimal di belakang titik desimal.

Untuk mengendalikan bagaimana data numerik diformat, Anda perlu menggunakan format kedua dari metode WriteLine(), seperti ditunjukkan di sini, yang membolehkan Anda untuk memformat informasi:

WriteLine(“string format”, arg0, arg1, ... , argN);

Dalam versi ini, argumen pada WriteLine() dipisahkan dengan koma dan bukan tanda +. string format memuat dua item: reguler, karakter yang akan ditampilkan, dan penspesifikasi format. Penspesifikasi format memiliki bentuk umum:

{argnum, width: fmt}

Di sini, argnum menspesifikasi jumlah argumen (mulai dari nol) yang akan ditampilkan. Lebar bidang minimum dispesifikasi oleh width, dan format dispesifikasi oleh fmt. width dan fmt bersifat opsional.

Selama eksekusi, ketika sebuah penspesifikasi format dijumpai di dalam string format, argumen terkait, yang dispesifikasi oleh argnum, diganti dan ditampilkan. Jadi, posisi dari spesifikasi format di dalam string format menentukan dimana data akan ditampilkan. Oleh karena itu, dalam bentuk sederhananya, penspesifikasi format mengindikasikan argumen mana yang akan ditampilkan. Sebagai contoh, {0} mengindikasikan arg0, {1} mengindikasikan arg1, dan seterusnya.

Dimulai dari contoh sederhana. Statemen

Console.WriteLine("Pebruari mempunyai {0} atau {1} hari.", 28, 29);

menghasilkan keluaran berikut:

Pebruari mempunyai 28 atau 29 hari.

Seperti yang Anda lihat, nilai 28 menggantikan {0}, dan 29 menggantikan {1}. Jadi, penspesifikasi format mengidentifikasi lokasi dimana argumen berurutan, dalam kasus ini 28 dan 29, ditampilkan di dalam string. Di samping itu, perhatikan nilai-nilai yang dipisahkan dengan koma, bukan dengan tanda +.

Berikut adalah variasi dari statemen sebelumnya yang menspesifikasi lebar bidang minimum:

Console.WriteLine("Pebruari mempunyai {0,10} atau {1,5} hari.", 28, 29);

menghasilkan keluaran berikut:

Pebruari mempunyai         28 atau              29 hari.

Seperti yang Anda lihat, spasi ditambahkan untuk mengisi bidang yang tidak dipakai.

Argumen yang berkaitan dengan perintah format tidak harus konstanta. Sebagai contoh, program ini menampilkan tabel kuadrat dan kubik, yang menggunakan perintah format dalam menampilkan nilai.

// Menggunakan perintah format.
using System;

class OpsiPenampilan {
    static void Main()
    {
        int i;
       
        Console.WriteLine("Nilai\tKuadrat\tKubik");
        for (i = 1; i < 10; i++)
            Console.WriteLine("{0}\t{1}\t{2}", i, i * i, i * i * i);
    }
}

Keluaran ditampilkan di sini:

Nilai   Kuadrat Kubik
1       1       1
2       4       8
3       9       27
4       16      64
5       25      125
6       36      216
7       49      343
8       64      512
9       81      729

Cara termudah menspesifikasi suatu format adalah menyediakan sebuah template yang akan digunakan WriteLine(). Untuk melakukannya, tunjukkan contoh format yang Anda inginkan menggunakan tanda # untuk menandai posisi dijit. Anda juga dapat menspesifikasi titik desimal dan koma. Sebagai contoh, berikut adalah cara yang lebih baik dalam menampilkan 10 dibagi dengan 3:

Console.WriteLine("Berikut adalah 10/3: {0:#.##}", 10.0/3.0);

Keluaran dari statemen di atas adalah

Berikut adalah 10/3: 3.33

Pada contoh tersebut, template yang dipakai adalah #.##, yang memberitahukan WriteLine() untuk menampilkan dua dijit di belakang titik desimal. Penting dipahami bahwa WriteLine() dapat menampilkan lebih dari satu dijit di depan titik desimal, jika diperlukan.

Berikut adalah satu contoh lain. Statemen

Console.WriteLine("{0:###,###.##}", 123456.56);

menghasilkan keluaran ini:

123,456.56

Jika Anda ingin menampilkan nilai moneter, gunakan penspesifikasi format C. Sebagai contoh,

decimal uang;

uang = 12323.09m;
Console.WriteLine("Uang saat ini adalah {0:C}", uang);

Keluarannya adalah (format dalam dollar Amerika):

Uang saat ini adalah $12,323.09

Format C dapat pula dipakai untuk memperbaiki keluaran dari program diskon harga yang telah diberikan sebelumnya:

// Menggunakan format C untuk menampilkan dollar dan cent.
using System;

class GunakanDecimal2
{
    static void Main() {
        decimal harga;
        decimal diskon;
        decimal harga_diskon;
      
        // Menghitung harga diskon.
        harga = 19.95m;
        diskon = 0.15m; // persen diskon 15%

        harga_diskon = harga - (harga * diskon);

        Console.WriteLine("Harga setelah diskon: {0:C}", harga_diskon);
    }
}

Berikut adalah keluaran program:

Harga setelah diskon: $16.96


Literal
Dalam C#, literal berarti nilai tetap yang direpresentasikan dalam format bacaan manusia. Sebagai contoh, angka 100 adalah sebuah literal. Literal dan kegunaannya telah digunakan dalam suatu format pada beberapa contoh program sebelumnya. Sekarang saatnya membahasnya secara formal.

Literal C# dapat berupa sembarang tipe sederhana. Cara setiap literal direpresentasikan bergantung pada tipenya. Seperti dijelaskan sebelumnya, literal string diapit dengan dua tanda kutip tunggal. Misalnya, ‘a’ dan ‘%’ keduanya adalah literal string.

Literal integer dispesifikasi sebagai angka tanpa komponen pecahan. Sebagai contoh, 10 dan -100 keduanya adalah literal integer. Literal titik-mengambang memerlukan titik desimal yang diikuti dengan komponen pecahan. Sebagai contoh, 11.123 adalah literal titik-mengambang. C# juga membolehkan Anda untuk menggunakan notasi saintifik bagi angka titik-mengambang.

Dalam C#, literal memiliki tipe. Pertanyaannya adalah tipe apakah literal numerik? Sebagai contoh, apakah tipe dari 12, 123987, atau 0.23? Untungnya, C# menspesifikasi beberapa aturan sederhana yang bisa menjawab pertanyaan ini.

Pertama, untuk literal integer, tipe literal adalah tipe integer terkecil yang bisa menampungnya, dimulai dari int. Jadi, sebuah literal integer adalah bertipe int, uint, long, atau ulong, bergantung pada nilainya. Kedua, literal titik-mengambang adalah bertipe double.

Jika tipe default C# bukanlah yang Anda inginkan untuk sebuah literal, Anda bisa menspesifikasi secara eksplisit tipenya dengan mencantumkan sufiks. Untuk menspesifikasi sebuah literal long, tempelkan l atau L. Sebagai contoh, 12 adalah sebuah int, tetapi 12L adalah sebuah long. Untuk menspesifikasi sebuah integer tak-bertanda, tempelkan u atau U. Jadi, 100 adalah sebuah int, tetapi 100U adalah uint. Untuk menspesifikasi integer long tak-bertanda, gunakan ul atau UL. Sebagai contoh, 984375UL bertipe ulong.
Untuk menspesifikasi literal float, tempelkan F atau f pada nilai. Sebagai contoh, 10.19F adalah bertipe float. Meskipun berlebihan, Anda dapat menspesifikasi literal double dengan menempelkan D atau d. (Seperti disebutkan sebelumnya, literal titik-mengambang secara default adalah double).

Untuk menspesifikasi literal decimal, nilai terkait diikuti dengan m atau M. Sebagai contoh, 9.9M adalah sebuah literal decimal.


Literal Heksadesimal
Seperti yang Anda ketahui, dalam pemrograman kadangkala lebih mudah untuk menggunakan sistem bilangan berbasis 16 menggantikan basis 10. Sistem bilangan basis 16 disebut dengan heksadesimal dan menggunakan dijit 0 sampai 9 dan huruf A sampai F (yang mewakili nilai 10, 11, 12, 13, 14, dan 15). Sebagai contoh, bilangan heksadesimal 10 adalah 16 dalam desimal. Karena frekuensi penggunaan angka heksadesimal yang sangat tinggi, C# membolehkan Anda untuk menspesifikasi literal integer dalam format heksadesimal. Literal heksadesimal harus diawali dengan 0x. Berikut adalah dua contoh literal heksadesimal:

hitung = 0xFF; // 255 dalam desimal
tambah = 0x1a; // 26 dalam desimal


Runtun Escape
Literal karakter yang diapit dengan dua kutip tunggal berlaku pada hampir semua karakter, kecuali bebera karakter, seperti carriage return. Selain itu, untuk beberapa karakter tertentu, kutip tunggal dan kutip ganda, memiliki makna spesial dalam C#, sehingga Anda tidak dapat menggunakannya secara langsung. Karena dua alasan ini, C# menyediakan beberapa runtun escape spesial, yang kadangkala dikenal pula sebagai konstanta karakter backslash, yang ditampilkan pada Tabel 2.2.

Sebagai contoh, statemen berikut menugasi ch dengan karakter tab:

ch = '\t';

Contoh selanjutnya menugaskan sebuah kutip tunggal pada ch:

ch = '\'';

Runtun escape
Deskripsi
\a
Alert (bell)
\b
Backspace
\f
Form feed
\n
New line (garis baru)
\r
Carriage return
\t
Tab horisontal
\v
Tab vertikal
\0
Null
\’
Kutip tunggal
\”
Kutip ganda
\\
Backslash

Tabel 2.2 Runtun escape


Literal String
C# mendukung satu lagi tipe literal: literal string. Literal string adalah himpunan karakter yang diapit oleh dua kutip ganda. Sebagai contoh,

“Ini adalah literal string”

adalah sebuah literal string. Anda telah melihat banyak literal string pada statemen WriteLine() pada beberapa program terdahulu. Di samping karakter normal, literal string dapat pula memuat satu atau lebih runtun escape. Sebagai contoh, perhatikan program berikut, yang menggunakan runtun escape \n dan \t.

// Demonstrasi runtun escape dalam string.
using System;

class DemoString
{
    static void Main() {
        Console.WriteLine("Baris Satu\nBaris Dua\nBaris Tiga");
        Console.WriteLine("Satu\tDua\tTiga");
        Console.WriteLine("Empat\tLima\tEnam");
       
        // Menampilkan kutip
        Console.WriteLine("\"Kenapa?\", Dia berujar.");
    }
}

Keluaran program adalah:

Baris Satu
Baris Dua
Baris Tiga
Satu    Dua     Tiga
Empat   Lima    Enam
"Kenapa?", Dia berujar.

Perhatikan bagaimana runtun escape \n dipakai untuk menghasilkan baris baru. Anda tidak perlu menggunakan beberapa statemen WriteLine() untuk mendapatkan keluaran banyak baris baru. Anda hanya perlu menyisipkan \n di dalam string panjang pada titik dimana Anda ingin baris baru diperlukan. Selain itu, perhatikan juga bagaimana tanda kutip ganda dihasilkan di dalam suatu string.

Selain format literal string yang baru saja dijelaskan, Anda juga dapat menspesifikasi literal string verbatim. Literal string verbatim diawali dengan @, yang diikuti oleh sebuah string yang dikutip. Jadi, Anda dapat menyertakan baris-baru, tab, dan lainnya, tetapi Anda tidak perlu menggunakan runtun escape. Satu-satunya pengecualian adalah bahwa untuk mendapatkan kutip ganda (“), Anda harus menggunakan dua kutip ganda secara berurutan (“”). Berikut adalah sebuah program yang mendemonstrasikan literal string verbatim:

// Demonstrasi literal string verbatim.
using System;

class Verbatim {
  static void Main() {
      Console.WriteLine(@"Ini adalah literal
string verbatim yang
ditempatkan pada beberapa baris.
");
      Console.WriteLine(@"Berikut adalah keluaran yang ditab:
1   2   3   4
5   6   7   8
");
      Console.WriteLine(@"Programer berkata, ""Saya suka C#.""");
  }
}

Keluaran program adalah:

Ini adalah literal
string verbatim yang
ditempatkan pada beberapa baris.

Berikut adalah keluaran yang ditab:
1   2   3   4
5   6   7   8

Programer berkata, "Saya suka C#."

Hal penting yang perlu diperhatikan dalam program tersebut adalah bahwa literal string verbatim ditampilkan persis sama dengan apa yang dituliskan di dalam program.

Keuntungan literal string verbatim adalah bahwa Anda dapat menentukan keluaran di dalam program Anda yang sama persis dengan apa tertampil pada layar. Namun, pada kasus string baris-jamak, identasi (pengaturan posisi) akan mengaburkan kemudahan pembacaan program. Karena alasan ini, semua program pada buku ini membatasi penggunaan literal string. Yang perlu Anda ingat adalah bahwa literal string verbatim bisa berguna pada banyak situasi pemformatan.

Satu hal terakhir: Jangan bingung dalam membedakan string dengan karakter. Literal karakter, seperti ‘X’, merepresentasikan huruf bertipe char. Literal string yang hanya memuat satu huruf, seperti “X”, tetap sebuah string.


Lebih Dekat Dengan Variabel
Variabel dideklarasikan menggunakan format statemen berikut:

tipe nama-var;

dimana tipe adalah tipe data variabel dan nama-var adalah namanya. Anda dapat mendeklarasikan sebuah variabel bertipe sembarang (yang valid). Adalah hal penting untuk memahami bahwa kapabilitas suatu variabel ditentukan oleh tipenya. Sebagai contoh, variabel bertipe bool tidak dapat dipakai untuk menyimpan nilai titik-mengambang. Selain itu, tipe suatu variabel tidak bisa diubah setelah pendeklarasiannya. Variabel bertipe int tidak bisa diubah menjadi bertipe char, misalnya.

Semua variabel dalam C# harus dideklarasikan sebelum digunakan. Sebagai aturan umum, hal ini diperlukan karena kompiler harus mengetahui tipe data sebuah variabel sebelum kompiler mengkompilasi sembarang statemen yang menggunakan variabel tersebut. Hal ini juga memampukan kompiler untuk melakukan pemeriksaan tipe.

C# mendefinisikan beberapa jenis variabel. Jenis variabel yang dipakai sejauh ini adalah variabel lokal karena dideklarasikan di dalam sebuah metode.


Menginisialisasi Variabel
Salah satu cara untuk memberikan nilai kepada sebuah variabel adalah melalui statemen penugasan, seperti yang Anda telah lakukan sebelumnya. Cara lainnya adalah dengan memberikan nilai awal ketika variabel tersebut dideklarasikan. Untuk melakukannya, nama variabel diikuti dengan tanda sama dengan dan nilai yang akan ditugaskan. Bentuk umum inisialisasi variabel ditampilkan di sini:

tipe nama-var = nilai;

Di sini, nilai adalah nilai yang akan diberikan kepada variabel ketika variabel itu diciptakan. nilai harus kompatibel dengan tipe yang dispesifikasi. Berikut diberikan beberapa contoh inisialisasi variabel:

int hitung = 10; // memberikan hitung nilai awal 10
char ch = 'X'; // menginisialisasi ch dengan huruf X
float f = 1.2F; // f diinisialisasi dengan 1.2

Ketika mendeklarasikan dua atau lebih variabel bertipe sama yang dipisahkan dengan koma, Anda dapat memberikannya nilai awal. Sebagai contoh,

int a, b = 8, c = 19, d; // b dan c mempunyai nilai awal

Pada kasus ini, hanya b dan c yang diinisialisasi.


Inisialisasi Dinamis
Meskipun contoh-contoh sebelumnya hanya menggunakan konstanta sebagai penginisialisasi, C# membolehkan variabel diinisialisasi secara dinamis, menggunakan sembarang ekspresi valid di titik dimana variabel tersebut dideklarasikan. Sebagai contoh, berikut adalah sebuah program pendek yang menghitung sisi miring dari sebuah segitiga, bila diberikan dua sisi lainnya.

// Demonstrasi inisialisasi dinamis.
using System;

class InisialDinamis {
    static void Main() {
        // Panjang kedua sisi.
        double s1 = 4.0;
        double s2 = 5.0;
       
        // Secara dinamis menginisialisasi sisi_miring.
        double sisi_miring = Math.Sqrt((s1 * s1) + (s2 * s2));
        Console.Write("Sisi miring suatu segitiga dengan kedua disi " +
                      s1 + " dan " + s2 + " adalah ");

        Console.WriteLine("{0:#.###}.", sisi_miring);
    }
}

Berikut adalah keluaran program:

Sisi miring suatu segitiga dengan kedua disi 4 dan 5 adalah 6.403.

Di sini, tiga variabel lokal, yaitu s1, s2, dan sisi_miring, dideklarasikan. Dua variabel pertama, s1 dan s2, diinisialisasi dengan konstanta. Namun, sisi_miring diinisialisasi secara dinamis dengan panjang sisi miring suatu segitiga. Perhatikan bahwa inisialisasi melibatkan pemanggilan Math.Sqrt(). Seperti yang telah dijelaskan, Anda dapat menggunakan sembarang ekspresi yang valid di titik inisialisasi. Karena pemanggilan terhadap Math.Sqrt() valid di titik tersebut, ia dapat dipakai di dalam inisialisasi sisi_miring.


Variabel Bertipe Implisit
Seperti yang telah dijelaskan, dalam C# semua variabel harus dideklarasikan. Normalnya, deklarasi mencakup tipe variabel, seperti int atau bool, diikuti dengan nama variabel. Namun, sejak C# 3.0, menjadi memungkinkan bagi kompiler dalam menentukan tipe suatu variabel lokal berdasarkan nilai yang dipakai untuk menginisialisasinya. Hal ini dikenal dengan variabel bertipe implisit.

Variabel bertipe implisit dideklarasikan menggunakan katakunci var, dan harus diinisialisasi. Kompiler menggunakan tipe penginisialisasi dalam menentukan tipe variabel. Berikut adalah sebuah contohnya:

var e = 2.7183;

Karena e diinisialisasi dengan literal titik-mengambang (secara default, double), maka tipe dari e adalah double. Jika e dideklarasikan seperti ini:

var e = 2.7183F;

maka e bertipe float.

Program berikut mendeklarasikan tipe variabel yang dideklarasikan secara implisit.

// Demonstrasi tipe variabel secara implisit.
using System;

class VariabelBertipeImplisit {
  static void Main() {
    // Berikut adalah variabel bertipe implisit.
    // Keduanya bertipe double karena ekspresi
    // penginisialisasi bertipe double.
    var s1 = 4.0;
    var s2 = 5.0;

    // Sekarang, sisi_miring bertipe implisit. Tipenya double
    // karena tipe nilai balik dari Sqrt() adalah double.
    var sisi_miring = Math.Sqrt( (s1 * s1) + (s2 * s2) );

    Console.Write("Sisi miring dari suatu segitiga dengan kedua sisi " +
                  s1 + " dan " + s2 + " adalah ");

    Console.WriteLine("{0:#.###}.", sisi_miring);
    // Statemen berikut tidak akan dikompilasi karena
    // s1 adalah sebuah double dan tidak dapat ditugasi nilai decimal.
    // s1 = 12.2M; // Error!
  }
}

Keluaran program sama dengan sebelumnya. Hal penting yang perlu ditekankan di sini adalah bahwa suatu variabel bertipe implisit tidak bisa diubah semena-mena. Perhatikan komentar ini di dalam program:

// s1 = 12.2M; // Error!

Penugasan ini tak valid karena s1 bertipe double. Jadi, ia tidak bisa ditugasi sebuah nilai decimal. Satu-satunya perbedaan antara variabel bertipe implisit dan variabel yang ditipe secara eksplisit adalah bagaimana tipe ditentukan. Begitu tipe telah ditentukan, variabel telah memiliki tipe, dan tipe ini tetap selama variabel itu eksis. Jadi, tipe dari s1 tidak dapat diubah selama ekskusi program.

Satu hal terakhir: Hanya boleh satu variabel bertipe implisit yang dapat dideklarasikan pada satu waktu. Oleh karena itu, deklarasi berikut:

var s1 = 4.0, s2 = 5.0; // Error!

adalah salah dan tidak bisa dikompilasi karena mencoba untuk mendeklarasikan s1 dan s2 pada waktu yang bersamaan.


Skop dan Usia Variabel
Sejauh ini, semua variabel yang dipakai dideklarasikan di awal metode Main(). Namun, C# membolehkan variabel lokal dideklarasikan di dalam sembarang blok. Blok diawali dengan kurung kurawal buka dan diakhiri dengan kurung kurawal tutup. Blok mendefinisikan skop. Jadi, setiap kali Anda memulai blok baru, itu artinya Anda menciptakan skop baru. Skop menentukan visibilitas nama-nama yang dikenali oleh bagian-bagian program Anda tanpa memerlukan kualifikasi. Skop juga menentukan usia variabel lokal.

Skop yang paling penting dalam C# adalah yang didefinisikan oleh suatu kelas dan yang didefinisikan oleh suatu metode. Diskusi tentang skop kelas (dan variabel yang dideklarasikan di dalamnya) dilakukan nanti pada buku ini. Untuk sekarang, hanya skop yang didefinisikan oleh metode yang akan dibahas.
Skop yang didefinisikan oleh metode diawali dengan kurung kurawal buka dan diakhiri dengan kurung kurawal tutunp. Namun, jika metode tersebut mempunyai parameter, parameter tersebut juga disertakan di dalam skop yang didefinisikan oleh metode.

Sebagai aturan umum, variabel lokal yang dideklarasikan di dalam sebuah skop tidak dikenali oleh kode yang didefinisikan di luar skop tersebut. Jadi, ketika Anda mendeklarasikan sebuah variabel di dalam suatu skop, maka Anda melindunginya dari akses atau modifikasi dari luar skop. Aturan skop merupakan fondasi bagi enkapsulasi.

Skop dapat dibuat bersarang. Ketika ini terjadi, skop sebelar luar mengapit skop sebelah dalam. Ini berarti bahwa variabel lokal yang dideklarasikan di dalam skop luar dapat dikenali oleh kode di dalam skop sebelah dalam. Tetapi tidak sebaliknya. Variabel lokal yang dideklarasikan di dalam skop sebelah dalam tidak dikenali oleh kode di luarnya (meski berada di dalam skop sebelah luar).

// Demonstrasi skop blok.
using System;

class DemoSkop {
    static void Main() {
        int x; // dikenali oleh semua kode di dalam Main()
       
        x = 10;
        if (x == 10)
        { // mulai skop baru
            int y = 20; // hanya dikenali di dalam blok ini
           
            // x dan y keduanya dikenali di sini.
            Console.WriteLine("x dan y: " + x + " " + y);
            x = y * 2;
        }
        // y = 100; // Error! y tidak dikenali di sini.
       
        // x masih dikenali di sini.
        Console.WriteLine("x adalah " + x);
    }
}

Keluaran program ditampilkan di sini:

x dan y: 10 20
x adalah 40

Seperti diindikasikan pada komentar, variabel x dideklarasikan di awal skop Main() dan dapat diakses (dikenali) oleh semua kode di dalam Main(). Di dalam blok if, y dideklarasikan. Karena blok mendefinisikan skop, y hanya dikenali oleh kode di dalam blok tersebut. Ini mengapa di luar blok tersebut, baris y = 100; tidak dikenali. Jika Anda menghapus simbol komentar //, maka error kompilasi akan terjadi karena y tidak di kenali di luar bloknya. Di dalam blok if, x dapat dipakai karena kode di dalam blok tersebut memiliki akses terhadap variabel tersebut.

Di dalam suatu blok, variabel dapat dideklarasikan dimanapun, tetapi hanya bisa diakses setelah titik pendeklarasiannya. Jadi, jika Anda mendefinisikan sebuah variabel di awal metode, maka variabel itu dapat diakses oleh semua kode di dalam metode tersebut. Sebaliknya, jika Anda mendeklarasikan variabel di akhir suatu blok, maka ia hanya menjadi variabel sia-sia, karena tidak ada kode yang dapat mengaksesnya.

Jika suatu deklarasi variabel melibatkan penginisialisasi, maka variabel tersebut akan diinisialiasi-ulang setiap kali blok yang memuatnya dimasuki program. Sebagai contoh, perhatikan program ini:

// Demonstrasi usia suatu variabel.
using System;

class VarInitDemo {
  static void Main() {
      int x;

      for(x = 0; x < 3; x++) {
          int y = -1; // y diinisialisasi setiap kali blok dimasuki
          Console.WriteLine("y adalah: " + y); // selalu menampilkan -1
         
          y = 100;
          Console.WriteLine("y sekarang menjadi: " + y);
      }
  }
}

Berikut adalah keluaran program:

y adalah: -1
y sekarang menjadi: 100
y adalah: -1
y sekarang menjadi: 100
y adalah: -1
y sekarang menjadi: 100

Seperti yang dapat Anda lihat, y selalu diinisialisasi-ulang dengan -1 setiap kali loop for dimasuki program. Meskipun y ditugasi nilai 100, nilai ini akan hilang.

Ada satu hal aneh dalam aturan skop C# yang bisa mengejutkan Anda: Meskipun blok bisa dibuat bersarang, tidak ada variabel yang dideklarasikan di dalam skop sebelah dalam yang dapat memiliki nama sama dengan variabel yang dideklarasikan oleh skop sebelah luar. Sebagai contoh, program berikut, yang mencoba mendeklarasikan dua variabel terpisah dengan nama sama, tidak akan berhasil dikompilasi.

/*
Program ini mencoba mendeklarasikan sebuah variabel
di dalam skop sebelah dalam dengan nama sama dengan
variabel yang didefinisikan di dalam skop sebelah luar.
*** Program ini tak akan bisa dikompilasi. ***
*/
using System;

class VariabelBersarang {
    static void Main() {
        int hitung;
        for (hitung = 0; hitung < 10; hitung = hitung + 1)
        {
            Console.WriteLine("Ini adalah hitung: " + hitung);
            int hitung; // ilegal!!!
            for (hitung = 0; hitung < 2; hitung++)
                Console.WriteLine("Program ini bermasalah!");
        }
    }
}

Jika Anda memiliki latar belakang pemrograman C/C++, maka Anda mengetahui tidak ada batasan nama seperti ini. Jadi, dalam C/C++ deklarasi hitung di dalam blok loop for sebelah dalam seutuhnya valid. Namun, dalam C/C++, deklarasi semacam itu akan menyembunyikan variabel sebelah luar. Perancang C# merasa bahwa jenis penyembunyian nama seperti ini dapat dengan mudah menyebabkan error pemrograman dan tidak mengijinkan penggunaannya.


Konversi Tipe dan Casting
Dalam pemrograman, adalah hal umum dijumpai untuk mengubah satu tipe variabel menjadi tipe lain. Sebagai contoh, Anda bisa jadi ingin menugaskan nilai int menjadi kepada sebuah variabel float, seperti ditunjukkan di sini:

int i;
float f;

i = 10;
f = i; // menugaskan int ke suatu float

Ketika beberapa tipe kompatibel dicampur di dalam suatu penugasan, nilai dari sisi sebelah kanan operator penugasan secara otomatis dikonversi menjadi tipe dari sisi sebelah kiri. Jadi, pada fragmen tersebut, nilai di dalam i dikonversi menjadi float dan kemudian ditugaskan kepada f. Namun, karena aturan pemeriksaan-tipe C#, tidak semua tipe kompatibel, dan jadi, tidak semua konversi secara implisit diijinkan. Sebagai contoh, bool dan int tidak kompatibel. Untungnya, masih dimungkinkan terjadinya konversi antara tipe-tipe tak-kompatibel menggunakan cast. Sebuah cast melakukan konversi eksplisit. Konversi tipe otomatis dan operasi cast didisikusikan di sini.


Konversi Otomatis
Ketika suatu tipe data ditugaskan kepada variabel bertipe lain, konversi tipe otomatis akan terjadi secara otomatis jika
·         Kedua tipe kompatibel.
·         Tipe tujuan memiliki rentang lebih besar dari tipe sumber.

Ketika kedua kondisi ini dipenuhi, konversi melebar akan terjadi. Sebagai contoh, tipe int selalu cukup besar untuk menampung nilai bertipe byte, dan kedua int dan byte merupakan tipe integer yang kompatibel, jadi konversi implisit bisa diterapkan.

Untuk konversi melebar, tipe-tipe numerik, termasuk tipe integer dan tipe titik-mengambang, adalah kompatibel satu sama lain. Sebagai contoh, program berikut valid karena konversi long menjadi double merupakan suatu konversi melebar yang secara otomatis dilakukan.

// Demonstrasi konversi implisit dari long ke double.
using System;

class LtoD {
    static void Main() {
        long L;
        double D;
      
        L = 100123285L;
        D = L;
       
        Console.WriteLine("L dan D: " + L + " " + D);
    }
}

Meskipun konversi implisit dari long menjadi double bisa dilakukan, konversi implisit dari double menjadi long tidak bisa dilakukan karena bukan merupakan konversi melebar. Jadi, versi berikut dari program sebelumnya menjadi tak-valid:

// *** Program ini tidak bisa dikompilasi. ***
using System;

class LtoD {
    static void Main() {
        long L;
        double D;
       
        D = 100123285.0;
        L = D; // Ilegal!!!
      
        Console.WriteLine("L dan D: " + L + " " + D);
    }
}

Selain pembatasan yang telah dijelaskan, konversi implisit antara decimal dan float atau double tidak bisa dilakukan, atau dari tipe numerik menjadi char atau double. Di samping itu, char dan bool tidak kompatibel satu sama lain.


Operasi Cast Atas Tipe Tak-Kompatibel
Meskipun konversi tipe implisit cukup membantu, operasi itu tidak bisa memenuhi semua kebutuhan pemrograman karena hanya bisa diterapkan pada konversi melebar di antara tipe-tipe kompatibel. Untuk kasus selain itu, Anda harus menerapkan cast. Sebuah cast adalah instruksi kepada kompiler untuk mengkonversi keluaran suatu ekspresi menjadi tipe yang diinginkan. Jadi, kompiler meminta dilakukan konversi tipe secara eksplisit. Operasi cast mempunyai bentuk umum:

(tipe-target) ekspresi

Di sini, tipe-target menspesifikasi tipe yang diinginkan. Sebagai contoh, diberikan

double x, y;

Jika Anda ingin tipe konversi x/y  menjadi int, Anda dapat menuliskan

(int) (x / y)

Di sini, meskipun x dan y bertipe double, operasi cast mengkonversi keluaran ekspresi menjadi int. Sepasang kurung yang mengapit x/y diperlukan. Karena jika kurung tidak digunakan, operasi cast hanya akan diterapkan pada x dan bukan pada keluaran pembagian. Operasi cast diperlukan di sini karena konversi implisit dari double menjadi int tidak bisa dilakukan.

Ketika operasi cast melibatkan konversi menyempit, informasi bisa hilang. Sebagai contoh, ketika operasi cast dilakukan terhadap long menjadi int, informasi bisa hilang jika nilai dari long lebih besar dari rentang sebuah int karena bit-bit signifikan akan terhapus. Ketika suatu nilai titik-mengambang dicast menjadi tipe integer, komponen pecahan akan hilang akibat pemotongan. Sebagai contoh, jika nilai 1.23 ditugaskan kepada sebuah integer, nilai yang dihasilkan adalah 1. Komponen pecahan 0.23 akan hilang.

Program berikut mendemonstrasikan beberapa konversi tipe yang memerlukan operasi cast. Program ini juga menunjukkan beberapa situasi dimana operasi cast dapat menyebabkan data hilang.

// Demonstrasi operasi cast.
using System;

class DemoCast {
  static void Main() {
    double x, y;
    byte b;
    int i;
    char ch;
    uint u;
    short s;
    long l;

    x = 10.0;
    y = 3.0;

    // Cast double menjadi int, komponen pecahan hilang.
    i = (int) (x / y);
    Console.WriteLine("Keluaran integer dari x / y: " + i);
    Console.WriteLine();

    // Cast int menjadi byte, tidak ada data hilang.
    i = 255;
    b = (byte) i;
    Console.WriteLine("b setelah penugasan 255: " + b +
                      " -- tidak data hilang.");

    // Cast int menjadi byte, data hilang.
    i = 257;
    b = (byte) i;
    Console.WriteLine("b setelah penugasan 257: " + b +
                      " -- data hilang.");
    Console.WriteLine();

    // Cast uint menjadi short, tidak ada data hilang.
    u = 32000;
    s = (short) u;
    Console.WriteLine("s setelah penugasan 32000: " + s +
                      " -- tidak ada data hilang.");

    // Cast uint menjadi short, data hilang.
    u = 64000;
    s = (short) u;
    Console.WriteLine("s setelah penugasan 64000: " + s +
                      " -- data hilang.");
    Console.WriteLine();

    // Cast long menjadi uint, tidak ada data hilang.
    l = 64000;
    u = (uint)l;
    Console.WriteLine("u setelah penugasan 64000: " + u +
                      " -- tidak ada data hilang.");

    // Cast dari long menjadi uint, data hilang.
    l = -12;
    u = (uint)l;
    Console.WriteLine("u setelah penugasan -12: " + u +
                      " -- data hilang.");
    Console.WriteLine();

    // Cast int menjadi char.
    b = 88; // kode ASCII untuk X
    ch = (char)b;
    Console.WriteLine("ch setelah penugasan 88: " + ch);
  }
}

Keluaran program ditampilkan di sini:

Keluaran integer dari x / y: 3

b setelah penugasan 255: 255 -- tidak data hilang.
b setelah penugasan 257: 1 -- data hilang.

s setelah penugasan 32000: 32000 -- tidak ada data hilang.
s setelah penugasan 64000: -1536 -- data hilang.

u setelah penugasan 64000: 64000 -- tidak ada data hilang.
u setelah penugasan -12: 4294967284 -- data hilang.

ch setelah penugasan 88: X

Akan diperiksa setiap penugasan. Operasi cast terhadap (x/y) menjadi int menghasilkan pemotongan komponen pecahan (fraksional), dan informasi hilang.

Tidak ada informasi yang hilang terjadi ketika b ditugasi nilai 255 karena sebuah byte dapat menampung nilai 255. Namun, ketika percobaan dilakukan untuk menugasi b dengan nilai 257, informasi hilang terjadi karena 257 melebihi rentang suatu byte. Pada kedua kasus, operasi cast dibutuhkan karena konversi implisit dari int menjadi byte tidak bisa dilakukan.

Ketika variabel short, s, ditugasi nilai 32,000 melalui variabel uint, u, tidak ada data yang hilang karena sebuah short dapat menampung nilai 32,000. Namun, dalam penugasan selanjutnya, u mempunyai nilai 64,000, yang berada di luar rentang sebuah short, dan data menjadi hilang. Pada kedua kasus, operasi cast diperlakukan karena konversi implisit dari uint menjadi short tidak bisa dilakukan.

Selanjutnya, u ditugasi nilai 64,000 melalui variabel long, l. Pada kasus ini, tidak ada data yang hilang karena 64,000 masih berada di dalam rentang sebuah uint.  Namun, ketika nilai -12 ditugaskan kepada u, data menjadi hilang karena sebuah uint tidak bisa menampung nilai negatif. Pada kedua kasus, operasi cast diperlukan karena konversi implisit dari long menjadi uint tidak bisa dilakukan.


Konversi Tipe Dalam Ekspresi
Selain terjadi di dalam penugasan, konversi tipe juga terjadi di dalam ekspresi. Di dalam suatu ekspresi, Anda dapat dengan bebas mencampur dua atau lebih berbagai tipe data berbeda sepanjang kompatibel satu sama lain. Sebagai contoh, Anda dapat mencampur short dan long di dalam sebuah ekspresi karena keduanya adalah tipe numerik. Ketika berbagai tipe data dicampur di dalam sebuah ekspresi, maka dikonversi menjadi tipe yang sama melalui basis operasi-demi-operasi.

Konversi dilakukan melalui aturan promosi tipe C#. Berikut adalah algoritma promosi tipe C#:

IF satu operand adalah decimal, THEN operand lain dipromosikan menjadi decimal (kecuali jika salah satu operand bertipe float atau double, pada kasus itu akan terjadi error).

ELSEIF satu operand bertipe double, maka operand kedua dipromosikan menjadi double.

ELSEIF satu operand bertipe float, maka operand kedua dipromosikan menjadi float.

ELSEIF satu operand bertipe ulong, maka operand kedua dipromosikan menjadi ulong (kecuali jika operand kedua bertipe sbyte, short, int, atau long, pada kasus tersebut akan terjadi error).

ELSEIF satu operand bertipe long, maka operand kedua dipromosikan menjadi long.

ELSEIF satu operand bertipe uint dan operand kedua bertipe sbyte, short, atau, int, maka kedua operand dikonversi menjadi long.

ELSEIF satu operand bertipe uint, maka operand kedua dipromosikan menjadi uint.

ELSE kedua operand dipromosikan menjadi int.

Adalah hal penting untuk dipahami bahwa promosi tipe hanya diterapkan pada nilai di dalam ekspresi yang sedang dievaluasi. Sebagai contoh, jika nilai dari sebuah variabel bertipe byte dipromosikan menjadi int di dalam suatu ekspresi, maka di luar ekspresi variabel tersebut masih sebuah byte. Promosi tipe hanya mempengaruhi evaluasi atas suatu ekspresi.

Promosi tipe dapat mengarah ke hasil yang tidak diinginkan. Sebagai contoh, ketika suatu operasi aritmatika melibatkan dua nilai byte, runtun berikut terjadi. Pertama, operand byte dipromosikan menjadi int, memberikan hasil int. Jadi, keluaran sebuah ekspresi yang melibatkan dua nilai byte akan menghasilkan sebuah int. Ini mungkin bukan apa yang Anda bayangkan. Perhatikan program berikut.

// Kejutan Promosi tipe!
using System;

class PromDemo
{
    static void Main()
    {
        byte b;
        b = 10;
        b = (byte)(b * b); // cast diperlukan!!
       
        Console.WriteLine("b: " + b);
    }
}

Di luar dugaan Anda, operasi cast terhadap byte diperlukan ketika menugaskan b * b kembali kepada b!. Alasannya adalah karena di dalam b * b, nilai b dipromosikan menjadi int ketika ekspresi tersebut dievaluasi. Jadi, b * b menghasilkan nilai int, yang tidak bisa ditugaskan ke variabel byte tanpa operasi cast.

Situasi yang sama terjadi pada char. Sebagai contoh, dalam fragmen berikut, operasi cast terhadap char diperlukan karena promosi atas ch1 dan ch2 menjadi int di dalam ekspresi

char ch1 = 'a', ch2 = 'b';
ch1 = (char) (ch1 + ch2);

Tanpa adanya operasi cast, hasil penjumlahan ch1 dan ch2 akan bertipe int, yang tidak bisa ditugaskan kepada variabel char.


Menggunakan Cast Dalam Ekspresi
Operasi cast dapat diterapkan pada bagian spesifik dari sebuah ekspresi panjang. Ini memberikan Anda kendali atas konversi tipe yang terjadi di dalam sebuah ekspresi yang sedang dievaluasi. Sebagai contoh, perhatikan program berikut. Program tersebut menampilkan beberapa akar kuadrat atas angka dari 1 sampai 10. Program juga menampilkan bagian bulat dan bagian pecahan dari setiap hasil, secara terpisah. Untuk melakukannya, program menggunakan operasi cast dalam mengkonversi hasil dari Math.Sqrt() menjadi int.

// Menggunakan cast di dalam sebuah ekspresi.
using System;

class CastExpr {
  static void Main() {
    double n;

    for(n = 1.0; n <= 10; n++) {
      Console.WriteLine("Akar kuadrat atas {0} adalah {1}",
                        n, Math.Sqrt(n));
   
      Console.WriteLine("Bagian angka bulat: {0}",
                        (int)Math.Sqrt(n));
  
      Console.WriteLine("Bagian pecahan: {0}",
                        Math.Sqrt(n) - (int)Math.Sqrt(n));
   
      Console.WriteLine();
    }
  }
}

Berikut adalah keluaran program:

Akar kuadrat atas 1 adalah 1
Bagian angka bulat: 1
Bagian pecahan: 0

Akar kuadrat atas 2 adalah 1.4142135623731
Bagian angka bulat: 1
Bagian pecahan: 0.414213562373095

Akar kuadrat atas 3 adalah 1.73205080756888
Bagian angka bulat: 1
Bagian pecahan: 0.732050807568877

Akar kuadrat atas 4 adalah 2
Bagian angka bulat: 2
Bagian pecahan: 0

Akar kuadrat atas 5 adalah 2.23606797749979
Bagian angka bulat: 2
Bagian pecahan: 0.23606797749979

Akar kuadrat atas 6 adalah 2.44948974278318
Bagian angka bulat: 2
Bagian pecahan: 0.449489742783178

Akar kuadrat atas 7 adalah 2.64575131106459
Bagian angka bulat: 2
Bagian pecahan: 0.645751311064591

Akar kuadrat atas 8 adalah 2.82842712474619
Bagian angka bulat: 2
Bagian pecahan: 0.82842712474619

Akar kuadrat atas 9 adalah 3
Bagian angka bulat: 3
Bagian pecahan: 0

Akar kuadrat atas 10 adalah 3.16227766016838
Bagian angka bulat: 3
Bagian pecahan: 0.16227766016838





2 comments: