librelist archives

« back to archive

multiples implementaciones de una interfaz

multiples implementaciones de una interfaz

From:
Mariano Guerra
Date:
2011-07-08 @ 08:57
buenas,

 imaginemos que voy a implementar un modulo que expone una api que
tiene multiples implementaciones para distintos casos y uno puede
hacer una nueva implementacion

la idea es que el usuario de la api siempre use la misma api y tenga
que hacer el minimo trabajo para ponerlo a andar y que no tenga que
hacer grandes cambios si cambia de implementacion

ejemplo, una libreria para manipular xml o html

tenemos la api externa y una implementacion para xml y otra para html
(y posiblemente otras para otros tipos de datos)

como implementarian esto?

PD: me quiero mantener alejado de parametrized modules

Re: [erlar] multiples implementaciones de una interfaz

From:
Juan Jose Comellas
Date:
2011-07-08 @ 13:54
Este es todavía un problema en Erlang. Yo no encontré todavía una forma
"limpia" de hacer algo que los lenguajes orientados a objectos resuelven con
mucha facilidad combinando herencia y polimorfismo.

1) La primer opción que se me ocurre es la que ya descartaste (módulos
parametrizados).

2) Crear un behaviour con la interfaz que vas a querer soportar en cada uno
de los módulos y después implementar los módulos. En la aplicación tendrías
que guardar el nombre del módulo en una variable e invocar a las funciones
usando la variable (ej. Module:func()).

3) Armar un módulo que actúe como wrapper e invoque al módulo que
corresponda según lo que recibe.

4) Si los módulos tienen mucho código y datos en común podrías usar la
herencia de módulos (-extends()), pero ésto es aún menos usado que los
módulos parametrizados. Podés ver una presentación de ésto en:
http://www.erlang.org/euc/07/papers/1700Carlsson.pdf

Yo he usado las 3 primeras opciones en distintos casos. La forma más simple
es con módulos parametrizados, pero casi nadie les tiene mucho aprecio. Lo
raro es que los que más lo usan (mochiweb y misultin para encapsular a los
requests HTTP) no veo que lo necesiten tanto.

Juanjo


2011/7/8 Mariano Guerra <luismarianoguerra@gmail.com>

> buenas,
>
>  imaginemos que voy a implementar un modulo que expone una api que
> tiene multiples implementaciones para distintos casos y uno puede
> hacer una nueva implementacion
>
> la idea es que el usuario de la api siempre use la misma api y tenga
> que hacer el minimo trabajo para ponerlo a andar y que no tenga que
> hacer grandes cambios si cambia de implementacion
>
> ejemplo, una libreria para manipular xml o html
>
> tenemos la api externa y una implementacion para xml y otra para html
> (y posiblemente otras para otros tipos de datos)
>
> como implementarian esto?
>
> PD: me quiero mantener alejado de parametrized modules
>

Re: [erlar] multiples implementaciones de una interfaz

From:
Nahuel Greco
Date:
2011-07-08 @ 14:16
2011/7/8 Juan Jose Comellas <juanjo@comellas.org>:
> 4) Si los módulos tienen mucho código y datos en común podrías usar la
> herencia de módulos (-extends()), pero ésto es aún menos usado que los
> módulos parametrizados. Podés ver una presentación de ésto en:
> http://www.erlang.org/euc/07/papers/1700Carlsson.pdf
>

Esta no la tenía... a leer! :)

Saludos,
Nahuel Greco.

Re: [erlar] multiples implementaciones de una interfaz

From:
Ale
Date:
2011-07-08 @ 15:11
El día 8 de julio de 2011 11:16, Nahuel Greco <ngreco@gmail.com> escribió:
> 2011/7/8 Juan Jose Comellas <juanjo@comellas.org>:
>> 4) Si los módulos tienen mucho código y datos en común podrías usar la
>> herencia de módulos (-extends()), pero ésto es aún menos usado que los
>> módulos parametrizados. Podés ver una presentación de ésto en:
>> http://www.erlang.org/euc/07/papers/1700Carlsson.pdf
>>
>
> Esta no la tenía... a leer! :)

Este también tiene mucha pinta:
http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.58.79&rep=rep1&type=pdf

>
> Saludos,
> Nahuel Greco.
>



-- 
Ale.

Re: [erlar] multiples implementaciones de una interfaz

From:
Ale
Date:
2011-07-08 @ 14:09
> Yo he usado las 3 primeras opciones en distintos casos. La forma más simple
> es con módulos parametrizados, pero casi nadie les tiene mucho aprecio. Lo
> raro es que los que más lo usan (mochiweb y misultin para encapsular a los
> requests HTTP) no veo que lo necesiten tanto.

En chicago boss los usan
http://www.evanmiller.org/chicago-boss-guide.html para crear los
modelos de datos. Cuando los vi ahí me parecieron muy interesantes y
útiles.

Saludos,
-- 
Ale.

Re: [erlar] multiples implementaciones de una interfaz

From:
Nahuel Greco
Date:
2011-07-08 @ 13:37
Tendrías un modulo A que usa una API B que puede estar implementada en
C o D, creo que se reduce a:

1- Usar parametrized modules (por qué no querés?).
2- Declarar en B un behaviour a implementarse por C/D y hacer un
switcheo de files a C o D en el build process.
3- Mantener el estado en A de que estás usando C/D
  3.1- Si hay código en B que usa a C/D (ej, si quisieras hacer algo
como http://en.wikipedia.org/wiki/Template_method_pattern ), declarar
un behaviour en B a ser implementado por C/D y en A mantener un estado
(que podría ser un proceso lanzado por B, o en su forma mínima un
atomo 'c', 'd') que pasarías al llamar a las funcs de B, que a su vez
usan las de C/D.
  3.2- Si B existe solo para definir la API, definirla como behaviour
y que C/D la implementen. Luego en A usar C/D directamente a través de
una constante ?MODCorD:fun1().
4- (No es un idioma común) Retornar desde B un record con closures de
C/D y desde A usar ese record.

Saludos,
Nahuel Greco.



2011/7/8 Mariano Guerra <luismarianoguerra@gmail.com>:
> buenas,
>
>  imaginemos que voy a implementar un modulo que expone una api que
> tiene multiples implementaciones para distintos casos y uno puede
> hacer una nueva implementacion
>
> la idea es que el usuario de la api siempre use la misma api y tenga
> que hacer el minimo trabajo para ponerlo a andar y que no tenga que
> hacer grandes cambios si cambia de implementacion
>
> ejemplo, una libreria para manipular xml o html
>
> tenemos la api externa y una implementacion para xml y otra para html
> (y posiblemente otras para otros tipos de datos)
>
> como implementarian esto?
>
> PD: me quiero mantener alejado de parametrized modules
>

Re: [erlar] multiples implementaciones de una interfaz

From:
Mariano Guerra
Date:
2011-07-08 @ 13:46
2011/7/8 Nahuel Greco <ngreco@gmail.com>:
> Tendrías un modulo A que usa una API B que puede estar implementada en
> C o D, creo que se reduce a:
>
> 1- Usar parametrized modules (por qué no querés?).

me parece un hack medio fiero :S

> 2- Declarar en B un behaviour a implementarse por C/D y hacer un
> switcheo de files a C o D en el build process.

el tema es que todas las implementaciones tendrian que estar
disponibles en tiempo de ejecucion, me parece que lo de behavours es
la bocha, pense que eran algo propio de otp, lo mio seria un modulo
con una api comun y corriente

> 3- Mantener el estado en A de que estás usando C/D
>  3.1- Si hay código en B que usa a C/D (ej, si quisieras hacer algo
> como http://en.wikipedia.org/wiki/Template_method_pattern ), declarar
> un behaviour en B a ser implementado por C/D y en A mantener un estado
> (que podría ser un proceso lanzado por B, o en su forma mínima un
> atomo 'c', 'd') que pasarías al llamar a las funcs de B, que a su vez
> usan las de C/D.

pero de esta forma las implementaciones correrian en un proceso
aparte? seria un cuello de botella si por ejemplo multiples procesos
quieren correr funciones del modulo.

>  3.2- Si B existe solo para definir la API, definirla como behaviour
> y que C/D la implementen. Luego en A usar C/D directamente a través de
> una constante ?MODCorD:fun1().

como dije arriba en tiempod e ejecucion se pueden usar los dos modulos a la vez

> 4- (No es un idioma común) Retornar desde B un record con closures de
> C/D y desde A usar ese record.

estaba pensando en algo como un closure pero me parecio medio hackoso.

***

aclaro por que me parece que no fui claro.

quiero algo asi como una interfaz de java/go o abstract base class de
python, digamos, A expresa la api y los otros la implementan, pero
quiero enforcement en tiempo de compilacion si es posible.

otra cosa es que mi modulo/api va a ser un modulo, osea no va a ser un
gen_server ni nada por el estilo y es probable que algunas llamadas
quieran ser lanzadas en otro proceso por lo que levantar un unico
proceso es un bottleneck y que el cliente tenga que levantar un
proceso me parece un poco un hack.

ahora me pongo a mirar behaviours

disclaimer (aunque creo que se nota): si bien he programado en erlang
bastante nunca use toda la parte otp asi que por ahi estoy preguntando
una boludes :P

Re: [erlar] multiples implementaciones de una interfaz

From:
Nahuel Greco
Date:
2011-07-08 @ 14:14
2011/7/8 Mariano Guerra <luismarianoguerra@gmail.com>:
> 2011/7/8 Nahuel Greco <ngreco@gmail.com>:
>
>> 2- Declarar en B un behaviour a implementarse por C/D y hacer un
>> switcheo de files a C o D en el build process.
>
> el tema es que todas las implementaciones tendrian que estar
> disponibles en tiempo de ejecucion, me parece que lo de behavours es
> la bocha, pense que eran algo propio de otp, lo mio seria un modulo
> con una api comun y corriente
>

El tema de Behaviours es un feature del lenguaje, no de OTP. El
problema es que siempre se explica relacionado a OTP y por eso
confunde, pero es muy simple. En un modulo B definís algo similar a
una interface en Java:

-module(b)
-export([behaviour_info/1, start:/1])

behaviour_info(callbacks) ->
        [{myfun,1}];
behaviour_info(_Other) ->
       undefined.

Lo que declara que si otro módulo quiere implementar el behaviour b,
va a tener que implementar y exportar myfun/1. Luego en el modulo A
hacés:

-module(a)
-behaviour(b)
-export([myfun/1])

myfun ->
      %% implementacion de myfun

Y lo que hace el compilador cuando compila A es simplemente tirar
warnings si le falta definir myfun u otra funcion declarada en el
behaviour. Nada más, that's all.


>> 3- Mantener el estado en A de que estás usando C/D
>>  3.1- Si hay código en B que usa a C/D (ej, si quisieras hacer algo
>> como http://en.wikipedia.org/wiki/Template_method_pattern ), declarar
>> un behaviour en B a ser implementado por C/D y en A mantener un estado
>> (que podría ser un proceso lanzado por B, o en su forma mínima un
>> atomo 'c', 'd') que pasarías al llamar a las funcs de B, que a su vez
>> usan las de C/D.
>
> pero de esta forma las implementaciones correrian en un proceso
> aparte? seria un cuello de botella si por ejemplo multiples procesos
> quieren correr funciones del modulo.
>

Desgloso las dos posibilidades:

1- desde A harías b:fun(c) (sin procesos extra).
2- desde A harías Pid = b:start(c), lo que te devolvería un proceso
que incluye el estado de que lo inicializaste con c, y luego usarías
b:funx(Pid)..

Es similar a usar gen_server:call(atom... o gen_server:call(Pid..

>>  3.2- Si B existe solo para definir la API, definirla como behaviour
>> y que C/D la implementen. Luego en A usar C/D directamente a través de
>> una constante ?MODCorD:fun1().
>
> como dije arriba en tiempod e ejecucion se pueden usar los dos modulos a la vez
>

Bueno, en ese caso para esto no sería una constante sino una variable
Module = (c / d).


> estaba pensando en algo como un closure pero me parecio medio hackoso.
>

No es un idioma usual.

Saludos,
Nahuel Greco.

Re: [erlar] multiples implementaciones de una interfaz

From:
Juan Jose Comellas
Date:
2011-07-08 @ 14:10
Las behaviours son bastante fáciles de usar. Son básicamente módulos que en
la invocación a la función behaviour_info(callbacks) responden con una lista
de tuplas con el nombre y la aridad de las funciones de la interfaz que
querés proveer.

Ejemplo:

-module(pbx_fsm).
-export([behaviour_info/1]).

-spec behaviour_info(callbacks | any()) -> [{FunctionName :: atom(), Arity
:: non_neg_integer()}] | undefined.
behaviour_info(callbacks) ->
    [{dialplan, 3},
     {on_event, 2},
     {execute, 2},
     {execute, 3}];
behaviour_info(_Other) ->
    undefined.

En este ejemplo todos los módulos que implementen la interfaz del behaviour
van a tener que definir las funciones: dialplan/3, on_event/2, execute/2 y
execute/3 de la siguiente manera:

-module(pbx_fsm_conference).
-behaviour(pbx_fsm).
-export([dialplan/3, on_event/2, execute/2, execute/3]).
[... implementación de las funciones ...]


Saludos,

Juanjo

2011/7/8 Mariano Guerra <luismarianoguerra@gmail.com>

> 2011/7/8 Nahuel Greco <ngreco@gmail.com>:
> > Tendrías un modulo A que usa una API B que puede estar implementada en
> > C o D, creo que se reduce a:
> >
> > 1- Usar parametrized modules (por qué no querés?).
>
> me parece un hack medio fiero :S
>
> > 2- Declarar en B un behaviour a implementarse por C/D y hacer un
> > switcheo de files a C o D en el build process.
>
> el tema es que todas las implementaciones tendrian que estar
> disponibles en tiempo de ejecucion, me parece que lo de behavours es
> la bocha, pense que eran algo propio de otp, lo mio seria un modulo
> con una api comun y corriente
>
> > 3- Mantener el estado en A de que estás usando C/D
> >  3.1- Si hay código en B que usa a C/D (ej, si quisieras hacer algo
> > como http://en.wikipedia.org/wiki/Template_method_pattern ), declarar
> > un behaviour en B a ser implementado por C/D y en A mantener un estado
> > (que podría ser un proceso lanzado por B, o en su forma mínima un
> > atomo 'c', 'd') que pasarías al llamar a las funcs de B, que a su vez
> > usan las de C/D.
>
> pero de esta forma las implementaciones correrian en un proceso
> aparte? seria un cuello de botella si por ejemplo multiples procesos
> quieren correr funciones del modulo.
>
> >  3.2- Si B existe solo para definir la API, definirla como behaviour
> > y que C/D la implementen. Luego en A usar C/D directamente a través de
> > una constante ?MODCorD:fun1().
>
> como dije arriba en tiempod e ejecucion se pueden usar los dos modulos a la
> vez
>
> > 4- (No es un idioma común) Retornar desde B un record con closures de
> > C/D y desde A usar ese record.
>
> estaba pensando en algo como un closure pero me parecio medio hackoso.
>
> ***
>
> aclaro por que me parece que no fui claro.
>
> quiero algo asi como una interfaz de java/go o abstract base class de
> python, digamos, A expresa la api y los otros la implementan, pero
> quiero enforcement en tiempo de compilacion si es posible.
>
> otra cosa es que mi modulo/api va a ser un modulo, osea no va a ser un
> gen_server ni nada por el estilo y es probable que algunas llamadas
> quieran ser lanzadas en otro proceso por lo que levantar un unico
> proceso es un bottleneck y que el cliente tenga que levantar un
> proceso me parece un poco un hack.
>
> ahora me pongo a mirar behaviours
>
> disclaimer (aunque creo que se nota): si bien he programado en erlang
> bastante nunca use toda la parte otp asi que por ahi estoy preguntando
> una boludes :P
>