strange warning when open file

Discussion in 'Perl Misc' started by George Mpouras, Aug 15, 2012.

  1. Do you have any idea how to fix the warning
    Name "main::FH" used only once: possible typo at C:\work\Files\test.pl
    at the following code ?



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

    my $output_dir = '/tmp';
    my %File = (
    'mc' => { '12' => '', '13' => '', },
    'mp' => { '12' => '', '13' => '', },
    );


    foreach my $key1 (keys %File)
    {
    foreach my $key2 (keys %{$File{$key1}})
    {
    $File{$key1}{$key2} = { *FH => \"$key1,$key2" , 'FILE' =>
    "$output_dir/$key1,$key2" };
    open $File{$key1}{$key2}{'FH'}, '>', $File{$key1}{$key2}{'FILE'} or die
    "Could not open file \"$File{$key1}{$key2}{'FILE'}\" because \"$^E\"\n";
    }
    }

    # Write something
    print {$File{nc}{12}{FH}} "test nc 12\n";
    print {$File{alp}{14}{FH}} "test alp 14\n";

    # Close the filehandlers
    foreach my $key1 (keys %File) {
    foreach my $key2 (keys %{$File{$key1}}) {
    close $File{$key1}{$key2}{'FH'} or die "Could not close file
    \"$File{$key1}{$key2}{'FILE'}\" because \"$^E\"\n" }}
    George Mpouras, Aug 15, 2012
    #1
    1. Advertising

  2. sorry for the tipo

    print {$File{nc}{12}{FH}} "test nc 12\n";
    print {$File{alp}{14}{FH}} "test alp 14\n";

    should be

    print {$File{mc}{12}{FH}} "test mc 12\n";
    print {$File{mp}{13}{FH}} "test mp 13\n";

    Of course the warning issue remains
    George Mpouras, Aug 15, 2012
    #2
    1. Advertising

  3. "George Mpouras" <> writes:

    > Do you have any idea how to fix the warning
    > Name "main::FH" used only once: possible typo at C:\work\Files\test.pl
    > at the following code ?


    And it doesn't tell you a line number where it encounters the name
    main::FH?

    My perl does, it is on line 16.

    > foreach my $key2 (keys %{$File{$key1}})
    > {
    > $File{$key1}{$key2} = { *FH => \"$key1,$key2" , 'FILE' => "$output_dir/$key1,$key2" };


    i.e. this line.

    You are using a variable called *FH here and nowhere else in your
    script. Which is what perl tries to warn you about.

    Variables using the * sigil is a class of variables called
    typeglobs. Just like variables starting with the $ sigil ara scalars and
    variables starting with the @ sigil is arrays.

    Typeglobs are an internal type used by perl to hold symbol table
    entries. Previously it was used for references and filehandles, but this
    usage is deprecated. You can read more about typeglobs in the perldata
    manual page.


    What you probably meant was the string 'FH'. You can do this by either
    just removing the * and use the stringification feature of the =>
    operator or explicitly use a string like you do for the FILE field.

    //Makholm
    Peter Makholm, Aug 15, 2012
    #3
  4. Peter Makholm <> writes:

    [...]

    > Variables using the * sigil is a class of variables called
    > typeglobs. Just like variables starting with the $ sigil ara scalars and
    > variables starting with the @ sigil is arrays.
    >
    > Typeglobs are an internal type used by perl to hold symbol table
    > entries. Previously it was used for references and filehandles, but this
    > usage is deprecated.


    The short way to describe what 'a typeglob' actually is would be 'what
    a symbol is in Lisp': An object which aggregates a number of 'slots'
    used by the language for different purposes and which is usually
    stored in a symbol table where it can be found by doing an 'ordinary'
    name lookup which thus provides a way to employ the functionality
    provided by the 'slots' by name. For a perl typeglob, the
    commonly-used slots would be (assuming the name pointing to the typeglob was
    richard) $richard, the slot used for scalars, %richard, the hash slot,
    @richard, the array slot and lastly, the &richard slot for
    subroutines. The *-notation can be used to refer to the typeglob
    itself, eg, in the case of a named I/O handle (another typeglob slot),
    the syntax \*richard could be used to pass a reference to that
    (actually, to the typeglob itself) to a subroutine (*richard{IO} could
    be used to create a reference to the 'thing' in the I/O handle slot).

    Another use of *richard would be to assign a reference to something to
    one of the slots, eg

    *richard = sub { return 'richard'; }

    creates an anonymous subroutine returning 'richard' and assigns a reference
    to that to the subroutine slot of the glob associated with the name
    richard. Effectively, this binds a name to this anonymous subroutine
    (or vice versa). This is also the way how importing subroutines from
    other modules works.

    The reference to references refers to a deficiency of some ancient
    programming language someone reportedly used somewhere about twenty
    years ago. It ought to be forgotten nowadays. Likewise, in ancient
    versions of Perl5, the only way to create an I/O handle was to refer
    to a typeglob via the symbol table of the current package, eg

    open(IN, '</etc/passwd')

    will open the file /etc/passwd for reading and deposit the
    corresponding I/O handle in the I/O handle slot of the typeglob
    associated with the name IN. Nowadays, it is usually more convenient
    to use an 'undefined' scalar variable for this purpose: This cause an
    anonymous typeglob to be created and assigned to this variable
    (actually, a reference to it is assigned). This has the nice
    additional benefit that the filehandle will be closed automatically
    when the scalar variable goes out of scope (be warned that this is
    another highly blasphemous heresy because 'mighty sheep' garbage
    collectors don't provide this functionality ...)
    Rainer Weikusat, Aug 15, 2012
    #4
  5. The reference to references refers to a deficiency of some ancient
    programming language someone reportedly used somewhere about twenty
    years ago. It ought to be forgotten nowadays. Likewise, in ancient
    versions of Perl5, the only way to create an I/O handle was to refer
    to a typeglob via the symbol table of the current package, eg

    open(IN, '</etc/passwd')



    As you can see Rainer the code is dynamic. In reality the hash is also
    dynamic, so I will end up with hundrends of open fileshat they will get
    written also dynamic using the hash keys as filehanl pointers
    So using a simple keyword like IN is not good enough.
    I have to use the full path of hash keys as a unique FH identifier, othelse
    all writings will be wrong.
    This is why i used the * ...
    George Mpouras, Aug 15, 2012
    #5
  6. George Mpouras

    Willem Guest

    George Mpouras wrote:
    ) As you can see Rainer the code is dynamic. In reality the hash is also
    ) dynamic, so I will end up with hundrends of open fileshat they will get
    ) written also dynamic using the hash keys as filehanl pointers
    ) So using a simple keyword like IN is not good enough.
    ) I have to use the full path of hash keys as a unique FH identifier, othelse
    ) all writings will be wrong.
    ) This is why i used the * ...

    That's not how filehandle/fileglob references work.

    Try this:

    use strict;
    use warnings;

    my %x;
    $x{one}{FILE} = "testfile-one.txt";
    $x{two}{FILE} = "testfile-two.txt";
    for my $xx (keys %x) {
    open $x{$xx}{FH}, '>', $x{$xx}{FILE} or die "Failed to open: $_\n";
    }
    for my $xx (keys %x) {
    print { $x{$xx}{$FH} } "Text for $xx\n" or die "Failed to print: $_\n";
    }
    for my $xx (keys %x) {
    close $x{$xx}{FH} or die "Failed to close: $_\n";
    }

    And also try to figure out why it works.


    SaSW, Willem
    --
    Disclaimer: I am in no way responsible for any of the statements
    made in the above text. For all I know I might be
    drugged or something..
    No I'm not paranoid. You all think I'm paranoid, don't you !
    #EOT
    Willem, Aug 15, 2012
    #6
  7. Actually thats what I did. It works ( I wonder why ... )


    # Open Files
    foreach my $key1 (keys %File)
    {
    foreach my $key2 (keys %{$File{$key1}})
    {
    $File{$key1}{$key2} = { FH => undef , 'FILE' =>
    "$output_dir/$key1,$key2" };
    open $File{$key1}{$key2}{'FH'}, '>', $File{$key1}{$key2}{'FILE'} or die
    "Could not open file \"$File{$key1}{$key2}{'FILE'}\" because \"$^E\"\n";
    }
    }
    George Mpouras, Aug 15, 2012
    #7
  8. "George Mpouras" <> writes:
    > Actually thats what I did. It works ( I wonder why ... )
    >
    >
    > # Open Files
    > foreach my $key1 (keys %File)
    > {
    > foreach my $key2 (keys %{$File{$key1}})
    > {
    > $File{$key1}{$key2} = { FH => undef ,


    The assignment is not needed: The first time the other code uses
    $File{$key1}{$key2}{FH} in a rvalue context which needs a reference
    to a 'value' of some type, a suitable value will be created and a
    reference to it assigned to the hitherto 'undefined' location
    (so-called 'auto-vivification'). One of these contexts is the first
    argument to an open call which is either supposed to be the name of a
    typeglob or a reference to a type glob, cf the following example:

    --------------
    open($passwd, '<', '/etc/passwd');
    print($passwd, "\n");
    --------------

    which (on a system where a file named /etc/passwd exists ;-) prints
    the reference to the anonymous glob which was assigned to $passwd when
    autovivification took place.

    As Peter Makholm already wrote earlier: The error in your original
    code was that you wrote

    *FH => undef

    in a hash definition. The =>-operator automaically quotes its left
    argument if "it begins with a letter or underscore and is composed
    only of letters, digits and underscores" (=> perlop(1)). This is not
    the case here, hence *FH is evaluated as an expression. The value of
    this expression is the typeglob currently associated with the name FH
    in the symbol table of the current package, which causes the warning
    to be printed. It will probably also not do what you wanted wrt
    creating a hash entry because *FH stringfies to the fully-qualified
    name of the referenced typeglob, cf

    -----------
    my $h = { *FH => 'FH' };

    print $h->{*FH}, "\n";

    package haha;

    print $h->{*FH}, "\n";

    print("The solution: ", keys(%$h), "\n");
    -----------

    [in German, the letter 'h' is pronounced 'ha']
    Rainer Weikusat, Aug 15, 2012
    #8
  9. Thanks for the *info !
    George Mpouras, Aug 15, 2012
    #9
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Pete Becker
    Replies:
    0
    Views:
    1,373
    Pete Becker
    Feb 10, 2005
  2. Replies:
    3
    Views:
    1,126
    Mark Rae
    Jan 23, 2007
  3. B. Williams

    warning C4267 and warning C4996

    B. Williams, Oct 26, 2006, in forum: C++
    Replies:
    17
    Views:
    2,627
  4. WARNING! Prosoftstore.com is a SCAM! WARNING!

    , Jul 8, 2007, in forum: ASP .Net Web Services
    Replies:
    0
    Views:
    317
  5. Julian Mehnle
    Replies:
    17
    Views:
    866
    Julian Mehnle
    May 18, 2006
Loading...

Share This Page