OVH Cloud OVH Cloud

Forcer un contexte (de liste)

7 réponses
Avatar
Patrice Karatchentzeff
Salut,

Encore moi avec un problème à la c... ;-)

Je suis tombé sur un classique problème de contexte de liste/scalaire
en Perl (que j'ai quand même mis plusieurs heures à détecter... et
autant à corriger).

Voici un extrait de code simplifié :

#!/usr/bin/perl -w

use strict;
use Tk;

my $top = MainWindow -> new;
my $menu = $top -> Frame();
$menu -> pack();

my @cascade = ("[\"cascade\" => \"un\"],", "[\"cascade\" => \"deux\"],");

my $entree = $menu -> Menubutton(-text => "mon menu",
-menuitems => [@cascade]
);

$entree -> pack();

MainLoop;

Bon, je décortique : j'ai un ensemble de menus dynamiques à faire (je
ne connais pas leur nombre) et « -menuitems » demande une liste entre
[]. Donc, je charge une liste (ici @cascade) et je la balance dans
-menuitems.

Jusque là, logique.

Problème : ici, manifestement, le contexte de -menuitems est scalaire
(un bravo à celui qui trouve l'info sans lire le code...) et donc,
@cascade renvoie un scalaire, soit la longueur de la liste et mon menu
déroulant en cascade a bien deux entrées... vides.

La correction que j'ai trouvé (balèze, je m'étonne moi-même parfois)
est d'éclater la liste à l'aide d'eval :

-menuitems => [ eval "@cascade"]

avec cela, cela fonctionne... mais je ne sais pas pourquoi. Je me
doute que j'ai changé de contexte mais je ne comprends pas trop
pourquoi.

En fait, ma question est plus générique : peut-on changer de contexte
à volonté ? Je me doute bien que j'ai truandé un peu (mais bon, ce ne
serait pas du perl sinon ;-)) mais existe-il une solution perlienne
pour cela ?

La doc est bien avare à ce sujet : elle parle bien du problème de
contexte mais ne fait que poser le problème...

Merci d'avance,

PK

--
      |\      _,,,---,,_       Patrice KARATCHENTZEFF
ZZZzz /,`.-'`'    -.  ;-;;,_   mailto:p.karatchentzeff@free.fr
     |,4-  ) )-,_. ,\ (  `'-'  http://p.karatchentzeff.free.fr
    '---''(_/--'  `-'\_)       

7 réponses

Avatar
Ronan Le Hy
Patrice Karatchentzeff a écrit:
Voici un extrait de code simplifié :
my @cascade = ("["cascade" => "un"],", "["cascade" =>
"deux"],");

my $entree = $menu -> Menubutton(-text => "mon menu",
-menuitems => [@cascade]
);


Bon, je décortique : j'ai un ensemble de menus dynamiques à faire (je
ne connais pas leur nombre) et « -menuitems » demande une liste entre
[]. Donc, je charge une liste (ici @cascade) et je la balance dans
-menuitems.


-menuitems ne demande rien en terme de contexte (pour le bon
fonctionnement du programme, la valeur associée à menuitem doit être une
référence à un tableau, ce qui est différent). [@cascade] est dans un
contexte de liste (voir programme de démo plus bas pour s'en convaincre).

Problème : ici, manifestement, le contexte de -menuitems est scalaire
et donc,
@cascade renvoie un scalaire, soit la longueur de la liste et mon menu
déroulant en cascade a bien deux entrées... vides.


Je ne connais pas très bien Tk, mais j'ai réussi à faire marcher votre
bout de code -- j'ai l'impression qu'il y a une méprise sur ce qu'attend
-menuitem comme valeur, ou alors au niveau de votre perception de ce que
sont les références. Démo, incluant une analyse des contextes:

#!/usr/bin/perl
use strict;
use warnings;
use Tk;

sub context
{
my $w = wantarray;
warn shift, ': contexte ', defined $w ? $w ? 'de liste' :
'scalaire' : 'vide';
}

[context 'entre crochets']; # liste!
my %h = (toto => context 'valeur', context 'cle' => 2); # liste partout!

my @cascade = ([cascade => "un"], [cascade => "deux"]);
my $entree = MainWindow->new->Frame()->pack()->Menubutton(-text => "mon
menu",
-menuitems =>
@cascade)->pack();

MainLoop;

__END__

Note que la cascade est juste un tableau de références à des tableaux,
qui peut très bien être construit à la volée.

La correction que j'ai trouvé (balèze, je m'étonne moi-même parfois)
est d'éclater la liste à l'aide d'eval :

-menuitems => [ eval "@cascade"]


Wouahh.

c'est équivalent à:
-menuitems => [ eval q/["cascade" => "un"], ["cascade" => "deux"], /]

ie:
-menuitems => [ ["cascade" => "un"], ["cascade" => "deux"] ]

Etait-il vraiment besoin de passer par là? Pourquoi ne pas avoir stocké
directement une liste de références à des listes dans @cascade (comme je
l'ai fait dans mon exemple)? Les eval de chaînes, c'est vraiment très
rarement nécessaire, et assez dangeureux.

En fait, ma question est plus générique : peut-on changer de contexte
à volonté ? Je me doute bien que j'ai truandé un peu (mais bon, ce ne
serait pas du perl sinon ;-)) mais existe-il une solution perlienne
pour cela ?


Je suis preneur aussi si quelqu'un connaît un bon texte didactique sur
les contextes.

HTH

--
Ronan

So, the "there is more than one way of doing it" is just a marketing
slogan, because in reality, there's just one way of doing it, and
alternatives are "bad style"?
Abigail in clpm

Avatar
dominix
"Ronan Le Hy" wrote in message
news:3f5f60a6$0$20187$
Patrice Karatchentzeff a écrit:
...


Je suis preneur aussi si quelqu'un connaît un bon texte didactique sur
les contextes.



le seul que je connaisse est en anglais.
c'est de mjd, peut etre que qq a déjà traduit.

http://perl.plover.com/context.html

HTH

--
dominix

Avatar
dominix
"Ronan Le Hy" wrote in message
news:3f5f60a6$0$20187$
Patrice Karatchentzeff a écrit:

...

Je suis preneur aussi si quelqu'un connaît un bon texte didactique sur
les contextes.



et egalement.

http://www.perl.com/lpt/a/1999/11/sins.html


--
dominix

Avatar
Patrice Karatchentzeff
Ronan Le Hy writes:

[...]

Avec beaucoup de retard, pour cause de retard à l'allumage...

#!/usr/bin/perl
use strict;
use warnings;
use Tk;

sub context
{
my $w = wantarray;
warn shift, ': contexte ', defined $w ? $w ? 'de liste' :
'scalaire' : 'vide';

}

[context 'entre crochets']; # liste!
my %h = (toto => context 'valeur', context 'cle' => 2); # liste partout!

my @cascade = ([cascade => "un"], [cascade => "deux"]);
my $entree = MainWindow->new->Frame()->pack()->Menubutton(-text =>
"mon menu",

-menuitems
=>
@cascade)->pack();


MainLoop;

__END__

Note que la cascade est juste un tableau de références à des tableaux,
qui peut très bien être construit à la volée.


Toutafé. Merci.

En fait, le bogue que j'ai fini par trouvé est ailleurs mais c'est
tout de même grâce à toi ;-)

En fabricant ma liste à la volée justement, j'avais un truc du genre :

@cascade = (@cascade, ["cascade" => "$sortie"]);

où $sortie était la clé d'un hashage...

*Mais* j'avais écrit cela :

@cascade = (@cascade, "["cascade" => "$sortie"],");

et du coup, un print sur ma liste me renvoyait bien une liste des
éléments que je voulais au lieu d'une liste de référence... c'est ce
qui m'a induit en erreur : je pensais que c'était le comportement
normale d'une liste, d'où le recours à eval pour y arriver dans ce cas
(obligatoire puisque l'on exécute alors un programme perl).

Du moins, si j'explique bien mon erreur...

La correction que j'ai trouvé (balèze, je m'étonne moi-même parfois)
est d'éclater la liste à l'aide d'eval :
-menuitems => [ eval "@cascade"]



Wouahh.

c'est équivalent à:
-menuitems => [ eval q/["cascade" => "un"], ["cascade" => "deux"], /]

ie:
-menuitems => [ ["cascade" => "un"], ["cascade" => "deux"] ]

Etait-il vraiment besoin de passer par là? Pourquoi ne pas avoir
stocké directement une liste de références à des listes dans @cascade
(comme je l'ai fait dans mon exemple)? Les eval de chaînes, c'est
vraiment très rarement nécessaire, et assez dangeureux.


C'est surtout dû à un bogue de mes p'tits doigts ;-)

Enfin, je pose une nouvelle question (liée) pendant que j'y suis :

Où as-tu cette explication pour eval ? La seule explication un peu
détaillée que je connaisse est dans _Programmation avancée en Perl_
chez O'Reilly et il ne fait toujours mention que des eval de
*scalaires*, jamais de listes... et la doc de Perl est muette
là-dessus (enfin, je n'ai pas trouvé...).

Merci en tout cas du coup de main : j'ai marné presque une semaine
pour comprendre les tenants et aboutissements de mon problème ;-)

PK
--
      |      _,,,---,,_       Patrice KARATCHENTZEFF
ZZZzz /,`.-'`'    -.  ;-;;,_   mailto:
     |,4-  ) )-,_. , (  `'-'  http://p.karatchentzeff.free.fr
    '---''(_/--'  `-'_)       


Avatar
Paul GABORIT
À (at) 17 Sep 2003 22:45:38 +0200,
Patrice Karatchentzeff écrivait (wrote):
En fabricant ma liste à la volée justement, j'avais un truc du genre :

@cascade = (@cascade, ["cascade" => "$sortie"]);


Qui peut aussi s'écrire :

push @cascade, ["cascade" => "$sortie"];

en évitant une recopie inutile de @cascade.

--
Paul Gaborit - <http://www.enstimac.fr/~gaborit/>
Perl en français - <http://www.enstimac.fr/Perl/>
Remove '.OOO' from e-mail address - Supprimez '.OOO' de l'adresse e-mail

Avatar
Jedaï
Patrice Karatchentzeff wrote:

La correction que j'ai trouvé (balèze, je m'étonne moi-même parfois)
est d'éclater la liste à l'aide d'eval :
-menuitems => [ eval "@cascade"]



Wouahh.

c'est équivalent à:
-menuitems => [ eval q/["cascade" => "un"], ["cascade" => "deux"], /]

ie:
-menuitems => [ ["cascade" => "un"], ["cascade" => "deux"] ]

Etait-il vraiment besoin de passer par là? Pourquoi ne pas avoir
stocké directement une liste de références à des listes dans @cascade
(comme je l'ai fait dans mon exemple)? Les eval de chaînes, c'est
vraiment très rarement nécessaire, et assez dangeureux.



C'est surtout dû à un bogue de mes p'tits doigts ;-)

Enfin, je pose une nouvelle question (liée) pendant que j'y suis :

Où as-tu cette explication pour eval ? La seule explication un peu
détaillée que je connaisse est dans _Programmation avancée en Perl_
chez O'Reilly et il ne fait toujours mention que des eval de
*scalaires*, jamais de listes... et la doc de Perl est muette
là-dessus (enfin, je n'ai pas trouvé...).

Merci en tout cas du coup de main : j'ai marné presque une semaine
pour comprendre les tenants et aboutissements de mon problème ;-)

PK


En fait si il n'est fait mention que des evals de scalaires, c'est parce
que les eval de liste n'existe pas, si tu mets une liste, elle est donc
simplement évaluée en contexte scalaire/string et donc transformé en une
string tout simplement :) (puis évaluée et eval renvoit une liste)

(je crois.... ;) )

--
Jedai



Avatar
Patrice Karatchentzeff
Jedaï writes:

[...]

En fait si il n'est fait mention que des evals de scalaires, c'est
parce que les eval de liste n'existe pas, si tu mets une liste, elle
est donc simplement évaluée en contexte scalaire/string et donc
transformé en une string tout simplement :) (puis évaluée et eval
renvoit une liste)


OK, je comprends : mais avec l'option -w, je pense que Perl devrait
dire quelque chose là-dessus quand on tente un truc tordu comme cela.

Merci

PK

--
      |      _,,,---,,_       Patrice KARATCHENTZEFF
ZZZzz /,`.-'`'    -.  ;-;;,_   mailto:
     |,4-  ) )-,_. , (  `'-'  http://p.karatchentzeff.free.fr
    '---''(_/--'  `-'_)