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

топ 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 придавит собой всё приложение )

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

Предыдущие записи блогера :
Архив записей в блогах:
20 июля 1926 года не стало Феликса Дзержинского (1877—1926) — большевика, революционера, первого чекиста. На его похоронах встретилось все тогдашнее Политбюро ЦК ВКП(б) Рыков, Калинин, Троцкий, Каменев, Сталин, Томский, ...
- А почему вы бегаете и носите всем подарки с натянутой дежурной улыбкой? - Ну как же! Если я не буду бегать, меня люди не поймут! - И что с того? - Они меня осудят! zelanton почему-то хочет меня как-то подловить на праздновании непонятных праздников, ...
А что интересного ты, камрад, возил на прицепе? А выпив по-молодости немного лишнего пива ездил ли в тазу привязанном на верёвке к автомобилю? И что, инетресно, за страна? Угорщина или Сербия? Или может Эстония? Если было и улучшениями не улучшится - удалю. ...
Мировое сообщество впаяло Радовану Караджичу 40 лет тюрьмы, что по факту является пожизненным заключением. Долго тянуть не стали - привели и зачитали приговор. Свирепость цивилизованного правосудия вполне оправдана - в назидание всем, кто хочет противостоять Западу, преподнесен очередной у ...
Сергей и Алена, хорошие знакомые моей подруги Кристины ,  казались идеальной парой. Между ними было какое-то удивительное взаимопонимание, которому я страшно завидовала. Пытаюсь подобрать слово, и первое, что приходит на ум: правильно. У них все было очень правильно. Хорошая семья ...