SOA в JSON

VK API, например в методе wall.get, возвращает список постов. В этих постах могут быть атачменты: картинки, видео и музыка. Как их отдает вк: отдельно указывается поле "type" с значением "image", "video" или "music" и отдельно данные по атачу в зависимости от типа.

Как парсить это в типизированном языке? Например в Go требуется перед парсингом JSON указать, какие поля каких типов мы хотим вытащить. А тут эти поля мы можем узнать только во время парсинга. Поэтому есть только два костыльных решения:

  1. Сделать структуру ImageOrVideoOrMusic в которую парсить все возможные поля, а те поля которых нет игнорировать. Понятно какие поля в этой структуре: поля картинок, поля видео и поля для музыки. Почему костыль: много памяти на эту структуру, много кода, структура, которая называется "картинка или видео или музыка" по факту хранит "картинка И невалидное видео И невалидная музыка ИЛИ невалидная картинка И видео И невалидная музыка ИЛИ невалидная картинка И невалидное видео И музыка", то есть расхождение между синтаксисом и семантикой.

  2. Сделать два парсинга: первый в тривиальную структуру с полем только для типа, второй парсинг в нужную структуру в зависимости от типа. Почему костыль: два прохода на парсинг, временная структура.

Почему вообще возникли такие проблемы и можно ли от них избавиться? Корень проблемы в том, что JSON как формат пришел из динамического языка JS позволяет в массиве (списке) хранить данные разных типов. У нас это список обьектов Картинка|Музыка|Видео. Причем нам еще повезло, что мы смогли четко ограничить типы этих обьектов, могло быть такое, что эти обьекты содержат абсолютно разные данные в разных форматах.

По сути это AOS - Array Of Structs, только вместо структур здесь одна из структур фиксированного набора. Кто знаком с алгебраическими типами знает, что это сумма типов. Одним из подходов к работе с AOS является преобразование его в SOA - Struct Of Arrays, структуру, в которой поля это массивы значений исходных структур. В случае выше можно было сделать что-то аналогичное на уровне поля type: разбить поле с атачами на три поля: список картинок, список видео и список музыки. Хранить эти списки в SOA или в AOS уже не важно как, обычно используют AOS, а на преимущества SOA кладут болт. Так, у нас будет три, возможно пустых, поля "images", "videos" и "musics" с списками фиксированной структуры. Запарсится это тривиально в подобную структуру:

struct {
  Images []struct {...} `json:"images"`,
  Videos []struct {...} `json:"videos"`,
  Musics []struct {...} `json:"musics"`,
}