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

Все мои проблемы с 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]](http://l-stat.livejournal.com/img/userinfo.gif)
Отвечаю, уважаемый крокодил - в случае динамически типизированных языков не нужен вообще.
В Python - к нему даже подходить не нужно. Интроспекция позволяет бесшовно встраиваться в пользовательский код (благодаря __call__, getatrr + **kwargs).
JavaScript - аналогично python.
С++? Java? C#? Не друг с другом, заметьте, а с другими языками или между собой.
Слова SOAP, DCOM, CORBA нифига не спасут - эти система интегрируются в языки далеко не естественным для них образом. Да и тащить CORBA, когда мне нужен light rpc... Из пушки по воробьям гуманней - они улететь могут. А CORBA придавит собой всё приложение )