28

I found that I can declare two variables in one statement using:

my ($a,$b)=(1,2); 

But I think this syntax may be confusing, for instance, if we had five variables declarations, it would be difficult to see which value belongs to which variable. So I think it would be better if we could use this syntax:

my $a=1, $b=2; 

I wonder, why is this kind of declaration not possible in Perl? And are there any alternatives?

(I am trying to avoid repeating my for each declaration like: my $a=1; my $b=2;)

3
  • 2
    "Why" might not be a very productive question in this context. Commented Apr 12, 2014 at 14:44
  • @TLP, Value next to the variable to receive the value is more readable. Repeating my is annoying and noise. It's kinda like how SQL's UPDATE syntax is better than its INSERT syntax. Commented Apr 12, 2014 at 14:55
  • Technically you could go with (my $a=1), (my $b=2); but that seems worse than my $a=1; my $b=2;. Commented Apr 12, 2014 at 22:52

6 Answers 6

21

No. Variables declared by my are only named once the next statement begins. The only way you can assign to the newly created variable is if you assign to the variable it returns. Think of my as new that also declares.

As for your particular code,

my $a=1, $b=2; 

means

((my $a)=1), ($b=2); 

Obviously, no good.

If you had used variables that weren't already declared[1], you would have gotten a strict error.


  1. $a and $b are predeclared in every namespace to facilitate the use of sort.
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks, for the clarification! I find this restriction a little bit annoying, but I understand I will have to live with it until someone improves the perl language :)
Perhaps, but it allows open(my $fh, ...) and while (my $line = <>) { } which are less onerous than my $fh; open($fh, ...) and { my $line; while ($line = <>) { } }. Overall, Perl's approach wins out over the one you suggest. That said, nothing prevents both a declaration statement (what you want) and a declaration expression (my) to exist in parallel. The declaration statement can even be added using a CPAN module in the same way that Syntax::Feature::Loop adds the keyword loop { ... }.
@HåkonHægland: I think it's worth pointing out that you are highly unlikely to need to declare and define so many variables at once in a properly-written Perl program. Variables should be declared as close as possible to their first point of use, and if you think you need to create five or more variables at the same point in a program then perhaps you should be looking at a hash or an array? I don't believe I've ever seen Perl code like that in fifteen years of using the language.
19

I'm new to Perl, but I'll tell you what I've learned so far.

I'm going to change to using $start and $end instead of $a and $b, because $a and $b are special variables that are always declared.

To answer your original question, you can declare and assign multiple variables in a single line like this:

my ($start, $end) = (1, 2); 

Personally, I find that about the same typing and less clear than having each on a separate line:

my $start = 1; my $end = 2; 

However, I think it is useful for assigning subroutine parameters to named variables, because subroutine parameters come in a list called @_:

use strict; sub print_range { my ($start, $end) = @_; print "Range is from $start to $end.\n"; } print_range(10, 20); # => Range is from 10 to 20. 

You can see some more quirks of the my statement in the documentation, including a way to ignore some of the values in the list.

Comments

18

Below is the method to declare multiple variable in one line in perl:

my ($day, $mon, $year, $hr, $min, $sec) = (0) x 6; 

Here, all the above variables has been initialized with 0. The repetition operator 'x' is used.

4 Comments

This is quite nice but can this be accomplished with 6 being automatically calculated so one does not need to change number of elements if an element is added?
@EvrenYurtesen: Yes its possible to automatically calculate the value 6 in your logic and you can use it as a variable. Eg: my $repeat=6; my ($day, $mon, $year, $hr, $min, $sec) = (0) x $repeat; But you need to check how you can manage the LHS part of assignment operator. Eg: If you change the value of $repeat=10, in this case six variables namely my ($day, $mon, $year, $hr, $min, $sec) will be assigned with 0s. But rest will be lost. So you need to check on this part if you will keep repeat value dynamic.
If you wish to leave the declared variables undefined you can simply do my ($day, $mon, $year, $hr, $min, $sec);
I have adopted this method. map { ($_) = '' } my ($x, $y, $z); You don't need to count anything. I put the $_ in () to confuse perlcritic into thinking I know what I'm doing :)
1

For variable declarations, I think my ($a,$b)=(1,2);, as pointed out, is definitely sufficient.

But for hash value initializations, you are allowed to use this syntax...

my $stuff = {}; $stuff->{hello} = $stuff->{thing} = 123; print(Dumper($stuff)); 

The result here will be...

$VAR1 = { 'hello' => 123, 'thing' => 123 }; 

This is neat, because you can initialize different keys for different arrays to the same value.

You are limited to using the same value for each, but this might just be perfect for a hash initialization.

1 Comment

Well, you are allowed to you that syntax for anything. The result of a Perl scalar assignment is the value you assigned. You could have my $n = $var[$m] = $hash{$key} = $ARGV[0] if you wanted.
-1

I have adopted this method.

map { ($_) = '' } my ($x, $y, $z); 

replacing '' with 0 for the digity ones.

You don't need to count anything.

I put the $_ in () to confuse perlcritic into thinking I know what I'm doing :)

The only way I can think of using this method with variable values is to do something like:-

my @v = (1,23,'Bill',41); map {($_) = shift @v} my ($x,$y,$r,$s); 

or if some are defined already:-

my $x = 7; my @v = (1,23,'Bill',41); map {($_) = shift @v} ($x,my ($y,$r,$s)); 

2 Comments

That's a pretty evil way of doing things, which might be acceptable if you hate your coworkers. But, consider that you haven't solved the problem. You still have to get the right number of variables in the list to map and those have to line up with the corresponding things in @v. You've merely done extra work with no improvement in the problem of getting the right things in the right positions. I'd even say that you've made it worse by separating and obfuscating what lines up with what.
You are correct, I wouldn't use this either. I still like map { ($_) = '' } my ($x, $y, $z); for defining/initializing multiple vars
-2

To avoid confusion in those cases, one could usually do like this:

my ($a, $b, $c, $d) = ( 1, # => $a 2, # => $b 3, # => $c 4 # => $d ); 

According to the KISS principle.


ikegami notes the alternative would be:

my $a = 1; my $b = 2; my $c = 3; my $d = 4; 

1 Comment

I think that's awful. The second one simpler, shorter, and not prone to having incorrect comments.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.