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

is it possible to test if a sub is context sensitive and returns differently in listcontext? I mean before calling the sub and idependent of parameters?

Replies are listed 'Best First'.
Re: check for wantarray?
by Crackers2 (Parson) on Dec 26, 2008 at 01:21 UTC
    Intuitively, I'd say you can't. What about a sub like this:
    sub bizarre { if ($_[0] eq "context-sensitive") { return wantarray?["sna","fu"]:"snafu"; } else { return "bar"; } }
    which is sometimes context-sensitive? I suppose you could mark a sub context-sensitive if it is for at least one set of parameters, but that might have limited value.
Re: check for wantarray?
by ikegami (Patriarch) on Dec 26, 2008 at 10:07 UTC

    What does wantarray have to do with it? All of the following return something different based on context:

    • sub { ...; @foo }
    • sub { ...; ($x,$y) }
    • sub { ...; /(...)/ }
    • sub { ...; grep { ... } @x }
    • and I could go on and on and on and on

    What about

    sub foo { ...; bar() }

    The whole "independent of parameters" bit is problematic too.

    sub { ...; if ($_[0]) { $foo } else { @bar } }

    It might be possible to identify some subs that only return a scalar by poking at the opcode tree, but for many subs, it probably would be quite hard to tell.

      Excellent point. Here's one that surprised the hell out of me one time:

      sub { ...; $x..$y }

      Holy flip-flop operator, Batman!

      I thought I was going crazy until I reread the relevant bits of perlop.


      TGI says moo

Re: check for wantarray?
by Bloodnok (Vicar) on Dec 25, 2008 at 23:10 UTC
Re: check for wantarray?
by CountZero (Bishop) on Dec 26, 2008 at 09:57 UTC
    Your question is "Only perl can parse Perl" in disguise.

    The answer is that only by running the program you can answer your question.

    CountZero

    A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James

          The answer is that only by running the program you can answer your question.
      
      OK, but how can I answer this by running??? 
      
      I'm calling different subs in list context. Some return a reference 
      of an array, others return an array by list.
      
      How can I distinguish both if the the array has only one element, 
      a reference of an array?
      
      Even calling both a second time in scalar context doesn't help.
      

        [ Please don't use <pre>. All you have to do is put <p> in front of every paragraph. ]

        I don't think CountZero meant to imply that it's possible by running the program, only that it can be impossible without running the program. Such is the nature of dynamic languages such as Perl.

        How can I distinguish both if the the array has only one element, a reference of an array?

        By reading the docs. There's no way to know programatically.

        If this is a problem you can call all subroutines in array context and examine the first and possible remainder of the array elements for expected return values.
        @ret = somesub(); if (ref $ret[0] eq 'HASH') { .... } elsif (ref $ret[0] eq 'ARRAY') { .... }
        etc. Messy but would take care of the problem. This is how I handle some XML data structures deparsed from API calls to certain applications that can return an array of hashrefs, an arrayref of hashrefs, a single hashref or undefined.
        You will have to examine the return value(s).
        • If more than one value is returned, the sub returned a list, you will then have to examine each element (see next bullet point).
        • If only one value is returned, the ref function can help you to determine what kind of value was returned.
        • From the docs:
          ref EXPR ref
          Returns a non-empty string if EXPR is a reference, the empty string otherwise. If EXPR is not specified, $_ will be used. The value returned depends on the type of thing the reference is a reference to. Builtin types include:
          • SCALAR
          • ARRAY
          • HASH
          • CODE
          • REF
          • GLOB
          • LVALUE
          If the referenced object has been blessed into a package, then that package name is returned instead. You can think of ref as a typeof operator.

          CountZero

          A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James

Re: check for wantarray?
by Anonymous Monk on Dec 26, 2008 at 19:02 UTC
    Why do you care? What problem are you really trying to solve?