http://www.perlmonks.org?node_id=82604

I've been looking at Perl from a different perspective lately, with the hope of gaining insights I'd otherwise miss. Perhaps I'll go into that more in another post. For now, I've got a question.

When I say *a = *b; in what context is *b being evaluated?

The interesting thing is that in whichever context it may be, both *b and \*b seem to return the same thing...

after all, *a = *b; is equivalent to *a = \*b; ("equivalent" being the Third Camel's word, not mine).

Could be list context. It should be easy to see their return values in standard output, since print() takes things in list context...

> perl -e 'print *b,"\n";' *main::x > perl -e 'print \*b,"\n";' GLOB(0x80d1f44)

Hmm... maybe not. In list context, they return different values. Scalar context?

> perl -e 'print scalar(*b),"\n";' *main::x > perl -e 'print scalar(\*b),"\n";' GLOB(0x80d1f4c)
Doesn't seem so. Well, but there are different scalar contexts. Now the Camel promises that "operations never know or care which scalar context they're in", but I'm willing to try them anyway. There's numeric context:

> perl -e 'print "$_\n" for (0..*b);' 0 > perl -e 'print "$_\n" for (0..\*b);' 0 1 2 3 4 5 6 7 (and so on)

Interesting... but still quite different. Boolean context?

> perl -e 'print "Yup\n" if *b;' Yup > perl -e 'print "Yup\n" if \*b;' Yup

Well, that's something. But there are only two possible results, I believe, for boolean context; true and false.

> perl -e 'print "Yup\n" if 1;' Yup

So it seems that 1 returns the same thing in boolean context that *b does; it returns true. However:

> perl -e '*a = 1; print *a,"\n";' *main::1 > perl -e '*a = *b; print *a,"\n";' *main::b

makes it seem like it can't be boolean context either. Didn't make much sense anyway. Same thing applies to void context; not only does it not make sense, but *x and 1 seem to have (or lack?) the same return value (as far as I can figure, which isn't all that far).

String context? Well, to be doubly sure that what I tried before was stringy, I'll say:

> perl -e '$x = "-> " . *b . " <-"; print "$x\n";' -> *main::b <- > perl -e '$x = "-> " . \*b . " <-"; print "$x\n";' -> GLOB(0x80d1f80) <-

"Don't care" context seems like it must be equivalent to one of the other scalar contexts... and that runs me fresh out of the contexts listed in the Camel's glossary. Chapter 2 also mentions a interpolative context, which may or may not be fair to call a context in the same sense as scalar and list contexts. But in any case, by definition, "interpolative context only happens inside quotes, or things that work like quotes", and *b is not quoted in the code in question (aside from the single quotes which the shell grabs).

So... can it be? Eureka! I've discovered a new context! ;-)

Okay, I'm being a little silly. However while I know that "Perl automatically dereferences the typeglob reference for you", that doesn't really answer the question. When does Perl automatically dereference the typeglob reference? Not in any clear way in the examples above. It does so it when the lvalue is a typeglob; it does it in what *seems* to be another context, a "typeglob context".

Now I'm playing a little loose here, and my reasoning may well have holes in it; I trust my bretheren will be considerate enough to stomp the unsound parts to bits for my benefit.

But isn't it interesting that such a line of inquiry even makes sense?

Look at what the Camel says about interpolative context: perhaps it's not fair to call it a context in the same sense as scalar and list contexts. (Then again, maybe it is.)

Maybe? Hang on... this is a programming language! The implementation details are known right down to the bones; for a given instance of the perl binary, how the language works is not in question.

But interpolative context is. This is what's interesting about all this to me: the notion of different models being better or worse for describing a programming language, an unambiguous piece of engineering. Knowing how it works is, apparently, not enough to answer the question.

So far as I've seen, nobody speaks about C or Java in such terms. Perhaps because the theory normally dictates the structure of programming languages, rather than inspiring them, and later describing them?

Well, food for thought anyway. A linguist's fingerprints are certainly visible here.

Replies are listed 'Best First'.
Re: Taken out of Context
by japhy (Canon) on May 23, 2001 at 20:51 UTC
    <merlyn>First, I point you to an article I wrote.</merlyn>

    Basically, doing *alias = \$name makes $alias and $name the same thing. Thus, doing *alias = \*name is making all things with a symbol name 'alias' the same thing as those with the name 'name' (in some specific package, let's say main::).

    The wonderful thing about globs is that they can be used where references are expected: @{ *foo } is like @{ \@foo }. Thus, you can use a glob where you would ordinarily use a reference to a glob. That means that you can say *alias = *name instead of *alias = \*name.

    Another reason that *alias = *name works the same way as *alias = \*name is because you can assign a string to a typeglob:

    *foo = "bar"; print *foo; # *main::bar *foo = "this::that"; print *foo; # *this::that
    So, since a glob in scalar context is its "name", you can assign that name to a glob.

    P.S. You can't say \*alias = ..., since you can't assign to a reference of something (that's why \$foo = \$bar doesn't work).

    japhy -- Perl and Regex Hacker

      Thank you for the reply, and for the link to the well-written and informative article. I'm afraid, however, that it seems a little beside the point.

      I'm really not asking how to get something done, or how Perl behaves under certain circumstances. If that were my concern, it would be false laziness on my part to bother people with questions before I'd Read The Fine Manuals. What interests me are the generalizations we make to describe how Perl behaves.

      For instance, take your statement:

      Thus, you can use a glob where you would ordinarily use a reference to a glob.

      Can I? Well, if I ordinarily said:

      > perl -e '$y = '*main::z'; $x = \*y; print $$x,"\n";'

      And expected Perl to reply:

      *main::y

      Then I should be able to use a glob instead:

      > perl -e '$y = '*main::z'; $x = *y; print $$x,"\n";'

      And expect the same reply. Instead I get:

      *main::z

      Now I know you know this; it's evident from looking at the Passing Globs section of your article. But your generalization about Perl's behavior doesn't hold in all cases.

      Of course you do qualify: where references are expected but that brings us around to my point. How do I know what's expected? You don't mean where references are expected by Petruchio, the programmer, but where they're expected by Perl. How do we characterize such expectations when talking about Perl? We invoke the notion of context. Your generalization works if you assume a certain context, but it is only valid within that context.

      I hope you see what I'm getting at. We could talk about Perl in a lot of ways. We could say that the program

      > perl -e 'print 1+1,"\n";'

      will print

      2

      and that

      > perl -e 'print 1+2,"\n";'

      will print

      3

      and so on and on and on, but (unimaginably enormous) collections of facts such as these aren't helpful for humans trying to understand Perl.

      We can resort to a more abstract approach, and simply read the source code without fear of being mislead; but while that may be necessary to truly understand Perl, I doubt whether that's sufficient either. Frankly, if Larry (as he says) gets confused and has to resort to very high level abstractions to understand Perl, I don't think there's much hope for humans in general to simply swallow that much code whole without conceptually reducing it.

      So we're left making generalizations about Perl... reducing various behaviors to certain principles which we can apply to predict behavior. One of these generalizations we call "context".

      Now if Perl had "theoretical axes to grind", it seems likely that the theories which guided the creation of the language would be unambiguous and reliable. Perl, however, seems to grow along whichever paths seem convenient, without feeling obliged to adhere to theory. Thus it is much harder to characterize adequately.

      I guess my real concern here is the adequacy of the model into which I seek to fit Perl, in order to understand it properly. If taking that model too seriously is going to leave me with conceptual blind spots, I want to know.

      In any case, though, I look forward to reading your article at length when I have time, and giving it the careful attention it deserves. Thanks for the reply.

        I do realize the error in my generalization about using typeglobs and refs to typeglobs. Thanks for pointing it out as a false generalization.

        japhy -- Perl and Regex Hacker

      Firstly, I wanted to say that I enjoyed your article. It's well written and very informative. :-) However, I noticed a small (debatable?) bug in your one_each() function.

      The problem is that you don't check to make sure that the function is being called on the same two arrays each time. Consider:

      my @a = qw(a0 a1 a2); my @b = qw(b0 b1 b2); my @c = qw(c0 c1 c2 c3 c4); my @d = qw(d0 d1 d2 d3 d4); print '(',join(',', one_each(@a, @b)),")\n"; print '(',join(',', one_each(@a, @b)),")\n"; print '(',join(',', one_each(@c, @d)),")\n"; print '(',join(',', one_each(@c, @d)),")\n";

      It prints:

      (a0,b0) (a1,b1) (c2,d2) ()

      So, even though you're giving it two new arrays in the second two calls, it uses the position and size from the first two calls. I think an easy way to "fix" this would be to store a copy of the references to the arrays in one of your closure variables and compare it to the references passed in each time, resetting if they're different. Or, perhaps, if you didn't want the position to reset even if you use different arrays, you could just not store the sizes but, rather, check them from the arrays themselves each time. That way the sizes would be correct without resetting the position.

      *shrug* Up to you, though. Just thought I'd mention it. Again, props for a well done article.

      bbfu
      Seasons don't fear The Reaper.
      Nor do the wind, the sun, and the rain.
      We can be like they are.

(tye)Re: Taken out of Context
by tye (Sage) on May 24, 2001 at 03:48 UTC

    So when are "< file", "file", and "<file" all the same string? When I use them in the second-argument-to-open context, of course!

    My point is that the concept of "context" isn't always the best choice and you have found a case where it isn't. *b and \*b are different (but somewhat similar) scalar values. You can prove that "context" isn't what makes these act the same here:

    $b= "B"; *y= *b; print "$y\n"; *y= \*b; print "$y\n";
    by noting that they also act the same here:
    $b= "B"; $x= *b; *y= $x; print "$x: $y\n"; $z= \*b; *y= $z; print "$z: $y\n"; __END__ Produces: *main::b: B GLOB(0x1bb2b1c): B

    So it isn't that *y= provides some special, magical context that causes *b and \*b to be the same. It is that the act of assigning something to a glob ends up calling some C function inside of perl and that C function decides to do the same things when given a glob or a ref to a glob.

            - tye (but my friends call me "Tye")
Re: Taken out of Context
by chipmunk (Parson) on May 24, 2001 at 00:52 UTC
    When I say *a = *b; in what context is *b being evaluated?
    Well, the left-hand side of the assignment is a glob, so it must be that *b is evaluated in glob context! :)

    But, really, I'm not sure I understand the point of this question. *b is *b whether its in list context or scalar context.

    What is it that you're really asking?

      Well, the left-hand side of the assignment is a glob, so it must be that *b is evaluated in glob context!

      That is, in all seriousness, precisely what I'm suggesting.

      *b is *b whether its in list context or scalar context.

      Correct. But *b is not \*b in list context or scalar context, or any other named context I can find. And yet they are the same in statements like *a = *b; and *a = \*b; Hence, I am suggesting that this constitutes an example of a distinct context, unlike the others.

      In short, I am asking for criticism of this theory.

      I am also trying to see what interest there is in this sort of approach to thinking about Perl; I've been doing a lot of it lately, and it's been quite interesting and educational. We customarily look at Perl as a tool, for the purpose of accomplishing our objectives with it. While this, of course, interests me greatly, I fear it can be a limiting perspective; I also wonder whether the models we're using to describe Perl have unsatisfactory limitations.

      One monk privately said in jest, "it's all too theoretical." I'm afraid many people will view such discussions that way in earnest. Nonetheless, this sort of thing seems significant to me.