Beefy Boxes and Bandwidth Generously Provided by pair Networks
Your skill will accomplish
what the force of many cannot
 
PerlMonks  

Re: Evil Interview Questions

by chromatic (Archbishop)
on Feb 09, 2008 at 00:21 UTC ( [id://667116]=note: print w/replies, xml ) Need Help??


in reply to Evil Interview Questions

Regardless of whether the function returns a list or an array...

Can you show an example of a function that returns an array? (Not an array reference.)

Replies are listed 'Best First'.
Re^2: Evil Interview Questions
by Limbic~Region (Chancellor) on Feb 09, 2008 at 00:27 UTC
Re^2: Evil Interview Questions
by kyle (Abbot) on Feb 09, 2008 at 04:08 UTC

    Can you show an example of a function that returns an array?

    While you haven't said so, I'm guessing that what you have on your mind is something like what you said in Re^4: returning tied array, which is to say:

    You can only return scalars and lists and (nothing) from subroutines. You can't return arrays or hashes directly, only as lists or references.

    I suspect this statement is more meaningful to perl programmers than to Perl programmers. I haven't read perlguts, let alone perl source, but I'm guessing that under the covers somewhere, in the sea of C, it's really true that nothing can escape a sub besides a scalar, a list, or Nothing.

    That having been said, please consider:

    sub get_list { return ( 4, 5, 6 ); } sub get_array { @x = ( 4, 5, 6 ); return @x; }

    get_list and get_array return the same collection of values in different ways. They do different things in scalar context. This is why I think there's a difference between returning a list and returning an array—they behave differently.

    One might say that they both do the same thing in scalar context—return a scalar (neither list, nor array).

    I think these points of view are looking at the sub from different sides of the return. This is the difference between "imply" and "infer". It's the difference between what one says and what another hears. It's the difference between expression and interpretation.

    If I scream "value" into the Void, have I still said something?

    I think one could correctly say that sub { @_ } returns an array. It always returns an array regardless of context. Its caller may receive from it a scalar or a list or Nothing, depending on the context it provides, but what the sub itself does is the same every time.

    I have in my head a call like this:

    ... = get_stuff();

    Inside get_stuff somewhere there's a return with some "stuff" after it. I'm guessing that perl takes that "stuff" and turns it into something that makes sense to whatever "..." is, and it does that before the "stuff" gets out of get_stuff. So what actually comes out of the sub can only be a scalar, a list, or Nothing.

    I could conceive of it being implemented differently. It could pass out of the sub whatever the sub "said" it wanted to return, and then coerce it into the appropriate type once it got there.

    If that were the case, would we still say that subs can only return scalars, lists, or Nothing? Would they really behave any differently? More to the point, how is any of this distinction relevant to Perl programmers?

      I think one could correctly say that sub { @_ } returns an array. It always returns an array regardless of context.

      Try pushing on to the "array" returned from your sub then:

      sub return_array { @_ } my $new_count = push (return_array(qw( foo bar ))), 'baz';

      (There's an even subtler trick related to a fundamental truth about the semantics of Perl 5 in that example, which I only realized after I chose it.)

      I'm guessing that under the covers somewhere, in the sea of C, it's really true that nothing can escape a sub besides a scalar, a list, or Nothing.

      The implementation is what it is to support the semantics of Perl-with-an-uppercase-P. I'm not interested in an ontological debate as to which came first, but the internals could change if p5p decided that these language semantics needed to change.

      More to the point, how is any of this distinction relevant to Perl programmers?

      I find that correctly understanding the semantics of a programming language has a positive effect on the quality and correctness of code written in that language.

      This reads to me like it is motivated by the all-too-common and deceptively flawed meme of "an array in scalar context gives its size while a list in scalar context returns its last element". I've seen that used to justify so very many flawed conclusions. You can also use it to make flawed justifications to quite a few "correct" conclusions, but that just demonstrates how the flaws in that meme are deceptive (which is probably part of why it is still "all too common").

      The subroutine does /not/ return an array that then decides to give its size when it finds itself in a scalar context. There are many other ways that thinking "this sub returns an array" will mislead people. So it is better to divorce yourself from both of these flawed ways of thinking about context in Perl.

      And, no, my objections are not based on some secret knowledge on how Perl works internally. They are based on repeatedly seeing people make mistakes about how Perl scripts would behave based on these ideas. There are lots of cases where these ideas give the right answer. But the cases where they lead to the wrong answers are surely more important.

      - tye        

        This reads to me like it is motivated by the all-too-common and deceptively flawed meme...

        I think I know better than that (but I can see how someone reading might think otherwise).

        sub get_array { my @x = (4, 5, 6); return @x; } sub get_list { return (10, 11, 12, get_array()); } my @as_array = get_list(); my $as_scalar = get_list(); print "last list item: $as_array[-1]\n"; print "list in scalar: $as_scalar\n"; __END__ last list item: 6 list in scalar: 3

        Not only that, the context extends to everything in a list after return:

        sub context_in_position { my ($position_name) = @_; my $wa = wantarray; my $context; if ( $wa ) { $context = 'list' } elsif ( defined $wa ) { $context = 'scalar' } else { $context = 'void' } print "context in position '$position_name': $context\n"; return; } sub list { return ( context_in_position( 'a' ), context_in_position( 'b' ), ); } print "list() in void:\n"; list(); print "list() in scalar:\n"; scalar list(); print "list() in list:\n"; () = list(); __END__ list() in void: context in position 'a': void context in position 'b': void list() in scalar: context in position 'a': scalar context in position 'b': scalar list() in list: context in position 'a': list context in position 'b': list

        I think some Perl programmers might find it pretty surprising that in an expression like ( foo(), bar() ), foo() would find !wantarray(), but that's what happens.

        Do you still think I'm missing something here? Really, I want to get this straight, conceptually.

        The subroutine does /not/ return an array that then decides to give its size when it finds itself in a scalar context.

        I've heard the news that the array finds itself in a scalar context even before it makes it "out the door" to the wild world outside the sub. The context that sub is in seems to extend into the sub, into the place where the return "happens."

        That said, it seems blindingly obvious that return @this returns an array! So, here's a question for you. Is there any way to explain what happens, consistently and accurately, if we accept the statement that "return @this returns an array"? I think such an explanation would be far more readily accepted and understood than an explanation that starts with "you can't return arrays."

        (As an aside, it is likewise obvious that return IO::File->new() returns "a new IO::File object", but this fits nicely in the "scalar, list, or Nothing" idea because the object is a scalar. But would we say that an array is a list or a scalar? And if we say that an array is a list, how do we explain how it behaves differently from a list in scalar context?)

        There are lots of cases where these ideas give the right answer. But the cases where they lead to the wrong answers are surely more important.

        I'd be very interested to read some of the cases you refer to.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://667116]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others surveying the Monastery: (4)
As of 2024-03-29 01:45 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found