[Perl] equivalencia de un case

Salvador Ortiz Garcia sog@msg.com.mx
13 Mar 2002 00:00:05 -0600


On Tue, 2002-03-12 at 16:00, Gunnar Wolf wrote:
> > > Voy a implementar en una programacion que tengo operativa en PERL un =
modulo de traduccion por llamarlo de alguna forma.
> > >
> > > Se trata de hacer algo como el sistema que utiliza el php-nuke
> > >
> > > Pero PERL no tiene ninguna sentencia equivalente.
> >(...)
> > Ahora que, a mi me gusta m=E1s usando un hash:
> >
> > my %Maps =3D (
> >    '0001' =3D> 'Mensaje n=FAmero uno',
> >    '0002' =3D> 'Mensaje n=FAmero dos',
> >     # Etc;
> > };
>=20
> A m=ED me gusta abundar un poco en esto, si vas a pasar seguido por esta
> construcci=F3n:
> %tipo =3D ( 'a' =3D> sub { print "Es de tipo A\n"; },
>           'b' =3D> sub { print "No, no me gusta...\n"; },
>           'c' =3D> sub { otraCosa(1,2); } );
>=20
> Y cuando lo requieras, la llamas as=ED:
>=20
> &{$tipo{$expr}};

Pues abundemos ;-)

Primero, ya s=E9 que adoras el &, pero creo que es m=E1s claro si usas:

   $tipo{$expr}->()

Dos, y m=E1s importante, los "closures" son herramientas poderosas, pero
hay que tener cautela al usarlos:

Si lo que quieres es una tabla de mapeo es mucho m=E1s eficiente y m=E1s
claro hacerla directa como la que puse primero.

Si lo que quieres en un "despachador de funciones", es mejor en t=E9rminos
de eficiencia, y se usa igual, hacer un hash de referencias simples a
funciones, aunque escribas m=E1s:

sub func1 { ... }
sub func2 { ... }
...

%dispatch =3D ( 'a' =3D> \&func1, 'b' =3D> \&func2, ... );
$dispatch{$selector}->(...);

O incluso puedes hacer algunos jueguitos con namespaces:

sub MyDisp::a { ... }
sub MyDisp::b { ... }

"MyDisp::$selector"->(...); # Sog's style
&{"MyDisp::$selector"}(...) ; # Gunnar's style

Pero crear N closures, que te capturan, cada uno, todo el =E1mbito l=E9xico
de tu programa sin una necesidad real lo considero excesivo.

Si no queda claro a qu=E9 me refiero, hagsmos un "factory" de contadores,
ejemplo en que los closures son la mejor opci=F3n, pero en que tengo el
=E1mbito l=E9xico controlado y lo necesito:

# Ejemplo Verboso por claridad
sub ContFactory {
   my $Base =3D shift;              # Desde donde cuento
   my $Incremento =3D shift || 1;   # De cuantos en cuantos
   my $func =3D sub {               # Construyo un closure, en cuyo =E1mbit=
o
      my $current =3D $Base;        # tengo atrapados $Base e $incremento
      $Base +=3D $Incremento;
      return $current;
   };
   return $func;                  # Lo devuelvo
}

# Construyo un contador1, desde 0, con incr de 10=20
$cont1 =3D ContFactory(0,10);
# Ahora otro, desde 15 con incr de 3
$cont2 =3D ContFactory(15,3);
# Los llamo uso unas cuantas veces
for(0..10) {
   print $cont1->()," ",$cont2->()," ";
}

Pregunta capsiosa:  "Cual es el valor de $Base ahora?"
Respuesta posible:  "Cu=E1l $Base?, la atrapada en $cont1 o la en $cont2?"

Ahora si, cada uno de los contadores carga con su _propia_ instancia de
las variables l=E9xicas existentes en el =E1mbito en que el closure fu=E9
creado y te garantiza un encapsulamiento total, pues no existe forma de
que desde "afuera" se alteren, pues cuando ContFactory regres=F3
desaparecieron de cualquier =E1mbito externo.

Por supuesto que eso tiene sus costos y en un descuido acabas teniendo N
instancias inutiles de un mont=F3n de variables.

Saludos.

Salvador Ortiz.