Абстракции в Erlang
От: DarkIT  
Дата: 11.12.09 23:30
Оценка:
Пытаюсь изменить мировоззрение и поизучать ерланг.

1. И может глупый вопрос но как быть с абстракциями в нем.
В джаве я привык пользоваться интерфейсами и в зависимости от условий подсовывать конкретную имплементацию.
А есть ли такая возможность в ерланге или там это делается совсем по другому.
Как пример — есть интерфейс IQueue и в рантайме могу использовать различные ее реализации — сериализация в файл, БД, только память, вобще нет очереди — все синхронно. Т.к. интерфейс один и тот же то ничего менять не надо — а как в ерланге?

2. Опять же в джаве есть универсальный АПИ для работы с БД — JDBC. А что у ерланга и насколько он вобще умеет работать с распространенными БД.


3. Есть ли аналог JAR — чтобы упаковывать библиотеки в отдельные бандлы а не все в кучу сваливать.
Re: Абстракции в Erlang
От: Lloyd Россия  
Дата: 11.12.09 23:35
Оценка: +1
Здравствуйте, DarkIT, Вы писали:

DIT>В джаве я привык пользоваться интерфейсами и в зависимости от условий подсовывать конкретную имплементацию.

DIT>А есть ли такая возможность в ерланге или там это делается совсем по другому.

В динамических языках это как-то не особо и нужно. Там же типизация утиная.
Re[2]: Абстракции в Erlang
От: DarkIT  
Дата: 11.12.09 23:42
Оценка:
Здравствуйте, Lloyd, Вы писали:

L>В динамических языках это как-то не особо и нужно. Там же типизация утиная.


Не совсем понимаю — вот как пример вызов метода: io:read('enter>')
Мы же явно указываем модуль и метод — как тут заабстрагируешься?

П.С. возможно вопросы очень тупые (представляю себе такие в джава топике ) — но просьба отнестись с понимаем тк пока в доке не нашел ответа на вопросы.
Re[3]: Абстракции в Erlang
От: Lloyd Россия  
Дата: 11.12.09 23:46
Оценка:
Здравствуйте, DarkIT, Вы писали:

L>>В динамических языках это как-то не особо и нужно. Там же типизация утиная.


DIT>Не совсем понимаю — вот как пример вызов метода: io:read('enter>')

DIT>Мы же явно указываем модуль и метод — как тут заабстрагируешься?

А не надо указывать модуль, работай через объект-обертку, так же как ты собирался делать в java

P.S. Я на самом деле erlang не знаю, делаю предположения на основе общих соображений о динамич. языках.
Re: Абстракции в Erlang
От: Аноним  
Дата: 12.12.09 03:15
Оценка: +1
Здравствуйте, DarkIT, Вы писали:

DIT>В джаве я привык пользоваться интерфейсами и в зависимости от условий подсовывать конкретную имплементацию.

DIT>А есть ли такая возможность в ерланге или там это делается совсем по другому.
DIT>Как пример — есть интерфейс IQueue и в рантайме могу использовать различные ее реализации — сериализация в файл, БД, только память, вобще нет очереди — все синхронно. Т.к. интерфейс один и тот же то ничего менять не надо — а как в ерланге?

Ну, можно примерно сэмулировать объектно-ориентированный подход, используя процесс на объект.
Для абстракции, представляющей очередь, например, любой процесс, реализующий операции с очередью должен будет
отвечать на сообщения {enqueue, Elem} -> ok, dequeue -> Elem.

Передавая пид процесса функциям, работающим с очередью, мы отвязываемся
от конкретной реализации. Можно пойти чуть дальше, и написать модуль-обёртку, скрывая протокол обмена сообщениями вызовами функций.

Смотри также behaviours.

Или без процессов,

-module(queue).

new(Module) -> {Module, Module:new()}.
deq({Module, Data}) -> {E, NQ} = Module:deq(Data), {E, {Module, NQ}}.
enq({Module, Data}, E) -> {Module, Module:enq(Data, E)}.


-module(myqueue).

new() -> [].
deq(Data) -> [H|T] = lists:reverse(Data), {H, lists:reverse(T)}.
enq(Data, E) -> lists:reverse([E|lists:reverse(Data)]).


 ...
 Queue = queue:new(myqueue),
 process_queue(Queue).

 ...
 process_queue(Queue) ->
  {E, DQ} = queue:deq(Queue),
  queue:enq(DQ, E).


DIT>2. Опять же в джаве есть универсальный АПИ для работы с БД — JDBC. А что у ерланга и насколько он вобще умеет работать с распространенными БД.



Есть модуль ODBC, есть чисто эрланговые для postgres и mysql.

DIT>3. Есть ли аналог JAR — чтобы упаковывать библиотеки в отдельные бандлы а не все в кучу сваливать.


Если не изменяет память, с 13 версии появилась такая возможность, паковать отдельные приложения в zip архив аля java.
Re: CouchDb
От: DemAS http://demas.me
Дата: 12.12.09 12:48
Оценка:
DIT>2. Опять же в джаве есть универсальный АПИ для работы с БД — JDBC. А что у ерланга и насколько он вобще умеет работать с распространенными БД.

С распространенными не знаю, но я работал с CouchDb.
Re: Абстракции в Erlang
От: Mamut Швеция http://dmitriid.com
Дата: 13.12.09 10:47
Оценка: 12 (1)
DIT>1. И может глупый вопрос но как быть с абстракциями в нем.
DIT>В джаве я привык пользоваться интерфейсами и в зависимости от условий подсовывать конкретную имплементацию.
DIT>А есть ли такая возможность в ерланге или там это делается совсем по другому.
DIT>Как пример — есть интерфейс IQueue и в рантайме могу использовать различные ее реализации — сериализация в файл, БД, только память, вобще нет очереди — все синхронно. Т.к. интерфейс один и тот же то ничего менять не надо — а как в ерланге?

Каждый модуль — это «черный ящик», выдающий наружу определенный интерфейс.

Поэтому представим, что для сериализации/десериализации модуль должен выставлять наружу ровно два метода: serialize/1 и deserialize/1:

-module(любой_модуль).

-export([
    serialize/1,
    deserialize/1
]).


serialize(Data) ->
    что-то-делаем.

deserialize(Data) ->
    что-то-делаем.



Предположим, у нас есть модули 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, который будет в зависимости от конфигурации возвращать имя модуля, который будет заниматься сериализацией. Типа:


Serializer = serializer_factory:get(Какая-то-конфигурационная-инфа),
Serializer:serialize(Data)



DIT>2. Опять же в джаве есть универсальный АПИ для работы с БД — JDBC. А что у ерланга и насколько он вобще умеет работать с распространенными БД.



В Эрланге с тим как бы посложнее.

— есть Erlang ODBC: http://www.erlang.org/doc/apps/odbc/index.html. Построен поверх MS ODBC и поэтому требует МС-ные рова к базам.
— есть отдельные дрова к PostgreSQL, MySQL и т.п.

DIT>3. Есть ли аналог JAR — чтобы упаковывать библиотеки в отдельные бандлы а не все в кучу сваливать.


Ну, не обязательно же все в кучу сваливать А аналогов JAR нет


dmitriid.comGitHubLinkedIn
Re: Абстракции в Erlang
От: Evgeny_V  
Дата: 14.12.09 06:22
Оценка:
Здравствуйте, DarkIT, Вы писали:

DIT>Пытаюсь изменить мировоззрение и поизучать ерланг.


DIT>1. И может глупый вопрос но как быть с абстракциями в нем.

DIT>В джаве я привык пользоваться интерфейсами и в зависимости от условий подсовывать конкретную имплементацию.

Есть такое или примерно такое, почитайте в документации по эрлангу в разделе Working With OTP и там DesignPrinciples, а там 6.3 User-Defined Behaviours
.
Поищите в документации про behaviour и behaviour_info
Например можно сказать, что следующий список функций должен реализовать "модуль-наследник"
-export([behaviour_info/1]).
behaviour_info(callbacks) ->
    [{start_standalone,         1}, 
     {start_service,            1},
     {stop_service,             1},
     {services,                 0},
     {service_info,             1}];
behaviour_info(_) ->
    undefined.


А про базы, там же в документации DataBase Applications, раздел ODBC
Re: Абстракции в Erlang
От: DarkIT  
Дата: 15.12.09 13:21
Оценка:
Всем спасибо за ответы.

Потихоньку начинает все проясняться.

Теперь мучает вопрос а где же сохранять временные данные не тягать же что надо в функцию.
Или модуль это просто группировка функций и шаринг данных не предусмотрен.
А то после мира ООП не понимаю куда можно сохранить ПИД процесса который в создали в функции start, чтобы потом метод stop мог его завершить.
Т.е. в рамках ООП наружу ПИД вобще нету смысла вытаскивать и про внутреннюю кухню знает только конкретный объект класса.
А в ерланга получается у меня нету места для сохранения и области видимости в рамках модуля или чего то статичного.

Как пример кеш — в джава делается очередь в виде какой либо коллекции и синхронизируется доступ. Вопрос не про синхронизацию а имено что некая сущность живет для всех объектов и наружу торчит только положить в кеш, достать из кеша.
Re[2]: Абстракции в Erlang
От: crable США  
Дата: 15.12.09 16:29
Оценка: +1
Здравствуйте, DarkIT, Вы писали:

DIT>Всем спасибо за ответы.


DIT>Потихоньку начинает все проясняться.


DIT>Теперь мучает вопрос а где же сохранять временные данные не тягать же что надо в функцию.

DIT>Или модуль это просто группировка функций и шаринг данных не предусмотрен.
DIT>А то после мира ООП не понимаю куда можно сохранить ПИД процесса который в создали в функции start, чтобы потом метод stop мог его завершить.
DIT>Т.е. в рамках ООП наружу ПИД вобще нету смысла вытаскивать и про внутреннюю кухню знает только конкретный объект класса.
DIT>Как пример кеш — в джава делается очередь в виде какой либо коллекции и синхронизируется доступ. Вопрос не про синхронизацию а имено что некая сущность живет для всех объектов и наружу торчит только положить в кеш, достать из кеша.DIT>А в ерланга получается у меня нету места для сохранения и области видимости в рамках модуля или чего то статичного.

Так вот же оно
Автор:
Дата: 12.12.09
. Единственное отличие от 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.
Re[2]: Абстракции в Erlang
От: ArtDenis Россия  
Дата: 16.12.09 10:13
Оценка:
DarkIT пишет:
>
> Т.е. в рамках ООП наружу ПИД вобще нету смысла вытаскивать и про
> внутреннюю кухню знает только конкретный объект класса.
А зачем к процессу через PID обращаться? Эрланг предусматривает более
удобные для этого способы. Советую прочитать про процессы в доке
эрланга. Там это всё хорошо разжёвано.
Posted via RSDN NNTP Server 2.1 beta
[ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
Re[2]: Абстракции в Erlang
От: Mamut Швеция http://dmitriid.com
Дата: 16.12.09 15:15
Оценка: 4 (1)
DIT>Потихоньку начинает все проясняться.

DIT>Теперь мучает вопрос а где же сохранять временные данные не тягать же что надо в функцию.

DIT>Или модуль это просто группировка функций и шаринг данных не предусмотрен.

Модуль — это просто группировка функций. «Объектом» можно считать Эрланговский процесс

DIT>А то после мира ООП не понимаю куда можно сохранить ПИД процесса который в создали в функции start, чтобы потом метод stop мог его завершить.

DIT>Т.е. в рамках ООП наружу ПИД вобще нету смысла вытаскивать и про внутреннюю кухню знает только конкретный объект класса.
DIT>А в ерланга получается у меня нету места для сохранения и области видимости в рамках модуля или чего то статичного.

DIT>Как пример кеш — в джава делается очередь в виде какой либо коллекции и синхронизируется доступ. Вопрос не про синхронизацию а имено что некая сущность живет для всех объектов и наружу торчит только положить в кеш, достать из кеша.


Для этого нужно смотреть в сторону поведения (behaviour) gen_server, http://www.erlang.org/doc/design_principles/gen_server_concepts.html

Что делает 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").


dmitriid.comGitHubLinkedIn
Re[3]: Абстракции в Erlang
От: DarkIT  
Дата: 16.12.09 16:59
Оценка:
Здравствуйте, Mamut, Вы писали:

M>Для этого нужно смотреть в сторону поведения (behaviour) gen_server, http://www.erlang.org/doc/design_principles/gen_server_concepts.html


M>Что делает gen_server? Он является оберткой над неким процессом с неким внутренним состянием.


Супер — буду вникать. Большое спасибо. В джаве ветке я подумал бы, что это и так все легко и можно легко понять. А тут опа и сам в роли зеленого новичка
Re[4]: Абстракции в Erlang
От: Mamut Швеция http://dmitriid.com
Дата: 17.12.09 08:10
Оценка:
M>>Для этого нужно смотреть в сторону поведения (behaviour) gen_server, http://www.erlang.org/doc/design_principles/gen_server_concepts.html

M>>Что делает gen_server? Он является оберткой над неким процессом с неким внутренним состянием.


DIT>Супер — буду вникать. Большое спасибо. В джаве ветке я подумал бы, что это и так все легко и можно легко понять. А тут опа и сам в роли зеленого новичка



На самом деле, все действительно все легко понять Просто оно какое-то немного другое, что сбивает с толку


dmitriid.comGitHubLinkedIn
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.