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

I have two functions, function A and function B.

The result of Function B is one of the parameters that is passed to function A. Function A then does something with this and returns the result.

The problem I have is that I'm not sure what Function B is going to return. It may return a scalar, it may return an array or it may return a hash. It may even be a reference to one of these.

Therefore, this makes it very difficult to code Function A when you're not sure what it's going to get. Obviously the correct way would be always to pass Function A a reference to whatever Function B returned, but how can I create the reference to it when I don't know what it's going to be?

Function A can easily detect references and scalars (if it only got one value), but if it gets more than one value, then it could either be an array or a hash, and I can't see how it could tell the difference unless it was a reference.

As an extra bonus, the call to Function A, with whatever is being passed to it (the result of Function B and whatever other parameters), must be a single line.

Challenge extended.

  • Comment on Auto-detecting returned or passed variable type

Replies are listed 'Best First'.
•Re: Auto-detecting returned or passed variable type
by merlyn (Sage) on Aug 19, 2004 at 19:52 UTC
    if pigs could fly...

    Your challenge doesn't make sense from a Perl perspective. You are abusing the terminology.

    • A subroutine can be called in a void context, in which case, it returns nothing.
    • A subroutine can be called in a scalar context, in which case it always returns a scalar.
    • A subroutine can be called in a list context, in which case it always returns a list.

    The types of values a subroutine returns is not decided by the subroutine, but by the caller. Therefore, your challenge is meaningless. And it can never return "an array" or "a hash". It'll be a scalar or a list, depending on the context in which it's called.

    -- Randal L. Schwartz, Perl hacker
    Be sure to read my standard disclaimer if this is a reply.

      I think I'm just not explaining myself well.

      Here's a rough example...

      $result = $obj->functionA($obj->functionB());

      I want whatever function B returns to be passed as a reference to function A. I don't know what function B is going to return because that whole line is generated by a Parse::RecDescent grammar which is writing the Perl script based on the parsing of a scripting language I designed.

      If I knew functionB was always going to return a list, I could do...

      $result = $obj->functionA([ $obj->functionB() ]);

      Or if I knew it was going to be a hash...

      $result = $obj->functionA({ $obj->functionB() });

      I've thought of writing a function which takes in some values and returns a reference to them, whatever they might be...

      $result = $obj->functionA($obj->createrightreftype($obj->functionB()));

      But I can't think of any way to make createrightreftype do the right thing.

      Does that make any more sense? I'm finding it difficult to describe this.

        $result = $obj->functionA($obj->functionB());
        That's going to be calling method functionB in a list context. Therefore, the one and only answer you can have in Perl is "it is returning a list". Every other thing you think it might be doing is not happening.

        Your statement of "always going to return a list" is therefore true. Your statement of "going to be a hash" is therefore always false.

        I don't see the confusion here. It's the caller that decides what the called routine returns. It's that simple.

        -- Randal L. Schwartz, Perl hacker
        Be sure to read my standard disclaimer if this is a reply.

Re: Auto-detecting returned or passed variable type
by VSarkiss (Monsignor) on Aug 19, 2004 at 20:10 UTC

    Obviously the correct way would be always to pass Function A a reference to whatever Function B returned, but how can I create the reference to it when I don't know what it's going to be?
    You don't have to know what it's returning to take a reference to it:funcA(\funcB());will pass a single reference (scalar) to whatever funcB returns.

    Update
    The note below is correct. Ignore this.

      Not if funcB returns a list. Then funcA would get a single reference to the last item in the list. Not to the whole list.
        Are you sure?
        $ perl -e " sub a{return (1,2)} sub b{print scalar @_, map $$_, @_} b(\a());"
        prints 212
Re: Auto-detecting returned or passed variable type
by ikegami (Patriarch) on Aug 19, 2004 at 21:49 UTC
    The problem I have is that I'm not sure what Function B is going to return. It may return a scalar, it may return an array or it may return a hash. It may even be a reference to one of these

    That's not exactly right. Perl subroutines can return list of scalars. That's it. If you try to return something that isn't, it gets converted. The conversion occurs inside the function, so there's no way for the outside to know what was passed to return inside the function. Unfortunately, what you request cannot be done in Perl.

    However, that doesn't mean there's no solution to your problem. There might be an alternative way of achieving what you want. Maybe there's a way of causing Function B that hasn't occured to you. Parse::RecDescent is very powerful and very flexible, so I'm sure we could find a way to help you if you were to post some of your code.