- Dalam struktur data, jika pemisah trailing diizinkan saat item dipisahkan dengan koma, penambahan, penghapusan, dan penataan ulang item bisa diperlakukan sebagai perubahan teks dengan pola yang sama
- JSON melarang koma setelah member terakhir, sehingga saat menambahkan atau menghapus key di posisi paling akhir muncul kasus khusus yang juga memaksa perubahan pada baris yang sudah ada
- Record Haskell, deklarasi variabel TLA+, dan aturan Prolog juga menangani perubahan pada baris pertama dan terakhir secara berbeda karena posisi pemisah atau simbol penutup
- Python dan Go mengizinkan koma trailing tetapi tidak mengizinkan koma leading, sementara Alloy mengizinkan koma leading maupun trailing
- Pemisah trailing dapat menimbulkan ambiguitas parsing pada struktur kontrol, dan dalam beberapa sintaks data juga dipakai untuk membedakan makna, seperti tuple satu elemen di Python
Masalah koma terakhir di JSON
- Dalam objek JSON, koma di antara member diperbolehkan, tetapi koma setelah member terakhir tidak diizinkan oleh tata bahasa
{
"a": 1,
"b": 2,
"c": 3
}
- Pada objek yang sama, jika koma ditambahkan setelah member terakhir seperti
"c": 3,, hasilnya menjadi JSON yang tidak valid
{
"a": 1,
"b": 2,
"c": 3,
}
- Jika koma trailing diizinkan, menambahkan
"x" sebelum "a" dan "y" setelah "c" hanya memerlukan penambahan baris dengan bentuk yang sama
{
+ "x": 0,
"a": 1,
"b": 2,
"c": 3,
+ "y": 4,
}
- Dalam tata bahasa JSON saat ini, saat menambahkan key di posisi terakhir, baris terakhir yang sudah ada yaitu
"c": 3 juga harus diberi koma, sehingga perubahannya menjadi lebih rumit
{
+ "x": 0,
"a": 1,
"b": 2,
- "c": 3
+ "c": 3,
+ "y": 4
}
- Saat menghapus elemen pun, tidak cukup hanya menghapus baris terkait; harus dipastikan juga tidak ada koma trailing yang tersisa pada baris terakhir
- Jika nilai objek itu sendiri berupa array atau objek multiline, transformasi akibat “tanpa koma trailing” menjadi lebih rumit lagi
Kasus serupa di bahasa lain
-
Record Haskell
- Haskell dapat memakai gaya “bullet point parsial” pada tipe record, dengan koma ditempatkan di awal tiap baris
data Drone = Drone
{ xPos :: Int
, yPos :: Int
, zPos :: Int
}
- Pendekatan ini memudahkan perubahan pada baris terakhir, tetapi justru membuat perubahan pada baris pertama lebih sulit
-
TLA+
- Di TLA+, bentuk tanpa koma akhir pada daftar variabel dan sequence adalah valid
VARIABLES a, b, c
vars ==
- Dalam sintaks yang sama, jika koma ditambahkan setelah item terakhir maka hasilnya tidak valid
VARIABLES a, b, c,
vars ==
- Saat menulis spesifikasi TLA+, variabel tingkat atas sering terus ditambahkan, sehingga batasan ini terasa tidak nyaman
- Dalam DSL PlusCal, masalah yang sama tidak ada, dan deklarasi variabel dapat ditulis sebagai daftar yang dipisahkan titik koma
(*--algorithm foo {
variables a; b; c;
-
Prolog
- Bahasa logika seperti Prolog bukan hanya tidak mengizinkan pemisah trailing, tetapi juga memakai simbol terminasi terpisah
foo(A, B, C) :-
A = 1, % comma
B = 2, % comma
C = 3. % period!
- Simbol titik terakhir bisa dianggap seperti kurung kurawal penutup jika diletakkan di baris terpisah, tetapi itu bukan sintaks standar dan tetap tidak memberi pemisah trailing
foo(A, B, C) :-
A = 1,
B = 2,
C = 3
.
Pendekatan yang lebih baik
-
Bahasa yang mengizinkan pemisah trailing
- Go mengizinkan koma setelah item terakhir dalam map literal
valid := map[string]int{
"a": 1,
"b": 2,
"c": 3,
}
- Python juga mengizinkan koma setelah item terakhir dalam dictionary
valid = {
"a": 1,
"b": 2,
"c": 3,
}
- Koma di Python dan Go boleh muncul di belakang, tetapi tidak di depan, sehingga gaya bullet point yang sepenuhnya konsisten tetap tidak bisa dibuat
invalid = {
, "a": 1
, "b": 2
, "c": 3
}
-
Pemisah leading dan Alloy
- TLA+ mengizinkan konjungsi leading dan disjungsi leading, tetapi tidak mengizinkan bentuk yang ditempelkan di belakang seperti
(a &&)
// Not TLA+ but the same semantics
|| && a == 1
&& b == 2
|| && a == 3
&& b == 4
- Alloy mengizinkan koma leading dan koma trailing sekaligus
sig Valid {
, a: 1
, b: 2
}
sig AlsoValid {
a: 1,
b: 2,
}
- Alloy juga mengizinkan pemisah kosong, sehingga baris yang hanya berisi beberapa koma tetap dianggap valid
sig StillValid {
,, a: 1,,
,,,,,,,,,
,, b: 2,,
}
- Bentuk seperti ini oleh sebagian orang disebut “stuttering”
Sanggahan: ambiguitas parsing
-
Pemisah kontrol di Prolog
- Salah satu argumen yang menolak pemisah trailing adalah bahwa hal itu dapat membuat parsing menjadi ambigu
- Dalam Prolog, saat aturan diakhiri dengan titik, jelas bahwa
foo dan bar adalah definisi yang terpisah
foo(A, B) :-
A = 1,
B = 2.
bar(c).
- Jika simbol akhir aturan diganti menjadi koma,
bar(c) bisa ditafsirkan sebagai bagian dari definisi foo
foo(A, B) :-
A = 1,
B = 2,
bar(c),
- Dalam kasus ini,
foo bisa ditafsirkan benar hanya jika bar(c) juga benar
-
Pemanggilan metode Ruby
- Di Ruby, rantai metode tetap bisa dilanjutkan setelah line break, dan kode di bawah ini mencetak 5
puts 3.
succ().
succ()
- Jika pemisah trailing diizinkan setelah pemanggilan metode, akan menjadi tidak jelas apakah
quux() adalah fungsi top-level atau metode milik foo
foo.
bar().
baz().
quux()
- Kasus Prolog dan Ruby ini berkaitan dengan ambiguitas pada pemisah kontrol, bukan pemisah data
Pengecualian dalam sintaks data: tuple Python
- Python memakai tanda kurung baik untuk pengelompokan ekspresi maupun definisi tuple
(2+3) diperlakukan sebagai evaluasi ekspresi, sehingga hasilnya bertipe int
>>> x = (2+3)
>>> type(x)
(2+3,) diperlakukan sebagai tuple satu elemen karena adanya koma trailing
>>> x = (2+3,)
>>> type(x)
- Dalam kasus Python ini, pemisah data trailing berfungsi membedakan ekspresi biasa dari tuple satu elemen
1 komentar
Komentar Lobste.rs
Tata bahasa JSON memang menyatakan bahwa koma boleh diletakkan di antara dua anggota objek, tetapi koma penutup tidak boleh diletakkan setelah anggota. Saya rasa ini tidak bisa disebut sebagai “kesalahan desain”, karena itu bukan sebuah pilihan JSON dibuat sekitar 2000~2001 sebagai subset dari ECMAScript 3, dan RFC 4627 yang bersifat informatif ditulis pada 2006. Karena merupakan subset JavaScript, JSON bisa langsung dijalankan di browser dengan
eval, dan itulah tujuan JSON sekaligus kunci keberhasilannya; API JSON native di browser sendiri baru ditambahkan pada 2009 ES5 baru menstandarkan koma penutup pada Desember 2009, jadi JSON dengan koma penutup sejak awal memang tidak mungkin ada karena tidak sesuai dengan tujuannyaIni salah satu ketidaknyamanan yang paling sering saya alami di Prolog. Saat mengerjakan predicate, akan lebih nyaman jika menambahkan
,true.di akhir, karena saat menyusun ulang baris di atasnya atau menjadikannya komentar, kita tidak perlu memikirkan titik di akhirwhere true / and ... / and ...; garis miring di sini berarti baris baru Dengan begitu, kondisi apa pun bisa diedit dengan mudah tanpa perlakuan khususZig mengizinkan koma penutup, dan ini bisa dipakai untuk mengendalikan formatter yang tidak dapat dikonfigurasi
.{1, 2, 3,}akan diubah menjadi seperti iniDan pada literal yang diformat vertikal, menghapus koma penutup berarti meminta penyusunan horizontal:
.{ 1, 2, 3 }Ini juga berlaku untuk definisi tipe kontainerstruct { a: u32, b: u32, }, signature fungsifn foo(a: u32, b: u32,) void {}, dan pemanggilan fungsifoo(1, 2,);Dalam semua kasus itu, koma penutup bisa dipakai untuk mengendalikan auto-format Saya sangat menyukai fitur ini sampai-sampai saya menambahkannya juga ke language server/auto-formatter HTML saya Before:After:
https://github.com/kristoff-it/superhtml
Saya 100% setuju. Bahasa baru tanpa separator penutup bagi saya pribadi langsung sedikit berkurang nilainya. Bukan sampai membuat saya membenci tata bahasanya, tetapi ini semacam ketidaknyamanan kecil yang terus terasa
foo(1,2,3,4,)?bar(,1,2,3,4)? Kalaufoo()mengizinkan parameter dengan jumlah variabel, apakah argumen terakhir adalahnil? Apakah parameter pertamabar()adalahnil?Dalam Clojure dan EDN, koma adalah spasi. Biasanya secara konvensi dipakai di antara pasangan key-value dalam map literal pada baris yang sama, tetapi sepenuhnya opsional
Menurut saya, alasan besar munculnya ketegangan di sini adalah karena saat ada beberapa klausa pada satu baris, kita memang membutuhkan separator dalam bentuk apa pun
Dalam kasus seperti ini, menambah atau menghapus argumen berdasarkan perbedaan per baris selalu terlihat canggung. Bahkan saat hanya ingin menjadikan satu argumen sebagai komentar, tetap perlu sedikit perhatian dan usaha. Sebagai gantinya, kita menerima keringkasan karena menaruh banyak item dalam satu baris Tetapi begitu kita mulai menaruh satu klausa per baris, idealnya kita ingin perbedaan yang lebih rapi dan cara yang mudah untuk menonaktifkannya dengan komentar baris biasa Jawaban yang jelas adalah memperlakukan baris baru sebagai separator standar
Banyak bahasa melakukan ini untuk
;. Jika gayanya mendorong agar tidak menaruh beberapa pernyataan dalam satu baris, maka;hampir tidak pernah terlihat. Saya tidak tahu ada bahasa yang melakukan hal yang sama untuk koma, tetapi saya pernah ingin mencobanya dalam bahasa hobi Tentu saja, Lisp menghindari masalah ini karena subekspresi dan subklausa selalu sepenuhnya dipisahkan, sehingga tidak ada separator sama sekaliIni salah satu alasan saya menyukai Lisp, atau lebih tepatnya S-expression. Satu detail yang perlu dipikirkan jadi berkurang