2

I have this code:

1. sub remCH();
2. # Some stuff
3. $line = remCH($line);
4.
5. sub remCH() {
6.     $rem = shift;
7.     $rem = chomp($rem);
8.     return ($rem);
9. }

I always get the following error when executing this code (line 24 would be line 3 in the above code):

Too many arguments for main::rem_CRLF at ./make_csv.pl line 24, near "$line)"

From what I understand, it is because the function is set to return something, but when I declared it, it was declared as "void".

How do I declare a function like below?

sub remCH(string/integer);
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Lucian
  • 115
  • 2
  • 12
  • The canonical question may be *[Perl Subroutine Prototyping -- The correct way to do it](https://stackoverflow.com/questions/8128918/)*. – Peter Mortensen Oct 06 '22 at 10:53
  • Related (but that is for the command-line): *[How can I pass command-line arguments to a Perl program?](https://stackoverflow.com/questions/361752/how-can-i-pass-command-line-arguments-to-a-perl-program)* – Peter Mortensen Oct 06 '22 at 10:57

2 Answers2

6
  • You should simply delete the function declaration (or "prototype" as they are known in Perl) in line #1. Your error is because the prototype (remCH()) declared the function to have a "zero parameters" signature, whereas your call passes it one parameter. Return type has nothing to do with it.

    There are some valid use cases for prototypes in Perl, but unless you know why you want to design your code that way, the rule of thumb is to never use a prototype. See this Stack Overflow post:

    Why are Perl 5's function prototypes bad?

  • Also, as per plusplus's wise comment, I missed that you had "()" in the function definition on line 5. Unlike C, you don't need them in Perl - please drop them. They turn the function definition into yet another prototype.


Having said that:

  • you can prototype a sub that takes one scalar parameter by using remCH($) prototype
  • you can have methods that check their types by switching to object-oriented Moose framework
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
DVK
  • 126,886
  • 32
  • 213
  • 327
  • So to translate what you just said, I should just remove line one and I should be fine, right? :D – Lucian Jun 17 '13 at 15:49
  • and remove the prototype on the second function declaration so it becomes `sub remCH {` ... – plusplus Jun 17 '13 at 15:51
  • @user2493988 - also, as plusplus correctly noted, get rid of parenthesis on line #5. Those constitute a second prototype. C syntax differs from Perl's – DVK Jun 17 '13 at 15:55
6

Perl does not have type signatures or formal parameters, unlike other languages like C:

// C code
int add(int, int);

int sum = add(1, 2);

int add(int x, int y) {
  return x + y;
}

Traditional Perl approach

Instead, the arguments are just passed as a flat list. Any type validation happens inside your code; you'll have to write this manually (but see below). You have to unpack the arglist into named variables yourself. And you don't usually predeclare your subroutines:

my $sum = add(1, 2);

sub add {
  my ($x, $y) = @_; # Unpack arguments
  return $x + $y;
}

If you predeclare your subs, you get the following:

  1. You can call the subs without parens
  2. You can change the way arguments are parsed with “prototypes”

Subroutine prototypes

A prototype can say

  • evaluate this argument in scalar context: sub foo($), or
  • this argument must be a hash variable, please pass it as a reference: sub foo(\%), or
  • this sub takes no arguments: sub foo(), etc.

Don't use these to validate the number of arguments. Actually, don't use them at all; they cause action at a distance. They aren't useful for type validation either.

Your error stems from the fact that you declared your sub as nullary, this caused a parse error.

Signatures

If you want the ability to declare your subroutines with named parameters, you can use a module that implements these.

  • From Perl 5.20 onwards, you can use feature 'signatures'. It is still marked as experimental, but the basic syntax is unlikely to change.

    use feature 'signatures';
    no warnings 'experimental::signatures'
    
    sub add($x, $y) { ... }
    
  • There are various CPAN modules like Method::Signatures. They might have benefits like integrated type checks, but can also be more buggy than solutions implemented in Core Perl.

    use Method::Signatures;
    
    func add(Int $x, Int $y) { ... }
    

However, these “signatures” have nothing to do with the prototypes of plain subs.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
amon
  • 57,091
  • 2
  • 89
  • 149
  • Thank you for explaining this. I think I'll take the short path and just delete all the pre-declarations of the subs – Lucian Jun 17 '13 at 20:25