http://qs1969.pair.com?node_id=1177168

dpchrist has asked for the wisdom of the Perl Monks concerning the following question:

I would like to write a subroutine is_typeglob($) that returns true when passed a type glob and returns false when not passed a type glob. (I already have a subroutine is_typeglob_ref($).)

This is a scratch program I wrote to experiment with some ideas:

2016-12-04 12:35:05 dpchrist@debian ~/sandbox/perl $ cat is_typeglob.pl #!/usr/bin/perl use strict; use warnings; use Data::Dumper; $Data::Dumper::Indent = 0; use Scalar::Util qw(blessed openhandle reftype); { no warnings 'once'; open (FH, '<', $0) or die "ERROR: open(): $!"; } for ( q(*ARGV ), q(*ARGV cmp '*ARGV' ), q(*ARGV cmp "*ARGV" ), q(*ARGV cmp '*::ARGV' ), q(*ARGV cmp "*::ARGV" ), q(ref *ARGV ), q(blessed *ARGV ), q(openhandle *ARGV ), q(reftype *ARGV ), ) { my $code = $_; my $r = eval $code; print Data::Dumper->Dump([$code, $r, $@], [qw(code r @)]), "\n"; } # $Id: is_typeglob.pl,v 1.1 2016/12/04 20:35:04 dpchrist Exp $

Here is a sample run:

2016-12-04 12:42:14 dpchrist@debian ~/sandbox/perl $ perl is_typeglob.pl $code = '*ARGV ';$r = *::ARGV;$@ = ''; $code = '*ARGV cmp \'*ARGV\' ';$r = 1;$@ = ''; $code = '*ARGV cmp "*ARGV" ';$r = 1;$@ = ''; $code = '*ARGV cmp \'*::ARGV\' ';$r = 1;$@ = ''; $code = '*ARGV cmp "*::ARGV" ';$r = 1;$@ = ''; $code = 'ref *ARGV ';$r = '';$@ = ''; $code = 'blessed *ARGV ';$r = undef;$@ = ''; $code = 'openhandle *ARGV ';$r = undef;$@ = ''; $code = 'reftype *ARGV ';$r = undef;$@ = '';

How do I determine if a variable contains a type glob?

Replies are listed 'Best First'.
Re: How do I determine if a variable contains a type glob?
by ikegami (Patriarch) on Dec 05, 2016 at 01:09 UTC

    reftype(\$s) eq 'GLOB' will be true if and only if $s contains a glob.

    $ perl -MScalar::Util=reftype -e' my $s = *STDOUT; CORE::say reftype(\$s) eq "GLOB"; ' 1

    reftype($s) eq 'GLOB' will be true if and only if $s contains a reference to a glob.

    $ perl -MScalar::Util=reftype -e' my $s = \*STDOUT; CORE::say reftype($s) eq "GLOB"; ' 1

    This is what open(my $fh, ...) places in $fh.

    $ perl -MScalar::Util=reftype -e' open(my $s, "<&", *STDOUT) or die $!; CORE::say reftype($s) eq "GLOB"; ' 1
Re: How do I determine if a variable contains a type glob?
by BrowserUk (Patriarch) on Dec 04, 2016 at 21:09 UTC

    Does this help?

    [0]{} Perl> print ref() for \my $fh, \*fh, my $ref = \*fh;; SCALAR GLOB GLOB

    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority". The enemy of (IT) success is complexity.
    In the absence of evidence, opinion is indistinguishable from prejudice.

      No. The OP asked about globs (e.g. *ARGV)

      Furthermore, use of ref instead of reftype will fail if the referenced var is blessed.

        That, and if someone tricks you there

        $ perl -wE'my $foo = bless [],"GLOB"; say ref $_ for $foo, \*ARGV' GLOB GLOB $ perl -MScalar::Util=reftype -wE'my $foo = bless [],"GLOB"; say refty +pe $_ for $foo, \*ARGV' ARRAY GLOB

        Enjoy, Have FUN! H.Merijn

        Man, you really talk a lot of twaddle!

        The OP asked about globs (e.g. *ARGV)

        And what do you think *fh is. (It's rhetorical.)

        Furthermore, use of ref instead of reftype will fail if the referenced var is blessed.

        How can "the reference be blessed", when (as you unnecessarily pointed out yourself) he asked about *GLOB not \*GLOB. It can't; because my suggestion was that he take the reference himself.

        Ie. His sub becomes something like:

        sub isIt{ local $^W; ref( \$_[0] ) =~ m[GLOB] ? 1 : 0; }

        And it is used like this:

        [0]{} Perl> printf "%s: %d\n", $_, isIt( $_ ) for *ARGV, *INC, *SIG, * +MATCH, *FH, *A, *B, *STDOUT, *CORE::say;; # *anything *main::ARGV: 1 *main::INC: 1 *main::SIG: 1 *main::MATCH: 1 *main::FH: 1 *main::A: 1 *main::B: 1 *main::STDOUT: 1 *CORE::say: 1

        And

        ... if the referenced var is blessed.

        You don't (*CAN'T*) bless a var; only a reference to one!

        You can pop-down now.


        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority". The enemy of (IT) success is complexity.
        In the absence of evidence, opinion is indistinguishable from prejudice.
Re: How do I determine if a variable contains a type glob?
by shmem (Chancellor) on Dec 04, 2016 at 22:53 UTC
    How do I determine if a variable contains a type glob

    A variable never contains a type glob. It either is a typeglob by itself - in that case the the string following the sigil can be looked up in the package's symbol table - or it contains a reference to a part of a typeglob (a typeglob slot entry container). In the latter case the reference carried inside the variable is identical to the contents of a certain typeglobs slot entry inside the symbol table. A none-typeglob (not package) variable never contains or is a type glob, all it can do is sharing the typeglob's reference for a certain type. Consider:

    #!/usr/bin/perl -l our $foo = "bar"; # foo is a package variable # hence *foo typglob exists print "typeglob *foo ", exists $main::{foo} ? "exists" : "doesn't exis +t"; print "typeglob *bar ", exists $main::{bar} ? "exists" : "doesn't exis +t"; print "foo typeglob: ", *foo; print "foo scalar slot ref: ",*{"main::foo"}{SCALAR}; my $bar = *foo; print "bar content: $bar"; my $baz = *{"main::foo"}{SCALAR}; print "baz content: $baz"; print $$baz; my $quux = \$foo; # reference to scalar slot of *foo print "quux is $quux";

    Note how *{"main::foo"}{SCALAR} and $baz and $quux all share the same reference, despite being different variables. So, if you want to determine whether a variable contains part of a typeglob, iterate over the keys of the current packages symbol table, and for each symbol, iterate over the typeglobs reference entries, and if those are equal to the variable's content, it shares some part(s) of a typeglob's values. That's all you can get.

    perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'

      A variable never contains a type glob. It either is a typeglob by itself

      Not so. Scalars can contain globs.

      my $fh = *STDOUT;

      Globs can also also contain other globs. (The slot is named GLOB.) That's how subpackages are stored.

        Indeed; thank you. Haddocks' Eyes, again.

        my $f = *STDOUT; $STDOUT{foo} = 'bar'; print *{$f}{HASH}{foo},"\n"; print ${$f}{foo},"\n"; __END__ bar bar

        ...resiling to my hermitage for a revision course of perl data.

        perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'
Re: How do I determine if a variable contains a type glob?
by Anonymous Monk on Dec 04, 2016 at 21:23 UTC
    Take a reference or let Prototypes do it for you
    #!/usr/bin/perl -- use strict; use warnings; sub istg(*) { warn shift } sub istgg { my $f = shift; my $ff=\$f; warn "$f $ff" } istg(1); istgg(1); istg(*ARGV); istgg(*ARGV); __END__ 1 at - line 4. 1 SCALAR(0x99ba0c) at - line 5. GLOB(0x99b5bc) at - line 4. *main::ARGV GLOB(0x99ba0c) at - line 5.
Re: How do I determine if a variable contains a type glob?
by RonW (Parson) on Dec 06, 2016 at 21:22 UTC

    Also, when testing if a reference refers to a glob, there is is_globref() in Ref::Util that tests the flags instead of requiring string-ifying the reference then comparing it to a string.