1 puan yazan GN⁺ 4 시간 전 | 1 yorum | WhatsApp'ta paylaş
  • Veri yapılarında öğeleri virgülle ayırırken sondaki ayırıcıya izin verilirse, öğe ekleme·silme·yeniden sıralama aynı tür metin değişikliğiyle işlenir
  • JSON, son üyenin ardından gelen virgülü yasakladığı için en sona anahtar eklerken veya silerken mevcut satırı da değiştirmeyi gerektiren bir özel durum ortaya çıkar
  • Haskell kayıtları, TLA+ değişken bildirimleri ve Prolog kuralları da ayırıcı konumu ya da bitiş simgesi nedeniyle ilk satır ve son satır değişikliklerini farklı şekilde ele alır
  • Python ve Go sondaki virgüle izin verir ama baştaki virgüle izin vermez; Alloy ise hem baştaki hem sondaki virgüle izin verir
  • Sondaki ayırıcılar kontrol yapılarında ayrıştırma belirsizliği yaratabilir; Python’daki tek öğeli tuple örneğinde olduğu gibi veri sözdiziminde de anlam ayrımı için kullanılabilir

JSON’da son virgül sorunu

  • JSON nesnelerinde üyeler arasında virgüle izin verilir, ancak son üyeden sonra gelen virgül sözdizimi açısından geçerli değildir
{
    "a": 1,
    "b": 2,
    "c": 3
}
  • Aynı nesnede "c": 3, gibi son üyeden sonra virgül eklenirse bu geçersiz JSON olur
{
    "a": 1,
    "b": 2,
    "c": 3,
}
  • Sondaki virgüle izin verilseydi, "a" önüne "x" eklerken ve "c" sonrasına "y" eklerken yalnızca aynı tür satır eklemeleri gerekirdi
{
+   "x": 0,
    "a": 1,
    "b": 2,
    "c": 3,
+   "y": 4,
}
  • Mevcut JSON sözdiziminde son konuma anahtar eklerken mevcut son satır "c": 3 satırına da virgül eklemek gerektiğinden değişiklik daha karmaşık hale gelir
{
+   "x": 0,
    "a": 1,
    "b": 2,
-   "c": 3
+   "c": 3,
+   "y": 4
}
  • Öğe kaldırılırken de yalnızca ilgili satırı silmek yetmez; son satırda sonda kalan bir virgül kalmadığından emin olmak gerekir
  • Nesne değerinin kendisi çok satırlı bir dizi ya da nesneyse, “sondaki virgül yok” kuralı nedeniyle dönüşüm daha da karmaşıklaşır

Diğer dillerde benzer örnekler

  • Haskell kayıtları

    • Haskell, kayıt tiplerinde virgülü her satırın başına koyan “kısmi madde işareti” stilini kullanabilir
    data Drone = Drone
      { xPos :: Int
      , yPos :: Int
      , zPos :: Int
      }
    
    • Bu yaklaşım son satırı değiştirmeyi kolaylaştırır, ancak ilk satırı değiştirmeyi daha zor hale getirir
  • TLA+

    • TLA+’ta değişken listeleri ve dizilerde sondaki virgül olmayan biçim geçerlidir
    VARIABLES a, b, c
    vars ==
    
    • Aynı sözdiziminde son öğeden sonra virgül eklenirse geçersiz olur
    VARIABLES a, b, c,
    vars ==
    
    • TLA+ belirtimleri yazarken en üst düzey değişkenlere sürekli yenileri eklendiği için bu kısıt rahatsız edicidir
    • PlusCal DSL’de aynı sorun yoktur ve değişken bildirimleri noktalı virgülle sıralanabilir
    (*--algorithm foo {
    variables a; b; c;
    
  • Prolog

    • Prolog gibi mantık dilleri yalnızca sondaki ayırıcıya izin vermemekle kalmaz, ayrıca ayrı bir bitiş simgesi de kullanır
    foo(A, B, C) :-
        A = 1, % comma
        B = 2, % comma
        C = 3. % period!
    
    • Son noktayı ayrı bir satıra koyma yöntemi bunu süslü parantez gibi göstermeyi sağlayabilir, ancak bu standart sözdizimi değildir ve yine de sondaki ayırıcı elde edilmez
    foo(A, B, C) :-
        A = 1,
        B = 2,
        C = 3
    .
    

Daha iyi yaklaşım

  • Sondaki ayırıcıya izin veren diller

    • Go, map literal’larında son öğeden sonra virgüle izin verir
    valid := map[string]int{
            "a": 1,
            "b": 2,
            "c": 3,
        }
    
    • Python da dictionary’lerde son öğeden sonra virgüle izin verir
    valid = {
      "a": 1,
      "b": 2,
      "c": 3,
    }
    
    • Python ve Go’da virgül sona gelebilir ama başa gelemez; bu yüzden tam bir madde işareti stili oluşturulamaz
    invalid = {
        , "a": 1
        , "b": 2
        , "c": 3
    }
    
  • Baştaki ayırıcı ve Alloy

    • TLA+, öne alınmış birleşim ve öne alınmış mantıksal veya işlemlerine izin verir ama (a &&) gibi sona eklenen biçime izin vermez
    // Not TLA+ but the same semantics
    || && a == 1
       && b == 2
    
    || && a == 3
       && b == 4
    
    • Alloy, hem baştaki virgüle hem sondaki virgüle izin verir
    sig Valid {
        , a: 1
        , b: 2
    }
    
    sig AlsoValid {
        a: 1,
        b: 2,
    }
    
    • Alloy boş ayırıcılara da izin verir; bu yüzden yalnızca birden fazla virgül içeren satırlar da geçerli sayılır
    sig StillValid {
        ,, a: 1,,
        ,,,,,,,,,
        ,, b: 2,,
    }
    
    • Bu tür biçime bazı kişiler “stuttering” adını veriyor

Karşı argüman: ayrıştırma belirsizliği

  • Prolog’un kontrol ayırıcıları

    • Sondaki ayırıcıya karşı argümanlardan biri, ayrıştırmanın belirsiz hale gelebilmesidir
    • Prolog’da bir kural noktayla biterse foo ve barın ayrı tanımlar olduğu açıktır
    foo(A, B) :-
        A = 1,
        B = 2.
    
    bar(c).
    
    • Kural bitiş simgesi virgülle değiştirilirse bar(c) ifadesi foo tanımının bir parçası olarak yorumlanabilir
    foo(A, B) :-
        A = 1,
        B = 2,
    
    bar(c),
    
    • Bu durumda foo, ancak bar(c) de doğruysa doğru kabul edilecek şekilde yorumlanabilir
  • Ruby’de metot çağrıları

    • Ruby’de satır sonundan sonra da metot zinciri devam edebilir; aşağıdaki kod 5 yazdırır
    puts 3.
         succ().
         succ()
    
    • Metot çağrılarından sonra sondaki ayırıcıya izin verilirse quux()’un en üst düzey bir fonksiyon mu yoksa foo’nun bir metodu mu olduğu belirsizleşir
    foo.
      bar().
      baz().
    
    quux()
    
    • Prolog ve Ruby örnekleri veri ayırıcılarıyla değil, kontrol ayırıcılarıyla ilgili belirsizliklerdir

Veri sözdiziminde istisna: Python tuple’ı

  • Python, parantezleri hem ifadeleri gruplamak hem de tuple tanımlamak için kullanır
  • (2+3) bir ifadenin değerlendirilmesi olarak işlenir ve int olur
>>> x = (2+3)
>>> type(x)

  • (2+3,) ise sondaki virgül nedeniyle tek öğeli bir tuple olarak işlenir
>>> x = (2+3,)
>>> type(x)

  • Python’daki bu örnekte sondaki veri ayırıcısı, ifade ile tek öğeli tuple arasında ayrım yapma işlevi görür

1 yorum

 
GN⁺ 4 시간 전
Lobste.rs görüşleri
  • JSON sözdizimi, bir nesnenin iki üyesi arasına virgül konulabileceğini ama üyeden sonra sonda gelen virgül konulamayacağını söyler. Buna “tasarım hatası” denebileceğini düşünmüyorum. Çünkü bu bir seçenek değildi JSON, 2000~2001 civarında ECMAScript 3'ün bir alt kümesi olarak oluşturuldu ve bilgilendirici RFC 4627 ise 2006'da yazıldı. JSON'un amacı ve başarısının anahtarı, JavaScript'in bir alt kümesi olması sayesinde tarayıcıda doğrudan eval ile çalışabilmesiydi; tarayıcıların yerel JSON API'si ise ancak 2009'da eklendi ES5'te sonda gelen virgülün tanımlanması da Aralık 2009'da oldu; yani sonda gelen virgüllü JSON, daha en baştan amacına uyan bir şey olarak var olamazdı

    • Yalnızca aktif eylemleri hata olarak görüyor gibisin ama hiçbir şey yapmamak da bir seçimdir; dolayısıyla buna hata demek de bence makul
  • Prolog'da en sık yaşadığım rahatsızlıklardan biri bu. Yüklemler üzerinde çalışırken sona ,true. eklemek işe yarıyor; böylece yukarıdaki satırları yeniden düzenlerken veya yorum satırı yaparken en sondaki noktayı dert etmene gerek kalmıyor

    • Benzer şekilde SQL'de ekibimiz where true / and ... / and ... biçiminde WHERE koşulunu kullanıyor. Buradaki eğik çizgiler satır sonunu ifade ediyor Bu sayede herhangi bir koşulu özel durum gibi ele almadan kolayca düzenleyebiliyoruz
  • Zig, sonda gelen virgülü destekliyor ve bunu yapılandırılamayan formatter'ı kontrol etmek için kullanabiliyor .{1, 2, 3,} şu hale dönüşüyor

    .{
       1,
       2,
       3,
    }
    

    Ayrıca dikey biçimlendirilmiş literal'de sonda gelen virgülü kaldırmak, yatay hizalama istediğin anlamına geliyor: .{ 1, 2, 3 } Bu şu durumlarda da çalışıyor: kapsayıcı tür tanımı struct { a: u32, b: u32, }, fonksiyon imzası fn foo(a: u32, b: u32,) void {}, fonksiyon çağrısı foo(1, 2,); Tüm bu durumlarda otomatik biçimlendirmeyi sonda gelen virgülle kontrol edebiliyorsun Bu özelliği o kadar sevdim ki kendi HTML dil sunucuma/otomatik formatter'ıma da ekledim Before:

    Foo
    
    

    After:

    Foo
    
    

    https://github.com/kristoff-it/superhtml

  • %100 katılıyorum. Sonda gelen ayırıcılar olmayan yeni diller bende kişisel olarak hafif bir eksi puan alıyor. Dilin sözdiziminden nefret edecek kadar değil ama küçük bir yara gibi, rahatsız edici bir şey

    • Fonksiyon çağrılarında da mı öyle? foo(1,2,3,4,)? bar(,1,2,3,4)? foo() değişken sayıda parametreye izin veriyorsa son argüman nil mi oluyor? bar() için ilk parametre nil mi oluyor?
  • Clojure ve EDN'de virgül boşluk sayılır. Genelde aynı satırdaki map literal içinde anahtar-değer çiftleri arasında geleneksel olarak kullanılır ama tamamen isteğe bağlıdır

    {:a 1 :b 2}
    ;=> {:a 1, :b 2}
    {:a,1,,,,,,,,,,:b,2,} ; if you must
    ;=> {:a 1, :b 2}
    
  • Bence burada gerilim yaratan başlıca neden, aynı satırda birden çok öğe olduğunda bir şekilde ayırıcıya ihtiyaç duyulması

    function(1, 2, 3, 4)
    

    Böyle durumlarda satır bazlı diff ile argüman ekleyip çıkarmak her zaman tuhaf görünür. Tek bir argümanı yorum satırı yapmak bile biraz dikkat ve emek ister. Bunun karşılığında bir satıra birden fazla öğe sığdırmanın kısalığını kabul etmiş olursun Ama satır başına tek bir öğe koymaya başladığında, ideal olarak daha temiz diff'ler ve basit satır yorumlarıyla kolayca devre dışı bırakma yöntemi istersin Açık cevap, satır sonunu standart ayırıcı olarak ele almaktır

    function(
      1
      2
      3
    )
    

    Birçok dil ; için bunu yapıyor. Bir satıra birden çok ifade koymamayı teşvik eden bir stile sahipsen ; neredeyse hiç görünmez. Virgül için de aynısını yapan bir dil bilmiyorum ama hobi dili projelerinde denemek istediğim olmuştu Elbette Lisp, alt ifadeler ve alt öğeler her zaman tamamen ayrıldığı için hiç ayırıcı olmadan bu sorunu pas geçiyor

  • Lisp'i, daha doğrusu S-ifadelerini sevmemin nedenlerinden biri de bu. Düşünmem gereken bir ayrıntı daha eksiliyor