Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic

Re: Function Prototypes and Array vs. List (Pt. 2)

by ariels (Curate)
on Jun 13, 2002 at 14:09 UTC ( #174205=note: print w/replies, xml ) Need Help??

in reply to Function Prototypes and Array vs. List (Pt. 2)

But you aren't "convert[ing] or expand[ing] an array into a list"; you're converting a list into a scalar. That's what the prototype means. It might not be what most people would want prototypes to mean, but that' still what the prototype means.

How do you convert a list to a scalar? Easy. Meditate on this bit from perlfunc:

Remember the following important rule: There is no rule that relates the behavior of an expression in list context to its behavior in scalar context, or vice versa.

There is no general rule.

You have to read the documentation for whatever it is you're using.

  • Comment on Re: Function Prototypes and Array vs. List (Pt. 2)

Replies are listed 'Best First'.
Re^2: Function Prototypes and Array vs. List (Pt. 2)
by tadman (Prior) on Jun 13, 2002 at 14:28 UTC
    The thing is, the documentation doesn't say. It would be something like this, although with a bit more gritty realism:

    Creates a Foo object with the id parameter set accordingly. id should be a valid record identifier.
    So, I have an array @bob = ('Bob') which I want to use on this function. Eyeballing it, it looks like it would fit, so I go ahead and use it:
    Do you get a warning? Nope. Yet later, you might notice that for some reason your Foo has an id of 1, which doesn't make any sense. Maybe smoke starts pouring out of your Perl program because of acalar conversion induced program failure. You lose a life and must hit "P1 Start" to continue.

    Without checking the source code you're never really going to know for sure.

    Conceputally, I was hoping for either a quick idiomatic way to do it, or something like one of these:
    Foo::create(listify(@bob)); # List converter? Foo::create($bob[0..$#bob]); # Array slice as list?
    Instead, you're going to have to do some work, which is anti-Lazy. In the general sense:

    I certainly can't contest merlyn's "random crap" remark, so I'd say this was "premeditated ignorance". I knew the array had a single element and expected a particular behavior. After all, why expand twice (once on call, once on parameter import)? Well, sometimes you've just got to.
      See, I don't get this:

      Creates a Foo object with the id parameter set accordingly. id should be a valid record identifier.

      when put together with this:
      So, I have an array @bob = ('Bob') which I want to use on this function. Eyeballing it, it looks like it would fit
      What part of your brain says that when they wanted a "record identifier" (whatever that is, but it looks to be a single value), you can hand it an array?! That's the part that's off here. It's not Perl's fault you're trying to jam in something that doesn't make sense. And Perl has every right to given you surprising (to you) results when you've wandered out into unsuggested territory.

      As I saw somewhere in a purl factoid:

      You can't just throw random crap together and expect it to work.
      If I knew that the function was looking for a scalar ID, and I had that ID as the first element of an array I'd know immediately that I needed to hand it an element:
      Case closed.

      -- Randal L. Schwartz, Perl hacker

      update: And if you can show me where you "Well, sometimes you've just got to." in actual useful code and not some junky little hypothetical misdesign, I'd be surprised.
        I'd say the specification of create is incomplete. Prototyping does act surprisingly because it goes against the list flattening you'd expect from unprototyped functions. Not specifying that a function is prototyped, or not saying that the first argument will be evaluated in scalar context means, IMO, that the description is incomplete (and hence wrong).

        I only use prototypes if there are clear benefits (\@ and & prototypes, sometimes a prototype with a single $ (which changes the way perl compiles your Perl)). But often it's too much of a nuisance.

        I also don't agree with your reasoning that with such a simple description of create you should use $array[0] Take a look at the description of POSIX::strftime. With your reasoning, the proper way of calling it would be:

        use POSIX; my @chunks = localtime; print strftime "some format", $chunks [0], $chunks [1], $chunks [2 +], $chunks [3], $chunks [4], $chunks [5 +], $chunks [6], $chunks [7], $chunks [8 +];
        instead of
        print strftime "some format", localtime;

        strftime could have been prototyped as $$$$$$$;$$$; the description doesn't say it's not, and spells out the arguments for strftime.


      No, your hypothetical create method is simply wrong. It's buggy. It should be (to paraphrase John Cleese) a NON-method. It should be bereft of life and pushing up the daisies.

      The only reason to use prototypes is in order to give your functions the same syntax as various Perl builtins. E.g., with prototypes you can write a mymap that will have the same semantics as map. Your ``create'' method isn't doing that; it's using a prototype in order to create a bug.

      I could equally well claim that map is broken, because this code

      my %hash = map { $_ => X => 1 } qw(a b c d)
      does something very strange.

      You're right about coding, though: In order to make sure code does not have a bug, it is not enough to check documentation. You must look at the code.

      Why are you using a prototype? So far you've shown excellent reasons for you not to use a prototype for this function. ``Doctor, whenever I leave the spoon in the cup and drink my tea, my eye hurts!''

        Eh, no, it's using a prototype to act as Perl buildins.... Remember that by default, subroutine calls gobble up all the arguments (unless there are parens), except subroutines that are prototypes to take zero or one argument. Witness:
        #!/usr/bin/perl -w use strict; sub all {print "@_\n"}; sub gobble_no_proto {return}; sub gobble_proto ($) {return}; all "foo", "bar", gobble_no_proto "baz", "quux", "fluff"; all "foo", "bar", gobble_proto "baz", "quux", "fluff"; __END__ foo bar foo bar quux fluff
        See the difference?


Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://174205]
[shmem]: they are too close to each other
[shmem]: J.S.Bach said: "playing Clavier is darn easy. All you have to do is to push the right key with the right finger at the right time."

How do I use this? | Other CB clients
Other Users?
Others wandering the Monastery: (8)
As of 2017-04-27 14:25 GMT
Find Nodes?
    Voting Booth?
    I'm a fool:

    Results (508 votes). Check out past polls.