Himpunan unik di Scala

Katakanlah saya memiliki sebuah List dari angka seperti berikut

val list = List(1, 2, 3, 4, 2, 3, 4)

Jika saya ingin membuatnya tidak berisi angka berulang, saya bisa panggil method distinct dari List tersebut.

scala> val list = List(1, 2, 3, 4, 2, 3, 4)
list: List[Int] = List(1, 2, 3, 4, 2, 3, 4)

scala> list.distinct
res1: List[Int] = List(1, 2, 3, 4)

Nah bagaimana jika isi List adalah objek dari kelas buatan sendiri?

Pertama, mari kita coba gunakan case class. Katakanlah saya butuh menyimpan dua buah nilai yaitu posisi: Int dan asamAmino: String yang menyatakan sebuah mutasi gen seperti berikut.

case class M1(val posisi: Int, val asamAmino: String)

Mari kita uji apakah distinct bisa bekerja sesuai harapan.

scala> case class M1(val posisi: Int, val asamAmino: String)
defined class M1

scala> val list = List(M1(1, "a"), M1(2, "b"), M1(1, "c"), M1(3, "b"), M1(1, "a"))
list: List[M1] = List(M1(1,a), M1(2,b), M1(1,c), M1(3,b), M1(1,a))

scala> list.distinct
res2: List[M1] = List(M1(1,a), M1(2,b), M1(1,c), M1(3,b))

Terlihat masih oke.. Bagaimana kalau pakai class biasa?

scala> class M2(val posisi: Int, val asamAmino: String) {
     | override def toString() = "%d%s".format(posisi, asamAmino)
     | }
defined class M2

scala> val list = List(new M2(1, "a"), new M2(2, "b"), new M2(1, "c"), new M2(3, "b"), new M2(1, "a"))
list: List[M2] = List(1a, 2b, 1c, 3b, 1a)

scala> list.distinct
res3: List[M2] = List(1a, 2b, 1c, 3b, 1a)

Wah tidak bekerja sesuai harapan ternyata 🙁 Mutasi 1a masih berjumlah ganda. Mungkin karena si Scala atau Java tidak tahu cara mengecek dengan benar apakah dua buah objek M2 itu bernilai sama atau tidak. Kalau yang dibandingkan hanyalah alamat memori, tentu saja akan berbeda semua.

Setelah ngubek2 internet, akhirnya saya mendapatkan sebuah petunjuk di StackOverflow.com. Pada saat pengecekan kesamaan nilai, Scala menggunakan dua buah method untuk mencari tahu apakah dua buah objek bernilai sama atau tidak. Dua method tersebut adalah hashCode dan equals. Nilai hashCode akan dibandingkan terlebih dahulu dan jika sama, maka method equals akan dipanggil agar si objek membandingkan sendiri dengan objek lain apakah mereka bernilai sama atau tidak.

Berbekal dari informasi tersebut, kita bisa ubah si kelas M2 menjadi seperti berikut.

class M3(val posisi: Int, val asamAmino: String) {
  override def toString() = "%d%s".format(posisi, asamAmino)

  override def hashCode = posisi

  override def equals(other: Any) =
    if (other.isInstanceOf[M3]) {
      val m = other.asInstanceOf[M3]
      m.posisi == posisi && m.asamAmino == asamAmino
    } else false
}

Untuk hashCode, agar sederhana saya samakan saja nilainya dengan nilai posisi. Pada saat pemangilan equals, nilai posisi dan asamAmino akan dibandingkan untuk memutuskan apakah dua buah mutasi bernilai sama atau tidak.

Mari kita coba lagi..

scala> val list = List(new M3(1, "a"), new M3(2, "b"), new M3(1, "c"), new M3(3, "b"), new M3(1, "a"))
list: List[M3] = List(1a, 2b, 1c, 3b, 1a)

scala> list.distinct
res0: List[M3] = List(1a, 2b, 1c, 3b)

Hore berhasil!

Mengapa saya ngga memakai case class saja sehingga tidak perlu repot2 mengimplementasikan hashCode dan equals? Karena dalam kasus yang saya hadapi, kelas mutasi ini berada dalam wilayah bahasa Java! Yap, saya sedang mencampur2 kode Java dan Scala.

Mari kita ubah si kelas mutasi menjadi bahasa Java lalu digunakan dari Scala.

public class M4 {
  private int posisi;
  private String asamAmino;

  public M4(int posisi, String asamAmino) {
    this.posisi = posisi;
    this.asamAmino = asamAmino;
  }

  public int getPosisi() {
    return posisi;
  }

  public String getAsamAmino() {
    return asamAmino;
  }

  @Override
  public int hashCode() {
    return posisi;
  }

  @Override
  public boolean equals(Object other) {
    if (other instanceof M4) {
      M4 m = (M4)other;
      return posisi == m.getPosisi() && asamAmino.equals(m.getAsamAmino());
    }
    return false;
  }

  @Override
  public String toString() {
    return posisi + asamAmino;
  }
}

Wah kodenya jadi bengkak ya? 😀 Silakan lihat kode lengkap dapat dilihat di https://gist.github.com/fajran/5718827

Lua + SunSPOT = LuaSPOT

If you are looking for English version of this post, check the project page directly. I put a lot of documentations there and all are in English 🙂

Setelah hampir dua bulan tertunda (sambil nunggu restu dr pembimbing juga sih), akhirnya saya merilis seluruh kode dan dokumentasi proyek yang saya dan rekan saya kerjakan. Kerjaan ini merupakan tugas kuliah Network Programming di Universiteit van Amsterdam yang dikerjakan di bawah bimbingan Rudolf Strijkers.

Jadi, apakah LuaSPOT ini?

Ada sebuah alat kecil namun cukup canggih yang dikenal sebagai sensor network, atau lebih tepatnya wireless sensor network (WSN) karena menggunakan media komunikasi nirkabel. Salah satu produk WSN adalah Sun SPOT yang tentu saja dibuat oleh Sun Microsystems.

Sun SPOT ini bisa dibilang sebuah komputer kecil yang dapat menjalankan aplikasi Java (Java ME). Aplikasi ini lalu akan dapat menggunakan fasilitas yang disediakan oleh Sun SPOT seperti fasilitas komunikasi nirkabel, mengakses data dari sensor yang ada, dan membaca data masukan yang dikirimkan ke alat ini. Cek halaman Flickr saya dan artikel di Wikipedia tuk pendahuluan lebih lanjut.

Proyek yang saya kerjakan untuk tugas kuliah ini adalah menjadikan Sun SPOT ini bisa menjalankan skrip! Setelah melihat beberapa pilihan yang ada, akhirnya saya memilih Lua sebagai bahasa skrip yang didukung. Salah satu alasannya adalah karena ada Lua Virtual Machine, yang bernama Kahlua, yang dapat berjalan di atas Java ME (dan tentunya Sun SPOT) hehe..

Tidak hanya sekedar menjalankan skrip, Sun SPOT yang sudah dipasangi aplikasi yang saya dan rekan buat ini juga dapat menjalankan lebih dari satu skrip secara bersamaan. Selain itu, skrip dapat dipasang ke dalam Sun SPOT on-the-fly! Tidak perlu mendatangi setiap Sun SPOT yang ada untuk menginstal skrip tambahan, cukup kirim perintah (yang menyertakan skrip di dalamnya) ke setiap Sun SPOT yang ada (broadcast atau point to point, baik langsung maupun tak langsung alias dg perantara), wirelessly.

Setiap skrip akan menyediakan satu atau lebih fungsi yang dapat dipanggil dengan teknik Remote Procedural Call (RPC). Sebuah base station atau Sun SPOT lainnya, dapat mengirim sebuah paket data yang berisi perintah untuk menjalankan fungsi yang terkandung dalam skrip yang sudah terpasang dalam Sun SPOT tujuan.

Gambar di atas menunjukkan arsitektur aplikasi yang dibuat. Di paling bawah, tentu saja, ada Sun SPOT itu sendiri. Aplikasi inti yang kami buat ada di bagian tengah, yaitu Lua SPOT. Kahlua yang kami pakai bisa dibilang juga ada di lapisan tengah. Pada lapisan atas, terdapat aplikasi-aplikasi yang fungsi2nya dapat dipanggil melalui mekanisme RPC.

Bagian dari Lua SPOT yang bertugas menangani instalasi skrip secara fungsional juga berada pada lapisan atas. Dengan kata lain, instalasi skrip dilakukan dengan perintah RPC yang sama!

Sun SPOT tidak memiliki fasilitas komunikasi yang canggih. Tidak ada mekanisme routing yang dapat digunakan untuk mengirim data ke Sun SPOT lain melalui beberapa Sun SPOT perantara. Oleh karena itu, perlu dibuat sebuah fungsi routing agar jaringan Sun SPOT yang dibuat dapat menjadi lebih canggih. Kami juga mengimplementasikan fungsi routing yang dapat melakukan penerusan pesan dari satu Sun SPOT ke Sun SPOT lain. Kami mengimplementasikannya dalam bentuk aplikasi lain =D Jadi, pengiriman pesan juga dilakukan dengan RPC!

Aplikasi Manager yang bertugas untuk mengatur instalasi aplikasi ditulis dalam bahasa Java. Sedangkan, aplikasi router yang menjadi aplikasi standar pada Lua SPOT ditulis dalam bahasa Lua! Konsekuensinya, andai fungsi routing yang ada tidak dapat memenuhi kebutuhan, silakan buat fungsi routing yang baru yang ditempatkan menjadi aplikasi baru atau bahkan mengantikan yang ada.

Konsep sederhana namun sangat canggih ini saya adaptasi dari cara komunikasi yang digunakan oleh Smartcard. Kebetulan dulu saya juga pernah mengerjakan proyek Smartcard di UI 🙂

Ada satu konsep baru dalam dunia jaringan komputer, yaitu active network. Hal ini didefinisikan sebagai sebuah jaringan yang dapat diubah perilakunya dengan memasang sebuah aplikasi ke jaringan tersebut. Sebagai contoh, kita bisa mengirim sebuah paket data yang berisi program kecil. Router yang menerima paket data ini akan membaca program tersebut dan mengeksekusinya. Lua SPOT yang dibuat ini dapat dijadikan sebagai dasar untuk membangun active network tersebut 🙂

Jadi, bisa dibilang pada dasarnya Lua SPOT adalah sebuah RPC server yang menerima pesan dan meneruskannya ke aplikasi/fungsi yang ada. Aplikasi yang ada ditulis dalam bahasa skrip Lua dan dapat dipasang secara dinamis melalu jaringan nirkabel yang ada.

Yap, sekian saja penjelasan (yang tidak bisa dibilang) singkat atas proyek tugas kuliah yang saya kerjakan dua bulan lalu. Tuk informasi lebih lanjut, silakan cek dokumentasi yang sudah saya letakkan di halaman proyek: http://github.com/fajran/luaspot/tree/master 🙂