Пытаюсь изменить мировоззрение и поизучать ерланг.
1. И может глупый вопрос но как быть с абстракциями в нем.
В джаве я привык пользоваться интерфейсами и в зависимости от условий подсовывать конкретную имплементацию.
А есть ли такая возможность в ерланге или там это делается совсем по другому.
Как пример — есть интерфейс IQueue и в рантайме могу использовать различные ее реализации — сериализация в файл, БД, только память, вобще нет очереди — все синхронно. Т.к. интерфейс один и тот же то ничего менять не надо — а как в ерланге?
2. Опять же в джаве есть универсальный АПИ для работы с БД — JDBC. А что у ерланга и насколько он вобще умеет работать с распространенными БД.
3. Есть ли аналог JAR — чтобы упаковывать библиотеки в отдельные бандлы а не все в кучу сваливать.
Здравствуйте, DarkIT, Вы писали:
DIT>В джаве я привык пользоваться интерфейсами и в зависимости от условий подсовывать конкретную имплементацию. DIT>А есть ли такая возможность в ерланге или там это делается совсем по другому.
В динамических языках это как-то не особо и нужно. Там же типизация утиная.
Здравствуйте, Lloyd, Вы писали:
L>В динамических языках это как-то не особо и нужно. Там же типизация утиная.
Не совсем понимаю — вот как пример вызов метода: io:read('enter>')
Мы же явно указываем модуль и метод — как тут заабстрагируешься?
П.С. возможно вопросы очень тупые (представляю себе такие в джава топике ) — но просьба отнестись с понимаем тк пока в доке не нашел ответа на вопросы.
Здравствуйте, DarkIT, Вы писали:
L>>В динамических языках это как-то не особо и нужно. Там же типизация утиная.
DIT>Не совсем понимаю — вот как пример вызов метода: io:read('enter>') DIT>Мы же явно указываем модуль и метод — как тут заабстрагируешься?
А не надо указывать модуль, работай через объект-обертку, так же как ты собирался делать в java
P.S. Я на самом деле erlang не знаю, делаю предположения на основе общих соображений о динамич. языках.
Здравствуйте, DarkIT, Вы писали:
DIT>В джаве я привык пользоваться интерфейсами и в зависимости от условий подсовывать конкретную имплементацию. DIT>А есть ли такая возможность в ерланге или там это делается совсем по другому. DIT>Как пример — есть интерфейс IQueue и в рантайме могу использовать различные ее реализации — сериализация в файл, БД, только память, вобще нет очереди — все синхронно. Т.к. интерфейс один и тот же то ничего менять не надо — а как в ерланге?
Ну, можно примерно сэмулировать объектно-ориентированный подход, используя процесс на объект.
Для абстракции, представляющей очередь, например, любой процесс, реализующий операции с очередью должен будет
отвечать на сообщения {enqueue, Elem} -> ok, dequeue -> Elem.
Передавая пид процесса функциям, работающим с очередью, мы отвязываемся
от конкретной реализации. Можно пойти чуть дальше, и написать модуль-обёртку, скрывая протокол обмена сообщениями вызовами функций.
DIT>2. Опять же в джаве есть универсальный АПИ для работы с БД — JDBC. А что у ерланга и насколько он вобще умеет работать с распространенными БД.
Есть модуль ODBC, есть чисто эрланговые для postgres и mysql.
DIT>3. Есть ли аналог JAR — чтобы упаковывать библиотеки в отдельные бандлы а не все в кучу сваливать.
Если не изменяет память, с 13 версии появилась такая возможность, паковать отдельные приложения в zip архив аля java.
DIT>1. И может глупый вопрос но как быть с абстракциями в нем. DIT>В джаве я привык пользоваться интерфейсами и в зависимости от условий подсовывать конкретную имплементацию. DIT>А есть ли такая возможность в ерланге или там это делается совсем по другому. DIT>Как пример — есть интерфейс IQueue и в рантайме могу использовать различные ее реализации — сериализация в файл, БД, только память, вобще нет очереди — все синхронно. Т.к. интерфейс один и тот же то ничего менять не надо — а как в ерланге?
Каждый модуль — это «черный ящик», выдающий наружу определенный интерфейс.
Поэтому представим, что для сериализации/десериализации модуль должен выставлять наружу ровно два метода: serialize/1 и deserialize/1:
Предположим, у нас есть модули serialize_to_file, serialize_to_db, serialize_to_ram, которые выставляют наружу эти функции.
Тогда:
Module1 = serialize_to_file,
Module2 = serialize_to_db,
Module3 = serialize_to_ram,
Data = какие-то данные,
Module1:serialize(Data), %% сохранили в файл
Module2:serialize(Data), %% сохранили в базу
Module3:serialize(Data), %% сохранили в память
То есть можно сделать какой-нить модуль serializer_factory, который будет в зависимости от конфигурации возвращать имя модуля, который будет заниматься сериализацией. Типа:
DIT>2. Опять же в джаве есть универсальный АПИ для работы с БД — JDBC. А что у ерланга и насколько он вобще умеет работать с распространенными БД.
В Эрланге с тим как бы посложнее.
— есть Erlang ODBC: http://www.erlang.org/doc/apps/odbc/index.html. Построен поверх MS ODBC и поэтому требует МС-ные рова к базам.
— есть отдельные дрова к PostgreSQL, MySQL и т.п.
DIT>3. Есть ли аналог JAR — чтобы упаковывать библиотеки в отдельные бандлы а не все в кучу сваливать.
Ну, не обязательно же все в кучу сваливать А аналогов JAR нет
Здравствуйте, DarkIT, Вы писали:
DIT>Пытаюсь изменить мировоззрение и поизучать ерланг.
DIT>1. И может глупый вопрос но как быть с абстракциями в нем. DIT>В джаве я привык пользоваться интерфейсами и в зависимости от условий подсовывать конкретную имплементацию.
Есть такое или примерно такое, почитайте в документации по эрлангу в разделе Working With OTP и там DesignPrinciples, а там 6.3 User-Defined Behaviours
.
Поищите в документации про behaviour и behaviour_info
Например можно сказать, что следующий список функций должен реализовать "модуль-наследник"
Теперь мучает вопрос а где же сохранять временные данные не тягать же что надо в функцию.
Или модуль это просто группировка функций и шаринг данных не предусмотрен.
А то после мира ООП не понимаю куда можно сохранить ПИД процесса который в создали в функции start, чтобы потом метод stop мог его завершить.
Т.е. в рамках ООП наружу ПИД вобще нету смысла вытаскивать и про внутреннюю кухню знает только конкретный объект класса.
А в ерланга получается у меня нету места для сохранения и области видимости в рамках модуля или чего то статичного.
Как пример кеш — в джава делается очередь в виде какой либо коллекции и синхронизируется доступ. Вопрос не про синхронизацию а имено что некая сущность живет для всех объектов и наружу торчит только положить в кеш, достать из кеша.
Здравствуйте, DarkIT, Вы писали:
DIT>Всем спасибо за ответы.
DIT>Потихоньку начинает все проясняться.
DIT>Теперь мучает вопрос а где же сохранять временные данные не тягать же что надо в функцию. DIT>Или модуль это просто группировка функций и шаринг данных не предусмотрен. DIT>А то после мира ООП не понимаю куда можно сохранить ПИД процесса который в создали в функции start, чтобы потом метод stop мог его завершить. DIT>Т.е. в рамках ООП наружу ПИД вобще нету смысла вытаскивать и про внутреннюю кухню знает только конкретный объект класса. DIT>Как пример кеш — в джава делается очередь в виде какой либо коллекции и синхронизируется доступ. Вопрос не про синхронизацию а имено что некая сущность живет для всех объектов и наружу торчит только положить в кеш, достать из кеша.DIT>А в ерланга получается у меня нету места для сохранения и области видимости в рамках модуля или чего то статичного.
. Единственное отличие от Java это синтаксис.
Erlang:
NewQueue=operation(Queue)
Java:
Queue.operation();
Ещё один вариант — использование процессов, в качестве объектов. На них, при желании, можно сделать полноценный ООП в стиле Java с наследованием и изменяемыми данными.
Кстати, возможно, будет полезным посмотреть на решениеProblem K, как на пример "идиоматического" дизайна на эрланге.
The last good thing written in C was Franz Schubert's Symphony No. 9.
DarkIT пишет: > > Т.е. в рамках ООП наружу ПИД вобще нету смысла вытаскивать и про > внутреннюю кухню знает только конкретный объект класса.
А зачем к процессу через PID обращаться? Эрланг предусматривает более
удобные для этого способы. Советую прочитать про процессы в доке
эрланга. Там это всё хорошо разжёвано.
DIT>Потихоньку начинает все проясняться.
DIT>Теперь мучает вопрос а где же сохранять временные данные не тягать же что надо в функцию. DIT>Или модуль это просто группировка функций и шаринг данных не предусмотрен.
Модуль — это просто группировка функций. «Объектом» можно считать Эрланговский процесс
DIT>А то после мира ООП не понимаю куда можно сохранить ПИД процесса который в создали в функции start, чтобы потом метод stop мог его завершить. DIT>Т.е. в рамках ООП наружу ПИД вобще нету смысла вытаскивать и про внутреннюю кухню знает только конкретный объект класса. DIT>А в ерланга получается у меня нету места для сохранения и области видимости в рамках модуля или чего то статичного.
DIT>Как пример кеш — в джава делается очередь в виде какой либо коллекции и синхронизируется доступ. Вопрос не про синхронизацию а имено что некая сущность живет для всех объектов и наружу торчит только положить в кеш, достать из кеша.
Что делает gen_server? Он является оберткой над неким процессом с неким внутренним состянием.
Грубо говоря, предположим, у нас есть такой процесс:
%% здесь State — просто список
%% но можно использовать что угодно
loop(State) ->
receive
%% добавляем новый элемент в список
{add, {Key, Value}} ->
NewState = [{Key, Value}] ++ State,
loop(NewState);
%% получаем значение элемента
{get, From, Key} ->
From ! proplists:get_value(Key, State, undefined),
loop(State)
end.
Для того, чтобы таким пользоваться, нужно делать много телодвижений:
Pid = spawn(fun() -> loop([]) end),
Pid ! {add, {"a", "b"}},
%% надо создать свой event loop
%% чтобы получить значение из списка
F = fun() ->
Pid ! {get, self(), "a"},
receive
Value ->
Value
end,
V = F().
То есть нам везде надо протягивать Pid.
Для облегчения тго дела у нас есть gen_server, который предназначен ровно для таких случаев:
-module(key_value_store).
-behaviour(gen_server).
%% --------------------------------------------------------------------
%% API/Interface
%% --------------------------------------------------------------------
-export([add/1, get/1]).
%% --------------------------------------------------------------------
%% gen_server callbacks - стандатртные функции, что из них надо — см. в доке
%% --------------------------------------------------------------------
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
-export([start_link/1]).
init(_Args) ->
{ok, []}. %% устанавливаем внутреннее состояние в []
start() ->
%% start(Module, Args, Options)
gen_server:start(?MODULE, [], []).
add(Data) ->
%% перенаправляем вызов собственно в процесс,
%% который занимается обработкой сообщений
gen_server:call(?MODULE, {add, Data}).
get(Key) ->
%% перенаправляем вызов собственно в процесс,
%% который занимается обработкой сообщений
gen_server:call(?MODULE, {get, Key}).
%% реализуем логику для обработки сообщений
%% собственно, вызов gen_server:call(?MODULE, Message)
%% практически равнозначе вызову Pid ! Message
%% то есть какое сообщение мы использовали в API
%% такое и надо матчить в handle_call
%% для обработки сообщения {add, {Key, Value}}
handle_call({add, {_Key, _Value} = Data}, _From, State) ->
NewState = [Data] ++ State,
{reply, ok, NewState}. %% ok пойдет вызывавшему
%% NewState сохранится в процессе
%% для обработки сообщения {get, Key}
handle_call({get, Key, _From, State) ->
Value = proplists:get_value(Key, State, undefined),
{reply, Value, State}. %% Value пойдет вызывавшему
%%State сохранится в процессе
Используется это так:
key_value_store:start(),
ok = key_value_store:add({"a", "b"}),
Val = key_value_store:get("a").
Супер — буду вникать. Большое спасибо. В джаве ветке я подумал бы, что это и так все легко и можно легко понять. А тут опа и сам в роли зеленого новичка
M>>Для этого нужно смотреть в сторону поведения (behaviour) gen_server, http://www.erlang.org/doc/design_principles/gen_server_concepts.html
M>>Что делает gen_server? Он является оберткой над неким процессом с неким внутренним состянием.
DIT>Супер — буду вникать. Большое спасибо. В джаве ветке я подумал бы, что это и так все легко и можно легко понять. А тут опа и сам в роли зеленого новичка
На самом деле, все действительно все легко понять Просто оно какое-то немного другое, что сбивает с толку