Мультиязычная разработка

топ 100 блогов zabivator18.01.2010 Одна из крайне неочевидных проблем кроется в способах взаимодействия программ, написанных на разных языках.
Все мои проблемы с json-rpc (за исключением кривых реализаций) кроются не в протоколе как таковом, не в постановке задачи (что мы хотим получить), а... в различиях языков.

Давайте рассмотрим незатейливый вызов

getObjectList( filter ) -> { ok, [ object1, object2, ... ] } | { error, Reason }

Записано в синтаксисе Erlang (для тех кто в теме про Ерланг проект - расслабтесь, с ним проблемы нету, проблемы в другом проекте. Ерланг просто удобная демонстрация).

Что делает эта функция?

Во-первых она принимает в качестве аргумента filter. Пусть этот filter описывает каким-то образом критерий выбора объектов из базы - например, условие поиска.
В качестве примера могу предложить вариант { [ "addDate", Date ] } - где Date - самая давняя дата поступления искомых объектов в базу. Таким образом, вызов просит найти все объекты в базе, поступившие после указанной даты.

Во-вторых, она возвращает результатом кортеж - либо ok (всё хорошо) и список объектов в результате, либо error - диагностирующую ошибку, а также её описание.

Давайте рассмотрим как работает с этой функцией клиент.
Если результатом является { ok, [ object1, object2 ] } - то всё хорошо, клиент получил ожидаемый ответ, и продолжает работу.
Если результатом является { error, Reason } - то нужно обработать ошибку. Например, показать пользователь диалог.

В данном примере уже видны проблемы. Функция getObjectList не имеет чётко зафиксированного результата. У неё на выходе альтернативы. Эти альтернативы имеют разную структуру - либо значение "ok" (допустим, это просто строка) и список объектов некоторого типа, либо значение "error" и строка с описанием ошибки.

В языках Ocaml, Erlang вернуть такую ошибку на клиенте достаточно просто - тип return value данной функции - Sum Types - либо/либо.
В языке Python данной проблемы вообще не стоит - клиент получает на выходе структуру, структуру которой он легко может исследовать динамически:
what, result = call( fitler )
if what == "ok":
    # result - список
    # обрабатываем список...
elif what = "error":
    # result - описание ошибки
else:
    # внутрення ошибка - неожиданный ответ сервера

Можно тоже самое завернуть в dict, можно придумать что-нибудь с getattr (по сути, тоже самое использование dict в неявной форме).

С Haskell всё тоже хорошо (Ocaml вариант). И с JavaScript (Python вариант). И с Lisp (продолжения не рассматриваем, т.к. они слишком специфичны для Lisp - High Order Function между языками по TCP/IP не погоняешь, ДА, КОНЕЧНО можно это сделать - но мне кажется это будет overkill).

А что делать с языками C/С++ и Java? В них нету Sum Types. Есть? Вам показалось.
Variant из Java/C# не имеет никакого отношения к Sum Types. Как и void* в С/C++.

Наиболее близкий аналог, что можно найти - это boost.variant в C++
union в Си, интерфейсы в Java / C# + паттерн посетитель (boost.variant - всего лишь посетитель на стероидах)... попробуйте описать описываемую выше функцию в C#/Java/C++/C, а потом приходител и поделитесь результатом. Как в Line of Codes, так и примерами, так и вашими субъективными ощущениями.

А всё почему?

Все эти языки подразумевает различную обработку исключительных ситуаций.

C обычно нам предлагает Error Return Code, + GetLastErorr() (вернут код ошибки, дополнительные аргументы сложить в глобальную структура, доступаться к которой можно при помощи вызова GetLastError()).
setjmp/longjmp назвать удобным в использовании у меня язык не повернётся.

C++, Java, C# предлагают нам исключения.

Ocaml, Haskell - Sum Types + Pattern Matching. Ocaml также предлагает исключения.

Python, JavaScript уходят от решения проблемы благодаря динамической типизации - и пользователь может эмулировать Sum Types, может оформить функцию-обёртку, что разбирается с распространёнными типами ответов: "ok" или "error"? Если "ok" - отдать вызывающей функции, если "error" - предпринять действия (например, выбросить исключение) - таким изящным образом языки с динамической типизацией позволяют использовать любую стратегию обработки ошибок.
В Питоне такую обработку могут сильно облегчить декораторы.

Erlang предлагает на выбор либо pattern matching, либо exception (переход к исключениям как в Питоне).

Причесать разношёрстную компанию очень сложно. Представьте хотя бы проксирование исключений по rpc =)

Не так давно, уважаемый Мультиязычная разработка [info]plumqqz удивлялся в комментариях "зачем мне rpc транслятор?" - по сути транслятор из idl в обычный код.
Отвечаю, уважаемый крокодил - в случае динамически типизированных языков не нужен вообще.

В Python - к нему даже подходить не нужно. Интроспекция позволяет бесшовно встраиваться в пользовательский код (благодаря __call__, getatrr + **kwargs).
JavaScript - аналогично python.

С++? Java? C#? Не друг с другом, заметьте, а с другими языками или между собой.
Слова SOAP, DCOM, CORBA нифига не спасут - эти система интегрируются в языки далеко не естественным для них образом. Да и тащить CORBA, когда мне нужен light rpc... Из пушки по воробьям гуманней - они улететь могут. А CORBA придавит собой всё приложение )

Оставить комментарий

Предыдущие записи блогера :
Архив записей в блогах:
Недавно жж поздравил меня с тем, что мы вместе уже целых 17 лет из его собственных, как нынче выяснилось, 24.  Начиналось все, как в плохом романе. Мы расстались с мужем и жили отдельно, но вариант «уходя уходи» почему-то у нас работал из рук вон плохо. Свидетельства о разводе не ...
Швейцария планирует ежемесячно выплачивать гражданам страны по 2500 швейцарских франков (около 2500 евро), пишет The Independent. На июнь федеральное правительство уже запланировало проведение референдума по данному вопросу. Если граждане одобрят инициативу, то Швейцария станет п ...
Едем в воскресенье с мамой вечерком домой. Я сижу уткнувшись в смартфон. Разглядываю там фоточки няшных котиков и крольчат, показываю их маме. А она мне заявляет, что мол "лучше бы ты фотографии детишек маленьких смотрела и умилялась". И такая головой кивает с серьезным лицом, типа "да да ...
Вот придет война большая, Заберемся мы в подвал. Тишину с душой мешая Ляжем на пол, наповал. Мне, безрукому, остаться С пацанами суждено, И под бомбами шататься Мне на хронику в кино. Как чаинки вьются годы, Смерть поднимется со дна, Ты, как я, - дитя природы И прекрасен как ...
Вот, у меня на сегодняшний день есть 5,5 тыс. френдов. Некоторые говорят - не обращай внимания на них, пиши о чем хочешь, не подстраивайся! Неееее, нельзя так, я считаю. Иначе получится, что я такой стою на постаменте и вещаю - внемли человечество, ибо ...