KTV. Новый JSON

    В своём развитии мне пришлось пробежаться по нескольким этапам в нескольких направлениях: Java → Objective C → Swift, Web → Enterprise → Mobile, XML → JSON. Этим путём я шёл на протяжении более 15 лет, подолгу и внимательно задерживаясь на каждом этапе. Нужно идти дальше. За мобильными приложениями можно придумать что-то (наверное, пока не хочется), языков вообще пруд-пруди, ничего интереснее JSON'а не придумали. А зачем его менять?

    Дальше я расскажу почему мне не очень нравится JSON для некоторых применений и как, по моему мнению, его можно доработать, чтобы стало немного удобнее.

    Сразу должен отметить, что не рассматриваю KTV, как замену JSON. И ни в коем случае не рассматриваю его для использования в JavaScript'е. Это будет неудобно и неправильно. С другой стороны, ситуация, когда система описания объектов JavaScript'а используется в других языках для работы с типизированными данными — тоже странная, и её хочется поправить.

    Если вам интересно, что послужило изначальной причиной создания такого формата — можно почитать про S2 и про причины создания формата KTV

    Плюсы и минусы JSON


    Сам по себе JSON хороший.

    • Простой. Отдельное спасибо за отсутствие комментариев. Если бы их оставили, туда начали бы пихать мета-информацию (потому что JSON бедный очень) и нотация быстро превратилась бы в помойку.
    • Выразительный. Не так, как XML, но достаточно для широкого круга задач.
    • Сильно короче в записи, чем XML.

    Болезни JSON'а растут из истории создания. Нужно было, чтобы eval(что-то) в JavaScript'е выдавал объект, с которым удобно работать. К сожалению, eval'ы в других языках работают обычно по-другому (если вообще присутствуют), и сами языки отличаются. Используя этот формат с не-JavaScript, видны его недостатки.

    • Кавычки. По стандарту (в качестве стандарта я беру текст отсюда: http://www.json.org) все названия должны заключаться в кавычки. Если мы используем JSON, например, для передачи данных по сети, то это излишество.
    • Отсутствие типизации. Точнее, типы есть, но всего строка/число/true/false/null. И объекты с массивами. Всё. Ни дат, ни целых/дробных чисел нет. Нет возможности пометить типами объекты, чтобы проще было модель понять.
    • Отсутствие стандартов записи объектов. Это, например, может привести к массивам со смешанными объектами внутри. Когда приходится такое парсить — становится больно.
    • Отсутствие ссылок. Если в JSON записывать иерархическую структуру объектов, то регулярно встречаются ссылки на один и тот же объект из разных мест. JSON не даёт возможности сослаться на первое использование. Нужно либо что-то придумывать, либо повторять объекты целиком, что плохо сказывается на размере структуры и на сложности парсинга.

    Я попробовал найти формат, который бы работал как JSON (в идеале — являлся бы его надмножеством), но при этом умел стандартным образом решать часть или все перечисленные выше проблемы. Нашёл YAML.

    YAML


    YAML хорош. Он почти надмножество JSON, хорошо определён (http://www.yaml.org/spec/1.2/spec.html), легко читается. Но вместе с тем:

    • вложенность структур определяется отступами. В случае с передачей информации удобна была бы возможность их убирать. Любителей табуляции также не уважают, отступы делаются только пробелами.
    • YAML излишне сложный. Большое количество специальных символов, договоренности о структуре делают поддержку YAML'а сложной, парсеры — сложными (YAML 1.2 появился уже 7 лет как, но, согласно новостям с сайта, парсеры до сих пор поддерживают в основном предыдущие версии).

    В общем, YAML «не пошёл». Кроме него популярных форматов я не знаю. Если вдруг вы знаете — пишите, с удовольствием посмотрю.

    Пришло время представить то, что получилось у меня.

    KTV


    Key-Type-Value. Я так называю этот формат.

    Напишем простой объект на JSON'е:

    {
        "name": "Alex",
        "coolness": 3.1415,
        "isAProgrammer": true
    } 

    Если переписать это же на KTV, получится:

    {
        name: Alex
        coolness: 3.1415
        isAProgrammer: true
    }

    Казалось бы, ничего не поменялось. Но давайте присмотримся:

    • убрались кавычки. Они теперь обязательны только, если в ключе или значении есть нетривиальная строка. Обычные ситуации кавычек не требуют.
    • убрались запятые в конце строк. Их (или точки с запятой) можно ставить, если пишем несколько определений в одну строку. Но в традиционной записи их можно опустить.

    И первый и второй примеры — оба являются корректными KTV-файлами. Это очень важно, так как позволяет в KTV-парсер запихнуть стандартный JSON, и он его съест с удовольствием. А можно воспользоваться удобствами, типами например.

    Где же тут типы? В вышеприведенном случае типы выводятся из значений. «Alex» — это строчный литерал, значит тип name'а — «string», coolness'у достался «double», а isAProgrammer — «bool». Кроме этих типов есть ещё «null» (он же «nil», привет коллегам), «int» и «color». Давайте запишем этот же пример, но полностью указывая типы:

    {
        name(string): Alex
        coolness(double): 3.1415
        isAProgrammer(bool): true
    }

    Никуда не делись и вложенные объекты/массивы. С дополнениями:

    • И у объектов и у массивов могут быть типы. Для массива тип — это общий тип каждого объекта в массиве. Нельзя положить два разных типа (строка/число, или разные объекты) в массив.
    • Тип массива или объекта также может указывать на класс, к которому этот объект или массив необходимо привести при парсинге. Например:
      property(font): {name:..., size:...}
      может обозначать объект-шрифт, а
      property(point): [2, 3]
      может при распознавании быть преобразовано в объект-точку. В принципе, точку можно сделать также объектом (с пропертями x, y), но зачем? Мы ведь и так знаем, что там где.

    Присутствуют сылки, возможность сослаться на любую другую пропертю. Как-то так:

    {
        property: value
        another: @property
    }

    Это позволяет сократить запись некоторых ветвистых объектов, или просто задавать константы, обращаясь к ним в других частях файла. Первая возможность полезна в REST'е, если структура объектов нетривиальная. Вторая — в конфигурационных файлах.

    Идея миксинов также позаимствована из других языков. Они позволяют проперти одного объекта (или объектов) приделать другому объекту. Можно представить себе это, как наследование, но наследование — это из ООП, там поведение наследуется, тут только свойства. Так что лучше смешивать.

    {
        object: { a: ..., b: ...}
        object2(+object): { c: ..., d: ... }
    }

    В данном примере объект object2 будет после парсинга содержать как свои проперти, так и проперти из объекта object. То есть, a, b, c и d.

    Комментарии


    Я не удержался и организовал комментарии. Их можно задавать либо при помощи //, либо #. Оба типа комментариев — строчные, блочных комментариев нет.

    Со вторым типом (который октоторповый) есть небольшая проблема. Дело в том, что литерал цвета предполагается задавать как-раз в стандартном CSS-виде, то есть #rrggbbaa, что конфликтует с текущим вариантом записи комментариев. Так что, возможно, в будущем останется только С-вариант (//).

    Работа с форматом


    Для меня этот формат, и парсер этого формата нужен в двух местах:

    • чтобы хранить стилевую информацию в S2 (развитие Ångström Style System)
    • чтобы можно было улучшить общение между своими собственными серверами на Swift и приложениями на нём же.

    Поэтому я рассматриваю работу с форматом именно для Swift'а. В принципе, формат достаточно простой и не должно быть сложно организовать его парсер в любом языке.

    Проблемы Swift сейчас не позволяют сделать по-настоящему правильную загрузку/сериализацию объектов из/в KTV. Поэтому процесс работы с форматом предполагается следующий:

    • Создаются модельные классы. Как обычные классы (в том числе аннотированные @objc) или структуры. Каждый класс должен реализовывать протокол KTVGenerated.
    • При помощи генератора создаются расширения к этим классам, которые умеют загружать и сериализовывать объекты.
    • Используем сгенерированное для преобразования KTV в объекты и обратно (или в/из JSON).

    Модельная структура может выглядеть, например, так:

    public struct RootObject: KTVGenerated {
        var string:String // просто пропертя
        var stringOrNil:String? // optional
        var int:Int // числа
    
        var stringArray:[String] // массивы
        var stringDictionary:[String:Int] // ассоциативные массивы
    
        var object:ChildObject? // ссылка на другой модельный класс
    
        private var _privateString:String // эта пропертя не будет сериализовываться
        private(set) var _privateSetString:String // эта — тоже
        let _constantString:String // и константы тоже не сериализуем
    }

    Видно, что поддерживаются все основные фичи:

    • Типы (они должны прописываться явно, чтобы генератор смог корректно создать расширения классов.
    • Коллекции (массивы и ассоциативные массивы).
    • Иерархии объектов (ссылки на другие модельные классы)
    • Проперти, которые не участвуют в сериализации (это константы, приватные проперти и проперти с приватными сеттерами)

    История создания такого парсера — тема для отдельной статьи. Задачи одновременного поддержания структур и классов, способы задания атрибутов без наличия самих атрибутов, использование SourceKit'а вместо рефлекшна для анализа файлов, необходимость кастомных мапперов (например, для парсинга нестандартных дат). Сам парсер сейчас в процессе активной разработки, и постоянно меняется. Но, если будет достаточный интерес — выложу рабочий проект, обсудим варианты.

    Польза от очередного формата данных


    image
    https://xkcd.com/927/
    JSON — так себе формат для передачи данных между приложениями. Это — формат описания объектов в JavaScript'е. А мы постоянно используем его для совершенно других целей, впихивая и по делу и без дела.

    Мне кажется, пора переходить к чему-то, более приспособленному к выполняемым задачам. К новому Swift'у с его строгой типизацией, к сложным структурам данных, которые часто приходится передавать на мобильные клиенты с сервера. Нужен формат, синтаксис которого можно будет проверять в IDE, в процессе компиляции и при парсинге. И, мне кажется, что KTV, не меняя кардинально структуру, практически не усложняя уже известный формат, добавляет несколько удобных мелочей.

    Выкладываю экспериментальный исходный код с небольшим описанием. Там больше интересны приёмы для парсинга формата на Swift, нежели парсер. Но вдруг кому интересно будет посмотреть: http://github.com/bealex/KTV

    Скорее всего, я много чего упустил или не учёл. Может, у кого-то есть похожий опыт? Пишите в комментариях, или в почту: alex@jdnevnik.com, обсудим!

    Similar posts

    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 111

      +35
      Оо, в этом месяце еще не было джейсона без кавычек и с комментариями.
        –6
        Велосипеды — это наше всё!
          0
          Не знаете, как бы их найти тут? Я бы почитал про другие попытки, интересно.
            +7
            «Свой JSON» действительно появляется тут чуть ли не каждый месяц. И количество плюсов у комментария выше показывает, что все кроме вас их видят.

            Вот то, что я нашел за 5 минут:

            https://habrahabr.ru/post/247473/
            https://habrahabr.ru/post/269993/
            https://habrahabr.ru/post/269461/
            https://habrahabr.ru/post/130112/
            https://habrahabr.ru/post/248147/
              0
              Спасибо за ссылки!
                +2
                Всё-таки есть и обратная сторона — вы, как и я, заинтересовались заголовком и тизером и зашли почитать. Вопрос — чего мы с вами ожидали от статьи? Лулзов? А может, всё-таки, надеемся что кто-то таки придумал более удобный формат? Если второе, то я думаю, попытки имеют право быть — почему нет?
                  +2
                  Я, например, зашел посмотреть на проблему, которая привела к попытке создания своего формата. Если говорить про сериализацию, то ничего принципиально интересного в дополнительной типизации полей я не вижу, т. к. это усложняет десериализатор, но не даёт гарантий, что пришедший объект валиден (например, могут нарушаться какие-нибудь инварианты).

                  Ну и ради лулзов, ессно.
                  0
                    0
                    Да их еще несколько десятков тут найти можно.
                      0
                      Да, но там я заинтересованное лицо :)
              +1
              Автор пишет об излишестве кавычек (что ошибочно, ибо JSON позволяет в качестве ключа использовать {'i am a key': 'value'}), но в то же время хочет добавлять типы. Странно как-то.
                0
                Кавычки в KTV допустимы, как раз для таких случаев.
                  +1
                  Если мы используем JSON, например, для передачи данных по сети, то это излишество.

                  Я вот об этом. Вас беспокоят лишние байты, но в то же время Вы говорите о том, что нужно передавать типы.
                    0
                    Типы передавать необязательно, это я тоже отметил. Также, байтики нужно не только передавать, но и писать.

                    Ещё строки не способствуют строгой типизации. Внутри JSON'а — часто объекты, объекты, которые парсятся в строго-типизированные языки. Строки маппить в строготипизированный язык тяжело (посмотрите, сколько парсеров JSON'а существует). Мне кажется, что если зажать этот формат несколько сильнее, то его проще будет редактировать, проще контролировать и работать с ним. Не в любом контексте, а в том, который я указываю.
                      +2
                      Если JSON объект парсится в строго типизированном языке, то, скорее всего, существует контракт(модель). Т.е. принимающая сторона ожидает, что в проперти "name" будет лежать строка, а в проперти "age" целочисленный тип данных.
                        0
                        Это правда, но часто модель приходится делать уже по существующим JSON'ам (которые делались для сайта, например), поэтому изначально контракты отсутствовали, что приводит к очень, очень сложным моделям для парсинга. Как я отметил в статье, например, разные типы кладутся в коллекции или названия полей недопустимы для целевого языка.

                        Опять же, ссылки на объекты часто бывают полезны.
                          +3
                          то приводит к очень, очень сложным моделям для парсинга

                          Это уже проблема не JSON-а
                            –2
                            Конечно, это моя проблема, как разработчика. Про это я и говорю.
                              +2
                              А чем поможет ваш формат, если типы все равно не будут указаны (они ж не обязательны) ?
                                –1
                                Если не указывать типы, это просто чуть более короткий JSON, что приятно. Плюс, стандартные типы выведутся из типов литералов.
                                  +4
                                  А потом вы будете искать баги в своём парсере? Более короткий JSON? Зачем?
                  +2
                  Впрочем, использование такого значения в качестве ключа — порочная практика, так как не маппится нормально на разные языки программирования. Поэтому, всё же, ключи обычно — это строки без пробелов, и этот случай хочется сделать проще в написании.
                    +1
                    Вопрос не в хорошей\плохой практике, а в спецификации.
                      0
                      Какую спецификацию вы имеете в виду?
                        +1
                        Эту: An object structure is represented as a pair of curly bracket tokens surrounding zero or more name/value pairs. A name is a string.
                          0
                          А как эта спецификация относится к новому формату? :-)
                            0
                            Вы утверждали, что кавычки излишни, я же возразил что это не так. При чем это было написано "между прочим". Суть комментария была совершенно другая.
                              0
                              :) Ок, понял.
                    +1
                    Только двойные кавычки, прошу отметить. Иначе — ни один парсер не пропустит.
                    +1
                    Это формат удобочитаемый или для передачи данных по сети в большом объёме/с большой скоростью/быстрое сжатие? Потому что с первым проблем нет, а со вторым существующие решения не иделальны.
                      0
                      Смотря что подразумевается под большой скоростью и быстрым сжатием. Сам формат для больших структур с повторяющимися объектами должен быть сильно проще и короче, чем JSON (за счёт ссылок, например). Он по-прежнему текстовый, в этом смысле он будет похож на JSON (не как Protocol Buffers, например), и будет сжиматься как обычный текст (типы, например, в случае использования сжатия, почти исчезнут, так как они одинаковые).
                        0
                        Ничто не мешает использовать protobuf для описания формата и при этом сериализовывать данные в JSON.
                          0
                          Ммм. Занятный вариант, не думал пока про такое. Спасибо за идею!
                      +5
                      Передача строк без кавычек бред. Каждый раз придется проверять на ключевые слова, раз. Два, это заряженый пистолет нацеленый в ногу. Рано или поздно вы просмотрите код запроса сами.

                      object: { a: ..., b: ...}
                      object2(+object): { c: ..., d: ... }

                      Вот это зачем? И как программа должна догадываться когда это использовать? И что делать парсеру если вы поменяли свойства местами?

                      property: value
                      another: @property

                      Как ссылаться на объекты ниже, выше по иерерхии или в другой ветке?

                      Типы указывать вообще не нужно. Для всех данных есть модель которая их описывает. Если модели нет, то программе не с чем работать.

                      Посмотрите вот это.
                        –1
                        Передача строк без кавычек бред.

                        Я так не считаю. Плюс, я не говорю, что кавычки не нужны, я говорю, что они обычно не нужны в именах пропертей.

                        И что делать парсеру если вы поменяли свойства местами?

                        Резолвить это, как и ссылки, после чтения файла.

                        Как ссылаться на объекты ниже, выше по иерерхии или в другой ветке?

                        Сейчас у меня ссылки идут от корня структуры, это решает все проблемы.

                        Типы указывать вообще не нужно. Для всех данных есть модель которая их описывает.

                        Это не всегда так, плюс, иногда бывает удобно саму модель строить по этому файлу (про это я выложу статью на днях). В этом случае типы — необходимая вещь. Если же есть модель, то типы можно не указывать, как и в JSON.
                          +2
                          Я так не считаю. Плюс, я не говорю, что кавычки не нужны, я говорю, что они обычно не нужны в именах пропертей.

                          К названию свойств у меня нет притензий. Я про литерали строк ("Alex" => Alex).

                          Резолвить это, как и ссылки, после чтения файла.

                          Только вот зачем это? К тому-же что делать с коллизиями?

                          Сейчас у меня ссылки идут от корня структуры, это решает все проблемы.

                          Так себе решение.
                          Если уж хочется без свойств то лучше как-то так:

                          {
                              common#uniqueId: { ... },
                              object1: { prop: #uniqueId },
                              object2: { prop: #uniqueId }
                          }

                          Это не всегда так, плюс, иногда бывает удобно саму модель строить по этому файлу (про это я выложу статью на днях). В этом случае типы — необходимая вещь. Если же есть модель, то типы можно не указывать, как и в JSON.

                          Если вы строите модель, по запросами которые пишите, у меня для вас плохие новости. Но даже если у вас в руках только одна сторона провода, вот вы сделали запрос и получили ответ:

                          {
                              data: (...)
                          }

                          Во первых, как я узнаю тип корня? Во вторых, если было бы указано свойство data(Type), но у меня нету такого типа в проекте, как мне это поможет? Допустим я посмотрел запрос (нахрен такие апи) и по нему написал тип. Зачем мне теперь тип в ответе?
                          Допустим я получаю динамические данные в виде словаря:

                          // Плохой словарь
                          {
                              itemName1: { ... },
                              itemName2: { ... }
                          }
                          
                          // Хороший словарь
                          [
                              { key: "name1", value: { ... }, type: "Type1" },
                              { key: "name2", value: { ... }, type: "Type2" }
                          ]

                          И тут мне не нужен тип.
                            0
                            Если уж хочется без свойств то лучше как-то так:

                            Да, использование ID — один из способов. Но их сложно поддерживать (это не важно при автогенерации, важно при ручном написании).

                            И тут мне не нужен тип.

                            Да, я просто предлагаю внутри формата поддержку такого рода данных (если требуется). Завтра я опубликую статью про S2, станет чуть понятнее, как именно удобно этим пользоваться.

                            Во первых, как я узнаю тип корня?...

                            Это не та задача, для которой введены (повторюсь, необязательные) типы.

                            Но и тут они могут помочь. Например, приходил объект с типом A, а потом кто-то на сервере решил, что нужен в этом месте тип Б. Принимающая сторона может проверить тип и выдать сообщение об ошибке, вместо попытки впихнуть объект Б внутрь А.
                              0
                              Зачем вы данные руками пишете?
                                0
                                А почему HTTP протокол текстовый?
                                  0
                                  Ну, наверное, потому, что в те времена, когда его придумывали, о контенте в сети думали как о гипертексте (hypertext transfer protocol). Ну, и с тех пор появилось мнение о том, что это неправильно. HTTP 2 — бинарный. А вы зачем спрашиваете? Тоже JSON руками пишете?
                                    –2
                                    Будь HTTP изначально бинарным, то страницы мы сейчас открывали бы не по HTTPS, а по SFTP ;-) Сложное это дело, заниматься отладкой по бинарному протоколу.
                                  0
                                  Завтра будет статья про S2, там будет немного понятнее. Но вообще вопрос не совсем понятен. Что значит «зачем»? Иногда требуется для решения поставленной задачи. :)
                                    0
                                    Весьма интересно, что за задача по передаче данных, когда передаваемые данные руками пишутся.
                                      0
                                      :) Я старался не акцентировать внимание исключительно на передаче данных. Если вдруг где-то пропустил, покажите, пожалуйста. Передача данных — важная, но не единственная задача, решаемая такого рода форматами.
                            +1
                            http://jsonapi.org/ знаю. Проект правильный, будет здорово, если им (или аналогичным, не важно каким, на самом деле) будут пользоваться.
                            0
                            Почему не искаробочный plist?
                              0
                              Он далеко не всегда удобен. Плюс, его совсем неудобно генерировать на стороне сервера.
                                0
                                Уверен, для популярных веб-фреймворков найдется готовый плагин plist-сериализатора.
                                  0
                                  Это правда, но его неудобство не только в отсутствии плагинов. Это XML (или вообще бинарь), что усложняет чтение и запись, удлинняет (в случае текста) формат. Он крайне ограничен по типам, и, в отличие от базового XML — не допускает расширения. Даже вложенные объекты им не записать.

                                  Я пробовал его использовать в разных ситуациях и обычно это оказывалось неудобно.
                              +6
                              JSON — так себе формат для передачи данных между приложениями

                              Почему?

                              По стандарту [...] все названия должны заключаться в кавычки. Если мы используем JSON, например, для передачи данных по сети, то это излишество.

                              Почему это излишество? Это всего лишь более жесткое требование, упрощающее написание парсера.

                              Нет возможности пометить типами объекты, чтобы проще было модель понять.

                              А зачем аннотировать типы данных внутри формата передачи данных? Описывайте их в модели.

                              Отсутствие стандартов записи объектов.

                              Это банально неправда. JSON — и есть такой стандарт.

                              Это, например, может привести к массивам со смешанными объектами внутри.

                              Это позволяет массивы с разнотипными объектами. Это разве плохо?

                              Отсутствие ссылок.

                              Добавите ссылки — получите необходимость обработки циклов. Оно вам надо?
                                –2
                                Это банально неправда. JSON — и есть такой стандарт.

                                Он описывает то, как объекты записываются в JavaScript'е. В других языках, обычно, они описываются совершенно иначе. JSON это не учитывает никак.

                                Я не рассматриваю использование KTV для JavaScript'а, нужно это сразу было отметить, моя ошибка.

                                Это позволяет массивы с разнотипными объектами. Это разве плохо?

                                Да.

                                Добавите ссылки — получите необходимость обработки циклов. Оно вам надо?

                                А без ссылок — структуры разрастаются, порой, в несколько раз. Но есть и достоинства в обоих решениях.
                                  –1
                                  Он описывает то, как объекты записываются в JavaScript'е.

                                  Уже давно нет.

                                  В других языках, обычно, они описываются совершенно иначе.

                                  А кого это волнует? Язык передачи данных не должен учитывать, как описываются объекты на любой стороне, он должен быть совместимым с этими сторонами.

                                  Это позволяет массивы с разнотипными объектами. Это разве плохо?

                                  Да.
                                  Ну то есть возможность написать "у меня есть: корабль, машина, квартира и восемнадцать тонн бриллиантов" — это плохо?


                                  А без ссылок — структуры разрастаются, порой, в несколько раз.

                                  А как же компрессия, про которую вы же выше писали?
                                    0
                                    Уже давно нет.

                                    :) В других языках в названиях полей класса допустимы пробелы? Отсутствуют типы кроме строк, чисел, булевого и null? Ой ли.

                                    А кого это волнует? Язык передачи данных не должен учитывать, как описываются объекты на любой стороне, он должен быть совместимым с этими сторонами.

                                    Ну, давайте вернемся к XML, он тоже всё описывает.

                                    Ну то есть возможность написать «у меня есть: корабль, машина, квартира и восемнадцать тонн бриллиантов» — это плохо?

                                    Абстрактно — хорошо. В реальности использовать такие структуры очень сложно.

                                    А как же компрессия, про которую вы же выше писали?

                                    Вы правы, при передаче данных это менее важно, зип такое сожмет отлично. Но есть и другие моменты.

                                    При парсинге, в случае использования ссылок, можно использовать один и тот же объект в двух (двадцати) местах. Если же вы дублируете объекты в JSON'е, то и в памяти результирующие объекты будут разные. Это плохо.
                                      +2
                                      В других языках в названиях полей класса допустимы пробелы?

                                      В некоторых — да. Но, что важнее, то, как поля названы в передаваемой структуре, не обязано совпадать с тем, как поля названы на принимающей (или передающей) стороне. В некоторых языках, прямо скажем, и полей с классами может не быть, и что?

                                      Отсутствуют типы кроме строк, чисел, булевого и null?

                                      Важно, чтобы были строки, числа и далее по тексту. А то если пытаться охватить в нотации все возможные типы, вы никогда не закончите.

                                      Ну, давайте вернемся к XML, он тоже всё описывает.

                                      Во-первых, ваш логический скачок мне непонятен. XML как раз находится на другой стороне спектра — он очень сильно самодостаточен, в то время как JSON требует контекстной интерпретации.

                                      Ну а во-вторых, XML, кроме избыточности и сложности парсинга ничем не плох, в нем как раз решается половина того, что вас не устраивает.

                                      В реальности использовать такие структуры очень сложно.

                                      Что сложного?

                                      Если же вы дублируете объекты в JSON'е, то и в памяти результирующие объекты будут разные. Это плохо.

                                      Смотря для чего. Ну и да, повторюсь, ссылки — это круто, но как только вы их добавляете, вы получаете необходимость подсчета циклов (а это само по себе мило) и придумывание правил для вывода этой красоты из исходного графа в дерево.
                                        0
                                        … Важно, чтобы были строки, числа и далее по тексту. А то если пытаться охватить в нотации все возможные типы, вы никогда не закончите.

                                        Это правда. Но я и не пытаюсь это сделать.

                                        Я завтра опубликую статью про S2, где будет понятно, зачем я составляю такую структуру.

                                        Что сложного?

                                        Сложность в интерпретации и контроле за такими объектами. В Swift (я пишу именно в контексте этого языка) строгая типизация, коллекции — однотипные. Такие структуры тяжело туда впихнуть.

                                        Далее, сложность в использовании. Требуется обрабатывать массивы (мы сейчас про массивы, не про объекты, где типы у разных полей — разные) специальными средствами, простое итерирование не подходит. Нужно не забыть, что вдруг может попасться другой объект.

                                        Также такое поведение иногда провоцирует на откровенно неправильные структуры, например, когда массивы используются вместо объектов (по первому индексу — ID, потом имя, потом фамилия...).
                                          0
                                          Я завтра опубликую статью про S2, где будет понятно, зачем я составляю такую структуру.

                                          Ну то есть вы, на самом деле, пишете язык под конкретную задачу, но при этом вам не нравится JSON как формат передачи данных.

                                          В Swift (я пишу именно в контексте этого языка) строгая типизация, коллекции — однотипные.

                                          А я пишу на языках со строгой типизацией, где коллекции не однотипны (точнее, полиморфны). Зачем мне ваше искусственное ограничение?

                                          Требуется обрабатывать массивы (мы сейчас про массивы, не про объекты, где типы у разных полей — разные) специальными средствами, простое итерирование не подходит.

                                          Почему не подходит? Идете по коллекции итератором, дальше для каждого объекта принимаете решение. Вплоть до динамической диспетчеризации.
                                            +1
                                            Ну то есть вы, на самом деле, пишете язык под конкретную задачу, но при этом вам не нравится JSON как формат передачи данных.

                                            Я дополнил текст статьи. Как я уже сказал, я не рассматриваю KTV, как замену JSON. И не хочу, чтобы его использовали при работе с JavaScript'ом, это было бы глупо. Но я считаю, что JSON — не самый хороший вариант описания структур данных, в том числе и при их передаче.

                                            Зачем мне ваше искусственное ограничение?

                                            Видимо, вам оно не требуется. :-)

                                            Почему не подходит?

                                            Потому что в общем случае объекты в таком массиве могут быть любые. Динамическая диспетчеризация — это хорошо, но что, если с сервера в массиве начнет приходить тип, который не обрабатывается на клиенте? Появляется обработка ошибок, возможность сломаться в любой момент. Модель данных, наоборот, обычно старается зафиксировать формат передачи. А вы предлагаете его отпустить в свободное изменение и написать принимающей стороне хитрую динамическую логику. Не спорю, такие задачи тоже существуют, но их крайне мало и да, для таких задач JSON подойдёт лучше.
                                              +2
                                              Но я считаю, что JSON — не самый хороший вариант описания структур данных, в том числе и при их передаче.

                                              Но так и не указали на какой-нибудь "фундаментальный недостаток".

                                              Динамическая диспетчеризация — это хорошо, но что, если с сервера в массиве начнет приходить тип, который не обрабатывается на клиенте?

                                              А так будет рано или поздно, поэтому на эту ситуацию все равно надо заложиться.

                                              Появляется обработка ошибок, возможность сломаться в любой момент.

                                              А так вы обработку ошибок не пишете?

                                              Модель данных, наоборот, обычно старается зафиксировать формат передачи.

                                              И что делать, когда переданные данные не соответствуют этому формату?

                                              А вы предлагаете его отпустить в свободное изменение и написать принимающей стороне хитрую динамическую логику.

                                              Нет, не предлагаю. Я говорю, что бывают ситуации, когда это нужно, и лучше бы, если бы формат передачи это позволял.
                                                +1
                                                Мне кажется, что нужно выбирать инструменты, исходя из задачи. Подходит больше JSON — используем JSON, подходит KTV — используем его.

                                                У меня не было цели сделать универсальный формат для всего, поэтому не понимаю, с чем вы спорите. Да, он не подходит для всех задач, мне казалось, что я это чётко постулировал сам.
                                                  0
                                                  поэтому не понимаю, с чем вы спорите

                                                  Я спорю с тезисом "JSON — так себе формат для передачи данных между приложениями".
                                                    0
                                                    Ага, понял.
                                +3
                                TOML. Внизу страницы по ссылке список проектов его использующих и набор библиотек для разных языков.
                                  0
                                  Класс, спасибо, очень интересно. Мне хотелось быть ближе к привычному JSON'у, но формат очень интересный.
                                    0
                                    Tree занятный, спасибо. И простой, это огромный плюс. Но мне хотелось чего-то ближе к привычному JSON'у.

                                    Как бороться с развесистыми структурами — более-менее известно, KTV просто предлагает для этого способ, встроенный в формат.
                                      0
                                      Нет ничего ближе к привычному JSON, чем сам JSON. Реализовали бы KTV поверх JSON — сильно бы расширили число адептов и уменьшили сложность реализации.

                                      Речь о том, что развесистые структуры не нужны вообще — только плоские списки фиксированной глубины. Их и дебажить проще, и в реализации они проще, и работают быстрее, и отдельного формата данных не требуют.
                                        –1
                                        Увы, реальность требует разных структур.

                                        KTV — это надстройка над JSON, любой валидный JSON является валидным KTV. Если же зафиксировать какие-то правила JSON'а (как, например, предлагает http://jsonapi.org), то увеличится запись, мы немного приблизимся к XML по структуре (или даже к чему-то вроде XML-RPC), чего тоже хочется избежать.
                                          +1
                                          Например?

                                          А что толку от того, что JSON можно распарсить KTV парсером? JSON парсер и так есть везде. Вот если бы KTV можно было распарсить JSON парсером — это было бы полезно. Так что стремление сделать похоже, но несовместимо — контрпродуктивно, и можно быть смелее в выборе синтаксиса, лучше оптимизировав его под решаемые задачи.
                                            +1
                                            Например?

                                            Самый простой пример — когда у вас нет контроля за самим форматом. Приходится работать с тем, что есть.

                                            JSON парсер и так есть везде.

                                            Это совершенно верно.

                                            (Впрочем, когда был распространен XML, также говорили про сам JSON)
                                              0
                                              Изобретение своего формата тут мало чем поможет.

                                              При этом JSON не стали делать совместимым с XML.
                                                0
                                                При этом JSON не стали делать совместимым с XML.

                                                И это замечательно.
                                    0
                                    Есть ли бенчмарки скорости сериализации/десериализации в сравнении с JSON/YAML/Protobuf?
                                      0
                                      Пока нет. Мне интересно пока, на правильном ли я пути.

                                      По ощущениям, парсинг должен быть примерно, как JSON по скорости.
                                      +1
                                      Посмотрите на MessagePack http://msgpack.org/ сильно быстрее и компактнее JSON. Хотя типы поддерживает тоже только самые простые.
                                        0
                                        Ага, спасибо. Про него знаю. Он хороший, но бинарный, мне нужен именно текстовый формат, завтра опубликую статью про S2, из неё будет немного яснее, зачем.
                                          0
                                          Лучше уж CBOR. Тоже бинарный, но это как-никак RFC, да и возможностей больше.
                                          0
                                          Советую с комментариями следать следующее

                                          1. Однострочные комментарии — в стиле си-подобных языков, начинаются с // и до конца строки
                                          2. Многострочные комментарии — также в стиле си-подобных языков, начинаются и заканчиваются также как в С/С++ с /* и заканчиваются */
                                          3. Блочные комментарии — начинаются с #, за которыми следует корректный блок кода (фигурно-скобочная группа { } ). Удобно, когда нужно отключить целый блок и не хочется ставить закрывающий многострочный комментарий, искать куда бы поставить */, а затем удалять его когда блок снова понадобится.
                                            Вот тогда будет полный набор всех возможностей.
                                            0
                                            Третий вариант — очень интересен, спасибо. Не думаю, что буду его реализовывать (нет задачи сделать все-все-все), но как метод отладки структуры — супер!
                                              –1
                                              4) Выкинуть комментарии вообще, ибо не нужны они в формате передачи данных. Оно не для того, чтобы его читать.
                                                +1
                                                Формат требуется не только для передачи данных.
                                                  0
                                                  Ну расскажите нам тогда, зачем он ещё нужен.
                                                    0
                                                    Завтра опубликую про S2.
                                                      +3
                                                      Документация. Для этих целей даже был придуман (найден) способ комментариев в самом json.

                                                      {
                                                        "title": "заголовок",
                                                        "title": "KTV. Новый JSON"
                                                      }
                                                        0
                                                        :-) Не знал о таком. Смешной.
                                                          +2
                                                          Стандарт явно говорит, что поведение парсера в этом случае не определено. Например, мой вариант json_decode для Neovim превратит пример в {"_TYPE": v:msgpack_types.map, "_VAL": [["title", "заголовок"], ["title", "KTV. Новый JSON"]]}. RFC 7159:

                                                          An object whose names are all unique is interoperable in the sense
                                                          that all software implementations receiving that object will agree on
                                                          the name-value mappings. When the names within an object are not
                                                          unique, the behavior of software that receives such an object is
                                                          unpredictable. Many implementations report the last name/value pair
                                                          only. Other implementations report an error or fail to parse the
                                                          object, and some implementations report all of the name/value pairs,
                                                          including duplicates.
                                                            0
                                                            А json_decode из Vim покажет вам E721: Duplicate key in Dictionary: "title".

                                                            Замечу, что мой парсер не просто выдаст такой прикольный словарь, но ещё и будет парсить пример два раза: один до того, как поймёт, что нужно использовать «специальный словарь», другой после: информация о порядке ключей на первом проходе не сохранялась, «особые случаи» намеренно не оптимизировались из‐за их предположительной редкости. Разумеется, это дело сопровождается двойным выделением памяти и дополнительным освобождением.
                                                          0
                                                          Зачем хранить документацию в JSON?
                                                            0
                                                            Наоборот. В документации хранится образец в виде json. Да хоть swagger документация тому пример. Только там комментарии в json не используется, т.к.это всё таки трюк.
                                                          0
                                                          Для хранения данных. Различные конфигурационные/настроечные файлы например. JSON и подобные ему форматы это не только web, если что.
                                                    0
                                                    Мне нравится, когда текст в одну строчку *_*

                                                    {name(string): Alexcoolness(double): 3.1415isAProgrammer(bool): true}
                                                      0
                                                      Можно разделять запятой или точкой с запятой, если в одну строчку
                                                        0
                                                        а если в тексте эти символы есть, их экранировать или как?
                                                          0
                                                          Текст в этом случае нужно заключить в кавычки. Экран стандартный: «\», после него символ считается частью строки.
                                                            0
                                                            Я еще очень надеюсь, что вы не добавите вместо кавычек отступы. Прям как в jade. А так задумка вполне нравится)
                                                              0
                                                              Спасибо!

                                                              Нет, на отступы рассчитывать не планируется.
                                                    • UFO just landed and posted this here
                                                        0
                                                        Всё так.

                                                        Я соберу отзывы, после чего напишу грамматику языка.
                                                        +7
                                                        ссылки убивают любые поточные процессоры. Плохо.
                                                          0
                                                          Это правда. Но JSON и так обычно парсится в ассоциативный массив, целиком. В редких случаях, когда нужна поточная обработка — можно ссылки запретить (или вообще не использовать KTV).
                                                          0
                                                          А что, если всё же разделить человекопонятные форматы для данных и конфигурации, и форматы машинного обмена данными? В таком случае, не потребуется долго и мучительно искать замену JSON, в которой будет больше типов/меньше кавычек. У нас, например, JSON используется, если нужно получить человекочитаемые данные, а для машинного обмена — CBOR. Сервер определяет, какой формат отдать на основе заголовка Accept. Выигрыш в скорости разбора почти в два раза по процессору и немного по памяти (не нужно буферизовать строку, если встречен '\'). Выигрыша в объёме данных около 5%.

                                                          P.S. Оба декодировщика — потоковые на основе std::basic_stream. Позволяет начать разбирать данные ещё до их полного получения.
                                                            0
                                                            Хорошее решение. Но такое редко необходимо, требует существенно больше поддержки на всех платформах, которые взаимодействуют.

                                                            С другой стороны, вы используете, например, JSON, а не XML. Почему? Потому что JSON удобнее. Мне кажется, что KTV будет ещё удобнее.
                                                            0
                                                            Плюсы и минусы JSON
                                                            Отсутствие ссылок
                                                            Справедливости ради, в спецификации JSON Schema они таки есть.

                                                            Это — формат описания объектов в JavaScript'е
                                                            По забавному совпадению, JSON-документ с некоторыми купюрами (null/None) является валидным описанием dict в Python. Кстати, именно поэтому ваше ограничение на тип объектов в массиве выглядит надуманным, в питоне, как и в JS, можно класть объекты разного типа в массив.
                                                              0
                                                              Ссылки несложно ввести, при необходимости, я так делал в ÅSS.

                                                              … можно класть объекты разного типа в массив

                                                              Это можно делать почти всегда, я не говорю про невозможность. Я говорю про неудобства, с этим связанные.
                                                              0
                                                              Если нужно прямо сэкономить на трафике, возьмите protocol buffers ;) Если нет, то есть JSON и YAML, которые по крайней мере везде поддерживаются из коробки
                                                                0
                                                                Ради коллекции, упомяну свой велосипед: JSON с комментариями (jsonComm). Сделан на JS, не слишком трудно сделать на других языках, но скорости KTV (из-за кавычек и структуры) не достигнет.
                                                                  0
                                                                  Ага, спасибо, погляжу.
                                                                  +1
                                                                  Ну и для конфигов кроме вышеупомянутого toml ещё порекомендую HOCON
                                                                    +1
                                                                    Ни в коем случае не хочу сказать, что JSON идеален, и всегда для всего подходит. Таких стандартов и форматов просто не бывает. Но конкретно описанные вами проблемы — исключительно проблемы плохого кода.

                                                                    Кавычки. По стандарту (в качестве стандарта я беру текст отсюда: www.json.org) все названия должны заключаться в кавычки. Если мы используем JSON, например, для передачи данных по сети, то это излишество.

                                                                    Вы серьёзно? Вы правда считаете, что 0.5% оптимизации объёма чего-то стоят? Может, тогда стоит сэкономить в языках разработки на пробелах, табуляции и точках с запятой, чтобы экономить диск программиста?

                                                                    Отсутствие типизации. Точнее, типы есть, но всего строка/число/true/false/null. И объекты с массивами. Всё. Ни дат, ни целых/дробных чисел нет. Нет возможности пометить типами объекты, чтобы проще было модель понять.

                                                                    Типизация указана в модели, которая используется вашим генератором и потребителем. Если типы одинаковые, то сериализируются и десериализируются они одинаково. И совершенно непонятно, зачем вам "понимать" JSON. Разве что если вам привезли тележку неизвестного JSON и сказали его познавать. Но это какая-то странная ситуация.

                                                                    Отсутствие стандартов записи объектов. Это, например, может привести к массивам со смешанными объектами внутри. Когда приходится такое парсить — становится больно.

                                                                    А вы это вручную парсите? Не надо так! У меня даже на Arduino стоит библиотека для создания и разборки JSON. И если у вас корректная модель, то никакой боли не возникает.

                                                                    Отсутствие ссылок. Если в JSON записывать иерархическую структуру объектов, то регулярно встречаются ссылки на один и тот же объект из разных мест. JSON не даёт возможности сослаться на первое использование. Нужно либо что-то придумывать, либо повторять объекты целиком, что плохо сказывается на размере структуры и на сложности парсинга.

                                                                    Не надо ничего придумывать, в случае повторяющихся объектов надо использовать идентификаторы объектов, которые заменят вам любые ссылки. Всё придумано давно и очень очевидно.

                                                                    Про комментарии в стандарте для передачи данных даже говорить не буду — и так очевидно.

                                                                    Зато вы придумали свой стандарт. И если вам придётся работать с кем-то ещё, или другими сервисами — вас все проклянут — никому не хочется разбираться с самописным стандартом.
                                                                      0
                                                                      Вы правы.

                                                                      Но, кроме указанных вами кейсов, существуют и другие, в которых решения, которые я применяю — более выгодны, чем применяемые вами. Для этого и существует множество форматов, которые используются в разных ситуациях.

                                                                      Но вы правы, всё перечисленное мной можно реализовать в JSON. Впрочем, и в простом тексте можно, и в XML, и в ещё многих-многих вариантах.
                                                                        0
                                                                        Да, жду вашу публикацию про S2 — очень интересно посмотреть, какой будет кейс под такое решение. Возможно, лучше было бы объединить публикации — или выкатить одновременно — тогда было бы понятнее, зачем вам такой формат.
                                                                          0
                                                                          Первая часть тут: https://habrahabr.ru/post/278787/

                                                                          Сейчас немного обкатаю код на Swift и через какое-то время выложу вторую часть, вместе со ссылкой на библиотеки и исходный код.

                                                                    Only users with full accounts can post comments. Log in, please.