Prototypes/Parameters to a Function/Sub-Routine

Discussion in 'Perl Misc' started by O. Olson, Aug 1, 2007.

  1. O. Olson

    O. Olson Guest

    Hi,
    I would like to know if it is possible to enforce the number and type
    of the parameters in a function prototype. Assuming that a person does
    not circumvent the prototypes using &.

    I have tried the following that tries to say that the function
    printScalar () should only accept a single Parameter. This does not
    work i.e. does not compile.

    # This function would print the time variable passed
    sub printScalar(my $num)
    {
    print "$num";
    }


    I have looked at perlsub at http://perldoc.perl.org/perlsub.html - and
    I am not sure if the answer to my Question is NO.

    This would be of more importance when I am working with Objects i.e.
    to ensure that the reference passed, is an object of a certain class.

    Thanks a lot.
    O.O.
    O. Olson, Aug 1, 2007
    #1
    1. Advertising

  2. O. Olson

    Paul Lalli Guest

    On Aug 1, 11:41 am, "O. Olson" <> wrote:
    > I would like to know if it is possible to enforce the number and type
    > of the parameters in a function prototype. Assuming that a person does
    > not circumvent the prototypes using &.


    That is supposed to be the idea behind subroutine prototypes, yes.
    But they don't work correctly.

    > I have tried the following that tries to say that the function
    > printScalar () should only accept a single Parameter. This does not
    > work i.e. does not compile.
    >
    > # This function would print the time variable passed
    > sub printScalar(my $num)


    What part of perlsub gave you the idea that was valid syntax?

    > {
    > print "$num";


    perldoc -q quoting

    > }
    >
    > I have looked at perlsub athttp://perldoc.perl.org/perlsub.html- and
    > I am not sure if the answer to my Question is NO.
    >
    > This would be of more importance when I am working with Objects i.e.
    > to ensure that the reference passed, is an object of a certain class.


    What you are trying to do is:

    sub printScalar($) {
    my $num = shift;
    print $num;
    }

    Doing that, when someone calls your subroutine with something other
    than one scalar value, they will get a syntax error:

    $ perl -le'
    sub printScalar($) {
    my $num = shift;
    print $num;
    }
    printScalar(10, 20);
    '
    Too many arguments for main::printScalar at -e line 6, near "20)"
    Execution of -e aborted due to compilation errors.


    However, as I said, prototypes do NOT work correctly. For example,
    you would probably expect this to give a similar error, wouldn't you?
    $ perl -le'
    sub printScalar($) {
    my $num = shift;
    print $num;
    }
    my @nums = (10, 20);
    printScalar(@nums);
    '

    But instead, this program executes just fine, and displays the number
    "2". Why? Because you told the subroutine to take a scalar
    argument. The user passed an array. So Perl "helpfully" took that
    array, and evaluated it in scalar context, and an array in scalar
    context gives its size.

    Similarly, you'd probably expect this to return an error that a list
    is required:

    $ perl -le'
    sub printArray(@) {
    my @nums = @_;
    print for @nums;
    }
    printArray();
    '

    But this program executes just fine. Because an "empty" list is still
    a list. We could go on and on. Say you want a subroutine to take two
    scalars:
    sub printBoth($$);
    but if a user calls it like so:
    my @mixmax = (5, 10);
    printBoth(@minmax);
    Perl will throw an error, even though the array does indeed contain
    two scalars.


    End result, you can't enforce this type of checking at compile time.
    You have to do it manually at runtime.

    sub printObject {
    @_ == 1 or
    croak "Invalid number of arguments passed to printObject";
    my $obj = shift;
    ref $obj or
    croak "Argument to printObject is not a reference";
    UNIVERSAL::isa($obj, "MyClass") or
    croak "Argument to printObject is not a MyClass";
    #etc . . .
    }

    Paul Lalli
    Paul Lalli, Aug 1, 2007
    #2
    1. Advertising

  3. O. Olson

    Klaus Guest

    On Aug 1, 5:41 pm, "O. Olson" <> wrote:
    > Hi,
    > I would like to know if it is possible to enforce the number and type
    > of the parameters in a function prototype. Assuming that a person does
    > not circumvent the prototypes using &.
    >
    > I have tried the following that tries to say that the function
    > printScalar () should only accept a single Parameter. This does not
    > work i.e. does not compile.
    >
    > # This function would print the time variable passed
    > sub printScalar(my $num)
    > {
    > print "$num";
    >
    > }
    >
    > I have looked at perlsub athttp://perldoc.perl.org/perlsub.html- and
    > I am not sure if the answer to my Question is NO.


    Looking at the article "Far More Than Everything You've Ever Wanted to
    Know about Prototypes in Perl" by Tom Christiansen:
    http://library.n0i.net/programming/perl/articles/fm_prototypes/
    I would say the answer to your question is probably no.

    > This would be of more importance when I am working with Objects i.e.
    > to ensure that the reference passed, is an object of a certain class.


    You can test the package name of an object, see perldoc -f ref

    --
    Klaus
    Klaus, Aug 1, 2007
    #3
  4. On Wed, 01 Aug 2007 08:41:36 -0700, "O. Olson" <>
    wrote:

    > I would like to know if it is possible to enforce the number and type
    >of the parameters in a function prototype. Assuming that a person does


    No. Perl 5 does not have a type system. Perl 6 will, but it will still
    be optional.

    >I have tried the following that tries to say that the function
    >printScalar () should only accept a single Parameter. This does not
    >work i.e. does not compile.
    >
    ># This function would print the time variable passed
    >sub printScalar(my $num)


    In fact that's not a valid syntax. You want

    sub printScalar ($) { ... }

    instead.

    >This would be of more importance when I am working with Objects i.e.
    >to ensure that the reference passed, is an object of a certain class.


    You're out of luck! Prototypes do not work at all when subs are called
    as methods. Still talking 'bout Perl 5, of course...


    Michele
    --
    {$_=pack'B8'x25,unpack'A8'x32,$a^=sub{pop^pop}->(map substr
    (($a||=join'',map--$|x$_,(unpack'w',unpack'u','G^<R<Y]*YB='
    ..'KYU;*EVH[.FHF2W+#"\Z*5TI/ER<Z`S(G.DZZ9OX0Z')=~/./g)x2,$_,
    256),7,249);s/[^\w,]/ /g;$ \=/^J/?$/:"\r";print,redo}#JAPH,
    Michele Dondi, Aug 1, 2007
    #4
  5. On Wed, 01 Aug 2007 09:49:14 -0700, Paul Lalli <>
    wrote:

    >Similarly, you'd probably expect this to return an error that a list
    >is required:
    >
    >$ perl -le'
    >sub printArray(@) {
    > my @nums = @_;
    > print for @nums;
    >}
    >printArray();
    >'
    >
    >But this program executes just fine. Because an "empty" list is still
    >a list.


    In fact this is perfectly fine, if you ask me, and not a good example
    of prototypes failing. I'm not really sure but I think that even Perl
    6's powerful signatures do not provide means to specify that a list to
    be passed must have a specific size, or even more simply that it is
    non empty.


    Michele
    --
    {$_=pack'B8'x25,unpack'A8'x32,$a^=sub{pop^pop}->(map substr
    (($a||=join'',map--$|x$_,(unpack'w',unpack'u','G^<R<Y]*YB='
    ..'KYU;*EVH[.FHF2W+#"\Z*5TI/ER<Z`S(G.DZZ9OX0Z')=~/./g)x2,$_,
    256),7,249);s/[^\w,]/ /g;$ \=/^J/?$/:"\r";print,redo}#JAPH,
    Michele Dondi, Aug 1, 2007
    #5
  6. O. Olson

    Paul Lalli Guest

    On Aug 1, 1:56 pm, Michele Dondi <> wrote:
    > On Wed, 01 Aug 2007 09:49:14 -0700, Paul Lalli <>
    > wrote:
    >
    > >Similarly, you'd probably expect this to return an error that a list
    > >is required:

    >
    > >$ perl -le'
    > >sub printArray(@) {
    > > my @nums = @_;
    > > print for @nums;
    > >}
    > >printArray();
    > >'

    >
    > >But this program executes just fine. Because an "empty" list is still
    > >a list.

    >
    > In fact this is perfectly fine, if you ask me, and not a good example
    > of prototypes failing.


    Perhaps not, but I think it is a decent example of prototypes not
    doing what someone new to Perl programming would *expect* them to do.

    Paul Lalli
    Paul Lalli, Aug 1, 2007
    #6
  7. On Wed, 01 Aug 2007 12:19:45 -0700, Paul Lalli <>
    wrote:

    >> >But this program executes just fine. Because an "empty" list is still
    >> >a list.

    >>
    >> In fact this is perfectly fine, if you ask me, and not a good example
    >> of prototypes failing.

    >
    >Perhaps not, but I think it is a decent example of prototypes not
    >doing what someone new to Perl programming would *expect* them to do.


    I'm thinking of it and I'm fairly sure that it's not the case, and in
    particular that as a newbie I wouldn't have expected so. But then it's
    probably because we tend to project our own way to see things on the
    others too.


    Michele
    --
    {$_=pack'B8'x25,unpack'A8'x32,$a^=sub{pop^pop}->(map substr
    (($a||=join'',map--$|x$_,(unpack'w',unpack'u','G^<R<Y]*YB='
    ..'KYU;*EVH[.FHF2W+#"\Z*5TI/ER<Z`S(G.DZZ9OX0Z')=~/./g)x2,$_,
    256),7,249);s/[^\w,]/ /g;$ \=/^J/?$/:"\r";print,redo}#JAPH,
    Michele Dondi, Aug 2, 2007
    #7
  8. O. Olson

    -berlin.de Guest

    O. Olson <> wrote in comp.lang.perl.misc:

    [prototype question, has been answered]

    > This would be of more importance when I am working with Objects i.e.
    > to ensure that the reference passed, is an object of a certain class.


    It is usually an indication of a design error if a method has to
    care about the class an object comes from. If an object *can* invoke
    a method (through inheritance, for instance) the method should be able
    to handle it.

    Anno
    -berlin.de, Aug 2, 2007
    #8
  9. O. Olson

    O. Olson Guest

    Thanks Paul for your detailed discussion.

    On Aug 1, 6:49 pm, Paul Lalli <> wrote:
    > What part of perlsub gave you the idea that was valid syntax?
    >


    No, I did not mean to say that I got this idea from perlsub - just
    that I wanted to do something like this - but this was not available
    in Perlsub. Anyway now I got the idea.

    > UNIVERSAL::isa($obj, "MyClass") or
    > croak "Argument to printObject is not a MyClass";



    I think this is what I wanted i.e. a way to check if an object is of a
    certain class.

    Thanks again,
    O.O.
    O. Olson, Aug 3, 2007
    #9
  10. O. Olson

    O. Olson Guest

    On Aug 1, 7:26 pm, Michele Dondi <> wrote:
    >
    > No. Perl 5 does not have a type system. Perl 6 will, but it will still
    > be optional.


    Thanks Michele. I think would wait for Perl 6 - Whenever that's going
    to come out.
    O.O.
    O. Olson, Aug 3, 2007
    #10
  11. O. Olson

    O. Olson Guest

    On Aug 1, 10:01 pm, ""
    <> wrote:
    >
    > Perhaps you'll find the Params::Util module from CPAN helpful for
    > checking parameters.
    >

    Thanks Steven for pointing this out. I would try this out as soon as I
    get the time.
    O.O.
    O. Olson, Aug 3, 2007
    #11
  12. O. Olson

    O. Olson Guest

    On Aug 2, 1:50 pm, -berlin.de wrote:
    >
    > It is usually an indication of a design error if a method has to
    > care about the class an object comes from. If an object *can* invoke
    > a method (through inheritance, for instance) the method should be able
    > to handle it.
    >
    > Anno



    Thanks Anno.
    Consider if I have to compare two objects the same class. Something
    like:

    $obj1->diff($obj2)

    Where both $obj1 and $obj2 belong to the same class and the function
    diff() calculates the difference between them.

    In this case diff() needs to be able to ensure that the object passed
    as a parameter is of the same common class to be able to calculate the
    difference.

    O.O.
    O. Olson, Aug 3, 2007
    #12
  13. O. Olson

    -berlin.de Guest

    O. Olson <> wrote in comp.lang.perl.misc:
    > Thanks Paul for your detailed discussion.
    >
    > On Aug 1, 6:49 pm, Paul Lalli <> wrote:
    > > What part of perlsub gave you the idea that was valid syntax?
    > >

    >
    > No, I did not mean to say that I got this idea from perlsub - just
    > that I wanted to do something like this - but this was not available
    > in Perlsub. Anyway now I got the idea.
    >
    > > UNIVERSAL::isa($obj, "MyClass") or
    > > croak "Argument to printObject is not a MyClass";

    >
    >
    > I think this is what I wanted i.e. a way to check if an object is of a
    > certain class.


    If you know that $obj *is* an object, that's better written as

    $obj->isa( 'MyClass');

    Anno
    -berlin.de, Aug 3, 2007
    #13
  14. O. Olson

    -berlin.de Guest

    O. Olson <> wrote in comp.lang.perl.misc:
    > On Aug 2, 1:50 pm, -berlin.de wrote:
    > >
    > > It is usually an indication of a design error if a method has to
    > > care about the class an object comes from. If an object *can* invoke
    > > a method (through inheritance, for instance) the method should be able
    > > to handle it.
    > >
    > > Anno

    >
    >
    > Thanks Anno.
    > Consider if I have to compare two objects the same class. Something
    > like:
    >
    > $obj1->diff($obj2)
    >
    > Where both $obj1 and $obj2 belong to the same class and the function
    > diff() calculates the difference between them.
    >
    > In this case diff() needs to be able to ensure that the object passed
    > as a parameter is of the same common class to be able to calculate the
    > difference.


    Not necessarily. A user could present $obj2 coming from a subclass,
    in which case the test may fail, depending how it it done.

    In a purely OO design, the diff method would use accessor methods of
    the common class to compare values, not rely on a particular structure
    of the objects.

    Anno
    -berlin.de, Aug 3, 2007
    #14
  15. O. Olson

    O. Olson Guest

    On Aug 3, 2:03 pm, -berlin.de wrote:
    > Not necessarily. A user could present $obj2 coming from a subclass,
    > in which case the test may fail, depending how it it done.
    >
    > In a purely OO design, the diff method would use accessor methods of
    > the common class to compare values, not rely on a particular structure
    > of the objects.
    >
    > Anno


    Dear Anno,

    Thanks for taking interest - But I'm still not entirely clear what
    you mean. ( Let's not consider inheritance for a while, because it may
    complicate matters - and I'm not using it right now).

    Consider for example the following class

    -----------------------------------------------------
    package MyTime;

    sub new {
    my $inv = shift;
    my $class = ref( $inv ) || $inv;
    die "Too many arguments\n" unless @_ <=3;
    my $self;

    if ( @_ == 0 ) {

    my @time = localtime( );
    $self = { HOUR => $time[ 2 ],
    MINUTE => $time[ 1 ],
    SECOND => $time[ 0 ] };
    } else {
    $self = { HOUR => $_[ 0 ],
    MINUTE => $_[ 1 ] || 0,
    SECOND => $_[ 2 ] || 0 };
    }

    return bless $self, $class;
    }

    sub timeDiff {

    my $start_time = shift; # Start Time - First argument
    my $stop_time = shift; # Stop Time - Second argument


    print "Calculating the Time Difference between: " . $start_time-
    >as_text . " to " . $stop_time->as_text; #print "\n";


    my $start_seconds = $start_time->{HOUR}*3600 + $start_time-
    >{MINUTE}*60 + $start_time->{SECOND};

    my $stop_seconds = $stop_time->{HOUR}*3600 + $stop_time-
    >{MINUTE}*60 + $stop_time->{SECOND};


    my $diff_seconds = $stop_seconds - $start_seconds;

    print " = $diff_seconds \n";

    return $diff_seconds;

    }

    -----------------------------------------------------

    Assuming timeDiff() is called as:

    $time_start-> timeDiff($time_stop)

    -----------------------------------------------------


    My question is how can I ensure that the second argument passed to
    timeDiff() is of The same class MyTime.

    Thanks a lot,
    O.O.
    O. Olson, Aug 4, 2007
    #15
  16. O. Olson

    -berlin.de Guest

    O. Olson <> wrote in comp.lang.perl.misc:
    > On Aug 3, 2:03 pm, -berlin.de wrote:
    > > Not necessarily. A user could present $obj2 coming from a subclass,
    > > in which case the test may fail, depending how it it done.
    > >
    > > In a purely OO design, the diff method would use accessor methods of
    > > the common class to compare values, not rely on a particular structure
    > > of the objects.
    > >
    > > Anno

    >
    > Dear Anno,
    >
    > Thanks for taking interest - But I'm still not entirely clear what
    > you mean. ( Let's not consider inheritance for a while, because it may
    > complicate matters - and I'm not using it right now).
    >
    > Consider for example the following class


    There are ready-made time classes on CPAN that do time calculations.
    In a real application I would urge you to use one of those. I'll
    assume your implementation of MyTime is an exercise.

    > -----------------------------------------------------
    > package MyTime;
    >
    > sub new {
    > my $inv = shift;
    > my $class = ref( $inv ) || $inv;
    > die "Too many arguments\n" unless @_ <=3;


    You mean ">=".

    > my $self;
    >
    > if ( @_ == 0 ) {
    >
    > my @time = localtime( );
    > $self = { HOUR => $time[ 2 ],
    > MINUTE => $time[ 1 ],
    > SECOND => $time[ 0 ] };
    > } else {
    > $self = { HOUR => $_[ 0 ],
    > MINUTE => $_[ 1 ] || 0,
    > SECOND => $_[ 2 ] || 0 };
    > }
    >
    > return bless $self, $class;
    > }
    >
    > sub timeDiff {
    >
    > my $start_time = shift; # Start Time - First argument
    > my $stop_time = shift; # Stop Time - Second argument
    >
    >
    > print "Calculating the Time Difference between: " . $start_time-
    > >as_text . " to " . $stop_time->as_text; #print "\n";

    >
    > my $start_seconds = $start_time->{HOUR}*3600 + $start_time-
    > >{MINUTE}*60 + $start_time->{SECOND};

    > my $stop_seconds = $stop_time->{HOUR}*3600 + $stop_time-
    > >{MINUTE}*60 + $stop_time->{SECOND};

    >
    > my $diff_seconds = $stop_seconds - $start_seconds;
    >
    > print " = $diff_seconds \n";
    >
    > return $diff_seconds;
    >
    > }
    >
    > -----------------------------------------------------
    >
    > Assuming timeDiff() is called as:
    >
    > $time_start-> timeDiff($time_stop)
    >
    > -----------------------------------------------------
    >
    >
    > My question is how can I ensure that the second argument passed to
    > timeDiff() is of The same class MyTime.


    You could say

    die "..." unless $time_stop->isa( 'MyTime);

    but I simply wouldn't bother.

    If someone calls ->timeDiff with an inappropriate argument, access to
    ->{ HOUR} will fail and you'll see warnings about using an undefined
    value. (Your *are* running with warnings and strict, aren't you?)
    That should be enough to detect and correct the error.

    On the other hand, you are duplicating the code to transform a
    time value to seconds in your timeDiff method. Instead, define
    a method (code untested)

    sub inSecs {
    my $time =shift;
    ($time->{ HOUR}*60 + $time->{ MINUTE})*60 + $time->{ SECOND};
    }

    and base timeDiff on that:

    sub timeDiff {
    my ( $start, $stop) = @_;
    $stop->inSecs - $start->inSecs;
    }

    Besides the better code re-use, this makes sure that a call with a
    non-time will fail because the ->inSecs method won't be defined.

    Anno
    -berlin.de, Aug 4, 2007
    #16
  17. O. Olson

    O. Olson Guest

    Dear Anno,

    Thank you for your explanations - I think this is what I wanted. If
    the have any more doubts, I would post them to another thread as they
    would be unrelated to this topic.

    Thanks again,
    O.O.
    O. Olson, Aug 4, 2007
    #17
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. D. Shane Fowlkes

    just tinkering with a Sub Routine in ASP.NET

    D. Shane Fowlkes, Nov 12, 2003, in forum: ASP .Net
    Replies:
    5
    Views:
    434
    Scott M.
    Nov 13, 2003
  2. Neo
    Replies:
    6
    Views:
    410
    Mark A. Odell
    Dec 2, 2003
  3. Ben
    Replies:
    2
    Views:
    883
  4. Syren Baran

    function prototypes and function addresses

    Syren Baran, Jan 9, 2008, in forum: C Programming
    Replies:
    6
    Views:
    306
  5. Lawrence D'Oliveiro

    Death To Sub-Sub-Sub-Directories!

    Lawrence D'Oliveiro, May 5, 2011, in forum: Java
    Replies:
    92
    Views:
    2,020
    Lawrence D'Oliveiro
    May 20, 2011
Loading...

Share This Page