Комментарии. Jsonnet принимает комментарии в стиле С ( /* … */ ) и С++ ( // )
Ссылки. Ключевое слово self может быть использовано для ссылки на текущий объект. Оператор $ позволяет использовать корневой объект.
Арифметические и условные операторы. Оператор + может складывать числа, строки, массивы и объекты. Операторы == и != возвращают true или false. Оператор if работает как тернарный оператор ?: в С. Далее несколько примеров с операторами языка и результат. Примеры взяты со страницы проекта.
// bar_menu.3.jsonnet { foo: 3, bar: 2 * self.foo, // Multiplication. baz: "The value " + self.bar + " is " + (if self.bar > 5 then "large" else "small") + ".", array: [1, 2, 3] + [4], obj: {a: 1, b: 2} + {b: 3, c: 4}, equality: 1 == "1", }
Результат:
{ "foo": 3, "bar": 6, "baz": "The value 6 is large.", "array": [1, 2, 3, 4], "obj": {a: 1, b: 3, c: 4}, "equality": false }
Создание массивов и объектов. Для создания массивов и объектов используется конструкция с оператором for, как показано в примере ниже:
{ foo: [1, 2, 3], bar: [x * x for x in self.foo if x >= 2], baz: { ["field" + x]: x for x in self.foo }, obj: { ["foo" + "bar"]: 3 }, }
Результат:
{ "foo": [ 1, 2, 3 ], "bar": [ 4, 9 ], "baz": { "field1": 1, "field2": 2, "field3": 3 }, "obj": { "foobar": 3 } }
Модульность. Код написанный на Jsonnet может быть разбит на несколько файлов и затем объединятся с помощью оператора import. Внутренняя механика заключается в простом склеивании файлов.
Функции. Jsonnet значения могут содержать функции. Они помечаются как скрытые поля и не транслируются в JSON. Пример такой функции представлен ниже:
// bar_menu_utils.jsonnet { equal_parts(size, ingredients):: if std.length(ingredients) == 0 then error "No ingredients specified." else [ { kind: i, qty: size/std.length(ingredients) } for i in ingredients ], id:: function(x) x, }
Jsonnet также включает в себя локальные переменные, способ для наследования объектов путём импортирования, вычисляемые и опциональные поля.
Движок языка написан на С++11 с предоставлением обёртки API в стиле С для более лёгкого портирования на другие языки. Команда разработчиков сразу может предоставить библиотеки для С и Питона. Реализация для С++ может быть скомпилирована в JS с Emscripten. Еще доступен неофициальный пакет для nodejs.
Полные спецификации можно посмотреть на странице спецификации.
Некоторое сравнение с другими языками
JSON. Собственно, JSON описывает все данные буквально. Jsonnet имеет более свободный синтаксис и комментарии, для облегчения чтения данных людьми.
YAML. Так же является некоторым расширением JSON, который позволяет генерировать правильный JSON. Синтаксис языка очень компактный и файлы на YAML гораздо, короче чем они потом выходят в JSON формате. Несмотря на то, что язык создан в тех же целях, что и Jsonnet, создание, трансляция и уточнение данных проигрывает Jsonnet. В частности, YAML и Jsonnet имеют различные точки зрения на то, что должно означать «1+1». YAML говорит, что это строка «1+1», тогда как Jsonnet считает, что результат должен быть 2.
Другие языки с шаблонами. Jsonnet является шаблонным языком, который генерирует данные по алгоритмам с перемеживанием буквальных данных с вычислительными конструкциями. Большинство таких языков считают программы и результат простым текстом. Это значит, что на выходе может получится некорректный результат, если мы говорим о JSON. Большинство таких шаблонных языков не обладают знаниями о синтаксисе выходных данных и не могут проверять результат на правильность. Jsonnet такого недостатка лишён, так как это узкоспециализированный инструмент.
Сравнение с другими инструментами и языками, такими как Haskel, Nix, Coil, Pystachio и другими можно в деталях прочитать в руководстве к Jsonnet.
Вопросы и ответы
В оригинальном топике появились интересные вопросы и ответы от ведущего разработчика проекта Дэвида Каннингэма (David Cunningham).
Вопрос: Почему бы не воспользоваться уже существующим открытым стандартом EDN? На мой взгляд в нем есть все те же самые фичи и уже есть порты под разные языки.
Ответ: Хороший вопрос, но EDN не очень-то похож на Jsonnet. EDN – это «только данные», он не знает ничего о вычислениях или абстракциях. Он расширяем, и вы можете добавить недостающие конструкции, но тогда вы получите по факту новый язык, который будет непонятен другим системам.
Когда мы создавали Jsonnet, мы думали о том, что нам надо следовать общим стандартам. Мы выбрали JSON из-за его популярности, но мы так же пытались следовать существующим моделям программирования (главным образом js и python) так близко, как только возможно.
Хочу также заметить, что можно интегрировать Jsonnet в системы, которые работают с EDN, потому что возможно генерировать EDN с помощью нашей системы. Необходимо только написать специальную функцию «manifest». Такая работа проделана для INI файлов, конфигурационных файлов Lua и Python.
Наконец, Jsonnet доступна для 3х языков (С, Python, Javascript) и для любого языка, который может работать с С интерфейсом. Порты на другие языки запланированы, возможно с помощью портирования на Haxe.
Вопрос. Мне очень нравится проект, но разработчики должны были использовать стандартные JavaScript функции, а не изобретать из в stdlib. Базовые функции пропущены и добавление новых не простая задача, так что это своего рода ограничитель и я, к сожалению, вернулся на старый предпроцессор JSON.
Ответ. Stdlib определённо самая слабая часть проекта и то, что должно быть переписано, улучшено, и задокументировано прежде чем мы выпустим версию 1.0. Мы очень ждём ваших отзывов, особенно с примерами из реальной жизни.
В целом есть возможность расширить stdlib самостоятельно и написать свою собственную библиотеку для Jsonnet. Пример ниже сначала использует маленький трюк для добавления метода add2 в stdlib:
local std2 = std { // Temporarily define std2 to avoid self-reference. add2(x):: x + 2, }; local std = std2; // Bind std2 over std. // Rest of Jsonnet file below: { foo: std.add2(10), // Expands to 12. }
В общем случае, может быть невозможно скопировать функции из поддерживаемых языков, так как семантика может не иметь смысла в Jsonnet. Однако мы понимаем, что иметь необоснованные различия никому не поможет. И это является основной причиной, почему stdlib функции отвечающие за форматирование текста в точности совпадают с оператором % в Python.
На основе материалов:
- http://www.infoq.com/news/2015/04/jsonnet — тема свежая и владелец библиотеки на связи, так что можно поспрашивать напрямую в топике.
- http://google.github.io/jsonnet/doc/
И мы опять хотим привлечь ваше внимание к предстоящей конференции API & Backend (C#). Если вам есть что рассказать про детали реализации и управления API, сервисом на бэкенде. Если у вас есть интересные случаи связанные с генерацией сложных сообщений: заголовков и содержимого – мы ждем ваших историй!
Комментарии (66)
QtRoS
22.04.2015 16:54+94Господи, не надо трогать JSON, пусть останется хотя бы один простой и понятный текстовый формат, который железобетонно все поддерживают!
torbasow
23.04.2015 11:07+1Пусть добавят тип дата/время, и довольно. Можно ещё значение Infinity.
ef_end_y
23.04.2015 13:26+4не надо дату/время — нигде нет нормального стандарта. Используйте таймстамп лучше
splav_asv
23.04.2015 13:31+3Mithgol
24.04.2015 11:56+1При всём наличии этих хороших стандартов всегда можно вспомнить о том, что Twitter (как явствует из примера, официально приведённого
вон там) не стесняется возвращать время и дату в адском формате «Wed May 23 06:01:13 +0000 2007» (день недели, месяц, день, время, часовой пояс, год).
spmbt
22.04.2015 17:54> заменяет стандартный JSON и добавляет новые возможности без нарушения обратной совместимости. Среди таких возможностей: комментарии ...
Для поддержки комментариев делал проект github.com/spmbt/jsonComm — формат с комментариями (одно- и многострочными) и возможность смены ключей и значений в парах «ключ-значение» без удаления комментариев. Хабр
Он сейчас работает и расширен (код скоро будет добавлен в репо после тестирования) до возможности работы с фрагментами jsonComm в JS-файлах. Фрагменты выделяются специальными комментированными скобками с достаточно вольным синтаксисом.
lexore
22.04.2015 17:56+6Ну, и кто (и когда) должен вычислять «1 + 1»?
Генерирующая сторона в момент отправки?
Читающая сторона в момент приема?
А если json сохраняется в файл, нужно вычислять во время записи, или во время чтения?mayorovp
22.04.2015 20:52+1Это формат для конфигов. Разумеется, вычислять должна программа при чтении — просто потому что человек пишет.
zencd
23.04.2015 13:38JSON — это не формат для конфигов. Это формат обмена данными, и его применение конфигами не ограничивается.
mayorovp
23.04.2015 20:15+1Зато применение Jsonnet ими ограничивается.
Гугл открыла исходный код своего проекта Jsonnet, языка для конфигурации, который заменяет стандартный JSON и добавляет новые возможности без нарушения обратной совместимости.
Archon
23.04.2015 14:45+4JSON — настолько же формат для конфигов, насколько AVI — формат для гей-порно.
За все годы я только один раз использовал JSON для хранения конфигов, и этот JSON как писался машиной, так ей же и читался, человек (я) лишь один раз задал его формат в коде. Зато без использования JSON для передачи данных между какими-то сторонами не обходится нынче почти ни один проект, поскольку альтернатив, в общем-то, и нет (XML и основанные на нём стандарты в разы дороже по оверхеду).Alexeyco
23.04.2015 18:33Это актуально только если мы пишем что-то с нуля или не используем всех возможностей какого-либо фреймворка. Да и виндузятники (asp.net программисты) смотрят на вас сейчас с крайним недоумением. Буквально спрашивают «а если быстрее напилить бэкенд на SOAP, тогда как быть?»
Archon
24.04.2015 09:02+1Могу в ответ лишь предложить им уволиться и сменить род деятельности, поскольку никакой разницы для разработчика, делать SOAP-сервис или JSON-сервис, в .NET нет, а использовать «все возможности фреймворка», скидывая на пользователей все неудобства, связанные с повышенным оверхедом, они могут в своё свободное время, делая личные проекты.
Alexeyco
28.04.2015 01:34Все правильно ))) я когда был молодым и горячим, тоже считал, что все вокруг мне должны, и каждая моя идея — золото…
DsideSPb
22.04.2015 18:07+9JSON — формат обмена данными, у которого есть множество реализаций для самых разных языков программирования. Он как раз примечателен тем, что он не исполняем, а потому относительно безвреден, а вычислительные ресурсы по его преобразованию обычно близки к
О(strlen(message))
.
Если нужно обрабатывать данные перед преобразованием в JSON — как раз существующие реализации покрывают эти нужды. Ведь если есть JSON, то где-то рядом работает и преобразователь между JSON и нативными типами (как правило). Добавлять ещё один язык в технологический стек нерационально или даже опасно.
Я вижу только один адекватный способ применения: преобразование структуры JSON-документов — когда у нас есть только исходный документ и приёмник, в который надо послать документ с этими же данными, но в другой структуре. Больше я не вижу ситуаций, когда не используется реализация JSON на другом языке и потому есть свобода выбора. Но лично я даже в этой ситуации выбрал бы Ruby, Python (основы которого изучал бы на ходу, поскольку его не знаю) или JS/производные.
ZyXI
22.04.2015 18:18+5Тот, кто говорит, что в YAML 1+1 — это строка «1+1» явно ничего не понимает в YAML. Нужно преобразовывать 1+1 в 2 — напишите свой resolver или constructor (второе обязательно, первое нет). Гораздо проще взять готовый YAML парсер и приделать к нему constructor, чем писать новый формат.
Если что: resolver определяет, какой тёг соответствует данному синтаксическому дереву в случае, когда тёг не указан (здесь тёг — это тип). Обычно используется только для скаляров, именно благодаря resolver'ам в формате есть числа и true/false/null.
Constructor определяет, как из синтаксического дерева получить объект (строку/число/словарь/...). Определение тёга определяет constructor.
В стандарте описаны «стандартные» resolver'ы для трёх схем (безопасная, JSON-совместимая, основная (failsafe, json, core)), но нигде не написано, что они обязаны быть единственными.
Aingis
22.04.2015 18:56Комментарии и избавление от лишних кавычек это правильно, а всё остальное, что больше 'Hello, ' + 'world!' уже очень спорно.
ivlis
22.04.2015 19:03+16JSON это декларативный формат по свой сути. Зачем туда пихать императивные директивы вообще не понятно.
kzn
22.04.2015 21:04+4XML-bomb сделать не проблема.
Теперь видимо можно будет и JSON-bomb сделать :-)lany
23.04.2015 16:02+1Вот да, сразу возникают вопросы с безопасностью. Принимать JSON из недоверенного источника в принципе можно. Дыры в JSON-парсерах случаются очень редко. А тут сам формат подразумевает, что результат может вычисляться долго и захавает всю память.
Sane
22.04.2015 21:21+4В json не хватает четырех вещей — схемы, дат, комментариев и NaN. А так — идеальный формат.
Archon
23.04.2015 14:56+1Из всего вышеперечисленного для эффективной передачи данных не пригодится ничего (кроме, возможно, NaN). Схему передавать по сети (особенно мобильной) очень дорого, тем более, что предполагается, что общающиеся стороны знают про протокол обмена, и не крашатся от допустимых изменений (отсутствующее поле, значение null в любом из полей, новое поле). Если разработчик накосячил с типом, в который он хочет приводить поле — это не проблема формата передачи данных.
Самый простой способ избежать проблемы с кривыми руками и неверными типами — использовать схожие языки для обеих сторон (например, Java-фронтенд и C#-бекенд), и после фиксации протокола тупо копировать все структуры данных из сериализующего проекта в десериализующий, по пути исправляя синтаксис.
Даты и сейчас прелестно передаются в формате таймштампа. В случае, когда надо передать ещё и таймзону, её всё равно нельзя передавать цифрой +ЧЧММ после даты, а надо заводить отдельное строковое поле.Sane
23.04.2015 15:10+1Схему передавать и не надо — это просто стандратный способ проверить целостность данных, то есть вместо громоздкого текстового описания моего API и тучи реализаций на разных языках, я могу просто предоставить одну схему. Отсутствие схемы — это не минус самого формата, это минус его инфраструктуры, и хорошо, что json schema уже, как минимум, internet draft.
Для дат есть замечательный ISO 8601, самый распротраненный формат данных после строк и чисел. Иметь его в стандрате передачи данных было бы очень приятно.Archon
23.04.2015 15:53+1<нудная мутотень>
ISO 8601 прекрасен для случаев, когда надо передать отсылку на конкретную точку во времени, т.е. по сути, тот же таймштамп. Это прекрасно работает для дат в прошлом. Если же вы оперируете датами из будущего, это может быть неприемлемо. Например, пользователь сказал приложению «напомни мне захватить мир 5 января 2020 года в 11:00», после чего вы сохранили это таймштампом (или в ISO 8601, разницы нет). Через два года прилетает новая tzdata, таймзона пользователя меняет часовой пояс или параметры DST, и представление «5 января 2020 года в 11:00» теперь указывает на другую точку во времени. Но вы об этом не узнаете, и напоминание откроете не в 11:00, а в другое время. Ошибочка вышла…
</нудная мутотень>
Как передавать и хранить дату, надо решать в каждом случае отдельно, в первую очередь отталкиваясь именно от того, что нам нужно зафиксировать — точку во времени (таймштамп), или пользовательское представление о будущей дате (ISO 8601 + название таймзоны). В любом случае, как вы договоритесь делать в протоколе передачи, так можно и передавать, все существующие форматы дат, включая ISO 8601, отлично вписываются в строки.
Suvitruf
23.04.2015 10:36+1Мы изобретём новый json с
блекджекомкомментариями и арифметическими операторами © Google
jerom
23.04.2015 12:06Они были недостаточно креативны с комментами. Вот перловый модуль JSON в relaxed-режиме не только допускает end-commas в списках, но и комменты, начинающиеся с #:
search.cpan.org/~makamaka/JSON-2.90/lib/JSON.pm#relaxed
Ununtrium
Собственно, за отсутсвие комментариев в JSON можно сказать спасибо крокфорду с его шизофреническими идеями.
KvanTTT
Только этого мне не хватает в JSON. А все остальное из jsonnet на мой взгляд лишнее, т.к. это стандарт передачи данных, с которыми при необходимости может работать человек.
LastDragon
А как же запятая? :)
ivlis
comment: «This is your comment»;
Чем не устраивает?
DsideSPb
1. Корректен только в объектах/мапах.
2. Является частью данных, при преобразовании будет полностью загружен в память (что нужно дополнительно обходить, если это проблема).
ivlis
Если ваши комментарии настолько забивают память, то я думаю, что проблема не в JSON…
cmepthuk
Суть в самом подходе, если вы ещё этого не поняли. В любом языке и синтаксисе (если он подразумевает работу с переменными) тогда можно таскать просто строковую переменную, к которой «присваивать комментарий». Можно в окна (вместо дверей) входить, а микроскопами гвозди забивать — да
ivlis
JSON это неструктурированные данные. Комментарий — часть данных. В чём проблема?
Yavanosta
Допустим вы делаете конфиг для программы. И у вас есть два варианта: либо конфиг будет без комментариев, либо программа должна будет загружать комментарии в рантайме в память. Это не нужно и это оверхед, т.к. программа держит в памяти то что ей не нужно.
ivlis
И сколько там она загрузит этих комментариев? Если вы пишите хардкорный embedded на asm, тогда, наверное, вам json в принципе не подходит, не то что комментарии в нём. А если вы пишите на каком-нибудь js, ruby или python то переживать из-за пары байт в комментарии явно не стоит.
shmaltorhbooks
суть в том, что заранее неизвестно какой объем текста будет в комментариях. вы не можете утверждать, что его всегда будет «пару байт».
ivlis
Размер JSON вы тоже никогда не угадаете принципиально, так как у него нет схемы. Если вы используете JSON для данных, где можно определить схему, то you are doing it wrong.
mayorovp
У любого JSON есть неявная схема — это те представления о возможной структуре данных, которые писали программу, его генерирующую либо использующую.
Иногда эта схема даже описывается в документации.
Vidog
Для справки:
www.google.ru/?q=json%20schema
Punk_UnDeaD
Зачем программа должна будет загружать комментарии в память?
Пропустить комментарии во время считывания из файла — это элементарный конечный автомат.
Yavanosta
По большому счету есть две проблемы с таким подходом:
1) Комментарии являющиеся частью JSON тратят ресурсы. Да, они бы тратили ресурсы в любом случае, но всетаки если бы они вырезались на уровне парсера тратили бы меньше чем если делать это на более высоком уровне. Да, это копейки, но мы сейчас говорим о концептуальной проблеме стандарта.
2) Нет единого синтаксиса или соглашения для комментариев. Можно договориться, например, добавлять комментарий в виде поля "_comment" в объекте, примерно так:
Такой синтаксис, во первых не позволяет написать отдельные комментарии к param1 и param2, например так:
Во вторых нет поддержки «вырезания» таких комментариев на разных платформах, и если вы допустим пишете приложение с сервером на c# и клиентами на js, Java и Swift то вам придется написать четыре пусть и простых но прослойки которые будут вырезать _comment ноды из распарсеного дерева, или делать это на уровне тесктого препроцессора.
В третьих это не является стандартом и возможно в будущем вы столкнетесь с какой-то библиотекой или сторонним API которое использует поле _comment для каких-то своих целей, тогда вам придется как-то изворачиваться чтобы один JSON пропускать через вот этот парсер, а другой через другой.
Я не говорю что все эти проблемы нерешаемы или очень сложны, что нельзя прикрутить два парсера или что написать препроцессор очень сложно, но всем было бы удобнее, если бы комменатрии поддерживались в стандарте.
Punk_UnDeaD
Прошу прощения, невнимательно прочёл всю ветку.
PsyHaSTe
Ну меня в вашем предложении больше всего не устраивает, что если нужно будет итерироваться по потомкам, то постоянно нужно будет проверять, не является ли у нас элемент комментарием. Причем насколько я знаю, с одним именем может быть только один элемент хеш-таблицы, коей является JSON, соответственно при желании добавить несколько комментариев в разных местах нужно будет проверять каждый элемент, не начинается ли он на comment, формировать культуру «комментарии начинайте со слова comment, например comment1, commentValue, ...», при малейшей опечатке превращается в camment, coment и т.п., в предметной области, ну например, объект — фильм на афише или блог, может быть поле comments, который придется отдельно обрабатывать, потому что его может порезать проверка на то, что слово начинается на это слово…
Можно продолжать сколько угодно. Причем это это не единственные недостатки вашего подхода, а только в добавление к вышесказанному.
trikadin
А можно ссылку на эту тему? Гугл не силён в запросах «Шизофренические идеи Крокфорда» и «Крокфорд против комментариев», а почитать интересно)
spmbt
habrahabr.ru/post/247473 в разделе «Сыр-бор и источник»