Demystifier Dicky

A blogs dedicated for simple easy followed tutorial.
  • ReSharper Warning: ‘access to modified closure’

    Semenjak C# 2.0, programmer C# dapat mendeklarasikan sebuah anonymous delegate seperti layaknya bahasa fungsional, but not until the forthcoming C# 3.0 that this features is ubiquitously used as Microsoft introduce lambda expression. Lambda expression bisa dianggap sebagai anonymous delegate dalam bentuk lebih kompak sehingga code menjadi lebih enak dipandang dan creation is faster. Oke, bagi Anda yang hardcore pasti tahu bahwa lambda expression is more than that, but for this post, just think it as it is (noises-free-form of anonymous delegate). Namun, penggunaan lambda expression yang ekstensif tampaknya tidak membuat sebagian C# programmer sadar ada sesuatu yang bernama 'closure’, bahkan salah satu cara untuk mengukur kedalaman pemahaman bahasa seseorang itu bisa diukur dari apakah orang tersebut mengetahui closure atau tidak :)

    Action in action

    Salah satu yang ditambahkan Microsoft di C# 3.0 adalah Action, sebuah delegate yang memiliki return type void, dan parameter dapat anda deklarasikan secara generic. Microsoft mendeklarasikan 4 buah Action:

       1: delegate void Action();
       2: delegate void Action<T1>(T1 p1);
       3: delegate void Action<T1, T2>(T1 p1, T2 p2);
       4: delegate void Action<T1, T2, T3>(T1 p1, T2 p2, T3 p3);
       5: delegate void Action<T1, T2, T3, T4>(T1 p1, T2 p2, T3 p3, T4 p4);

    Apabila Anda ingin mendeklarasikan delegate dengan return void dan parameter lebih dari 4, mungkin Anda harus mengetik secara manual dengan melihat pola di atas. Salah satu contoh penggunaannya adalah seperti ini:

    Action action = () => System.Console.WriteLine(5);
    action();

    Code di atas akan menampilkan 5. Sekarang kita rubah sedikit menjadi seperti ini:

    int number = 5;
    Action action = () => System.Console.WriteLine(number);
    action();

    Anda jalankan dan tampilan tetap tidak berubah, yakni 5. Nah, sekarang mari kita usil sedikit dengan mengubah nilai number. Pengubahan dapat dilakukan di mana saja selain tentu saja, di atas deklarasi number :)

    int number = 5;
    Action action = () => System.Console.WriteLine(number);
    action();
    number = 7;

    Saat ini apabila Anda menggunakan ReSharper, maka teman Anda ini akan mengeluarkan kata-kata aneh, yakni: ‘access to modified closure’. What the heck is that? Oke, kita turuti kemauannya mengingat teman kita ini sudah setia menemani kita coding jauh melebihi wanita manapun :) Dengan menekan Alt-Enter, secara otomatis ReSharper akan mengubah code menjadi:

    int number = 5;
    int buffer = number;
    Action action = () => System.Console.WriteLine(buffer);
    action();
    number = 7;

    Code di atas membuat kita menjadi lebih bingung. Kenapa harus ada variabel buffer? Bukankah code di atas dan sebelumnya hasilnya selalu sama? Untuk alasan ini, beberapa orang mendisable warning nggak jelas tersebut. Apakah kali ini ReSharper sok tahu dengan menyarankan sesuatu yang useless? Sebelum menjawab ini, mari kita melihat nama warning tersebut: ‘access to modified closure’. Terdapat kata closure di sana, sesuatu yang biasanya cuma diketahui sama orang yang senang dengan konsep bahasa pemrograman :)

    Berbeda dengan anonymous delegate, generic, lambda expression atau fitur-fitur lainnya yang diekspos sebagai sebuah fitur, closure tidak pernah diekspos, sehingga cuma segelintir orang yang menyadari kehadirannya karena Microsoft cuma mengatakan tentang anonymous delegate atau lambda, sedangkan closure adalah sesuatu yang dilakukan secara sembunyi-sembunyi oleh C# compiler. Karena dilakukan di balik layar inilah, fitur ini bisa diketahui kalau Anda memiliki sifat tukang ngintip, mengintip MSIL yang digenerate oleh compiler.

    Closure Demystified

    Kalau Anda seorang yang senang dengan penjelasan yang baku beserta definisi-definisi, sebaiknya Anda membaca di tempat lain karena saya bukan PhD. Pada posting ini, sebisa mungkin penjelasan tentang closure adalah pragmatis disertai dengan contoh yang dapat langsung Anda praktekkan.

    Secara tidak sengaja, tadi kita telah membuat sebuah closure pada saat mengetik code ini:

    int number = 5;
    Action action = () => System.Console.WriteLine(number);
    action();

    Kita mengikutsertakan variabel number pada lambda expression, padahal number bukan variabel lokal pada lambda expression tersebut. Pada kasus ini, number berubah dari hanya variabel lokal, menjadi closure. Pada saat nilai number berubah, seperti yang kita ketikkan berikutnya, nilai closure tadi dimodifikasi, hence ‘modified closure’ words comes from, seperti yang diteriakkan ReSharper.

    Contoh lain:

    public static void Foo()
    {
        int localInFoo = 0;
        int closure = 1;
        Action action = () =>
                    {
                        int localInLambda = 5;
                        Console.WriteLine(localInLambda);
                        Console.WriteLine(closure);
                    };
        action();
    }

    Pada method Foo di atas, variabel yang berubah menjadi closure cuma satu yaitu variabel bernama closure. Yang lain hanyalah variabel lokal biasa, yang akan menjadi out of scope saat method Foo selesai dipanggil. Selanjutnya mari kita bahas apa kelebihan dari closure dibanding variabel lokal biasa.

    Mari kita ubah code kita menjadi seperti ini:

    int number = 5;
    Action action = () => System.Console.WriteLine(number);
    action();   // print 5
    number++;
    action();   // print 6

    Karena number adalah closure, maka pengubahan nilai number di luar lambda expression, juga akan diikuti oleh nilai number di dalam ekspresi, seperti terlihat dengan pemanggilan action berikutnya. Sebaliknya juga dapat dilakukan, pengubahan nilai number di lambda expression akan mengubah number di luar lambda expression, sehingga keduanya mirip reference type. Kalau Anda lihat dengan ILDASM, C# compiler memang mengimpilementasi closure dengan membungkusnya dengan auto-generated class yang notabene memang reference type, jadi wajar saja apabila kelakuannya bukan sekedar mirip, tapi memang reference type.

    Sifat lain dari reference type yang signifikan adalah, object berada di heap sehingga tidak lekas out-of-scope apabila keluar dari fungsi. Dengan melihat fungsi Foo di atas, variabel localInLambda akan segera teralokasi di stack saat action dipanggil dan segera terdealokasi selepas action selesai. Variabel localInFoo akan segera terdealokasi setelah Foo selesai. Sedangkan variabel closure yang tampak seperti lokal variabel dibungkus oleh compiler C# dengan sebuah class agar memiliki kelakuan seperti yang telah diterangkan. Saat Foo selesai, closure tidak terdealokasi seperti halnya variabel biasa, sampai object action di garbage collected oleh GC.

    Hal ini dapat terlihat jelas dengan menilik code di bawah:

       1: static void CreateClosure(ref Action someAction)
       2: {
       3:     int x = 5;
       4:     someAction = () => Console.WriteLine(x);
       5: } // normally, local variable x goes out of scope here
       6:  
       7: static void Main(string[] args)
       8: {
       9:     Action someAction = null;
      10:     CreateClosure(ref someAction);
      11:     someAction();   // print 5, which is x value
      12: }

    Karena variabel x adalah closure, nilainya terselamatkan. Kalau Anda pernah melakukan OOP di JavaScript, teknik yang digunakan untuk mensimulasikan class field adalah dengan closure, karena tidak terdapat sintaks untuk mendeklarasikan class di JavaScript.

    What in ReSharper’s Suggestion?

    Setelah Anda mengetahui closure, mari kita membahas kenapa ReSharper memberi warning apabila terdapat modified closure. What wrong with modified closure? Perhatikan code di bawah:

       1: var actions = new List<Action>();
       2: for (int i = 0; i < 10; i++)
       3: {
       4:     actions.Add(() => Console.WriteLine(i));
       5:     actionsIdea();
       6: }

    Seperti biasa, teman lama kita akan berteriak karena terdapat sebuah closure yaitu i, dan closure tersebut dimodifikasi (pada saat akhir loop, i++). Kalau Anda menjalankan program ini, maka hasilnya adalah pencetakan angka dari 0 hingga 9. Dan apabila Anda mengikuti suggest-nya ReSharper, maka code akan berubah menjadi:

       1: var actions = new List<Action>();
       2: for (int i = 0; i < 10; i++)
       3: {
       4:     int buffer = i;
       5:     actions.Add(() => Console.WriteLine(buffer));
       6:     actionsIdea();
       7: }

    Sekali lagi, ReSharper memberi sebuah variabel baru buffer sehingga closure yang tadinya adalah i, sekarang menjadi buffer. Perbedaannya, buffer tidak pernah berubah, sehingga The so called ‘modified closure’ tidak terjadi. Sekarang, memangnya kenapa closure tidak boleh diubah? Mengingat sekali lagi, dua code diatas hasilnya sama, dan akan selalu sama bahkan dengan looping ke sekian ratus juta pun. Nah, perbedaannya adalah, apabila pemanggilan action bukan saat itu juga, tapi suatu saat di masa depan (deferred call).

    Sekarang coba tebak keluaran dari code dengan tanpa buffer yang kita tambah:

       1: var actions = new List<Action>();
       2: for (int i = 0; i < 10; i++)
       3:     actions.Add(() => Console.WriteLine(i));
       4:  
       5: foreach (var action in actions)
       6:     action();

    Pemanggilan action tidak langsung, tapi dipanggil saat actions telah terisi semua. Karena nilai i terakhir adalah 9, maka tampilan dari program adalah angka 9 dengan kemunculan 10 kali, which is, not as we expected. Kalau Anda melakukan deferred call untuk solusi dengan buffer sesuai anjuran ReSharper, maka tampilan program adalah angka dari 0 hingga 9, seperti dengan harapan kita. Modified closure memang terkadang adalah bug yang tidak terlihat, terlebih apabila pemakaiannya adalah multithreading. Beruntung teman kita yang baik bernama ReSharper selalu berteriak apabila terjadi potensial closure bug, sehingga kita bisa dengan bebas menggunakan closure dengan nyaman.

    Share this post: | | | |
  • ReSharper Warning: sometimes useful sometime useless

    Pengenalan ReSharper  Inspection

    ReSharper adalah sebuah plugin bagus yang membuat pekerjaan utama Anda -- apalagi kalau bukan coding?-- menjadi jauh lebih mudah. Bagi yang ingin mencoba versi trialnya, feel free to peek the site. Salah satu fitur ReSharper adalah kemampuannya untuk memberikan warning, serta penawarannya untuk mengubah source secara otomatis, sehingga code menjadi lebih bug-free. Salah satu contoh adalah seperti ini:

       1: string someString = null;
       2: string otherString = someString.Substring(0, 3);

    Pada saat pemanggilan method Substring pada someString, kemungkinan terpanggilnya musuh besar semua programmer .NET dan Java (NullReferenceException) adalah bergantung pada apakah nilai someString adalah null atau bukan. Menilik dari simple code di atas, tentu saja someString selalu null, tapi pikirkan apabila antara line 1 dan 2 terdapat suatu proses di mana pada proses itu someString bisa mendapatkan nilai atau masih null, atau pikirkan misalkan someString itu berasal dari parameter. Tentu saja, bahkan para pemula akan melakukan pengecekan pada someString sebelum memanggil method Substring. Bagi penikmat ReSharper, otomatis tools ini akan memberikan peringatan ‘Possible System.NullReferenceException’, dan menawarkan diri untuk merubah source tadi menjadi memiliki pengecekan.

    Selain melakukan inspeksi pada kemungkinan terjadinya NullReferenceException, ReSharper melakukan banyak sekali inspeksi yang menjadikannya asisten Anda yang brilian saat coding, salah satu yang paling bagus adalah penawaran untuk menggunakan null coalescing operator (??). Terus terang, saya mengenal null coalescing operator karena menggunakan ReSharper. Dengan operator ini, code di bawah

       1: if ( someObject != null )
       2:     return someObject;
       3: return otherObject;

    dapat di-rewrite menjadi bentuk yang lebih ramping:

    return someObject ?? otherObject;

    Lebih jauh dari itu ReSharper akan memberi warning  apabila Anda salah menggunakan operator ?? seperti pada code di bawah:

    return new object() ?? otherObject;

    Code di atas selalu mengembalikan new object sehingga otherObject tidak pernah di return. Ingat, operator ?? dibaca dari kiri ke kanan, dan di sebelah kiri ?? tidak pernah null pada code di atas. Nilai otherObject tidak pernah tersentuh program (unreachable code). ReSharper akan memberi warning untuk setiap unreachable code dan tentu saja, menawarkan diri untuk merubahnya apabila Anda mengizinkannya.

    Bahkan… Terkadang ReSharper-pun Sok Tahu

    ReSharper memang teman yang baik, tapi untuk kasus tertentu, ReSharper berubah menjadi menyebalkan dengan selalu memberi warning-warning yang seharusnya tidak diberikan. Beruntung, Anda dapat mendisable ReSharper inspection untuk beberapa file saja, jadi untuk file yang di dalamnya terdapat hal yang Anda anggap ReSharper bodoh, cukup disable ReSharper inspection pada current editing file dengan menekan Ctrl-B.

    Lho.. memang bidang apa yang ReSharper tidak disarankan untuk melakukan inspeksi? Bidang tersebut adalah Platform Invoke. Kalau Anda biasa melakukan PInvoke, maka salah satu best practice-nya adalah membuat sebuah static class bernama NativeMethods yang di dalamnya terdapat deklarasi-deklarasi method yang Anda import. Nah, biasanya nama method dan nama enumeration adalah persis seperti versi native-nya, dimana nama-nama tersebut sangat tidak .NET friendly, seperti FFTW_FORWARD_PLAN atau glCreateMatrices dan sebagainya. Sebagai teman yang baik, tentu saja ReSharper berteriak-teriak apabila melihat nama-nama ekstrim seperti ini.

    Oke, kalau cuma sekedar memberi warning sih tidak apa-apa, tapi bagaimana kalau ReSharper sampai memberi error padahal Anda yakin bahwa source code yang telah Anda buat dengan hati-hati bisa di-compile? Kalau sudah begini sih tidak bisa ditolerir, cara yang terbaik ya disable ReSharper untuk file tersebut, tekan Ctrl-B :)

    Kalau Anda ingin tahu contohnya, contoh yang paling gampang adalah pemanggilan fungsi klasik printf (yeeah…! printf from stdio.h) dari managed code. Fungsi printf termasuk dalam standard library C yang tersimpan di msvcrt.dll (Microsoft Visual C Runtime). Kalau Anda pernah belajar C, Anda pasti tahu bahwa printf itu salah satu parameternya adalah varargs seperti terlihat di stdio.h

    _Check_return_opt_ _CRTIMP int __cdecl printf(_In_z_ _Printf_format_string_ const char * _Format, ...);

    dari prototipe printf terlihat bahwa parameter pertama bertipe const char * sebagai format string dan parameter keduanya adalah … (tiga buah titik atau vararg) sehingga printf dapat anda panggil dengan jumlah parameter berapapun. sesuai dengan prototipe di atas, padanan c# nya adalah:

    [dllimport("msvcrt")]
    private static extern void printf(string format, __arglist);

    yang menarik adalah penggunaan __arglist sebagai pengganti … di c. kalau anda menggunakan resharper, teman anda yang satu ini tidak mengenali __arglist sebagai keyword sehingga dia menganggap code anda error.  kalau anda ingin mengetahui bagaimana cara memanggil printf yang barusan kita deklarasikan, caranya adalah:

    printf("halo\n", __arglist());                          // halo
    printf("halo %s\n", __arglist("dunia"));                // halo dunia
    printf("halo %s %d %f\n", __arglist("dunia", 1, 2.5));  // halo dunia 1 2.5

    What Next?

    berikutnya, saya akan memberi penjelasan tentang salah satu warning aneh yang biasa diteriakkan oleh resharper apabila anda biasa menggunakan lambda expression atau anonymous method, yaitu ‘access to modified closure’. apakah dalam hal ini resharper sok tahu lagi atau tidak? until next session then.

    Share this post: | | | |
  • Fun with Functional - Currying di C#

    Apa itu Currying?


    Currying adalah sebuah teknik yang sangat lazim dipakai di bahasa pemrograman fungsional, seperti Haskell, LISP, OCaml, JavaScript, dan tentu saja, F#. Bagi yang belum memahami apa itu currying, lihatlah contoh program F# di bawah: 

    1. let add x y = x + y  
    2. printf "%d" (add 5 2) // should print 7

    Code di atas adalah deklarasi sebuah fungsi add. Tipe dari add adalah int -> int -> int. Bagi anda yang terbiasa memakai delegate System.Func maupun System.Action, tipe data add ini apabila ditulis dengan sintaksis C# menggunakan Func adalah Func<int, int, int>. Kedua buah int pertama adalah tipe parameter, dan int yang terakhir adalah function’s return type.

    Nah, C# adalah sebuah bahasa yang belum full functional programming seperti halnya F#, sehingga di F# kita dapat menuliskan bentuk seperti ini:

    1. let addFiveWith = add 5  
    2. printf "%d" (addFiveWith 2) // should print 7

    Tipe dari addFiveWith adalah int -> int, yaitu fungsi add yang tadinya memiliki dua buah parameter, menjadi tinggal satu, karena parameter pertama diganti dengan lima. Inilah yang disebut dengan currying, mendapatkan fungsi baru (addFiveWith) dengan memberi sebagian parameter pada fungsi awal (add).

    Salah satu cara pandang tentang apa itu currying adalah dengan memahami notasi dari tipe fungsi add. Ingat, notasi dari tipe add adalah:

    int -> int -> int

    Secara C#, hal tersebut ditulis sebagai:

    Func<int, int, int>

    Anda harus memahami bahwa keduanya walaupun sepintas sama, sebenarnya berbeda.  Pada C#, int yang terakhir selalu return type, artinya terdapat perbedaan yang jelas mana yang parameter dan mana yang return type. Nah, tipe add di dalam F# berbeda, tidak ada perbedaan yang jelas yang mana parameter dan mana yang return type, sehingga anda bebas menginterpretasikan  tipe add sebagai:

    (int -> int) -> (int) // fungsi dengan dua buah parameter int dan return type sebuah int

    (int) -> (int -> int) // fungsi dengan sebuah parameter int dan return type sebuah fungsi berparameter int dan return type int

    Pada saat anda memanggil add 5 2, maka return type adalah penjumlahan dari keduanya yaitu 7.
    Pada saat anda memanggil
    add 5, maka return type adalah sebuah fungsi yang berparameter int dan return type int yang bernilai parameter pertamanya ditambahkan dengan 5. Karena perbedaan inilah, maka lambda expression C# dan F# itu berbeda, seperti yang akan kita lihat nanti bagaimana cara mengonversinya.

    Apabila anda heran dari bahasa mana kata currying berasal, maka currying itu adalah nama seorang matematikawan Haskell Curry. Ya, bahasa Haskell yang kesohor adalah juga berasal dari namanya. Yang berjasa dalam menemukan currying sebenarnya bukan cuma Haskell Curry, tapi juga seorang bernama Moses Schönfinkel. Beberapa orang ada yang menyarankan untuk mengganti currying dengan Schönfinkelisation. Tanpa merendahkan Mas Moses, kita harus bersyukur bahwa nama yang terakhir tidak dipakai, mengingat kemungkinan terjadinya kesalahan ketik yang besar.


    Salah Satu Contoh, Currying Could be Useful

    Mari kita kembali ke masa kuliah dan mengambil analisis numerik, menghitung turunan secara numerik. Masih ingat apa itu turunan? Disebut sebagai perubahan sesaat dari sebuah fungsi, jadi kita bisa mendapatkan kemiringan (gradien) fungsi pada titik tertentu, dan bukan pada interval tertentu apabila turunan tidak digunakan. Pertama kali ditemukan oleh Sir Isaac Newton pada saat kuliah di Cambridge untuk memodelkan 3 hukum Newton. Saat itu Pak Ishak (sapaan akrab Newton) ingin merumuskan kecepatan sesaat maupun percepatan sesaat.

    Definisi asal turunan adalah:

     Definisi diferensial

    Terlihat jelas dari persamaan di atas bahwa kemiringan sesaat dapat ditemukan dengan membuat Δx sekecil mungkin, karena apabila Δx besar, maka persamaan di atas adalah definisi untuk mendapatkan kemiringan rata-rata, dan bukan sesaat. Untuk mengaproksimasi persamaan tersebut secara numerik, biasanya digunakan rumus:  

    Definisi diferensial numerik 

    Sip, mari kita tulis dalam bentuk F#:

    1. let derivative f x =
    2.     let dx = sqrt epsilon_float
    3.     (f(x + dx) - f(x - dx)) / (2.0 * dx)

    Agar persamaan di atas benar mengaproksimasi turunan, maka dx harus dibuat sekecil mungkin. Berhati-hati dengan bilangan floating point karena anda tidak dapat begitu saja memberikan sembarang nilai kecil. Beberapa nilai kecil floating point, apabila anda tambahkan dengan satu, hasilnya adalah satu (yang seharusnya satu koma sekian). Cara untuk mendapatkan bilangan kecil yang mana apabila ditambahkan dengan satu hasilnya bukan satu adalah seperti yang terlihat di atas. Konstanta epsilon_float didefinisikan di FSharp.PowerPack.dll. Tentu saja, anda bebas untuk mengganti nilai ini dengan 0.00005 atau terserah anda.

    Sebelum kita analisa tipe dari derivative, mari kita lihat bagaimana cara menggunakannya:

    1. let result = derivative (fun x -> x ** 2.0) 3.0
    2. printfn "%f" result // should print 6.0

    Tujuan dari fungsi tersebut adalah untuk menghitung turunan dari fungsi x kuadrat pada saat x bernilai 3. Seperti kita tahu, fungsi x^2 turunannya adalah 2.x, dan pada saat x bernilai 3, maka nilainya adalah 2 . 3 = 6. Parameter pertama pada pemanggilan derivative adalah sintaksis lambda expression di F#, yang apabila di C# kira-kira x => x ** 2.0  (tidak ada operator ** di C#, cuma pengandaian).

    Tipe dari derivative adalah:

    (float -> float) -> float -> float

    Sebelum menganalisa lebih jauh, anda harus ingat bahwa float di F# berarti System.Double. Parameter pertama adalah sebuah fungsi dengan sebuah parameter float dan return type float. Pada contoh pemanggilan di atas, parameter ini bernilai  (fun x -> x ** 2.0), diikuti oleh parameter kedua adalah float, anda suplai dengan nilai 3.0, yaitu anda ingin menghitung turunan dari x^2 di x = 3. Tentu saja, float yang terakhir adalah return type dari fungsi derivative, bernilai 6 apabila dua parameter adalah sesuai dengan yang di atas.

    Salah satu kelebihan F# adalah type inference is ubiquitous. F# compiler dan interpreter dapat mengenali tipe data di atas tanpa anda menulis secara eksplisit tipe dari f dan x. Lebih ekstrim lagi, apabila anda memanggil printfn "%d" result (bukan "%f" untuk menampilkan float) , anda akan mendapatkan compile-time-error dan bukan runtime-error. Artinya compiler dan interpreter F# mengecek sampai ke parameter format string, sesuatu yang biasanya dilakukan pada saat runtime.

    Nah, masih ingat dengan currying? Sepintas fungsi derivative cuma menghasilkan sebuah nilai float. Dengan menggunakan currying, anda bisa mendapatkan fungsi turunan seperti di bawah:

    1. let f x = x ** 3.0 + 3.0 * x
    2. let f' = derivative f // f' adalah turunan dari x^3 + 3x -> 3x^2 + 3
    3. printfn "%f" (f' 2.0) // 3.2.2 + 3 = 15

    Simple eh? Anda baru saja melihat salah kehebatan dari currying, kalau pada code di atas pemanggilannya adalah derivative f 2.0, anda akan mendapat sebuah nilai 15.0, namun kalau anda memanggilnya derivative f, anda akan mendapatkan sebuah fungsi turunan dari f. Jadi dengan currying, anda hanya membuat sebuah fungsi, return type bisa banyak, tergantung bagaimana parameternya. Biar lebih seru, mari kita membuat sebuah fungsi untuk menampilkan grafik dari fungsi dengan memanfaatkan komponen XYGraph yang dapat anda cari di internet.

    1. let Plot (from:float) (step:float) (final:float) (func:float -> float) =
    2.     let form = new Form(Visible = true, TopMost = true)
    3.     form.KeyPress.AddHandler (fun _ _ -> form.Close())
    4.     let graph = new XYGraph(Dock = DockStyle.Fill)
    5.     graph.XtraTitle <- String.Empty
    6.     graph.XtraLabelX <- String.Empty
    7.     graph.XtraLabelY <- String.Empty
    8.     
    9.     form.Controls.Add(graph)
    10.     let g = graph.AddGraph(String.Empty, Drawing2D.DashStyle.Solid, Color.Red, 1, false)
    11.     for x in from .. step .. final do
    12.         graph.AddValue(g, float32 x, float32 (func x))
    13.     graph.DrawAll()
    14.  
    15. let f x = x ** 3.0 + 3.0 * x
    16. let f' = derivative f // f' adalah turunan dari x^3 + 3x -> 3x^2 + 3
    17. printfn "%f" (f' 2.0) // 3.2.2 + 3 = 15
    18.  
    19. Plot -3.0 0.05 3.0 f
    20. Plot -3.0 0.05 3.0 f'

     

    Berikut adalah tampilan dari program di atas:

     

    Tampilan dua fungsi 

    Gambar kiri adalah fungsi f(x) =  (x^3 + 3x) dan gambar kanan adalah fungsi f’(x) =  (3x^2 + 3).

     

    Enough Talking About F#, I’m a C# Folks!


    Ternyata masih tidak ingin beralih ke F# rupanya. Oke, kalau begitu mari kita bahas bagaimana currying juga bisa dilakukan di C#. Pertama, perhatikan sebuah fungsi sederhana berikut:

    1. public static int Add(int number1, int number2)
    2. {
    3.     return number1 + number2;
    4. }
        

    Nah, untuk mendapatkan fungsi AddFiveWith seperti yang telah kita lakukan di awal, kira-kira code-nya adalah seperti ini:

    1. Func<int, int, int> addDelegate = Add;
    2.  
    3. var addFiveWith = addDelegate.Curry(5);
    4. Console.WriteLine(addFiveWith(7)); // akan mencetak 12

    Sekarang, mari kita analisa bersama, bagaimana kira-kira mengimplementasi fungsi Curry.

    Input dari fungsi ini adalah sebuah fungsi dengan jumlah parameter dua, disusul dengan sebuah parameter yang akan menggantikan parameter pertama dengan sebuah nilai dari user (5 untuk kasus di atas). Tipe data kembalian adalah sebuah fungsi dengan sebuah parameter, dan tipe kembalian dari fungsi ini adalah sama dengan fungsi asal. Untuk lebih jelasnya perhatikan code di bawah:

    1. public static TipeFungsiKembalian Curry<TypeList>(this TipeFungsiAsal fungsi, TipeParameter1FungsiAsal param1)
    2. {
    3.     // bla bla bla
    4. }

    Untuk mendapatkan TypeList, pertama mari kita menganalisa TipeFungsiAsal. TipeFungsiAsal adalah fungsi dengan parameter dua, masing-masing parameter boleh bertipe berbeda, dan return type dari fungsi ini boleh berbeda dari kedua parameternya. Maka kita dapat menulis TipeFungsiAsal sebagai:

    Func<T1, T2, TResult>

    Dengan mudahnya, tipe TipeParameter1FungsiAsal adalah T1.

    Terakhir TipeFungsiKembalian adalah sebuah fungsi dengan sebuah parameter yang mana tipe dari parameter ini adalah sama dengan tipe dari parameter ke dua dari fungsi asal, dan return type adalah sama dengan return type dari fungsi asal. Maka, tipenya adalah:

    Func<T2, TResult>

    Berarti, TypeList dapat kita tulis sebagai, T1, T2, TResult sehingga fungsi Curry signaturenya adalah: 

    1. public static Func<T2, TResult> Curry<T1, T2, TResult>(this Func<T1, T2, TResult> func, T1 param1)
    2. {
    3.     // bla bla bla
    4. }

    Terakhir, mari kita ganti “bla bla bla” dengan sesuatu yang dimengerti oleh C# compiler. Tipe kembalian adalah Func<T2, TResult>, yang diubah ke lambda expression menjadi:

    p2 => func(param1, p2);

    Harus diingat bahwa tipe kembalian dari func adalah TResult, sehingga lambda expression di atas bertipe Func<T2, TResult>. Dengan type inference, C# compiler cukup pintar untuk mengetahui bahwa tipe p2 adalah T2. Sekarang, fungsi Curry dapat kita implementasi dalam versi lengkap:  

    1. public static Func<T2, TResult> Curry<T1, T2, TResult>(this Func<T1, T2, TResult> func, T1 param1)
    2. {
    3.     return p2 => func(param1, p2);
    4. }

    Sederhana bukan? Mari kita lihat salah satu contoh penggunaan:

    1. public static double Derivative(Func<double, double> f, double x)
    2. {
    3.     double dx = 2.220446049e-8;
    4.     return (f(x + dx) - f(x - dx)) / (2*dx);
    5. }
    6.  
    7. Func<Func<double, double>, double, double> diff = Derivative;
    8. Func<double, double> xSquare = x => Math.Pow(x, 2);
    9.  
    10. var twoX = diff.Curry(xSquare); // mendapatkan turunan dari x kuadrat, yaitu 2 * x
    11. Console.WriteLine(twoX(2)); // 4
    12. Console.WriteLine(twoX(3)); // 6
    13. Console.WriteLine(twoX(4)); // 8

    Contoh penggunaan lain yang lebih sederhana:

    1. public static string NamaDanUsia(string nama, int usia)
    2. {
    3.     return string.Format("Halo, nama saya {0} berusia {1}", nama, usia);
    4. }
    5.  
    6. Func<string, int, string> namaUsiaDelegate = NamaDanUsia;
    7. var budiDenganUsia = namaUsiaDelegate.Curry("Budi");
    8.  
    9. Console.WriteLine(budiDenganUsia(3));  // Halo, nama saya Budi berusia 3
    10. Console.WriteLine(budiDenganUsia(10)); // Halo, nama saya Budi berusia 10
    11. Console.WriteLine(budiDenganUsia(20)); // Halo, nama saya Budi berusia 20

     

    Tentu saja, fungsi Curry yang kita buat hanya berlaku untuk fungsi dengan return type non-void (untuk yang void silakan implementasikan sendiri, dengan memanfaatkan System.Action), dan dengan dua buah parameter. Untuk tiga parameter dan selebihnya, masing-masing dibuat Curry-nya:

    1. public static Func<T2, T3, TResult> Curry<T1, T2, T3, TResult>(this Func<T1, T2, T3, TResult> func, T1 param1)
    2. {
    3.     return (p2, p3) => func(param1, p2, p3);
    4. }
    5.  
    6. Func<T2, T3, T4, TResult> Curry<T1, T2, T3, T4, TResult>(this Func<T1, T2, T3, T4, TResult> func, T1 param1)
    7. {
    8.     return (p2, p3, p4) => func(param1, p2, p3, p4);
    9. }
    10.  
    11. public static int AddNumbers(int n1, int n2, int n3, int n4)
    12. {
    13.     return n1 + n2 + n3 + n4;
    14. }
    15.  
    16. Func<int, int, int, int, int> addNumbersDelegate = AddNumbers;
    17.  
    18. var addFiveWith = addNumbersDelegate.Curry(5);
    19. var addFiveAndTwoWith = addNumbersDelegate.Curry(5).Curry(2);
    20. var ten = addNumbersDelegate.Curry(1).Curry(2).Curry(3)(4); // sintaks bodoh tapi bergaya pengganti addNumbersDelegate(1, 2, 3, 4)
    21. addFiveWith(3, 2, 1); // 11
    22. addFiveAndTwoWith(1, 2); // 10

     

    Setelah anda paham garis besarnya, silakan buat function overload-nya agar pemanggilan Curry tidak dilakukan berkali-kali seperti pada contoh di atas, contoh:

    1. // Curry dua parameter sekaligus
    2. Func<T2, T3, T4, TResult> Curry<T1, T2, T3, T4, TResult>(this Func<T1, T2, T3, T4, TResult> func, T1 param1, T2 param2)
    3. {
    4.     return (p2, p3, p4) => func(param1, param2, p3, p4);
    5. }

    Kalau anda mengkikuti sampai sejauh ini maka selamat! Anda telah membuat semacam framework agar C# dapat melakukan currying! 

     

    Konversi dari C# Func ke F# FastFunc:

    let Plot (from:float) (step:float) (final:float) (func:float -> float) = 


    Satu lagi, misal anda ingin menggunakan fungsi
    Plot di atas dalam program C#, maka kita akan menulis seperti ini:

    Plotter.Plot(0.0, 1.0, 10.0, x => Math.Pow(x, 2));

    Anda akan mendapati compile time error karena lambda expression dari C# itu adalah murni Delegate, sedangkan lambda expression di F# adalah bertipe FastFunc. Untuk melakukan konversi, gunakan fungsi ToFastFunc dari class FuncConvert sehingga perintah menjadi:

    Plotter.Plot(0.0, 1.0, 10.0, FuncConvert.ToFastFunc(new Converter<double, double>(x => Math.Pow(x, 2))));

    Atau biar lebih seamless, anda dapat membuat extension method seperti ini:

    1. public static FastFunc<T, TResult> ToFastFunc<T, TResult>(this Func<T, TResult> func)
    2. {
    3.     return FuncConvert.ToFastFunc(new Converter<T, TResult>(func));
    4. }
    5.  
    6. Func<double,double> f = x => Math.Pow(x, 2);
    7. Plotter.Plot(0.0, 1.0, 10.0, f.ToFastFunc());

    Pretty simple eh?

    Share this post: | | | |
  • Konsep Bilangan Berbasis

    Sering sekali saya bertemu dengan mahasiswa CompSci yang tidak mengerti bilangan berbasis. Tidak mengerti bukan berarti nilai mata kuliah  yang ada hubungannya dengan bilangan berbasis menjadi anjlok (seperti Organisasi Komputer misalnya), beberapa dari mereka bahkan ada yang cumm laude. Pemahaman mereka mengenai bilangan berbasis cuma sekadar hafalan rumus, sangat efektif apabila digunakan untuk sekedar mengerjakan soal ujian. Yup, saya mengetahui bahwa budaya ‘hafalan rumus’ bukan cuma terjadi untuk bilangan berbasis, tapi untuk mata kuliah lainnya, seperti kalkulus, probabilitas, dan sebagainya. Kealpaan pemahaman mengenai kalkulus untuk mahasiswa CompSci tentu saja sangat bisa ditolerir, karena jarang sekali ilmu tersebut diterapkan di dunia IT (jarang bukan berarti tidak sama sekali). Nah, bagaimana dengan kealpaan pemahaman mengenai bilangan berbasis? John Mauchly merancang komputer elektronik pertama dengan memanfaatkan konsep bilangan biner. File editor sangat umum menggunakan heksa desimal untuk mempermudah pengeditan. Intinya, bilangan berbasis itu teman kita, jangan sampai kita tidak mengerti apa itu bilangan berbasis.

    Let’s define ‘mengerti’

    Saya masih ingat pada saat masih SD dan pertama kali belajar perkalian. Yang diajarkan pertama kali adalah perkalian satu, perkalian dua, tiga dan sebagainya. Saya menghafal perkalian-perkalian itu sampai larut malam, karena takut kalau keesokan harinya disuruh maju ke depan sambil melafazkan perkalian tersebut. Kalau nggak hafal, tentu saja malu Men! Bagi saya saat itu perkalian itu cuma sekedar hafalan, hafalan perkalian dua, hafalan perkalian tiga dan sebagainya. Pandangan saya berubah suatu ketika saya berkunjung ke rumah tetangga dan kepala keluarga (bapaknya maksudnya) dari tetangga saya itu mengatakan sesuatu yang mengubah hidup saya selamanya (halah). Kata-kata itu adalah, ‘Empat kali dua itu, artinya adalah empatnya ada dua kali, jadi empat ditambah empat, hasilnya tentu saja delapan’. Saya waktu itu yang selalu menganggap bahwa perkalian itu adalah hafalan, tanpa ada makna tertentu dibaliknya, dibuat tercengang oleh kata-kata yang mungkin anak TK aja udah tau! Akhirnya saya sadar, bahwa dalam belajar matematika, rumus itu nggak penting! Yang penting itu konsep!

     
    Nah sekarang, orang yang ngerti perkalian itu yang mana sih? Misal ada orang yang hafal perkalian plus skill melakukan perhitungan dengan cepat, tapi tidak tahu bahwa lima dikali empat itu artinya adalah ‘limanya ada empat kali’ dibandingkan sama orang yang nggak hafal perkalian, tapi tahu arti dari lima dikali empat, orang yang mana yang dapat dianggap mengerti perkalian? Keduanya tentu saja parah, tapi entah kenapa, saya lebih cenderung memilih orang yang kedua (yang mengerti makna perkalian walaupun tidak hafal perkalian).

     

    Dewasa ini, kebanyakan dari orang yang belajar sains berada di dalam kuadran penghafal. Coba, tanya sama mahasiswa yang kalkulusnya dapat A, limit itu apa sih? Pasti nggak tahu. Kalkulus itu kan ilmu tentang limit, diferensial dan integral itu ujung-ujungnya limit, lha kalau limit nggak tau kok bisa dapet A J

     

    Di kampus saya (Binus), bahkan ada dosen senior yang nggak ngerti konsep. Saat itu saya sedang mengambil mata kuliah Probabilitas dan Statistika. Nah, beliau memberi soal yang menurut saya salah soal. Soalnya adalah mengenai sebaran binomial. Saya tahu persis bagaimana rumus sebaran binomial itu diturunkan, sehingga sebaran binomial itu cuma valid kalau peluang-peluangnya saling lepas (kalo bingung nggak usah dipikirin J ). Pada saat kelas selesai saya menghampiri beliau dan mengatakan bahwa soal yang tadi itu absurd. Beliau belum mau ngaku kalau soal itu salah. Waduh, udah lama ngajar kok gini aja nggak tau!? Minggu depannya saat ketemu lagi, akhirnya beliau mengakui kesalahannya. Salut, dosen senior yang berani mengaku salah, suatu saat saya baru tahu bahwa beliau adalah salah satu pembesar Badan Pusat Statistika.

    Belajar bilangan berbasis itu belajar apa sih?

    Tanpa disadari sebenarnya kita sudah diajarkan bilangan berbasis sejak TK. Kita dikenalkan kepada bilangan desimal, bilangan berbasis 10. Kita diajarkan cara menghitung dari 1 sampai 1000. Anak TK yang bisa menghitung dari 1 sampai 1000, kemungkinan juga bisa melanjutkan sampai 2000 (kalau nggak capek tentunya), karena sudah mengerti bagaimana pola dari bilangan desimal. Bagaimana 10, kemudian kenapa menjadi 11, kemudian 12, dari 399 kok bisa jadi 400, mereka sudah mengetahui pola penambahannya. Tidak kalah pentingnya, mereka juga sudah menyadari bahwa digit paling kanan itu bernilai satuan, diikuti dengan digit di kirinya yang bernilai puluhan dan sebagainya. Sampai di sini, dapat dikatakan bahwa anak TK tersebut sudah mengerti bilangan desimal.

     

    Orang yang sudah memahami desimal, belum tentu menyadari bahwa ada sistem bilangan berbasis selain sepuluh. Saat saya kelas 5 SD, ada sebuah game Nintendo yang judulnya DJ Boy, game tentang perkelahian sambil memakai sepatu roda. Pada game tersebut ditemukan adanya Easter egg. Dengan menekan suatu kombinasi tombol yang rumit (mirip-mirip atas, atas, bawah, a, b, a, b), akan menyebabkan nyawanya menjadi tidak terbatas. Kenapa tidak terbatas? Karena pada indikator jumlah nyawanya, terpampang sebuah angka yang aneh, yaitu angka 3C, dan setelah puluhan kali mati tetap belum game over, maka dapat disimpulkan nyawanya tidak terbatas! Benarkah tidak terbatas? Untuk mengujinya, saya sengaja masuk ke jurang (bukan saya yang masuk ke jurang, tapi karakter di dalam game tersebut) dan melihat indikator jumlah nyawanya. Sebelum masuk adalah 3C. Masuk jurang, mati sehingga nyawanya berkurang menjadi 3B. 3B? WTF!? Mirip-mirip ukuran pakaian dalam! Pola pengurangan berikutnya adalah:

     

    3A, 39, 38, 37,36, ..., 32, 31, 30, 2F, 2E, 2D, 2C, 2B, 2A, 29, 28, ..., 21, 20, 1F, 1E, 1D, ..., 12, 11, 10, F, E, D, C, B, A, 9, 8, ..., 3, 2, 1

     

    Bagaimana saat nyawanya 1 dan masuk ke jurang? Nyawanya habis dan game over! Jadi anggapan bahwa nyawanya tidak terbatas itu salah. Beberapa tahun kemudian, saya baru tahu bahwa pola-pola kriptik di atas itu ternyata adalah bilangan heksa desimal, bilangan berbasis 16. Orang yang memahami kenapa pola pengurangannya seperti itu, dan menyadari bahwa dalam heksa desimal itu digit paling kanannya bernilai satuan, diikuti digit di sebelah kirinya bernilai 16-an, di sebelah kirinya lagi bernilai 256-an, adalah orang yang mengerti bilangan heksa desimal.

     

    Orang yang mengerti bilangan berbasis, berarti adalah mengetahui pola penambahan untuk sistem bilangan berbasis berapapun.

     

    Orang yang mengerti bilangan berbasis, mengerti bahwa pola penambahan bilangan berbasis lima adalah:

     

    0, 1, 2, 3, 4, 10, 11, 12, 13, 14, 20, 21, 22, 23, 24, 30, 31, 32, 33, 34, 40, 41, 42, 43, 44, 100, 101, dan seterusnya...

     

    Orang yang mengerti bilangan berbasis, mengerti bahwa pola penambahan bilangan berbasis 12 adalah:

     

    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 1A, 1B, 20, 21, ..., 98, 99, 9A, 9B, A0, A1, A2, ..., A9, AA, AB, B0, B1, B2, ..., B9, BA, BB, 100, 101, dan seterusnya...

     

    Orang yang mengerti bilangan berbasis, mengerti pola penambahan untuk bilangan berbasis 8, 17, 20, 100, 1 milyar, 1 zillion, dan sebagainya...

     

    Orang yang tidak mengerti pola-pola di atas, terlepas dari berapa nilai mata kuliah Anda untuk pelajaran yang ada hubungannya sama basis, berarti ilmu Anda cuma hafalan :p

    Apa yang biasa diajarkan dosen pada kelas-kelas CompSci?

    Hal pertama yang diajarkan oleh dosen pada mahasiswa adalah bilangan berbasis itu ada banyak, contohnya adalah:

    • ·         Bilangan biner (berbasis dua)
    • ·         Bilangan oktal (berbasis delapan)
    • ·         Bilangan desimal (berbasis sepuluh)
    • ·         Bilangan heksa desimal (berbasis enam belas)

    Tentu saja, hal di atas sangat benar, tapi sekaligus menipu. Biasanya dosen tidak menekankan bahwa ada bilangan berbasis lain selain di atas, sehingga mahasiswa biasanya beranggapan bahwa bilangan berbasis itu ya cuma biner, oktal, desimal, atau heksa desimal. Kenyataannya, semua bilangan cacah yang lebih besar dari 1 itu ada bilangan basisnya, jadi ada bilangan berbasis tiga, empat, lima, seratus, satu miliar, satu caturta, dan sebagainya.

    Hal berikutnya yang diajarkan adalah bagaimana melakukan konversi dari bilangan berbasis selain sepuluh ke bilangan berbasis 10, sebagai contoh:

    ·         100101 (biner) = ... (desimal)

    ·         10263 (oktal) = ... (desimal)

    ·         2FB (heksa) = ... (desimal)

     

    Terkait dengan soal di atas, dosen langsung memberi rumus yang bersesuaian. Sebagai contoh adalah rumus untuk mengubah bilangan berbasis 8 ke 10:

     

    10263 (oktal)=1∙8^4+0∙8^3+2∙8^2+6∙8^1+3∙8^0 (desimal)

     

    Sekali lagi, tentu saja tidak ada yang salah dengan formula di atas, yang salah adalah dosen tidak memberi tahu dari mana asal-muasal rumus tersebut, dan tentu saja, mahasiswa yang telah terbiasa dengan budaya menghafal rumus dengan mudahnya ‘memahami’ rumus di atas.

     

    Berikutnya, dosen memberi bentuk soal lain yaitu bagaimana mengubah bilangan desimal menjadi bilangan berbasis lain dengan menggunakan metode pembagian. Lebih lanjut, bahkan dosen memberi cara paling mudah untuk melakukan konversi biner–oktal–heksa desimal dengan melakukan penggabungan pada beberapa digitnya. Seperti biasa, teknik penggabungan beberapa digit dalam rangka pemudahan pengonversian tidak diberi tahu untuk pasangan bilangan berbasis lainnya (bisa juga digunakan untuk pasangan bilangan berbasis 3-9-27, 5-25, dan sebagainya).

    Apa yang salah dengan metode di atas?

    Sepintas memang tidak ada yang salah dengan metode di atas, apalagi dengan fakta bahwa sebagian besar mahasiswa dapat melewati ujian dengan baik. Ingat tujuan utama mengetahui bilangan berbasis bukan cuma melakukan konversi dari bilangan berbasis anu ke bilangan berbasis ono, yang paling penting adalah mengerti arti dari bilangan berbasis itu sendiri. Saya masih ingat bahwa pada saat saya masih kelas dua SMP terdapat materi bilangan berbasis pada pelajaran matematika dan diberi tahu arti dari bilangan berbasis oleh kakak saya (lagi-lagi, guru saya hanya memberi rumus). Saat itu saya merasakan keanggunan dari matematika, betapa hebatnya matematikawan India ditambah ditemukannya angka nol oleh orang Arab sehingga terbentuk sistem bilangan paling bagus yang pernah ada. Bayangkan kalau bilangan berbasis tidak ditemukan, masak kita mau menghitung pake angka Romawi? No Man! Noooo...!

    Oke, metode tadi salah, lantas, apakah saya termasuk golongan yang mengerti atau bukan?

    Orang yang mengerti bilangan berbasis, dapat menjawab soal di bawah dengan masing-masing soal kurang dari lima detik! (sebenarnya lima detik itu kelamaan)

    • ·         Dalam heksa, berapakah 7AD + 1? (ingat ya dalam 5 detik)
    • ·         Bilangan berbasis satu itu ada nggak?
    • ·         Kenapa manusia menggunakan bilangan berbasis 10? Kenapa tidak berbasis 7, atau berbasis 16 sekalian biar kayak komputer?
    • ·         Apa yang salah dengan bilangan berbasis 5: 784?
    • ·         Dalam heksa, berapakah
        o  
      2F + 1?
        o  
      FF + 1?
        o  
      2FADFABDADF + 1?
        o  
      FFAB3F0 – 1?
    • ·         Berapakah, FAB(hex) x 10(hex)? ABCDEF(hex) x 100 (hex)?
    • ·         Bilangan berbasis 18 itu seperti apa sih? Coba nyatakan lambang-lambang bilangannya!
    • ·         Dalam bilangan berbasis 18, berapakah 100(18) – 1? (maksud 100(18) adalah 100 dinotasikan dalam bilangan berbasis 18)
    • ·         Bilangan berbasis tak berhingga itu seperti apa ya?

    Nah pembaca yang budiman, apabila anda dapat menjawab soal di atas dengan mudah, maka anda termasuk orang yang mengerti dan kalau ditemukan kesalahan dalam tulisan ini, please leave a comment!

    Damn, Saya tidak dapat menjawabnya, lantas Anda mau bilang kalo saya bodoh? sialan Lu!

    Tentu saja tidak! Yang membuat anda tidak mengerti bukan karena kebodohan, tapi karena tidak ada yang memberi tahu. Untuk mengerti konsep bilangan berbasis itu sama sekali tidak sulit, cuma butuh membaca tulisan ini J dan percayalah, sama sekali tidak sulit. Bahkan saya pernah ketemu sama orang pinter yang tidak mengerti basis. Orang itu saya anggap pinter bukan karena bisa meramal, bukan juga karena dia cantik (kenyataannya dia memang manis J ), tapi karena secara prestasi mengagumkan. Selalu juara umum di SMU, kalau ikut simulasi UMPTN di SSC Bandung skornya 80 persen ke atas (saya selalu 60 persenan), masuk elektro ITB secara PMDK (berarti rapornya bagus sekali), lulus *** laude, dan menjadi juara pada suatu lomba di Jerman saat mengambil S2 di sana. Lha kalo saya, S1  aja nggak lulus-lulus J

    Sebelum ditemukan angka Arab (basis 10)

    Gunakan imajinasi anda, anggap kita berada di suatu peradaban yang sangat sederhana sehingga belum ditemukan sebuah sistem bilangan, dan Anda disuruh oleh kepala suku untuk menciptakan sistem bilangan.

     

    Misalkan ada sebuah jeruk, bagaimana cara menotasikan nilai ‘satu’?

     

    Tentu saja, cara yang paling alami adalah dilambangkan dengan garis lurus seperti ini:

     

    I

     

    Sehingga, untuk menotasikan nilai ‘dua’ cukup dengan menambahkan garis lurus:

     

    II

     

    Demikian juga untuk menotasikan nilai-nilai berikutnya:

     

    III (sebagai notasi dari ‘tiga buah’)
    IIII ( sebagai notasi dari ‘empat buah’)
    IIIII ( sebagai notasi dari ‘lima buah’)

    Suatu saat, tentu saja juga dibutuhkan juga untuk menotasikan bilangan-bilangan besar seperti seratus, dua ratus, bahkan seribu. Oke, notasinya adalah

     

    IIIII IIIII IIIII IIIII IIIII IIIII IIIII IIIII IIIII IIIII IIIII IIIII IIIII IIIII IIIII IIIII IIIII IIIII IIIII IIIII (notasi dari ‘seratus’)

    IIIII IIIII IIIII IIIII IIIII IIIII IIIII IIIII IIIII IIIII IIIII IIIII IIIII IIIII IIIII IIIII IIIII IIIII IIIII IIIII IIIII IIIII IIIII IIIII IIIII IIIII IIIII IIIII IIIII IIIII IIIII IIIII IIIII IIIII IIIII IIIII IIIII IIIII IIIII IIIII (notasi dari ‘dua ratus’)

     

    Bagaimana dengan seribu? Silahkan tulis sendiri, yang penting anda mengerti kelemahan dari sistem bilangan yang baru kita rancang. Sudah waktunya untuk menemukan sebuah sistem yang baru, sistem yang bisa menotasikan bilangan besar dengan tulisan yang sedikit.

     

    Cara yang lain segera ditemukan untuk menotasikan bilangan, yaitu dengan menggunakan lambang bilangan, yang kira-kira seperti ini:

     

    ! 

    notasi dari

    ‘satu’

    @

    notasi dari

    ‘dua’

    #

    notasi dari

    ‘tiga’

    $

    notasi dari

    ’empat’

    %

    notasi dari

    ’lima’

    ^

    notasi dari

    ’enam’

    &

    notasi dari

    ’tujuh’

    *

    notasi dari

    ’delapan’

    ( 

    notasi dari

    ’sembilan’

    ) 

    notasi dari

    ’sepuluh’

    - 

    notasi dari

    ’sebelas’

     Dan sebagainya

     

    Dengan cara ini, semua bilangan dapat dinotasikan cukup dengan sebuah lambang bilangan. Semua bilangan dinotasikan dalam sebuah lambang artinya sebuah bilangan berapapun pasti ada lambang bilangannya, termasuk bilangan-bilangan besar seperti ‘seratus’ maupun ‘seribu’. Bisa menotasikan ‘seratus’ berarti dari ‘satu’ hingga ‘seratus’ ada lambang bilangannya sendiri sehingga kita harus menghafal banyak sekali lambang bilangan. Sistem bilangan yang seperti itu, tentu saja gagal.

     

    Sistem bilangan yang pertama walaupun harus menulis banyak ‘garis’ untuk menotasikan bilangan besar, tapi kita cuma harus menghafal sebuah lambang bilangan, yaitu ‘garis’. Untuk menotasikan bilangan besar dengan menggunakan sistem bilangan yang kedua, kita cukup menggunakan satu buah lambang bilangan (ingat semua nilai bilangan dibuat lambangnya), namun hal ini juga sulit karena lambang bilangan yang dibuat tentu saja tak berhingga. Kemudian, di antara kedua sistem bilangan tersebut, sistem bilangan mana yang terbaik? Tidak ada yang baik, keduanya absurd! Harus ditemukan sistem bilangan yang baru, sistem yang hanya terdiri dari sedikit lambang bilangan, dan bisa menotasikan bilangan besar dengan mudah.

    Sistem bilangan dengan sedikit lambang bilangan, namun dapat menotasikan bilangan besar dengan mudah? Emang ada?

    Tentu saja ada! Itulah yang disebut bilangan berbasis. Perhatikan bilangan yang setiap hari kita gunakan, ada berapa lambang bilangan? Ada sepuluh buah lambang bilangan, yaitu:

     

    0 1 2 3 4 5 6 7 8 9

     

    Cukup dengan menggunakan kesepuluh lambang bilangan tersebut, kita dapat menotasikan bilangan berapapun! Ingat, tidak ada sebuah lambang bilangan yang dapat menotasikan nilai ‘sepuluh’ karena lambang bilangannya cuma sampai 9, untuk menotasikan nilai ‘sembilan’. Lantas bagaimana cara menotasikan nilai ‘sepuluh’? Bisa, yaitu dengan menggabungkan lambang bilangan ‘1’ dan lambang bilangan ‘0’ menjadi ‘10’. Tentu saja, angka ‘10’ itu bukan lambang bilangan baru, karena cuma penggabungan dari lambang bilangan yang sudah ada. Bagaimana kalau ingin menotasikan ‘lima ratus dua puluh lima’? Ya gampang, dengan menggabungkan lambang bilangan tadi menjadi ‘525’. Tentu saja, hal tersebut bukan hal yang baru bagi anda, kemungkinan besar hal ini sudah diketahui semenjak TK. Saya cuma mau menunjukkan bahwa, sistem bilangan dengan sedikit lambang bilangan dan dapat menotasikan bilangan berapapun benar-benar ada!

    Sistem Bilangan Berbasis

    Sekarang kita akan menciptakan bilangan yang cuma menggunakan sedikit lambang bilangan dan dapat menotasikan bilangan berapapun. Misalkan ada lambang bilangan seperti ini:

     

    0 untuk menotasikan ‘kosong’
    1 untuk menotasikan ‘satu’
    2 untuk menotasikan ‘dua’
    3 untuk menotasikan ‘tiga’

     

    Jelas sekali untuk menotasikan antara ‘kosong’ hingga ‘tiga’ kita Cuma butuh sebuah lambang bilangan. Nah, bagaimana kalau ingin menotasikan nilai ‘empat’? Ingat, tidak ada lambang bilangan ‘4’, yang ada adalah ‘0’, ‘1’, ‘2’, ‘3’. Hal ini sama dengan pertanyaan, bagaimana cara menotasikan nilai ‘sepuluh’ pada bilangan desimal. Pada bilangan desimal, lambang bilangannya cuma antara ‘kosong’ hingga ‘sembilan’, dan untuk menotasikan ‘sepuluh’ adalah dengan menggabungkan beberapa lambang bilangannya, yaitu ‘1’ dan ‘0’ menjadi ‘10’. Kembali ke pertanyaan semula, bagaimana menotasikan nilai ‘empat’ pada sistem bilangan yang baru kita buat? Sama, yaitu ‘10’. Untuk lebih jelas mari kita melihat pola penambahannya:

     

    0

    kosong

    1

    satu

    2

    Dua

    3

    Tiga

    10

    Empat

    11

    Lima

    12

    Enam

    13

    Tujuh

    20

    Delapan

    21

    Sembilan

    22

    Sepuluh

    23

    Sebelas

    30

    Dua belas

    31

    Tiga belas

    32

    Empat belas

    33

    Lima belas

     

    Apakah anda dapat melihat polanya? Dimulai dari 0, kemudian 1, 2, 3. Lantas kenapa menjadi 10? Bayangkan sebuah odometer, yang angka-angkanya adalah dari 0 sampai 3. Digit yang paling kanan berputar dari 0, 1, 2, kemudian 3. Setelah 3, tentu saja odometer kembali lagi ke 0, disertai dengan penambahan (perputaran) 1 pada digit di sebelah kirinya. Hal ini berlanjut terus sehingga polanya adalah seperti di atas. Ingat pada odometer, digit paling kanan paling cepat berputar, diikuti dengan digit di sebelah kirinya, dan diikuti lagi dengan digit di sebelah kirinya lagi dan seterusnya. Apabila anda sudah mengerti dengan polanya, dapat ditebak bahwa bilangan berikutnya setelah 33 adalah:

     

    100

     

    Kenapa? Dimulai dari digit paling kanan yaitu 3. 3 bertambah satu, menjadi 0 lagi, tapi tentu saja disertai dengan penambahan satu pada digit di sebelah kirinya yang juga 3. 3 bertambah satu, menjadi 0, dan membuat digit di kirinya lagi (yaitu 0) bertambah 1, menjadi 1. Berikutnya adalah deret penambahan satu dari 100:

     

    101, 102, 103, 110, 111, 112, 113, 120, 121, 122, 123, 130, 131, 132, 133, 200,
    201, 202, 203, 210, 211, 212, 213, 220, 221, 222, 223, 230, 231, 232, 233, 300,
    301, 302, 303, 310, 311, 312, 313, 320, 321, 322, 323, 330, 331, 332, 333

     

    Sampai di sini, harusnya anda sudah dapat menebak bahwa angka berikutnya adalah : 1000.

     

    Dengan sistem ini, berarti kita dapat menotasikan bilangan berapapun dengan hanya tiga buah lambang bilangan. Sistem inilah yang disebut dengan sistem bilangan berbasis tiga. Artinya adalah sebuah  sistem bilangan yang memiliki tiga buah lambang bilangan. Bilangan berbasis 6 misalnya, artinya adalah sebuah sistem bilangan yang memiliki 6 buah lambang bilangan, dimulai dari 0, hingga 5. Sehari-hari, kita menggunakan bilangan desimal, bilangan berbasis 10. Artinya, bilangan desimal adalah bilangan yang memiliki 10 buah lambang bilangan, dari 0 hingga 9.

     

    Sebagai pembanding, berikut adalah tabel dari ‘satu’ hingga ‘lima puluh’ dari berbagai bilangan berbasis:

     

    Basis:

    2 (biner)

    4

    7

    8 (oktal)

    10 (desimal)


    1

    1

    1

    1

    1


    10

    2

    2

    2

    2


    11

    3

    3

    3

    3


    100

    10

    4

    4

    4


    101

    11

    5

    5

    5


    110

    12

    6

    6

    6


    111

    13

    10

    7

    7


    1000

    20

    11

    10

    8


    1001

    21

    12

    11

    9


    1010

    22

    13

    12

    10


    1011

    23

    14

    13

    11


    1100

    30

    15

    14

    12


    1101

    31

    16

    15

    13


    1110

    32

    20

    16

    14


    1111

    33

    21

    17

    15


    10000

    100

    22

    20

    16


    10001

    101

    23

    21

    17


    10010

    102

    24

    22

    18


    10011

    103

    25

    23

    19


    10100

    110

    26

    24

    20


    10101

    111

    30

    25

    21


    10110

    112

    31

    26

    22


    10111

    113

    32

    27

    23


    11000

    120

    33

    30

    24


    11001

    121

    34

    31

    25


    11010

    122

    35

    32

    26


    11011

    123

    36

    33

    27


    11100

    130

    40

    34

    28


    11101

    131

    41

    35

    29


    11110

    132

    42

    36

    30


    11111

    133

    43

    37

    31


    100000

    200

    44

    40

    32


    100001

    201

    45

    41

    33


    100010

    202

    46

    42

    34


    100011

    203

    50

    43

    35


    100100

    210

    51

    44

    36


    100101

    211

    52

    45

    37


    100110

    212

    53

    46

    38


    100111

    213

    54

    47

    39


    101000

    220

    55

    50

    40


    101001

    221

    56

    51

    41


    101010

    222

    60

    52

    42


    101011

    223

    61

    53

    43


    101100

    230

    62

    54

    44


    101101

    231

    63

    55

    45


    101110

    232

    64

    56

    46


    101111

    233

    65

    57

    47


    110000

    300

    66

    60

    48


    110001

    301

    100

    61

    49


    110010

    302

    101

    62

    50

     

    Wow, I can see The Truth! Pola di atas sudah jelas, jadi saya sudah ngerti basis?

    Sabar dulu. Saya belum memberi tahu pola pertambahan bilangan berbasis yang lebih besar dari 10. Sekaranglah saatnya. Mari kita tinjau bilangan berbasis 11, sebuah bilangan yang terdiri dari 11 buah lambang bilangan. Seperti biasa, dimulai dari 0 hingga 9:

     

    0 1 2 3 4 5 6 7 8 9

     

    Kira-kira, bilangan seperti apa yang tampil setelah 9? Untuk bilangan berbasis 11, nilai ‘sepuluh’ dapat dinotasikan hanya dengan sebuah lambang bilangan. Nah, mari kita sepakati sekarang bahwa lambang bilangan yang digunakan untuk menotasikan ‘sepuluh’ adalah A, jadi lambang-lambang bilangan yang ada di basis 11 adalah:

     

    0 1 2 3 4 5 6 7 8 9 A

     

    Apakah anda dapat menebak bilangan apa yang muncul setelah A?  Kalau masih tidak dapat, coba ingat kembali konsep odometer, dimana sekarang digit-digit pada odometer terdiri dari 11 lambang bilangan di atas. Digit paling kanan berputar dari 0, 1, ..., 9 dan hingga A. Berputar lagi tentu saja balik lagi ke 0, disertai dengan perputaran satu pada digit di sebelah kirinya (yang tadinya 0 berupah menjadi 1). Tentu saja, setelah A, adalah 10, diikuti dengan:

     

    11, 12, 13, 14, 15, 16, 17, 18, 19 ...

     

    Angka apa setelah 19? Tentu saja 1A. Bagaimana cara mengeja 1A ini? Apakah dengan mengatakan ‘satu A’? Pertanyaan yang sama adalah bagaimana cara mengeja 19? Apakah ‘satu sembilan’? Anak TK juga tau bahwa cara mengeja 19 adalah ‘sembilan belas’. Kalau 19 adalah ‘sembilan belas’, maka 1A adalah ‘A belas’. Pola penambahan berikutnya adalah:

     

    1A, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 2A, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 3A, 40, 41, ..., 97, 98, 99, 9A

     

    Angka apa setelah 9A? A ditambah satu berarti kembali ke 0, disertai dengan pertambahan satu dari 9 menjadi A. Jadi angka berikutnya adalah A0. Again, bagaimana cara mengeja A0? Dengan cara yang sama, mengejanya adalah ‘A puluh’. Pola penambahan berikutnya:

     

    A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, AA, 100, 101, 102, 103, 104, 005, 106, 107, 108, 109, 10A, 110, 111, dan seterusnya.

    Seperti biasa, cara mengeja A7 misalnya, adalah ‘A puluh tujuh’.

     

    Sebagai pembanding, berikut adalah  tabel dari berbagai bilangan berbasis yang lebih besar dari 10:

     

    Basis

    10

    14

    16

    18

    20


    0

    0

    0

    0

    0


    1

    1

    1

    1

    1


    2

    2

    2

    2

    2


    3

    3

    3

    3

    3


    4

    4

    4

    4

    4


    5

    5

    5

    5

    5


    6

    6

    6

    6

    6


    7

    7

    7

    7

    7


    8

    8

    8

    8

    8


    9

    9

    9

    9

    9


    10

    A

    A

    A

    A


    11

    B

    B

    B

    B


    12

    C

    C

    C

    C


    13

    D

    D

    D

    D


    14

    10

    E

    E

    E


    15

    11

    F

    F

    F


    16

    12

    10

    G

    G


    17

    13

    11

    H

    H


    18

    14

    12

    10

    I


    19

    15

    13

    11

    J


    20

    16

    14

    12

    10


    21

    17

    15

    13

    11


    22

    18

    16

    14

    12


    23

    19

    17

    15

    13


    24

    1A

    18

    16

    14


    25

    1B

    19

    17

    15


    26

    1C

    1A

    18

    16


    27

    1D

    1B

    19

    17


    28

    20

    1C

    1A

    18


    29

    21

    1D

    1B

    19


    30

    22

    1E

    1C

    1A


    31

    23

    1F

    1D

    1B


    32

    24

    20

    1E

    1C


    33

    25

    21

    1F

    1D


    34

    26

    22

    1G

    1E


    35

    27

    23

    1H

    1F


    36

    28

    24

    20

    1G


    37

    29

    25

    21

    1H


    38

    2A

    26

    22

    1I


    39

    2B

    27

    23

    1J


    40

    2C

    28

    24

    20

     

    Nah, apabila anda sudah mengerti pola di atas, maka anda telah mengerti apa itu bilangan berbasis. Mengerti bilangan berbasis, walaupun tanpa disertai pengetahuan mengenai rumus untuk melakukan konversi dari basis anu ke basis ino ataupun rumus-rumus lainnya. Ingat, rumus-rumus itu nggak penting! Oke, rumus tetap penting, nah, tugas Anda berikutnya, coba cari tahu kenapa rumusnya seperti itu J

    Oke, terima kasih atas penjelasannya, apalagi sudah mau capek-capek mbuatin tabel sama kita-kita!

    Yoi, sama-sama! Tapi ada beberapa yang harus saya tambahkan tentang kata capek. In fact, saya sama sekali tidak capek membuat tabel di atas. Mbuatnya pake C# lho, cuma beberapa baris. Berikut adalah source-nya, ready baked code! Just copy paste it to your favorite C# 3.0 compliance IDE.

     

    static class Program
    {
        static string ToBase(this int number, int toBase)
        {
            return number < toBase ? number.AsSingleChar() :
                ToBase(number / toBase, toBase) + (number % toBase).AsSingleChar();
        }

       
    static string AsSingleChar(this int number)
       
    {
           
    return number < 10 ? number.ToString() : ((char)(number + 'A' - 10)).ToString();
       
    }


       
    public static void Main()
       
    {
        
       Console.WriteLine("Basis\t10\t14\t16\t18\t20");
           
    for (int i = 1; i <= 40; ++i)
               
    Console.WriteLine("\t{0}\t{1}\t{2}\t{3}\t{4}", i, i.ToBase(14),
                    i.ToBase(16), i.ToBase(18), i.ToBase(20));
       
    }
    }

     

    Ada beberapa orang yang bilang, solusi di atas lambat karena menggunakan rekursif. Kalau anda termasuk yang mengatakan bahwa solusi di atas lambat, maka anda belum mengerti konsep yang namanya kompleksitas algoritma. Jangan terpaku sama semua yang rekursif itu lambat. Adalah benar bahwa solusi rekursif paling lambat di antara solusi lain yang tanpa menggunakan rekursif apabila kompleksitas algoritmanya sama, tapi solusi di atas walaupun menggunakan rekursif (yang berarti solusi paling lambat) tapi kompleksitasnya algoritma adalah O(b log n) dengan b adalah basis tujuan dan n adalah bilangan yang ingin dikonversi. Kompleksitas algoritma yang ada lognya adalah salah satu yang paling baik.

     

    Contoh, Anda ingin merubah bilangan 2147483647 (ini bukan bilangan ngasal lho! Ini adalah bilangan 32 bit yang paling besar) ke basis 2. Contoh ini adalah kasus terberat yang dihadapi oleh fungsi di atas, yaitu sebuah kasus di mana harus mengkonversi bilangan yang paling besar ke basis yang paling kecil.

     

    Sesuai dengan rumus: b log n = 2 log 2147483647 = 31

     

    Artinya apa? Artinya untuk kasus terburuk, ternyata dengan solusi di atas cuma membutuhkan 31 kali pemanggilan secara rekursif! Sangat bisa dimaafkan, jadi jangan sekali-kali menganggap solusi di atas lambat. Kalau Anda pernah memiliki pengalaman buruk dengan rekursif, coba tinjau kembali kompleksitas algoritmanya. Biasanya orang langsung memiliki pengalaman buruk dengan rekursif karena pengalaman pertama dia berkenalan dengan rekursif adalah untuk menghitung deret fibonacci. Wajar sekali kalau orang itu langsung ilfeel ama rekursif.

     

    Agar lebih cepat lagi, kita dapat mengoptimasi solusi di atas. Cara paling gampang adalah menggunakan rekursif dengan pencatatan (recursive with memoization) seperti ini:

     

    struct Pair<T1, T2>
    {
       
    public T1 First;
       
    public T2 Second;
    }


    private static readonly IDictionary<Pair<int, int>, string> baseMemos =
        new
    Dictionary<Pair<int, int>, string>();


    static
    string ToBase(this int number, int toBase)
    {
        var key = new Pair<int, int> { First = number, Second = toBase };
            return
    baseMemos.ContainsKey(key) ? baseMemos[key] :
               
    baseMemos[key] = number < toBase ? number.AsSingleChar() :
                   
    ToBase(number / toBase, toBase) + (number % toBase).AsSingleChar();
    }

     

    Sekarang, saya cukup yakin dengan solusi di atas untuk dipakai dalam real world application J

    Share this post: | | | |
  • SimplePos, Aplikasi Contoh Buat Belajar

    Melanjuti tutorial sebelumnya, saya telah melengkapi program pada tutorial tersebut yang tadinya cuma sebatas domain model, sampai dapat ditampilkan dengan Windows Form.

     Program ini saya buat karena berdasarkan pengalaman saya mengajar, biasanya yang paling sering ditanyakan oleh peserta adalah "bagaimana sih caranya menghubungkan class sama database?" dan "bagaimana caranya menghubungkan class sama user interface?" maupun bagaimana cara membuat program agar multilayer. Semoga pertanyaa-pertanyaan tersebut terjawab di dalam program ini.

    Pattern yang digunakan adalah Repository Pattern untuk mengabstraksi data akses, dan MVC agar --idealnya-- 'C' pada MVC dapat di-reuse pada segala jenis aplikasi, termasuk web, mobile, WPF, dan bahkan mungkin aplikasi yang UI-nya menggunakan suara.

    Dalam versi ini, database yang digunakan masih berupa memory, data di hard-code di dalam C#. Penggunaan database akan saya buat pada iterasi berikutnya. Tentu saja, karena penggunaan Repository Pattern, hal tersebut sangat mungkin dilakukan. Pengubahan dari menggunakan memory menjadi menggunakan database tidak akan merubah code yang sudah ada, tapi menambah code baru. Hal ini sesuai dengan Open Closed Principle.

    Program ini menggunakan fitur-fitur C# 3.0, seperti lambda expression, extension methods, predicate function. Bagi yang belum belajar C# 3.0, saya berencana membuat tutorial step-by-step untuk membuat program ini, seperti pada seri sebelumnya, sehingga para pemula juga bisa belajar.

    Tujuan utama dari program ini adalah sebagai program contoh bagi pemula yang ingin mengetahui bagaimana bentuk C# pada real world application. Bagi yang lebih berpengalaman dan melihat banyak kesalahan pada program ini, your comment are highly appreciated.

    Source code dapat diunduh di akhir halaman.

    Share this post: | | | |
  • This is My Style of Domain Model and Repository Pattern, What’s Your? (Part I)

     
     

    Repository pattern is a common solution for encapsulating data access. See Fowler’s Pattern of Enterprise Application Architecture for further details. Because pattern is technology agnostic, many writing you’ll seen on the web are the way too abstract, lack of technological details. Below, I want to show you how to achieve repository pattern by using C#. Off course, this is not the best solution, if you have some glitch about my implementation, please leave a comment.

    Let’s start with the simple sample. We want to implement a simple Point of Sales (POS) with these specifications:

    1.       System can save completed Sale.

    2.       For simplicity, system can only accept cash payment.

    3.       System can save Products data.

    4.       Sale contains one or more sales line item.

    Here is proposed model:

    First proposed UML 

    If you have read Larman’s Applying UML and Pattern (great book, I recommend to read it if you hasn’t), chance are great that you’re familiar with those model. Here, I want to signify the differences. There is no Store class (or Ledger class) that stores completed Sales, nor there is a ProductCatalog that stores ProductSpecification s. In my solution, completed Sales are stored in SaleRepository (or SaleDao), not Ledger class (as in Larman’s) and as you may have guessed it well, there will be ProductRepository (or ProductDao) that stores ProductSpecification s, not ProductCatalog as in Larman’s. Oh well... quite a difference eh? Just slight name difference, and as Shakespeare would say, “What is an a name?” OK, that not just name difference. On Larman’s, ProductCatalog and Store is part of the domain, something that you’ll see on real store on the real world. On the other hand, ProductDao or SaleDao is not part of the domain, so if you ask the storekeeper which part in this store is something called ‘product Dao’, you’ll sent by the storekeeper to nearby asylum. I’ll discuss this deeply later (discuss the repository, not the asylumJ).

    Here is the corresponding code for ProductSpecification:

    public class ProductSpecification
    {
       
    public string Id { get; set; }   
       
    public string Name { get; set; }   
       
    public decimal UnitPrice { get; set; }
       
       
    public string Description { get; set; }
    }

    Purist would say the code block above is some kind of anemic domain model (ADM), model that contains only data and no behavior at all. I, no purist nor ADM fan boy, as soon as I see appropriate behavior on ProductSpecification, I will put some methods there. Because this is just first iteration, there is no appropriate behavior sighted, just leave the model anemic.

    Here is corresponding code for SalesLineItem:

    public class SalesLineItem
    {   
       
    public int Quantity { get; set; }
       
       
    public ProductSpecification ProductSpecification { get; set; }
    }

    Leave it anemic again? No, because appropriate behavior sighted! SalesLineItem are good candidate to know what the subtotal is, so property called Subtotal should be there.

    public decimal Subtotal
    {
       
    get { return this.ProductSpecification.UnitPrice * this.Quantity; }
    }

    Is the subtotal formula just shown above do as it should do? Note the price. The price is product’s current price, not the price when the item sold, so when ProductSpecification’s price changed, the subtotal should change too. The SalesLineItem must save the price when the item sold, so there must be UnitPrice attribute in SalesLineItem. Let’s add it:

    public class SalesLineItem
    {
       
    public int Quantity { get; set; }
       
       
    public decimal UnitPrice { get; set; }

       
    public ProductSpecification ProductSpecification { get; set; }
        
       
    public decimal Subtotal
        {       
           
    get { return this.UnitPrice * this.Quantity; }
       
       
    }
    }

    To make SalesLineItem even easier to use, let’s make UnitPrice automatically filled with product’s price when SalesLineItem.ProductSpecification changed:

    public class SalesLineItem
    {   
       
    private ProductSpecification productSpecification;
        
       
    public int Quantity { get; set; }
       
       
    public decimal UnitPrice { get; set; }
           
       
    public ProductSpecification ProductSpecification
       
    {       
           
    get { return productSpecification; }
           
           
    set
     
           

               
    this.productSpecification = value;           
               
    this.UnitPrice = productSpecification.UnitPrice;
           
           
    }
       
       
    }    
       
    public decimal Subtotal
       
       
    {
           
           
    get { return this.UnitPrice * this.Quantity; }
       
       
    }
    }

    That’s enough for this simple scenario. 
    Here Payment class code: 

    public class CashPayment
    {   
       
    public decimal Amount { get; set; }
    }

    Some of the reader may found this class rather confusing, why on earth does this class even exists? Why not just make this class as single attribute on Sale class? The reason is two words... what if? What if in the future this system goes larger and payment is not just cash, but credit card as well? When the entity is simple, make it simple, as simple as single attribute. When the entity is complex, make a single class, completed with attributes and complicated behaviors if any. Other reason why this class exists, I want to show you the concept called aggregate, something that will be discussed later on this article.

    Last but not least, the Sale class code:

    public class Sale
    {   
       
    public string Id { get; set; }
       
       
    public DateTime Date { get; set; }
        
       
    public CashPayment Payment { get; set; }
       
       
    public IList<SalesLineItem> LineItems { get; set; }
    }

    Note the LineItems collection type. The type is not List<SalesLineItem> but IList<SalesLineItem>, the interface that List<T> implements. This is one of the fundamental agile designs, called Dependency Inversion Principle (DIP). The type must be of type IList<T> rather than List<T> not because of it violates the DIP (I don’t even care if that thing is called DIP), but believe me, I can foreseen the very chaos if you violates it. Just one sample, if you use NHibernate as data access, NHibernate will use its own implementation of IList<T>, not Microsoft System.Collection.Generic.List<T> that we used to use on day basis. So, if you force yourself to use List<T> instead of IList<T>, your domain model is not compatible with NHibernate (which is not good). This is not about NHibernate—of course you’re free to say Entity Framework is far more superior to NHibernate— but this is about the modularity of your solution.

    Now, what behavior does this class should have? Total is great candidate, so let’s add it:

    public decimal Total
    {   
        get { return this.LineItems.Sum(sli => sli.Subtotal); }

    } 

    Consider Sale.Date. When Sale is instantiated, Sale.Date should represent current time and date. This logic is contained in Sale’s constructor:

    public Sale()
    {   
       
    this.Date = DateTime.Now;
       
       
    this.LineItems = new List<SalesLineItem>();
    }

    Test Drive our Solution and Little Refactoring

    Now, the time has come for a little testing. If you’re fan of TDD, testing are the majority of your work, you’ve done testing even before you create above classes. Because this is not about TDD session (I always perform TDD on domain model), we create classes first before testing it.

    Suppose list of products listed in product catalog is:

    Identity Name Unit Price
    P01 Momogi 500
    P02 Pepsi 5000
    P03 Mizone 4500
     

    We want to buy 2 Momogi, and 1 Pepsi, the code representation is:

    public static void Main(string[] args)
    {   
       
    var momogiSpec = new ProductSpecification { Id = "P01", Name = "Momogi", UnitPrice = 500 };
       
       
    var pepsiSpec = new ProductSpecification {Id = "P02", Name = "Pepsi", UnitPrice = 5000};
       
       
    var mizoneSpec = new ProductSpecification { Id = "P03", Name = "Mizone", UnitPrice = 4500 };
        
       
       
    var momogiLineItem = new SalesLineItem {ProductSpec = momogiSpec, Quantity = 2};
       
       
    var pepsiLineItem = new SalesLineItem {ProductSpec = pepsiSpec, Quantity = 1};
        
       
       
    var sale = new Sale();
       
       
    sale.LineItems.Add(momogiLineItem);
       
       
    sale.LineItems.Add(pepsiLineItem);
        

       
    Console.WriteLine("Dicky POS\n---------");
       
       
    foreach (var lineItem in sale.LineItems)
           
           
    Console.WriteLine("{0,-10}({1,8:c}) x {2,3} : {3,8:c}",
               
               
    lineItem.ProductSpec.Name, lineItem.ProductSpec.UnitPrice,
               
               
    lineItem.Quantity, lineItem.Subtotal);
       
       
    Console.WriteLine("------------------------------------- +\nTotal is\t\t   : {0,8:c}", sale.Total);
    } 

    The output is below:

    Dicky POS
    ---------
    Momogi    (   Rp500) x   2 :  Rp1.000
    Pepsi     ( Rp5.000) x   1 :  Rp5.000
    ------------------------------------- +
    Total is                   :  Rp6.000

    The output is correct as expected. Next, what if we add three SalesLineItem, instead of two? To clarify this, see code below

    var momogiLineItem1 = new SalesLineItem {ProductSpec = momogiSpec, Quantity = 1};   
    var pepsiLineItem = new SalesLineItem {ProductSpec = pepsiSpec, Quantity = 1};
       
    var momogiLineItem2 = new SalesLineItem { ProductSpec = momogiSpec, Quantity = 1 };
        

    var
    sale = new Sale();
       
    sale.LineItems.Add(momogiLineItem1);
       
    sale.LineItems.Add(pepsiLineItem);
       
    sale.LineItems.Add(momogiLineItem2);

    And the output is:

    Dicky POS
    ---------
    Momogi    (   Rp500) x   1 :  Rp1.000
    Pepsi     ( Rp5.000) x   1 :  Rp5.000
    Momogi    (   Rp500) x   1 :  Rp1.000
    ------------------------------------- +
    Total is                   :  Rp6.000

    The total is correct, the item list is correct, but sale line item is not. Desired output is 2 Momogi and 1 Pepsi, not 1 Momogi, 1 Pepsi, and then 1 Momogi again. Yup, time for refactoring, but before that, let’s override each class’ Equals method. To define equality, we must refer to business rule, what conditions are two objects are considered equal? Below is the rule:

    Class Equality Properties
    Sale Id
    ProductSpecification Id
    SalesLineItem ProductSpecification
     

    Before we implement equality, you must remember one important thing, if you override Equals method, you must also override GetHashCode method. Hash code is integer representation of your object, should be unique between different objects, and same number between same objects. Hash code is used extensively in collection that requires hashing, like IDictionary. When overriding Equals, why not implement IEquatable<T> too?

    Equality for ProductSpecification:

    public bool Equals(ProductSpecification obj)
    {   
       
    if (ReferenceEquals(null, obj)) return false;
       
       
    if (ReferenceEquals(this, obj)) return true;
       
       
    return Equals(obj.Id, Id);
    } 

    public override bool Equals(object obj)
    {   
       
    if (ReferenceEquals(null, obj)) return false;
       
       
    if (ReferenceEquals(this, obj)) return true;
       
       
    if (obj.GetType() != typeof (ProductSpec
    ification)) return false;   
       
    return Equals((ProductSpec) obj);
    } 

    public override int GetHashCode()
    {   
       
    return (Id != null ? Id.GetHashCode() : 0);
    } 

    Equality for Sale:

    public bool Equals(Sale obj)
    {   
       
    if (ReferenceEquals(null, obj)) return false;
       
       
    if (ReferenceEquals(this, obj)) return true;
       
       
    return Equals(obj.Id, Id);
    } 

    public override bool Equals(object obj)
    {   
       
    if (ReferenceEquals(null, obj)) return false;
       
       
    if (ReferenceEquals(this, obj)) return true;
       
       
    if (obj.GetType() != typeof(Sale)) return false;
       
       
    return Equals((Sale)obj);
    } 

    public override int GetHashCode()
    {   
       
    return (Id != null ? Id.GetHashCode() : 0);
    }

    Equality for SalesLineItem:

    public bool Equals(SalesLineItem obj)
    {   
       
    if (ReferenceEquals(null, obj)) return false;
       
       
    if (ReferenceEquals(this, obj)) return true;
       
       
    return Equals(obj.productSpec, productSpec);
    } 

    public override bool Equals(object obj)
    {   
       
    if (ReferenceEquals(null, obj)) return false;
       
       
    if (ReferenceEquals(this, obj)) return true;
       
       
    if (obj.GetType() != typeof (Sale
    sLineItem)) return false;   
       
    return Equals((Sale
    sLineItem) obj);
    } 

    public override int GetHashCode()
    {   
       
    return (productSpec != null ? productSpec.GetHashCode() : 0);
    }

    If you use Resharper, you can generate equality (the code shown above) by pressing alt-insert then click the appropriate menu. That’s enough for equality, let’s back to our Sale class. We want to add same SalesLineItem to Sale will not add new SalesLineItem object, but we want Quantity property from existing SalesLineItem object in Sale.LineItems to be updated based on added SalesLineItem.Quantity. To clarify this, let’s add AddLineItem method to Sale class:

    public void AddLineItem(SalesLineItem lineItem)
    {   
       
    if (this.LineItems.Contains(lineItem)) // Contains use Equals method we've just overrided
           
    this.LineItems.Where(li => li.Equals(lineItem)).First().Quantity += lineItem.Quantity;   
       
    else
           
           
    this.LineItems.Add(lineItem);
    }

    Now, have we wanted to add new SalesLineItem to our Sale class, we should use this method instead of AddLineItem from collection (like we used before). So, just test if the code work as expected:

    var momogiLineItem1 = new SalesLineItem {ProductSpec = momogiSpec, Quantity = 1};   
    var pepsiLineItem = new SalesLineItem {ProductSpec = pepsiSpec, Quantity = 1};
       
    var momogiLineItem2 = new SalesLineItem { ProductSpec = momogiSpec, Quantity = 1 };
        

    var sale = new Sale();
       
    //sale.LineItems.Add(momogiLineItem1); sale.LineItems.Add is depreceated, use sale.AddLineItem instead
       
    //sale.LineItems.Add(pepsiLineItem);
       
    //sale.LineItems.Add(momogiLineItem2);
       
    sale.AddLineItem(momogiLineItem1);
       
    sale.AddLineItem(pepsiLineItem);
       
    sale.AddLineItem(momogiLineItem2);
     

    When we execute the program, the output screen is:

    Dicky POS
    ---------
    Momogi    (   Rp500) x   2 :  Rp1.000
    Pepsi     ( Rp5.000) x   1 :  Rp5.000
    ------------------------------------- +
    Total is                   :  Rp6.000

    Yes, the output is the same as we desired.

    What we’ve done

    So far, we’ve created the domain model which diagram shown below. The domain model is not anemic because we added some behavior to it when necessary. Notice CashPayment now can handle return, implemented in CashBack properties. The implementation is left as exercise for you, admirable readerJ. Thing we have not yet done is, where to store the domain model? That’s the use of repository, which we discuss on next part of this article. Yup, until next article then and don't forget to download the solution (see attachment link below).

    Final Class Diagram

    Share this post: | | | |
  • Tutorial Membuat Simple Math Expression Parser, Part I

    Beberapa bulan yang lalu, saya mendapat sms dari salah satu murid saya yang  kuliah di Malaysia. Isinya adalah sebuah pesan minta tolong agar dibuatkan salah satu tugas. Sebagai seorang gentleman, mana mungkin saya lepas tangan apabila ada seorang wanita membutuhkan bantuan. Yup, murid-murid saya kebanyakan cewek-cewek J. Ternyata, tugasnya adalah membuat sebuah program pake C++ yang dapat memproses string berupa persamaan matematika, dengan outputnya adalah nilai dari persamaan matematika tersebut.  Hmmm.. lumayan untuk mengisi waktu senggang di saat sela-sela mengerjakan sebuah proyek yang sampe sekarang belum kelar-kelar.  Karena dulu saya pernah meminjam The Dragon Book berbulan-bulan dari perpustakaan Binus hingga dendanya puluhan ribu (Binusian pasti dapat menebak berapa angka tepatnya), saya tahu pasti solusinya terdapat pada bagian awal buku tersebut dan saya masih ingat ini adalah program pertama yang saya buat pada saat selesai membaca chapter 1.

    Program cukup sederhana untuk dibuat, sehingga saya membuat tutorialnya, dengan harapan para beginner yang sudah dapat membuat program pada tutorial ini tertarik untuk belajar lebih lanjut, sehingga masuk tim inti dalam pengembangan compiler C#. Sebagai gambaran mengenai program yang akan dibuat, berikut adalah contoh ekspresi yang dapat diproses:

     

    Input

    Output

    5

    5

    1 + 1

    2

    2 * 3

    6

    1 + 2 * 3

    7

    (1 + 2) * 3

    9

    cos(0)

    1

    2 pow 3

    8

    4 pow (1/2)

    2

    2 * sin(3) * cos(3)

    -0.279415

    sin(2 * 3)

    -0.279415

     

    Selain nilai konstanta, program dapat mengolah variabel:

    Enter expression: var

    Enter value for var: 3

    Result: 3

     

    Enter expression:  x * sin(y) * cos(y)

    Enter value for x: 2

    Enter value for y: 3

    Result: -0.279415

     

    Oke, di atas adalah program dari sisi user, dari sisi programmer, berikut adalah statement-statement yang ada di fungsi Main:

    public static void Main()

    {

        var parser = new ExpressionParser();

        do

        {

            Console.WriteLine("Insert math expression: ");

            string expression = Console.ReadLine();

           

            if ( expression == "exit" )

                break;

     

            parser.Expression = expression;

     

            foreach (var variableName in parser.Variables.Keys)

            {

                Console.WriteLine("Enter value for {0}: ", variableName);

                parser.Variables[variableName] = double.Parse(Console.ReadLine());

            }

     

            Console.WriteLine("Result: {0}", parser.Evaluate());

     

        } while (true);

    }

     

     

    Cukup sederhana bukan? Lalu apa yang terdapat di dalam method ExpressionParser::Evaluate()? Nah, itu yang akan kita bahas pada part II. Lho, kok Cuma segitu part I nya? Sekarang internet udah mau ditutup, jadi saya harus pulang. Intinya, yang akan kita pelajari adalah state machines, dan grammar,  Oke? Jumpa lagi pada bagian berikutnya!

    Share this post: | | | |