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\"],");
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...
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 :
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
Patrice Karatchentzeff a écrit:
Voici un extrait de code simplifié :
my @cascade = ("["cascade" => "un"],", "["cascade" =>
"deux"],");
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 :
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
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 :
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
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
"Ronan Le Hy" <lehy@imag.fr> wrote in message
news:3f5f60a6$0$20187$626a54ce@news.free.fr...
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.
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"]
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 ;-)
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"]
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 ;-)
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"]
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 ;-)
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
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
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
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"]
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
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"]
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)
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
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.
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.
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.