Comments 34
Не совсем понял, откуда бенчмарк берёт размер библиотеки 3,70 кБ, когда web.js весит 29 кБ, а сжато передаётся порядка 6 кБ. Аналогичная картина и для конкурентов.
А где в опросе yaml?
Да вы что! Задавать такие вопросы в этом посте! Автор его на дух не переносит, поэтому и придумывает свои форматы. Этот не первый уже.
А сколько уже было?
На сайте автора можете список поискать. Больше всего он тут всех достал рекламой своего "tree".
Я, в целом, уважаю увлекающихся людей, но Дмитрий чересчур навязчиво свои мысли доносит.
А, посмотрел/припомнил. Понятно. То есть с навязчивозтью было бы фиг с ней, если бы предлагаемые решения были хорошие, но ведь они хуже конкурентов, в которых он даже не стал разбираться. Значит, получается диагноз: человек хочет не решать реальные проблемы, а хочет славы/популярности, причем чтоб практически на халяву, не приложив усилий даже на вменяемое оформление текстов. Следовательно, на такую попытку биологического доминирования и отвечать надо биологически - "бей их, унижай их, ссы им в лицо" (с)
Я так понимаю, "достал" он всех манерой общения? Вот в https://habr.com/ru/articles/966270/comments/#comment_29118098 вижу целую пачку оскорблений и переходов на личности вместо технических аргументов:
... если бы вы более внимательно читали, и меньше фантазировали. СДВГ хоть и не лечится, но его симптомы вполне поддаются купированию, если не запускать.
Особенно рекомендую учебник по физике за 7 класс. Можно взять его в библиотеке и освоить заранее - будете блистать своей эрудицей не только на Хабре, но и среди одноклассников, что куда почётней.
Вижу свои зубки у нашего дарования уже прорезались. Вот бы ещё язык не распускать научилось, чтобы не прикусило случайно... но тут уже вопрос к родителям.
опять нафантазировали невидимых розовых единорогов. Похоже вам тут уже без нейролептиков не обойтись.
Не хотелось бы травмировать вашу детскую психику, но
Про представление целых чисел в ЭВМ вообще и дополнительный код в частности вам расскажут в 8 классе. Учебник рекомендовать не буду, чтобы не перегружать лишней информацией, а то ваш 1КБ может совсем переполниться.
Не слышал, чтобы его кто-то использовал для бинаризации данных.
А JSON и XML?
А вот их используют, как бы кринжово это ни выглядело.
А что в Вашем понимании бинарные данные? Все данные в памяти ПК так или иначе бинарные.
А все данные в том же json - строки. Поэтому картинки, например, приходится кодировать в base64+utf8.
Картинки можно запихнуть в base64 и сохранить в YAML точно так же, как в JSON
А вы что доказать то пытаетесь?
Я пытаюсь понять, почему Вы так упираетесь.
Сказали был что про YAML не подумали - вопросов не было бы. Но Вы же сами зачем-то пытаетесь как-то обосновать отсутствие YAML в списке.
Единственная причина присутствия его в заголовке - его реально используют для сериализация бинарных данных. Оба они из другой категории: https://page.hyoo.ru/#!=8i7ao7_xfyxah
Забавно, что на хабре вы размер округлили вниз, а на NPM/Github округлили вверх.
Ну и сравнивать совместимость пока у вашего стандарта ровно одна реализация это кощунство ИМХО.
На связи участник IETF CBOR WG, занимающийся CBAR/CBAPT, альтернативным к принимаемому сейчас cbor-packed стандарту паковки CBOR. Так вот, глядя на что по ссылке - ЭТО не спека. Более того, неразбериха начинается уже в таблице для привлечения внимания - почему размер 100% лучше 30% и 40% ? Почему время обработки 120% лучше времени 100% ? Чтобы такого не было, нужно приводить абсолютные цифры, пример у автора cbor-x в https://gist.github.com/kriszyp/b623b85d2dc25ac9e3b07d8f39df9307 и кстати, в случае паковки положено приводить столбец еще и с gzip.
Переходя к самой "спеке", это не спека, а какая-то мазня на салфетках из ресторана. По ней не только невозможно сделать независимую имплементацию - ни алгоритмов, ни тест-векторов... - но даже просто понять, что собсно имел в виду автор. Ну вот допустим деление на 3 бита и 5 бит понятно (правда, тем, кто уже в теме, для остальных это вообще-то надо пояснять), но тут же справа на картинке "-27 <= num <= 27" - чего?.. такой диапазон в 5 бит не влезет. Значение Both ржачно - кому-то реально нужен такой bool? При этом остальные значения в spec куда-то пропали.
sint - целое число от −2n2104 до 2n2104-1. Семантика num - целое число со знаком. Значения от -1 до -27 помещаются в байт kind. Значения от -28 до -31 определяют число доп байт для представления больших чисел. -32 означает, что число доп байт указано в следующем байте. За числами от -28 резервируется индекс для ссылок.
Это вот что за порнография? Почему 2n и почему только до 2104 бит? Что, 4096-битный RSA-ключ уже нельзя? Почему они все здесь отрицательные, хотя uint ссылался sint и для положительных тоже?
blob - бинарник. Семантика num - число байт. Лейаут tnum аналогичен uint. После tnum идёт kind для задания типа элементаю. А после него сам бинарник. За всеми бинарниками резервируется индекс для ссылок.
Терминология просто ппц, что при этом должен значит тип в kind, абсолютно непонятно, потому что у нас уже снаружи этот самый kind, что за рекурсия такая?
Дальше, туплы. Нахер они нужны вместо обычных нормальных мапов, нам опять же никто не рассказывает. Зато лишние байты это тратит еще как. При этом до полноценных таблиц ни один горе-иззобретатель так и не сумел еще додуматься...
Наконец, расширяемость. То есть фактически её отсутствие. Каким-то неведомым вывертом мозга автор нормальную практику расширений и спецификаций объявляет "диким западом". В реальности же этот формат столь же нерасширяем, как msgpack. Соответственно, пассаж про прямую и обратную совместимость - чистой воды лживая лапша на уши, потому что таким же свойством будет обладать и банальный JSON - да, декодер точно так же может всё обработать, и? Он и в CBOR это сможет, и? Ну ладно, допустим:
маппинг происходит по совпадению шейпов, которые сериализуются вместе с объектами
[56.4, 37.3]
- вот это вот "шейп" чего имеет, простите? Это географические координаты? Или это температура внутри и снаружи нашего устройства? Или что-то еще третье, которое имеет три поля, но хвостовые можно не передавать для компактности в случае их равенства дефолтным значениям? Вот в CBOR будет однозначно, если тег 103 - это таки широта и долгота.
Или вот там в примере для этого вашего отвратительного Date (про который юмористические презентации есть) поле unix_time. Ну ладно, допустим оно там внутри такое (я к счастью JS не знаю и не пишу на нём). Опять же, что будет, если попадутся другие данные, в которых тоже будет поле unix_time, но это объект другого типа?
Наконец, расширяемость уровня самого формата. В CBOR это можно в широких пределах делать самими тегами, и собственно, самые первые теги, зарегестрированные после RFC, были 25/256 для паковки повторяющих строк (stringref), чуть позже для объектов вообще (28/29), что по совокупности дает то же самое, что здесь было описано как link, то есть совершенно ничего нового. Теперь допустим надо поддержать fp128 - и что тогда? Никак? Блоб длиной 16 байт? Отлично, как его отличать будет от, допустим, UUID ? В CBOR, кстати, тег для UUID зарегистрирован, как и для IPv6-адреса - так что эти блобы одинаковой длины легко отличить. В общем, что за поклёп на CBOR во фразе:
Расширения по задумке должны быть обратно совместимы, но на практике это не так.
решительно непонятно - есть примеры "расширений" CBOR (вообще-то они не таковы), которые не совместимы сами с собой с течением времени?
Про примеры XML и какой-то еще хрени, где неведомыми образом откуда-то берутся текстовые поля - откуда? - комментировать уже лень. На little endian я тоже уже устал ржать (что, и bignum'ы длиннее 8 байт тоже будут little-endian?).
Резюмируя: недоспецифицированная фигня с неочерченным кругом задач и сфер (вот, например, CBOR можно обрабатывать на IoT-устройствах с 1 Кб RAM, а здесь жестко забитый link этому помешает, несмотря на выгоды от паковки, поэтому cbor-packed и альтернативы делают не так), скорее всего неспособная выйти за пределы даже одного языка программирования. По сравнению с Интернет-Стандартом - не, не взлетит.
почему размер 100% лучше 30% и 40% ?
Там +30% и +40%
Почему время обработки 120% лучше времени 100% ?
Это не время обработки, а скорость.
Чтобы такого не было, нужно приводить абсолютные цифры
Абсолютные цифры на конкретных тестовых данных можете глянуть в бенчмарке. Эта таблица даёт примерную оценку вцелом.
в случае паковки положено приводить столбец еще и с gzip
gzip с какими настройками сжатия там где-то у вас положено? Зипование нивелирует разницу между форматами, но даёт просадку скорости в несколько раз. Смысла это замерять нет никакого - размер зависит в большей степени от уровня энтропии данных.
По ней не только невозможно сделать независимую имплементацию - ни алгоритмов, ни тест-векторов
Всё это есть в референсной реализации.
но тут же справа на картинке "
-27 <= num <= 27" - чего?.. такой диапазон в 5 бит не влезет.
Всё прекрасно влезает. Положительные числа начинаются с 000, а отрицательные с 111.
Значение Both ржачно - кому-то реально нужен такой bool?
Это значение не из булевой логики. Более известно как undefined. И да, оно реально нужно. И у вас оно тоже есть.
При этом остальные значения в spec куда-то пропали.
О чём речь?
Почему 2n и почему только до 2104 бит?
(9+254)*8 - ровно столько бит можно закодировать одним доп байтом. n - это суффикс бигинтов в JS, убрал его.
Что, 4096-битный RSA-ключ уже нельзя?
Он состоит из двух чисел по 2048 бит. Впрочем, сейчас RSA использовать уже нет смысла, так как эллиптическим кривым достаточно чисел размером на порядок меньше.
Почему они все здесь отрицательные, хотя uint ссылался sint и для положительных тоже?
Потому что речь про отрицательные num в байте kind.
Терминология просто ппц, что при этом должен значит тип в kind, абсолютно непонятно, потому что у нас уже снаружи этот самый kind, что за рекурсия такая?
Уточнил формулировку, чтобы даже вы её поняли.
Дальше, туплы. Нахер они нужны вместо обычных нормальных мапов, нам опять же никто не рассказывает.
А нахер нужны мапы вам кто сказал? В принципе, это +- то же самое. С той лишь разницей, что есть отдельный тип Map, который декодируется именно в словарь, а не в экземпляр ещё какого-нибудь класса.
Зато лишние байты это тратит еще как.
Да особо не тратит: обычно это длина кортежа + ссылка на шейп. Можно было бы избавиться от длины и брать её из шейпа, но я не придумал, как это сделать без адовых костылей. К тому же, разную длину можно для чего-нибудь приспособить. Например, для таблиц.
При этом до полноценных таблиц ни один горе-иззобретатель так и не сумел еще додуматься...
Полноценные - это какие?
Каким-то неведомым вывертом мозга автор нормальную практику расширений и спецификаций объявляет "диким западом".
Дикий запад - диапазон кастомных идентификаторов, которые каждый занимает какой хочет: "New entries in the range 32768 to 18446744073709551615 (upper half of "1+2", "1+4", and "1+8") are assigned by First Come First Served". При этом такие теги занимают минимум 3 байта и предполагают публичность, что не подходит для внутренних и временных проектов.
В реальности же этот формат столь же нерасширяем, как msgpack.
Отучаемся фантазировать о реальности, это так не работает.
Он и в CBOR это сможет, и?
Ну вот в реальности-то как раз и не может. Я проверял.

[56.4, 37.3]-вот это вот "шейп" чего имеет, простите?
Это список из двух чисел, тут нет никакого шейпа.
Это географические координаты?
Тогда был бы шейп [ "lat", "lon" ]
Или это температура внутри и снаружи нашего устройства?
А тут был бы [ "temp_ext", "temp_int" ]
Или что-то еще третье, которое имеет три поля, но хвостовые можно не передавать для компактности в случае их равенства дефолтным значениям?
В VaryPack такого нет.
Вот в CBOR будет однозначно, если тег 103 - это таки широта и долгота.
Только если декодер это поддерживает. Иначе там будет "какой-то массив с тегом 103". А вот если придёт "какой-то массив с тегом 67927" - поди догадайся, что это идентификатор кластера и записи в нём.
Опять же, что будет, если попадутся другие данные, в которых тоже будет поле unix_time, но это объект другого типа?
Какого ещё типа может быть объект с единственным полем под названием "unix_time"?
самые первые теги, зарегестрированные после RFC, были 25/256 для паковки повторяющих строк (stringref), чуть позже для объектов вообще (28/29), что по совокупности дает то же самое, что здесь было описано как link, то есть совершенно ничего нового
Но в отличие от CBOR, любая реализация VaryPack будет поддерживать ссылки.
Теперь допустим надо поддержать fp128 - и что тогда? Никак? Блоб длиной 16 байт? Отлично, как его отличать будет от, допустим, UUID ?
У одного будет шейп [ "fp128" ], у другого [ "uuid" ].
В CBOR, кстати, тег для UUID зарегистрирован, как и для IPv6-адреса - так что эти блобы одинаковой длины легко отличить.
Прекрасно, а теперь отличите мне UserEntity от ArticleEntity. В центральный реестр же примут все сущности моей предметной области, правда?
решительно непонятно - есть примеры "расширений" CBOR (вообще-то они не таковы), которые не совместимы сами с собой с течением времени?
С декодерами, их не поддерживающими. Скриншот с рекордами выше.
На little endian я тоже уже устал ржать
А что весёлого в отсутствии бессмысленного переворачивания байт как при записи, так и при чтении?
что, и bignum'ы длиннее 8 байт тоже будут little-endian?
Да, причём совместимо с int128, int256 и пр.
CBOR можно обрабатывать на IoT-устройствах с 1 Кб RAM, а здесь жестко забитый link этому помешает
Не помешает. Наоборот, сэкономит память.
cbor-packed и альтернативы делают не так
Ну а как же?
Там +30% и +40%
Это не время обработки, а скорость.
В таких случаях пишут размер в 130% беря за 100% минимальный, а скорость берут 100% за максимальную, чтобы было меньше. Всего этого выяснения можно было бы избежать при грамотном оформлении таблицы:
Абсолютные цифры на конкретных тестовых данных можете глянуть в бенчмарке. Эта таблица даёт примерную оценку вцелом.
...а именно, таблица должна быть оформлена как в приводишемся гисте автора cbor-x. В этом же, прости-хсспади, "бенчмарке", вместо такой таблицы приведён скриншот какой-то хери с какими-то галочками, какими-то килогерцами... чего вообще несёт.
gzip с какими настройками сжатия там где-то у вас положено? Зипование нивелирует разницу между форматами, но даёт просадку скорости в несколько раз. Смысла это замерять нет никакого - размер зависит в большей степени от уровня энтропии данных.
Чушь какая, "нивелирует". В том же гисте автора cbor-x я вижу разницу до 9% в размере, это в ряде применений (ниже про IoT будет подробнее) весьма существенно. Сравнение с гзипом вообще является в некотором роде эталонным - чтобы понять, а стоит ли вообще городить огород в самом формате, усложняя и замедляя его, если generic compressor справляется лучше? Тот же cbor-packed делается для условий, когда gzip попросту невозможен (снова ниже про IoT), я свой CBAR/CBAPT делаю как для таких условий, так и для тех, когда дополнительная предобработка улучшит компрессию, не забивая окно LZ-кодека (т.е. два прохода).
Настройки, как и вообще городить огород со своим алгоритмом, зависят от иерархии целей, порядка пунктов в списке приоритетов, ради которых делался формат. Вот у CBOR такой список есть, и там в качестве приоритетного есть еще простота имплементации (и он действительно реализуется в несколько строк кода на Си), поэтому за счет этого сам формат не столь компактен, как мог бы быть, зато в ROM-прошивке девайсины занимает считанные килобайты машинного кода (этот ваш варипак так не сможет). В этой же, тьфу, "спеке" подобного списка вообще нет, как и даже просто внятного списка целей, ради которых он существует - поэтому я понятия не имею, должен быть там gzip -1 или gzip -9, раз сами не проработали вопрос.
Всё это есть в референсной реализации.
Открою секрет, всем плевать на референсную реализацию, до тех пор, пока в спеке всё понятно, а если нет, значит спека очень плоха, но до этого шага еще надо заинтересовать прочитать спеку, для чего должна быть презентация или вроде того (как эта статья на Хабре), но в данном случае и "презентация" отвратительна и не вызывает у нормального человека интерес к спеке. Собсно, я полез, поскольку мне крайне интересна тема, в слабой надежде на что интересное, но вышло наоборот - пишу разбор, чтобы другие не тратили своё время.
Всё прекрасно влезает. Положительные числа начинаются с 000, а отрицательные с 111.
В "спеке" этого нет. Более того, там есть прямо противоположное - что в sint лежат положительные числа тоже. Да что там, на первой диаграмме в "спеке" вообще не понять кто на ком стоял, какое соотношение между всеми этими прямоугольниками. В "легенде" (только запутывающей) красным bits, но нарисованы под ним один байт. Зелёный подписан byte, но на рисунках там многобайтный float и num аж до 264 байт! Наверное специально, чтоб вражеские шпионы ничего не поняли.
Это значение не из булевой логики. Более известно как undefined. И да, оно реально нужно. И у вас оно тоже есть.
Неверно. Там сейчас написано "both (B) - undefined / логическая неопределённость". А что именно было написано до моего комментария, а? Где диффы страницы? Вводим в заблуждение, правя на ходу? За такое вообще канделябром бьют.
Теперь про "у вас тоже есть". Вот ничего подобного, в CBOR значение undefined есть ошибка. Это не какое-то там "оба сразу, и true и false, логически непонятное", это вполне конкретная запись ошибки энкодера (может у него эксепшн вылетел на поддереве) или вещей "вроде того". Например, вот у нас есть датчик температуры, он дает число или null, если температура за пределами его диапазона. А теперь если у нас переводящая в CBOR система потеряла связь с датчиком, для очередного опроса она может положить undefined - что будет значит "не пришел даже null", т.е. как null отсутствие значения, так тут например отсутствие самого null. К булям и логике оно не имеет никакого отношения, оно вообще вне нормальной data model приложения - это именно спецзначение самой кодировки.
| При этом остальные значения в spec куда-то пропали.
О чём речь?
О том, что для старших битов 010, значащих spec, младшие 5 битов должны означать что именно из этого самого spec - но на диаграмме там только 29, 30 и 31 для флоатов, даже булевы висят в вакууме без номера, об остальных же значениях в этом диапазоне вообще тишина - даже как reserved не помечены.
(9+254)*8 - ровно столько бит можно закодировать одним доп байтом. n - это суффикс бигинтов в JS, убрал его.
Допустим, тогда почему там щас теперь написано "от −2^2111 до 2^2111-1" ? Когда читатель взглянет, что-то еще третье станет написано? =) При этом конкретика кодирования - где лежит знак, как именно кодируются положительные, если в абзаце только "Семантика num - целое число со знаком. Значения от -1 до -27 помещаются в байт kind. Значения от -28 до -31 определяют число доп байт для представления больших чисел. -32 означает, что число доп байт указано в следующем байте. За числами от -28 резервируется индекс для ссылок." и не более - по-прежнему остается загадкой.
| Что, 4096-битный RSA-ключ уже нельзя?
Он состоит из двух чисел по 2048 бит. Впрочем, сейчас RSA использовать уже нет смысла, так как эллиптическим кривым достаточно чисел размером на порядок меньше.
Вранье. Достаточно запустить что-нибудь вроде awk '{print $2}' < ~/.ssh/id_rsa.pub | b64decode -r | hd и увидеть в начале что-то вроде:
00000000 00 00 00 07 73 73 68 2d 72 73 61 00 00 00 03 01 |....ssh-rsa.....|
00000010 00 01 00 00 02 01 00 ab c5 51 6b ec f5 db 74 d9 |.........Qk...t.|
то есть типовое значение 65537 для одного из значений, а другое, как и положено, занимает 512 байт (513 из-за лидирующего нуля чтоб не путать со знаком в MSB).
Собственно, это даже в википедии пишут, и про эллиптические кривые расскажите например Telegram'у =) хотя всё это не имеет значения, потому что большие числа могут иметь произвольную длину, и RSA-ключами их область применения далеко не ограничивается. То есть например для научных данных этот варипак тоже не подходит.
| Почему они все здесь отрицательные, хотя uint ссылался sint и для положительных тоже?
Потому что речь про отрицательные num в байте kind.
| Терминология просто ппц, что при этом должен значит тип в kind, абсолютно непонятно, потому что у нас уже снаружи этот самый kind, что за рекурсия такая?
Уточнил формулировку, чтобы даже вы её поняли.
Ну и где? Где эта формулировка? Где увидеть дифф страницы с изменением? Не вижу там никаких новых формулировок, зато смеюсь над "даже вы поняли" синдромом Даннинга-Крюгера.
А нахер нужны мапы вам кто сказал? В принципе, это +- то же самое. С той лишь разницей, что есть отдельный тип Map, который декодируется именно в словарь, а не в экземпляр ещё какого-нибудь класса.
Бгы, лол, а почему это должен был кто-то сказать? А самостоятельно додуматься уже никак? Вполне очевидно, что неупорядоченные мапы нельзя воспроизвести из сортированных туплов, а вот обратное возможно. Для чего это нужно? Да элементарно - производительность. Неупорядоченный словарь может быть (и обычно так и делают) реализуется хэш-таблицей, тогда как упорядоченный надо держать в виде дерева или же сортировать. В кодеке QCBOR код сортировки мапов (для достижения детерминизма) занимает около 1.2 Кб, что достигает более чем половины от размера всего остального (зависит от опций компиляции). Для constrained-имплементаций это очень заметный напряг.
Другое применение - наоборот, высокопроизводительные сервера, которые стримят. Для этих целей в CBOR, кстати, есть indefinite-length массивы и мапы (да и строки), чтобы не копить сначала в буфере. Варипак такого сценария не умеет.
Да особо не тратит: обычно это длина кортежа + ссылка на шейп. Можно было бы избавиться от длины и брать её из шейпа, но я не придумал, как это сделать без адовых костылей. К тому же, разную длину можно для чего-нибудь приспособить. Например, для таблиц.
В спеке вообще нет слова "шейп". Что это за зверь, никто не знает. Так что данное место идёт лесом.
Дикий запад - диапазон кастомных идентификаторов, которые каждый занимает какой хочет: "New entries in the range 32768 to 18446744073709551615 (upper half of "1+2", "1+4", and "1+8") are assigned by First Come First Served". При этом такие теги занимают минимум 3 байта и предполагают публичность, что не подходит для внутренних и временных проектов.
Ну и? Это вполне распространенная практика в интернет-протоколах, IANA для этого и создана. Более того, централизованный реестр как раз является противоположностью дикого запада. Наконец, "для внутренних и временных проектов" зарегистрирован диапазон приватных тегов начиная с 80000 - юзайте как хотите. Причем если мало, можно подать заявку и расширить диапазон приватных, там уже один раз кто-то так делал.
| В реальности же этот формат столь же нерасширяем, как msgpack.
Отучаемся фантазировать о реальности, это так не работает.
Пока что я наблюдаю фантазии как раз в голове автора varypack. Нам заявляют о совместимости в обе стороны, что невозможно при расширяемости. Механизмов расширений ни в этой статье, ни в "спеке" не описано. В отличие от CBOR, где они есть.
| Он и в CBOR это сможет, и?
Ну вот в реальности-то как раз и не может. Я проверял.
Ну и что должен показать скриншот куска какой-то имплементации, на языке, который я почти не знаю? Человеку разумному полагается уметь сформулировать свою мысль словами. Так что давайте, валяйте обосновывайте своё поклёп, коим боком произвольный декодер CBOR должен свалиться на валидном CBOR? Я лично в CBOR::XS наблюдаю возможность декодирования любого - незнакомые ему теги переводятся в класс CBOR::XS::Tagged, обрабатывайте себе в приложении как хотите, не дожидаясь индивидуальной поддержки от библиотеки.
| [56.4, 37.3]- вот это вот "шейп" чего имеет, простите?
Это список из двух чисел, тут нет никакого шейпа.
Ага, телепатия не удалась. В спеке вообще нет слова "шейп". Что это за зверь, никто не знает. Так что данное место идёт лесом.
| Это географические координаты?
Тогда был бы шейп [ "lat", "lon" ]
| Или это температура внутри и снаружи нашего устройства?
А тут был бы [ "temp_ext", "temp_int" ]
А вот теперь обещанное просвещение про IoT. Есть такое радио, IEEE 802.15.4, как вайфай, только очень ограниченное - 250 кбит/с, максимальный размер фрейма 127 байт. Причина - устройство, например умный выключатель на липучке, должно годами работать от батареи, а в основном её жрёт именно трансивер, то есть надо как можно меньше данных (можно даже O(N) или хуже алгоритмы, это не так критично, как размер пакета). Из этих 127 байт при максимальном шифровании канального уровня на L3 остается 81 байт. Дальше на этом работают Zigbee со своими протоколами, или 6LoWPAN, в случае которого "в лоб" IPv6-заголовок отожрал бы 40 байт, UDP еще 8 и на данные осталось бы всего 33 байта. Путем различных ухищрений в типовом случае размер доступного пэйлоада поднимают до 60-70 байт.
Так вот, этот ваш [ "lat", "lon" ] даже чисто самими строками занимает 8 байт, а еще заголовок массива. То есть 15% пакета уже сожрано, даже если он не повторяется в нём больше. Это - чрезмерно дохера. Двухбайтовый тег CBOR здесь гораздо, гораздо эффективнее. При этом, понятно, стараются делать такие схемы данных, чтобы избегать даже тегов по возможности. Однако:
| Или что-то еще третье, которое имеет три поля, но хвостовые можно не передавать для компактности в случае их равенства дефолтным значениям?
В VaryPack такого нет.
...вот видите, сэкономить таким образом не получится. И схем, типа JSON Schema, нет. А в CBOR есть CDDL, и там вполне себе можно задать опциональность некоторых полей. И, конечно же, схема необязательна - хочешь используй, хочешь в стиле JSON юзай или ручками пиши.
| Вот в CBOR будет однозначно, если тег 103 - это таки широта и долгота.
Только если декодер это поддерживает. Иначе там будет "какой-то массив с тегом 103". А вот если придёт "какой-то массив с тегом 67927" - поди догадайся, что это идентификатор кластера и записи в нём.
Ну разумеется. Это фундаментальное свойство сетевого взаимодействия вообще. Оно философское, если угодно, не техническое даже. Принимающая реализация должна поддерживать то, что ей приходит, при этом вообще всё в мире поддерживать невозможно. Абсолютно точно так же, ваш инстанс варипака обосрётся, если я пришлю ему свой класс MyFooFrobnicate. Которого у вас нет, и что с ним делать, понятия не имеете.
При этом в CBOR возможен по крайней мере вменяемый fallback, если был использован тег 26 или 27 (с именем класса и аргументами конструктора) в том плане, что обработчик может передать это куда-то дальше, сам не понимая, или хотя бы дать вменяемую диагностику. Неизвестный же набор полей вообще в большинстве случаев не несёт информации, от чего именно он.
| Опять же, что будет, если попадутся другие данные, в которых тоже будет поле unix_time, но это объект другого типа?
Какого ещё типа может быть объект с единственным полем под названием "unix_time"?
Бгы, юноша, ви таки снова делаете мене смешно! А если подумать? Эрудицию покачать? Да почти какого угодно. Это может быть, например, невалидный netflow, из которого пропали все поля, кроме таймштампа - тогда правильное поведение будет выкинуть ошибку, а не кастовать в черти чё. Или это может быть вполне валидный объект измерения с датчика, в котором отсутствие значения читается согласно данному конкретному application-layer протоколу как "возьми значение из предыдущей секунды, оно такое же". И снова здесь Date будет ошибкой типизации.
Но в отличие от CBOR, любая реализация VaryPack будет поддерживать ссылки.
Не просто "будет", а ДОЛЖНА поддерживать, что очень плохо, если это затратно - как для тех же constrained implementations в IoT. См. ниже.
| Теперь допустим надо поддержать fp128 - и что тогда? Никак? Блоб длиной 16 байт? Отлично, как его отличать будет от, допустим, UUID ?
У одного будет шейп [ "fp128" ], у другого [ "uuid" ].
Это, простите, объект, а не примитивный тип. С соответствующими накладными расходами. А в CBOR можно иметь тег на скаляре.
| В CBOR, кстати, тег для UUID зарегистрирован, как и для IPv6-адреса - так что эти блобы одинаковой длины легко отличить.
Прекрасно, а теперь отличите мне UserEntity от ArticleEntity. В центральный реестр же примут все сущности моей предметной области, правда?
Если вам непременно захотелось подать в центральный реестр все свои сущности, вместо приватного диапазона, то и регистрируйте каждой по своему номеру. Хотя из обсуждения выше уже должно быть понятно, что "шейпы" с "туплами" тупиковый путь, проще передать само название объекта, хоть то же "UserEntity", а для этого в CBOR уже даже есть готовые теги.
Причем, кстати, 27(["Date", 1762848671]) еще и места меньше займет, чем [["unix_time"], 1762848671] - то есть ваш варипак еще и по хваленой компрессии проигрывает.
| решительно непонятно - есть примеры "расширений" CBOR (вообще-то они не таковы), которые не совместимы сами с собой с течением времени?
С декодерами, их не поддерживающими. Скриншот с рекордами выше.
Как уже было сказано выше, скриншот невменько. Объясняйтесь словами, причем согласно спекам, а не реализациям.
| На little endian я тоже уже устал ржать
А что весёлого в отсутствии бессмысленного переворачивания байт как при записи, так и при чтении?
Да много чего, начиная с естественного упрощения отладки в хексдампах и заканчивая применениями детерминизма. Вот например, SQLite в экспериментальной 4 версии решили попробовать бэкендом key-value, соответственно пример подойдёт для любого key-value storage - мы хотим запихнуть ключ в такую базу, при этом она о наших форматах, естественно, ничего знать не будет - она может только сортировать ключи по алфавиту, т.е. в memcmp()-порядке. Вот, можете посмотреть, как они решали это для SQL-записей: https://sqlite.org/src4/doc/trunk/www/key_encoding.wiki - тот же самый подход никто не мешает применить для любого JSON-подобного кодирования, если мы в ключ как-то запихнём объект, чтоб он сортировался соответственно своим значениям. Так вот в Big Endian это можно сделать, в Little Endian - невозможно.
Все же аргументы за LE по типу перформанса в форматах сериализации бессмысленны - htonl() стоит копейки, и лень программиста совершенно не перевешивает использования.
| CBOR можно обрабатывать на IoT-устройствах с 1 Кб RAM, а здесь жестко забитый link этому помешает
Не помешает. Наоборот, сэкономит память.
| cbor-packed и альтернативы делают не так
Ну а как же?
Лулз какой. Сразу видно человека, который с реальным железом дела не имел, вращаясь в мире розовых пони скриптовых языков. На 1 Кб RAM вообще нет памяти для всяческих decode_json(), которые вернут готовое дерево в памяти. Там парсят инкрементально (event-based), прям на представлении в памяти. Соответственно, для того, чтобы ссылаться на предыдущие значения, нужно завести массив для них, а скорее связный список, если память фрагментирована. То есть например 6 байт (ptr, length, next). Это значит, варипак (или stringref CBOR, хотя тот оптимальнее сделан) потребует по 6 байт памяти на КАЖДЫЙ потенциальный элемент. И вот если мы за 10 пакетов с трудом получили наши полкилобайта, то теперь индексация съест всю оставшуюся память! А обрабатывать на чем дальше, простите?..
Поэтому stringref не для IoT делался, и cbor-packed тоже не вошёл в первоначальную спецификацию CBOR - только отвели в дизайне 16 значений для паковки, оставив проработку кучи сложных вопросов на потом. Дык вот, делается и cbor-packed, и CBAPT мой - сначала передачей таблицы элементов (обычно строк), которые и будут переиспользоваться ссылками дальше. То есть ключевой момент - передаётся совсем не всё подряд, как link в варипаке, а только нужные элементы, подбираемые под девайс/протокол. Которые, запросто может быть, уже присутствуют в ROM устройства, то есть тогда можно применить оптимизацию переписыванием массивом ссылок самого приёмного буфера с входным CBOR.
Всего этого выяснения можно было бы избежать
... если бы вы более внимательно читали, и меньше фантазировали. СДВГ хоть и не лечится, но его симптомы вполне поддаются купированию, если не запускать.
какими-то килогерцами... чего вообще несёт.
Особенно рекомендую учебник по физике за 7 класс. Можно взять его в библиотеке и освоить заранее - будете блистать своей эрудицей не только на Хабре, но и среди одноклассников, что куда почётней.
В этой же, тьфу, "спеке" подобного списка вообще нет, как и даже просто внятного списка целей, ради которых он существует - поэтому я понятия не имею, должен быть там gzip -1 или gzip -9
У всех свои цели, но раз зипование никак не упоминается, значит ужатие любой ценой не является приоритетной. Жую вам это последний раз - дальше уже сами. Вижу свои зубки у нашего дарования уже прорезались. Вот бы ещё язык не распускать научилось, чтобы не прикусило случайно... но тут уже вопрос к родителям.
Зелёный подписан byte, но на рисунках там многобайтный float и num аж до 264 байт! Наверное специально, чтоб вражеские шпионы ничего не поняли.
Удивительно, как вы догадались. Я же так старался всё зашифровать, не рисуя 264 зелёных квадратика. А тут вы, такой сообразительный, сходу меня раскусили. Радует только, что все остальные не столь умные, как вы, и ни за что не догадаются!
там сейчас написано "both (B) - undefined / логическая неопределённость". А что именно было написано до моего комментария, а? Где диффы страницы? Вводим в заблуждение, правя на ходу?
Если у вас ещё и проблемы с памятью (что, в принципе, не удивительно при хроническом недосыпе), то можете глянуть мета-информацию по каждому слову тут: https://sync.hyoo.ru/watch/#!section=search/search=jf99kg_f3vfrj/land=jf99kg_f3vfrj/head=tzhgi1_7kcn6x
Формулу пересчёта внутреннего времени в миллисекунды эпохи юникс найдёте здесь: https://github.com/hyoo-ru/crowd.hyoo.ru/blob/master/time/time.ts#L9
Вот ничего подобного, в CBOR значение undefined есть ошибка. Это не какое-то там "оба сразу, и true и false, логически непонятное", это вполне конкретная запись ошибки энкодера
Вы не поняли суть секции 5.7 спецификации и опять нафантазировали невидимых розовых единорогов. Похоже вам тут уже без нейролептиков не обойтись.
К булям и логике оно не имеет никакого отношения
Не хотелось бы травмировать вашу детскую психику, но всё же отмечу, что логика не ограничена лишь булевой алгеброй, которая принципиально не полна. Подробнее, если захотите лучше разобраться в логике, можете почитать тут: https://page.hyoo.ru/#!=ixy44o_3oga48
на диаграмме там только 29, 30 и 31 для флоатов, даже булевы висят в вакууме без номера
Вместо номеров, для них указаны ASCII-символы.
почему там щас теперь написано "от −2^2111 до 2^2111-1"
Потому что пересчитал внимательнее и поправил.
При этом конкретика кодирования - где лежит знак, как именно кодируются положительные
Про представление целых чисел в ЭВМ вообще и дополнительный код в частности вам расскажут в 8 классе. Учебник рекомендовать не буду, чтобы не перегружать лишней информацией, а то ваш 1КБ может совсем переполниться.
> Он состоит из двух чисел по 2048 бит.
Вранье.
Действительно, попутал с тем, как устроен ключ ECDSA. Современным динозаврам придётся кодировать RSA-ключ не в виде большого числа, а в виде бинарника. Ничего страшного.
про эллиптические кривые расскажите например Telegram'у
Обязательно расскажу. Сразу после рассказа про E2E-шифрование, которого там до сих пор нет нигде, кроме бестолковых "секретных чатов".
То есть например для научных данных этот варипак тоже не подходит.
В какой области науки не хватает 2111 бит для целых чисел?
Вполне очевидно, что неупорядоченные мапы нельзя воспроизвести из сортированных туплов, а вот обратное возможно.
При бинаризации в любом случае получаются упорядоченный список. Этот порядок вы можете проигнорировать, если хотите, и использовать любые удобные вам структуры.
сервера, которые стримят. Для этих целей в CBOR, кстати, есть indefinite-length массивы и мапы (да и строки), чтобы не копить сначала в буфере. Варипак такого сценария не умеет.
Я слабо представляю себе пользу от такого стриминга. Лучше каждый пакет данных представлять отдельным полноценным VaryPack бинарником, который можно полностью обработать, а не держать в памяти все временные данные в попытке обработать один большой CBOR бинарник по частям и думать, что со всем этим делать при обрыве соединение.
Ну и что должен показать скриншот куска какой-то имплементации, на языке, который я почти не знаю?
Что с совместимостью между CBOR библиотеками всё плохо из-за подхода к реализации этой самой совместимости. В данном случае объекты не отличимы от словарей, ибо в базе есть только мапки, а всё остальное достигается лишь через несовместимые между собой расширения.
Из этих 127 байт при максимальном шифровании канального уровня на L3 остается 81 байт.
Реализуйте своё шифрование и сможете задействовать до 112 байт.
При этом, понятно, стараются делать такие схемы данных, чтобы избегать даже тегов по возможности.
Очевидно, в таких условиях безсхемные форматы вообще не подходят, ибо возят с собой имена полей туда-сюда. Ваша экономия на 2 строках из 20, погоды тут не сделает.
И схем, типа JSON Schema, нет. А в CBOR есть CDDL
К формату бинаризации это всё и не относится - это не его уровня ответственность.
если я пришлю ему свой класс MyFooFrobnicate. Которого у вас нет
... то получите его POJO представление.
Неизвестный же набор полей вообще в большинстве случаев не несёт информации, от чего именно он.
К именам полей нужно подходить не менее ответственно, чем к именам классов. Вырожденный случай - использовать имя класса в качестве единственного имени поля.
Это может быть, например, невалидный netflow, из которого пропали все поля, кроме таймштампа
От того, что у вас нет значений некоторых полей, сами поля никуда не деваются.
Или это может быть вполне валидный объект измерения с датчика, в котором отсутствие значения читается согласно данному конкретному application-layer протоколу как "возьми значение из предыдущей секунды, оно такое же"
Отсутствие значения записывается как none или both. Оно не просто так кортежами называется. Это не словари, где набор полей может быть произвольным.
Это, простите, объект, а не примитивный тип.
Нет, из туплов могут получаться как объекты так и примитивы.
проще передать само название объекта, хоть то же "UserEntity", а для этого в CBOR уже даже есть готовые теги.
.. которые поддерживаются в одной единственной библиотеке, да.
Причем, кстати,
27(["Date", 1762848671])еще и места меньше займет, чем[["unix_time"], 1762848671]- то есть ваш варипак еще и по хваленой компрессии проигрывает.
unix_time - общеизвестный термин. Что скрывается за Date - никому не известно. День месяца? Число секунд? миллисекунд? наносекнд? Какой часовой пояс? Или это вообще идентификатор табельного дня?
Да много чего, начиная с естественного упрощения отладки в хексдампах
uint и sint показываются hex-вьювером как есть. Половина spec показываются им как первые буквы имени. Очень удобно. В CBOR до такого не додумались.
мы хотим запихнуть ключ в такую базу, при этом она о наших форматах, естественно, ничего знать не будет - она может только сортировать ключи по алфавиту, т.е. в memcmp()-порядке.
В результате имеем некорректную сортировку чисел разной байтовой длины, прекрасно.
Сразу видно человека, который с реальным железом дела не имел, вращаясь в мире розовых пони скриптовых языков. На 1 Кб RAM вообще нет памяти
Честно говоря, это крохоборство меня совсем не интересует. Экстравагантным девайсам - экстравагантные решения.
Если у вас ещё и проблемы с памятью (что, в принципе, не удивительно при хроническом недосыпе), то можете глянуть мета-информацию по каждому слову тут: https://sync.hyoo.ru/watch/#!section=search/search=jf99kg_f3vfrj/land=jf99kg_f3vfrj/head=tzhgi1_7kcn6x

Я вижу здесь какую-то галиматью вместо чего-то похожего на вывод git log -p, интерфейса сравнения драфтов datatracker.ietf.org или хотя бы сравения ревизий страницы на википедии. Пользоваться этим невозможно, совершенно неюзабельно.
Вижу свои зубки у нашего дарования уже прорезались. Вот бы ещё язык не распускать научилось, чтобы не прикусило случайно... но тут уже вопрос к родителям.
Вижу, автор приписывает оппонненту то, что в его проекциях характеризовало бы его самого - на технические аргументы ответить нечего, значит, раз пошли оскорбления и переходы на личности (собрал их https://habr.com/ru/articles/966270/#comment_29120442 тут на всякий). По сути-то претензии ответить не может - вот это:

- не бенчмарк, а какая-то невнятная херотень. Каким образом килогерцы приблизительно равны килобайтам, которые равны произведению байтов на микросекунды и некие неведомые klt - решительно непонятно; а главное, как это сравнивать между собой. Как нормальные люди оформляют таблицы с результатами бенчмарков, я уже показывал. Садись, два.
Формулу пересчёта внутреннего времени в миллисекунды эпохи юникс найдёте здесь: https://github.com/hyoo-ru/crowd.hyoo.ru/blob/master/time/time.ts#L9
Я ссылки на реализацию даже открывать не буду (тем более на убогих недоязыках) - это ДОЛЖНО быть в спеке. Садись, два.
> Вот ничего подобного, в CBOR значение undefined есть ошибка. Это не какое-то там "оба сразу, и true и false, логически непонятное", это вполне конкретная запись ошибки энкодера
Вы не поняли суть секции 5.7 спецификации и опять нафантазировали невидимых розовых единорогов. Похоже вам тут уже без нейролептиков не обойтись.
Ох, лол! Открываем секцию и читаем:
In some CBOR-based protocols, the simple value (Section 3.3) of
undefinedmight be used by an encoder as a substitute for a data item with an encoding problem, in order to allow the rest of the enclosing data items to be encoded without harm.
То есть именно и ровно то, что я написал. Если есть проблемы с пониманием написанного в спецификации (вот уж явно опять проекция с нейролептиками), можно пойти в архивы CBOR mail list, посмотреть задавал ли кто такой вопрос, или взять документацию (не код!) какой-нибудь реализации. Например, CBOR::XS описывает:
true, false, undefined
These CBOR values become [...] and Types::Serialiser::error, respectively. They are overloaded to [...]and false) or to throw an exception on access (for error). See the Types::Serialiser manpage for details.
Я подчеркнул относящееся к undefined.
Не хотелось бы травмировать вашу детскую психику, но всё же отмечу, что логика не ограничена лишь булевой алгеброй, которая принципиально не полна. Подробнее, если захотите лучше разобраться в логике, можете почитать тут: https://page.hyoo.ru/#!=ixy44o_3oga48
Мне давно неинтересно читать философские разглагольствования, парадоксом лжеца или троичной логикой я интересовался в юности, а в мейнстримных языках программирования у нас сугубо булева логика. Помимо того, что я уже показал, что в CBOR оно не для этого, будьте добры продемонстрировать, как с булевым значением "both" должен обращаться реальный код потребителя библиотеки.
Вместо номеров, для них указаны ASCII-символы.
О чем совершенно нет никакой нотации. Ну даже одинарных кавычек типа 'T', принятых во многих языках программирования.
Про представление целых чисел в ЭВМ вообще и дополнительный код в частности вам расскажут в 8 классе.
Автор, видимо, сам из 9 класса, если думает, что в реальной жизни в ходу какой-то один единственный формат, о котором рассказали в учебнике. И особенно это верно в форматах сериализации, где разный порядок байт, variable-length integers могут склеиваться из битовых кусков (а не быть ровным числом байт как в регистре), и знаковый бит может находиться где попало, даже между MSB и LSB нет предпочтения. LEB128 и git передают привет.
Автор, твоя проблема в том, что называемое тобой "фантазиями" в действительности есть многообразие реального мира, о котором у тебя попросту нет знаний, и ты свой узкий взгляд из тесного мирка принимаешь как что-то, понятное всем по умолчанию. Невежество, однако, совершенно не аргумент называть людей, которые видели гораздо больше тебя и предполагают множество вариантов интерпретаций, не понимающими школьниками. Иди лечи свой синдром Даннинга-Крюгера, и заодно на курсы этикета сходи.
> про эллиптические кривые расскажите например Telegram'у
Обязательно расскажу. Сразу после рассказа про E2E-шифрование, которого там до сих пор нет нигде, кроме бестолковых "секретных чатов".
Вообще не аргумент. Пишешь либу работы с Telegram (а у меня конвертер из их ужасного формата в CBOR работает) - должен поддерживать. Или, следуя той же "логике", немедленно откажись от своего Telegram-канала =)
В какой области науки не хватает 2111 бит для целых чисел?
А какая разница? Ни одна известная реализация больших чисел не ограничивает их таким произвольным числом, в формате сериализации поддержать более длинные тоже никакой проблемы не составляет. Вот вообще. Что, неужели для varypack это сложно? =)
> Вполне очевидно, что неупорядоченные мапы нельзя воспроизвести из сортированных туплов, а вот обратное возможно.
При бинаризации в любом случае получаются упорядоченный список. Этот порядок вы можете проигнорировать, если хотите, и использовать любые удобные вам структуры.
Вот номер очередной неграмотного владения речью. Что такое "бинаризация"? Определение термина где? Под ним может пониматься уйма вещей, прежде всего "сделать блоб из строки". Если же "бинаризация" значила "сериализация", то опять - садись, два. Более того, в случае мапов он не является упорядоченным - енкодер вправе выдать ключи в произвольном порядке, и я уже говорил, что требование упорядоченности создает большую нагрузку - что, если там миллион-другой ключей? Сортировка будет очень затратна. Не приходит в голову такое, да?
Иными словами, туплы вполне можно вводить в качестве дополнительного типа данных (и среди тегов CBOR подобное есть), но никак не в качестве базы и основы.
Я слабо представляю себе пользу от такого стриминга.
Вот-вот. Иди и изучи реальный мир, прокачай абстрактное мышление, посмотри, что людям на практике требуется. Только после этого пытайся изобретать новые форматы.
> Ну и что должен показать скриншот куска какой-то имплементации, на языке, который я почти не знаю?
Что с совместимостью между CBOR библиотеками всё плохо из-за подхода к реализации этой самой совместимости. В данном случае объекты не отличимы от словарей, ибо в базе есть только мапки, а всё остальное достигается лишь через несовместимые между собой расширения.
Я всё еще жду вменяемого человеческого описания, где именно и как сам подход CBOR - а не какой-то отдельной библиотеки, что может быть багом этой одной конкретной либы - мешает обсуждавшейся прямой и обратной совместимости (а не "между библиотеками", вижу попытку подмены тезиса). Словами через рот, буквами в тексте - не скриншотами, наскальной живописью или обезьяним уханием. Нет, предложение выше таковым не является, потому что за "объекты не отличимы от словарей" в том же IETF немедленно пошлют на три буквы и будут правы - во-первых, в data-модели JSON объект и есть словарь, во-вторых, заявлялось про прямую и обратную совместимость и что варипак её якобы обеспечивает (на самом деле нет - или расширения, или прямая+обратная), а не совместимость расширений между собой, что в общем случае невозможно.
Реализуйте своё шифрование и сможете задействовать до 112 байт.
Нет. Не сможете. Максимум 90 с копейками, путем радикальной смены стека протоколов (то есть не решение), при этом радикально 30-40 байт картину не изменят.
> При этом, понятно, стараются делать такие схемы данных, чтобы избегать даже тегов по возможности.
Очевидно, в таких условиях безсхемные форматы вообще не подходят, ибо возят с собой имена полей туда-сюда. Ваша экономия на 2 строках из 20, погоды тут не сделает.
Схемы по типу protobuf дадут геморрой с майнтенабельностью, чего как раз - наевшись за много лет - хотели избежать. А экономия на строках достигается легко (в теории, на практике много чего проработать надо, варипак так не сможет) путем передачи имени словаря строк вместо самого набора строк, даже однократного. Это сейчас для cbor-packed и CBAR как раз в процессе.
> И схем, типа JSON Schema, нет. А в CBOR есть CDDL
К формату бинаризации это всё и не относится - это не его уровня ответственность.
Не бинаризации, блъ, а сериализации. И нет, это таки его уровня ответственность, потому что есть целые форматы, построенные на схемах, например Protobuf. И у них есть свои достоинства, например производительность и компактность, которые self-described форматы скорее всего достичь не смогут. Именно поэтому CBOR описал иерархию целей, сразу заняв другую нишу - а вот выгод varypack перед protobuf при такой его ригидности пока что не видно.
> если я пришлю ему свой класс MyFooFrobnicate. Которого у вас нет
... то получите его POJO представление.
Необщепринятый термин, даже гуглить не буду, принципиально. Это ваша обязанность говорить языконезависимыми терминами и писать языконезависимые спеки.
> Неизвестный же набор полей вообще в большинстве случаев не несёт информации, от чего именно он.
К именам полей нужно подходить не менее ответственно, чем к именам классов. Вырожденный случай - использовать имя класса в качестве единственного имени поля.
Одним из преимуществ классов/ООП является как раз инкапсуляция, когда никому нет дела, как названы поля внутри, и можно не бояться, что оно с кем-то пересечётся. Varypack своими "шейпами" нарушает этот принцип очень сильно.
> Это может быть, например, невалидный netflow, из которого пропали все поля, кроме таймштампа
От того, что у вас нет значений некоторых полей, сами поля никуда не деваются. [...] Отсутствие значения записывается как
noneилиboth
Деваются. Зачем мне их передавать, если их нет? Они "не деваются" только в негибких структурах типа SQL-таблиц, но объекты/мапы JSON хороши как раз тем, что опциональное поле может отсутствовать. Это настолько выгодно при необходимости компактности передачи (о которой заявляет варипак), что применяется в других форматах. Например, в Telegram (при всей ужасности их TL, я в свое время писал на хабр статью), они типично экономят на опциональных полях, передавая их, если только стоит соответствующий бит во флагах:
chatFull#c9d31138 flags:# can_set_username:flags.7?true has_scheduled:flags.8?true translations_disabled:flags.19?true id:long about:string participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:flags.13?ExportedChatInvite bot_info:flags.3?Vector pinned_msg_id:flags.6?int folder_id:flags.11?int call:flags.12?InputGroupCall ttl_period:flags.14?int groupcall_default_join_as:flags.15?Peer theme_emoticon:flags.16?string requests_pending:flags.17?int recent_requesters:flags.17?Vector available_reactions:flags.18?ChatReactions = ChatFull;
Флагов может быть до 32 (хотя пару лет назад стали в некоторых крупных классах второе поле добавлять), то есть передача жестко фиксированных none (бгы, а если у поля null может быть валидным значением) в Varypack приведёт к передаче до 31 лишнего байта, по сравнению с 0 у CBOR или 4 у Telegram.
Даже кошмарный Telegram'ный TL оказался лучше VaryPack, стыдно должно быть!
> Или это может быть вполне валидный объект измерения с датчика, в котором отсутствие значения читается согласно данному конкретному application-layer протоколу как "возьми значение из предыдущей секунды, оно такое же"
Отсутствие значения записывается как
noneилиboth. Оно не просто так кортежами называется. Это не словари, где набор полей может быть произвольным.
Они-то называются, а вот их выбор в качестве основного структурного типа - крайне скверный дизайн.
> Это, простите, объект, а не примитивный тип.
Нет, из туплов могут получаться как объекты так и примитивы.
Не могут. Передайте своему преподавателю, что у вас проблемы с пониманием терминологии. Объект никак не может быть скаляром.
> проще передать само название объекта, хоть то же "UserEntity", а для этого в CBOR уже даже есть готовые теги.
.. которые поддерживаются в одной единственной библиотеке, да.
Все-все пересмотрели? Никто не мешает, однако, реализовать их самостоятельно в своей - спека очень простая.
> Причем, кстати,
27(["Date", 1762848671])еще и места меньше займет, чем[["unix_time"], 1762848671]- то есть ваш варипак еще и по хваленой компрессии проигрывает.unix_time - общеизвестный термин. Что скрывается за Date - никому не известно. День месяца? Число секунд? миллисекунд? наносекнд? Какой часовой пояс? Или это вообще идентификатор табельного дня?
Бгы, лол. Автор, у тебя в твоем собственном примере в "спеке" написано new Date - это вот ровно оно и есть. Гораздо лучше передавать имя объекта для определения этого самого объекта, чем определять его набором полей - которые могут пересекаться у разных объектов.
> Да много чего, начиная с естественного упрощения отладки в хексдампах
uint и sint показываются hex-вьювером как есть. Половина spec показываются им как первые буквы имени. Очень удобно. В CBOR до такого не додумались.
Неа, не показываются. Как раз по причине little-endian. И да, в CBOR не стали ломать стройность схемы, усложняя имплементацию, ради четырех букв в дебаге - с числами это приходится делать чаще.
> мы хотим запихнуть ключ в такую базу, при этом она о наших форматах, естественно, ничего знать не будет - она может только сортировать ключи по алфавиту, т.е. в memcmp()-порядке.
В результате имеем некорректную сортировку чисел разной байтовой длины, прекрасно.
Если не умеете сделать разную байтовую длину с обеспечением корректной сортировки, ваши проблемы. Авторы SQLite4 и CBOR умеют.
> Сразу видно человека, который с реальным железом дела не имел, вращаясь в мире розовых пони скриптовых языков. На 1 Кб RAM вообще нет памяти
Честно говоря, это крохоборство меня совсем не интересует. Экстравагантным девайсам - экстравагантные решения.
Неа. Хороший протокол/формат должен быть как советский инженер-строитель - уметь всё, от хибары до небоскрёба. TCP может, от ограниченных контроллеров до терабитных датацентров. CBOR тоже может, от маленьких IoT до строк в 2^64 длиной. Varypack не может, значит к хорошим не относится.
К "экстравагантным" в этой области можно было бы отнести какой-нибудь LoRaWAN и подобные, где размер пакета вообще 10-20 байт. Там да, только специализированные решения. Но где заводится IP, там должен быть пригоден и общий формат. В конце концов, это удобно, управлять например умным домом с обычного смартфона обычным IP+JSON(CBOR), вместо специализированных железяк для конвертации.
В общем, вменяемых аргументов я так и не увидел.
Я не буду вдаваться в технические сравнения, тут именно про текст статьи и код с ReadMe на гите.
Для себя я делю форматы сериализации на 2 категории:
1)Без схемы - возможность прикрутить схемы не учитываем: JSON/JSONB, XML, YAML, MessagePack в schemaless режиме. По сути сообщение в таком формате несет в себе достаточно метаданных для того чтоб его можно было понять, хоть как-то.
2)Требующие схемы - без схемы полностью понять данные нельзя - MessagePack(без использования schemaless режима), ProtoBuf.
Иначе их можно назвать как документ и запись/строка(по аналогии с документно-ориентированными БД и традиционными БД)
Судя по наличию шейпов, VaryPack это первый тип, то есть документ. Плюс парадигма "прочитать любой ценой, хоть как-то", то есть реф имплементация не строгая к данным.(насчет этого позже)
Это не плохо глобально, но ограничивает области применения, особенно для языков со статической типизацией.(хотя часть из них это нюансы реализации, но она же считается эталоном, не так ли?)
Вопросы, нюансы:
По самому стандарту: Типизация по шейпам:
1)Я так понимаю, если я на бэкенде/фронте добавлю в тип Foo новое поле(и оно будет внесено в шейп), то вторая сторона перестанет создавать тип Foo а будет просто получать обычный объект?
Если да, это минус. Это уже отсутствие обратной совместимости на уровне данных, так как запрещает делать плавное обновление(часто обновление идет так, обновляются все бэкенды, чтоб начали посылать дополнительные поля, а затем только обновляем фронты, чтоб начали использовать это поле. Это важно для приложений с горизонтальным масштабированием)
2)Как зарегистрировать 2 типа с одинаковыми шейпами?(например PointF(x,y:f32) и Point(x,y:int32))
3)Поддержка наследуемых типов?
В сочетании стандарта и реализации
Хотелось бы увидеть пример реализации какого-то расширения(не просто кастомного типа, а именно расширения) - да, хотя бы записи того же fp128, НЕ через существующие типы(иначе это просто конверсия), а именно через расширение стандарта.
Cкорее о реализации
1)Было бы неплохо иметь возможность запрещать работу с незарегистрированными типами, так как если код ожидает увидеть объект класса Foo(с его методами), то просто POJO его сломает.
2)Связано с п1, раз уж мы работаем с типами, было бы неплохо поддерживать строгую типизацию(хотя бы на уровне того бы мы могли ограничить сразу тип корневого объекта).
Сейчас выходит мы читаем, а только потом проверяем, а то ли мы прочитали.
Хотя может я где-то пропустил?
3)Тут я не уверен, но я верно понял сериализатор это синглтон? Очень не помешает возможность создавать экземпляры с разными настройками.
Хотя опять же, если брать как чисто документ, то это не сильно нужно. Так как текущая реализация это скорее, что-то записали, что-то прочитали. Например никто не мешает сейчас передать сообщение чтоб в наш объекта класса Foo(из примера) попадет объект в поля вместо number.
Это не плохо глобально, но ограничивает области применения, особенно для языков со статической типизацией.(хотя часть из них это нюансы реализации, но она же считается эталоном, не так ли?)
Статическая типизация хороша внутри приложения, но не на границе приложений. Приложение не должно падать от того, что в локальном хранилище, напрмиер, по любой причине оказались не те данные, которые оно ожидает. Поэтому в хранилище у нас динамическая типизация, с бесконфликтным слиянием разных типов, а прикладное апи вокруг него - строго типизировано с автоматическим кастом к нужным типам значений из базы.
часто обновление идет так, обновляются все бэкенды, чтоб начали посылать дополнительные поля, а затем только обновляем фронты, чтоб начали использовать это поле. Это важно для приложений с горизонтальным масштабированием
Правильнее всё же сперва обновить клиентов, чтобы они умели работать как со старыми типами, так и с новыми, а потом уже присылать им новые, в которых могут быть не только новые поля, но и изменение типов старых, а то и вообще их удаление. Не будете же вы возить ради обратной совместимости в шейпе 100500 полей, которые когда-либо были в типе? В конце концов, вы всегда можете в поле объекта поместить в отдельное поле словарь, куда свободно добавлять новые поля.
Как зарегистрировать 2 типа с одинаковыми шейпами?(например PointF(x,y:f32) и Point(x,y:int32))
Вы регистрируете rich функцию, которая на вход принимает кортеж, а на выходе любой нужный вам тип. В данном случае он может проверять тип аргументов и создавать разные структуры.
Поддержка наследуемых типов?
Наследование - из области типизации и поведения. А VaryPack хранит конкретные значения. Если же нужно в зависимости от значения созавать экземпляры разных классов, то для этого можно использовать фабрики. Например, так сделана поддержка DOM элементов через document.createElement.
да, хотя бы записи того же fp128, НЕ через существующие типы(иначе это просто конверсия), а именно через расширение стандарта.
В том и фишка, что он не требует для этого расширения.
Было бы неплохо иметь возможность запрещать работу с незарегистрированными типами, так как если код ожидает увидеть объект класса Foo(с его методами), то просто POJO его сломает.
Это делается через валидатор. Например, $mol_data: https://github.com/hyoo-ru/mam_mol/tree/master/data
Тут я не уверен, но я верно понял сериализатор это синглтон? Очень не помешает возможность создавать экземпляры с разными настройками.
Это тоже фича - отсутствие конфигурирования. Разве что регистрацию кастомных типов можно обособить через подкласс $mol_vary.
>часто обновление идет так, обновляются все бэкенды, чтоб начали посылать дополнительные поля, а затем только обновляем фронты, чтоб начали использовать это поле. Это важно для приложений с горизонтальным масштабированием
Правильнее всё же сперва обновить клиентов, чтобы они умели работать как со старыми типами, так и с новыми, а потом уже присылать им новые, в которых могут быть не только новые поля, но и изменение типов старых, а то и вообще их удаление.
Сразу видно отсутствие практического опыта, приводят реальный пример, так нет же... Хорошо, сказано "клиентов", ловим на слове. Пусть клиент - это мобильное приложение, то есть мы не можем повлиять на то, когда конкретный юзер обновится, значит в ходу будет одновременно и две, и три версии, и более... А бэкенды не обновлять нельзя. Всё, начинаем городить огород.
Не будете же вы возить ради обратной совместимости в шейпе 100500 полей, которые когда-либо были в типе?
С обычными объектами JSON не будем, хотя какой-то период сосуществования возможен, а вот с "шейпами" - придётся.
В конце концов, вы всегда можете в поле объекта поместить в отдельное поле словарь, куда свободно добавлять новые поля.
Бгы, начинаются костыли. Ладно, допустим добавили, а вот с удалением по-прежнему засада.
>да, хотя бы записи того же fp128, НЕ через существующие типы(иначе это просто конверсия), а именно через расширение стандарта.
В том и фишка, что он не требует для этого расширения.
Неа. Всё, что получится сделать - это boxed-тип, а не примитив. Например класс с полем из бинарной строки длиной 16. То есть вышеозначенная конверсия типов, а не расширение.
Это тоже фича - отсутствие конфигурирования
Вообще это, конечно, шедеврально - выдавать за фичи отсутствие фич, и отсутствие расширяемости и совместимости за расширяемость и совместимость, "которых нет у конкурентов".
Приложение не должно падать от того, что в локальном хранилище, напрмиер, по любой причине оказались не те данные, которые оно ожидает.
Падать не должно, а вот получить ошибку, было бы неплохо. Оно все равно не сможет работать непонятно с чем. Как минимум было бы неплохо или флаг передать при вызове распаковки, либо колбек.(хотя это особенности реализации именно)
Правильнее всё же сперва обновить клиентов, чтобы они умели работать как со старыми типами, так и с новыми, а потом уже присылать им новые, в которых могут быть не только новые поля, но и изменение типов старых, а то и вообще их удаление.
Я говорил именно про новое, хотя удаление будет иметь ту же проблему требования одновременности. Если мы обновим все фронты, проблема не уйдет. Сопоставление сломается.
Разве что дублировать шейпы на клиентах(две регистрации на один тип, с новым полем и без), которые потом было бы неплохо и убрать.
В том и фишка, что он не требует для этого расширения.
Ну это лукавство, вы заявляли легкость расширения VaryPack, а теперь вся наша расширяемость свелась к тому что мы можем объявить свой произвольный тип на основе шейпов. (причем что регистрация типов это семантика, которой в стандарте уделено лишь одно предложение, то есть по факту это деталь реализации скорее, нежели формата как такого). Так то и в JSON/JSONB можно через другой базовый блок выразить любой тип(те же бинарные данные в JSON через Base64, неприкольно, но можно жеж).


JSON? JSONB? BSON? CBOR? MsgPack? А, VaryPackǃ