Schrift
[thread]7958[/thread]

Tiefe Hash Strukturen aus Config bilden: Und warum while(<FH>) gefährlich ist (Seite 4)

Leser: 1


<< |< 1 2 3 4 5 6 7 >| >> 63 Einträge, 7 Seiten
betterworld
 2006-05-14 00:11
#65837 #65837
User since
2003-08-21
2613 Artikel
ModeratorIn

user image
[quote=Strat,11.05.2006, 16:07]Eine while-schleife ist ja im grunde nur ein if-block, der wiederholt ausgefuehrt wird (solange halt die bedingung wahr ist) Und bei einem if ( BEDINGUNG ) ist es ja auch klar, dass man, wenn man einen lokalen wert verwenden will, diesen selbst lokalisieren muss, z.B.
Code: (dl )
if( my $x = &SubBlabla(@params) ) {

wird's jetzt klara?[/quote]
Es ist schon einleuchtend. Aber ich bin ueberzeugt, dass viele Leute sich dessen nicht bewusst sind. Mit einem einfachen grep auf @INC-Verzeichnisse habe ich z. B. Module::ScanDeps gefunden. Und siehe da:
Code: (dl )
1
2
3
4
$ perl -e '$_="erfolgreich"; use Module::ScanDeps; print $Module::ScanDeps::VERSION, "\n"; scan_deps(files=>["lib/MyApp.pm"]); print "test $_\n"'
0.59
test
$


Mir war es am Anfang auch nicht bewusst.

Zu meiner Frage: Es ist in der Dokumentation erwaehnt, und zwar in perlop:
Quote
The $_ variable is not implicitly localized. You'll have to put a "local $_;"
before the loop if you want that to happen.
Das ist aber meiner Meinung nach nicht genug, denn wie in Module::ScanDeps zu sehen ist, tappt man viel zu leicht in die Falle. Vielleicht sollte einfach eine Warnung ausgegeben werden, wenn while(<>) in einer nicht $_-lokalisierten Umgebung benutzt wird.
Strat
 2006-05-14 00:34
#65838 #65838
User since
2003-08-04
5246 Artikel
ModeratorIn
[Homepage] [default_avatar]
[quote=betterworld,13.05.2006, 22:11]
Es ist schon einleuchtend. Aber ich bin ueberzeugt, dass viele Leute sich dessen nicht bewusst sind. ...
Mir war es am Anfang auch nicht bewusst.
[/quote]

ich befuerchte auch, dass sich viele leute dessen nicht bewusst sind. aber while ist mal was voellig anderes als ein for(each), auch wenn viele leute das wild durcheinanderwerfen. Dabei ist der skalare Kontext der while-bedingung doch schon ein sehr klarer hinweis, dass da was voellig anderes abgeht.

[quote=betterworld,13.05.2006, 22:11]
...
Vielleicht sollte einfach eine Warnung ausgegeben werden, wenn while(<>) in einer nicht $_-lokalisierten Umgebung benutzt wird.[/quote]
wieso? soll code wie der folgende wirklich eine warnung auswerfen?
Code: (dl )
1
2
while( <$FH> ) { last if /^\s*\#/ }
print "Der erste Kommentar oder shebang lautet: $_\n";


Dann muesste man IMHO auch bei den folgenden Konstrukten
Warnungen ausgeben:
Code: (dl )
1
2
3
4
5
foreach (@list3) {
$_ = 20;
}
# oder
@list1 = map { s/([^aeiou])/$1b$1/ig } @list2;

weil man da - absichtlich oder unabsichtlich - das input-array veraendert. Das erste Beispiel duerfte wohl nur manche neulinge wundern (sowas geht nicht in allen Programmiersprachen), aber beim zweiten Beispiel ist auch fuer fortgeschritten wohl haeufig nicht auf den ersten Blick klar, und wenn sowas unabsichtlich geschieht, kann man bei der Fehlersuche echt viel spass haben.
perl -le "s::*erlco'unaty.'.dk':e,y;*kn:ai;penmic;;print"
http://www.fabiani.net/
betterworld
 2006-05-14 01:06
#65839 #65839
User since
2003-08-21
2613 Artikel
ModeratorIn

user image
[quote=Strat,13.05.2006, 22:34]wieso? soll code wie der folgende wirklich eine warnung auswerfen?
Code: (dl )
1
2
while( <$FH> ) { last if /^\s*\#/ }
print "Der erste Kommentar oder shebang lautet: $_\n";
[/quote]
Wenn diese Zeilen in einer Sub-Routine oder in einem Modul stehen, dann ja.

Quote
Dann muesste man IMHO auch bei den folgenden Konstrukten
Warnungen ausgeben:
Code: (dl )
1
2
3
4
5
foreach (@list3) {
$_ = 20;
}
# oder
@list1 = map { s/([^aeiou])/$1b$1/ig } @list2;

weil man da - absichtlich oder unabsichtlich - das input-array veraendert.

Der erste Fall sieht mir eigentlich ziemlich beabsichtigt aus, weil das $_ innerhalb der Schleife nicht weiter verwendet wird. Daher ist es anscheinend die Absicht des Programmierers, das Array an sich zu veraendern.

Im zweiten Fall koennte man tatsaechlich eine Warnung ausgeben, weil es ein häufiger Fehler ist und ich mir wenige sinnvolle Anwendungen vorstellen kann, wo man ein derartiges Array wie @list1 braucht.

Warnungen auszugeben ist natuerlich immer problematisch, wenn man nicht sicher ist, ob etwas beabsichtigt ist oder nicht. Das ist aber bei while(<>) definitiv nicht der Fall. Selbst wenn ein Programmierer beabsichtigt, an die aufrufende Funktion ueber $_ die zuletzt eingelesene Zeile zurueckzugeben, ist das ein wirklich schlechter Stil.
bloonix
 2006-05-14 01:34
#65840 #65840
User since
2005-12-17
1615 Artikel
HausmeisterIn
[Homepage]
user image
@strat + betterworld, ich habe mich mal auf CPAN umgesehen, ganz
besonders bei den Linux::* Modulen, da dort sehr häufig auf das /proc
Filesystem zugegriffen und mit while gearbeitet wird.

In nur einem Modul habe ich ein while(my $line = <FH>){} entdeckt,
in den anderen Modulen ein while(<FH>){} ohne local $_; und
auch foreach(<FH>){}.

Es scheinen wirklich nicht viele zu wissen, aber gut, dass das hier so
gut diskutiert wurde, denn ich habe es schon auf meine ToDo Liste für
v1.14 geschrieben. Danke an euch. Auch an pq.\n\n

<!--EDIT|opi|1147558291-->
What is a good module? That's hard to say.
What is good code? That's also hard to say.
One man's Thing of Beauty is another's man's Evil Hack.
bloonix
 2006-05-14 01:41
#65841 #65841
User since
2005-12-17
1615 Artikel
HausmeisterIn
[Homepage]
user image
Code: (dl )
1
2
3
4
5
6
use strict;
use warnings;
use Linux::Statistics;
$_ = 20;
my $obj = Linux::Statistics->new( ProcStats => 1 );
print "$_\n";


Use of uninitialized value in concatenation (.) or string at ./test.pl line 7.

das wurmt mich jetzt!\n\n

<!--EDIT|opi|1147556544-->
What is a good module? That's hard to say.
What is good code? That's also hard to say.
One man's Thing of Beauty is another's man's Evil Hack.
murphy
 2006-05-14 03:23
#65842 #65842
User since
2004-07-19
1776 Artikel
HausmeisterIn
[Homepage]
user image
[quote=opi,13.05.2006, 22:34][...]
In nur einem Modul habe ich ein while(my $line = <FH>){} entdeckt,
in den anderen Modulen ein while(<FH>){} ohne local $_; und
auch foreach(<FH>){}.
[...][/quote]
Aber foreach (<FH>) { ... } ist ja eben gerade kein Problem, nur while (<FH>) { ... } ist eines, wenn man einmal davon absieht, dass foreach (<FH>) { ... } eine gewaltige Speicherplatzverschwendung werden kann.

Ich finde aber trotz Strats Erklärungsversuch das Verhalten von while buggy, und zwar aus folgendem Grund: Wäre die while-Bedingung einfach nur eine if-Abfrage, dann sollte man auf keinen Fall erwarten, dass ihr Wert überhaupt in $_ gespeichert wird. Da dies aber doch passiert, und zwar nur in dem speziellen Fall, dass über das Resultat eines readline-Aufrufes iteriert wird, und dabei immerhin noch genug Magie aktiv wird, um ein while (<FH>) { ... } effektiv in ein while (defined($_ = <FH>)) { ... } zu verwandeln, wäre es meines Erachtens sinnvoller auch noch $_ zu lokalisieren, zumal der am Schleifenende in $_ gespeicherte Wert in den allermeisten Fällen reichlich nutzlos ist.
When C++ is your hammer, every problem looks like your thumb.
bloonix
 2006-05-14 15:06
#65843 #65843
User since
2005-12-17
1615 Artikel
HausmeisterIn
[Homepage]
user image
[quote=murphy,14.05.2006, 01:23]Aber foreach (<FH>) { ... } ist ja eben gerade kein Problem[/quote]
ich weiß murphy, danke. es war ja nur ein hinweiß darauf, was ich
alles bei meiner suche gefunden habe ;)
What is a good module? That's hard to say.
What is good code? That's also hard to say.
One man's Thing of Beauty is another's man's Evil Hack.
Strat
 2006-05-14 15:22
#65844 #65844
User since
2003-08-04
5246 Artikel
ModeratorIn
[Homepage] [default_avatar]
[quote=betterworld,13.05.2006, 23:06]
Selbst wenn ein Programmierer beabsichtigt, an die aufrufende Funktion ueber $_ die zuletzt eingelesene Zeile zurueckzugeben, ist das ein wirklich schlechter Stil
[/quote]
genau, aber nur durch die verwendung der globalen variable.
Code: (dl )
1
2
3
4
5
6
7
8
9
10
sub Irgendwas {
my ($filename) = @_;

open (my $FH, "<", $filename) or die "Error: $!";

local $_;
while( <$FH> ) { last if /^\s*\#/ }

return $_;
} # Irgendwas

hingegen finde ich voellig ok (vorausgesetzt, auch $FH ist lokal, und ich wuerde anstelle von $_ auch eine benannte variable wie z.B. my $line verwenden)

Da sehe ich das Problem nicht bei perl selbst, sondern bei den vielen veroeffentlichten Codeschnipseln, die zwar an sich laufen, aber in einem groesseren Zusammenhang Probleme bereiten.

Ein CPAN-Modulautor muss IMHO sowas wissen (genauso wie das Problem mit den globalen FILEHANDLE's.

Ich schreibe gerade Thomas Klausner an, dem Autor von CPANTS, ob er nicht noch einen solchen Test reinnehmen kann (der hat uebrigens auf dem Perlworkshop vor einigen Jahren in Bonn einen Vortrag genau ueber dieses Thema gehalten)
perl -le "s::*erlco'unaty.'.dk':e,y;*kn:ai;penmic;;print"
http://www.fabiani.net/
betterworld
 2006-05-14 15:28
#65845 #65845
User since
2003-08-21
2613 Artikel
ModeratorIn

user image
[quote=Strat,14.05.2006, 13:22]
Code: (dl )
1
2
3
4
5
6
7
8
9
10
sub Irgendwas {
my ($filename) = @_;

open (my $FH, "<", $filename) or die "Error: $!";

local $_;
while( <$FH> ) { last if /^\s*\#/ }

return $_;
} # Irgendwas

hingegen finde ich voellig ok[/quote]
Ich auch. Aber es muesste doch moeglich sein, eine Warnung nur dann auszugeben, wenn while(<$FH>) benutzt wird, ohne dass in der aktuellen Subroutine vorher local($_) oder local(*_) geschrieben wurde\n\n

<!--EDIT|betterworld|1147606140-->
Strat
 2006-05-14 15:29
#65846 #65846
User since
2003-08-04
5246 Artikel
ModeratorIn
[Homepage] [default_avatar]
ich halte es aber fuer eine sehr gute Idee, die CPAN-Autoren, die solche Fehler begehen, darauf hinzuweisen (auch gleich darauf, wenn sie globale FILEHANDLEs verwenden, auch wenn letztere meist nicht so kritisch sind, weil sie sich in einem eigenen Package befinden)
perl -le "s::*erlco'unaty.'.dk':e,y;*kn:ai;penmic;;print"
http://www.fabiani.net/
<< |< 1 2 3 4 5 6 7 >| >> 63 Einträge, 7 Seiten



View all threads created 2006-05-09 17:07.