openlang

Проверка JSON до размеченного объединения

Утверждение типа парсером не является. Внешний ответ приходит байтами, и пока его никто не проверил, ничто в нём не говорит, какой это вариант.

Сначала декодирование текста и разбор JSON, у каждого свой путь отказа. Результат разбора должен попадать в проверку как unknown.

Поддерживаются два ответа. Метка ready с массивом строк items или метка failed со строкой message. Проверка во время выполнения должна убедиться в трёх вещах. Значение является объектом, метка нам известна, а данные для этой метки имеют нужную форму. Объект с ready без items неполон. Объект с waiting несёт метку, которой нет в нашем типе. Приведение через as к объединению не исправит ни то, ни другое.

После успешной проверки декодер возвращает размеченное объединение. Ветка с проверкой на ready сужает значение, и элементами можно пользоваться. Исчерпывающая проверка через never покажет необработанный вариант в объявленной модели. Для сопровождения это полезно, но в байты ответа она не смотрит.

С отклонённым вводом нужно что-то решить. Сообщить об ошибке декодирования или сознательно смоделировать неизвестный ответ как ещё один вариант. Тихое приведение к принятому объединению этот выбор пропускает.

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

Разговор продолжается 5

Следуя доводам
  1. Ссылка на ответ

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

    Функция, которая сопоставляет Right _ и возвращает True, примет Right undefined, ни разу не тронув полезную нагрузку. Попросите length этой нагрузки, и вычислению она понадобится, а там и случится сбой. А let loop = loop in loop можно дать тот же тип, и он не дойдёт ни до одного конструктора.

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

  2. Ссылка на ответ

    Добавим Deferred(ticket) третьим вариантом и посмотрим, куда расползётся изменение. Закрытый enum в Scala 3 даёт этому случаю собственные данные, и это удобно. Но меняется декодер, а за ним все потребители, включая отрисовку и сохранение. Пока все варианты принадлежат одной модели, такая согласованность окупается.

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

  3. Ссылка на ответ

    Что здесь означает отсутствие ticket? Пропущенный или null тикет может значить битый ответ. А может значить принятую отсрочку без номера для отслеживания. String? в Kotlin хотя бы покажет, что значения может не быть, но не скажет, какой из двух случаев перед нами. Оставьте поле допускающим null, и каждый потребитель Deferred(ticket) будет решать это по-своему. Эту границу я бы обозначил явно, прежде чем добавлять случай.

  4. Ссылка на ответ

    Для этого расширения это битый ответ. deferred требует, чтобы ticket присутствовал и был непустой строкой. Пропущенное свойство не проходит декодирование, null тоже, "" тоже. Это правило приёма, и живёт оно в декодере, рядом с проверкой метки.

    У пустого случая, который обычно хотят, уже есть место. ready с items, равным [], означает, что запрос завершился без элементов. Это настоящий результат. Отсрочка без тикета означает другое, и заимствовать эту форму ей незачем.

    Если сервис потом разрешит отсрочку без отслеживания, это будет новый вариант со своим именем и своей заметкой для вызывающего кода. Чего я не хочу, так это тихо собирать Deferred из отсутствия, потому что поле оказалось необязательным. Пока протокол меняется, отдельный вариант дёшево добавить и дёшево убрать.

  5. Ссылка на ответ

    Можно, наверное, вообще не пускать отклонённые тикеты в объединение. Если декодер возвращает Result<Response, ParseError>, они остаются на стороне ошибки, и вызывающий код сообщит об ошибке декодирования, не создавая ни Deferred, ни пустой Ready. Проверять вход по-прежнему должен декодер. Тип результата просто даёт сбою место, куда пойти.

Другие стороны того же вопроса

  1. Является ли List<Int> только для чтения снимком?

    List<Int> всего лишь представление только для чтения, а не снимок. Он сообщает потребителю, какие операции доступны через эту…

    Ответы 2kotlin