I've created a program for my own purposes in three different languages, Perl, Python, and Ruby. Each program will be posted in with their own tag but I will add links to them through on each post. The program itself is very simple, all it does is ask the user about three different languages which are saved into an array, it then prompts the user to choose a language that runs through an if statement, and if the user chooses the language they're writing in it then takes a random language from the array and outputs it.
use strict;
use warnings;
sub welcome {
my @choices = qw( Perl Python Ruby );
my $lang = 3;
print("Welcome, to the test script, this will test what language you would like to learn.. In order to find out these choices, write this same definition in all three different languages\n");
print("There are $lang, languages to chose from please pick one:\n");
print "@choices\n";
my $choice = <STDIN>;
chomp $choice;
if ($choice eq "Ruby") {
print("You have chosen Ruby!\n");
}
elsif ($choice eq "Python") {
print("You have chosen Python!\n");
}
else {
print("You're already writing in Perl!! Let me choose for you:\n");
my $rand_elm = @choices[rand @choices];
print "$rand_elm\n"
}
}
welcome();
Perl took me the longest out of all the programs I wrote, this was my first ever Perl script. With all the ;
and the random symbols I had to use to make variables and arrays, it was defiantly hard. However I really enjoyed writing this in Perl, it was something different. Perl maxed out as the longest program at a total of 30 lines. At one point I kept getting an NameError
that was due to me missing a ;
at the chomp function. All in all I think Perl is definitely a great language to learn.
I also have some questions about Perl:
- Is there any better syntax that I should be using here in order to shorten the program?
- Does Perl have an equivalent to Ruby's
puts
? - Why is it easier to use a
sub
instead of a function?
example:
welcome();
# instead of
sub welcome();
2 Answers 2
Here's my rewrite with some comments.
#! /usr/bin/perl
use warnings;
use strict;
sub welcome {
my @choices = qw( Perl Python Ruby );
my $count = @choices; # Perl knows the number of the elements in an array.
print << "__TEXT__"; # Print a "here" document.
Welcome to the test script, this will test what language you would
like to learn. In order to find out these choices, write this same
definition in all three different languages. There are $count languages
to chose from please pick one:
@choices
__TEXT__
chomp(my $choice = <STDIN>); # Read and chomp in one line.
if (grep $_ eq $choice, qw( Ruby Python )) { # No need to test separately.
print "You have chosen $choice!\n";
}
else {
print "You're already writing in Perl!! Let me choose for you:\n",
"$choices[rand @choices]\n"; # To extract a single element, use the ,ドル not @.
}
}
welcome();
sub defines a subroutine. What do you mean by "actual definition"?
Note that the program might choose Perl again.
-
\$\begingroup\$ The only thing I'd add is
$choice =~ s/^\s+|\s+$/g;
to trim leading/trailing whitespace to give theeq
operator a better chance. If this is used,chomp
is not necessary. \$\endgroup\$glenn jackman– glenn jackman2015年11月10日 13:55:09 +00:00Commented Nov 10, 2015 at 13:55 -
\$\begingroup\$ @choroba Your rewrite looks beautiful. I rewrote the question with an example \$\endgroup\$13aal– 13aal2015年11月10日 14:19:38 +00:00Commented Nov 10, 2015 at 14:19
-
1\$\begingroup\$ @LostBam:
welcome()
is a call,sub welcome {
is a definition. \$\endgroup\$choroba– choroba2015年11月10日 18:46:59 +00:00Commented Nov 10, 2015 at 18:46
What you did well
use strict;
,use warnings;
, andmy
scopingqw(list of words)
instead of('list', 'of', 'words')
- Generally straightforward, readable Perl.
Suggestions
There is a hard-coded correspondence between
my $lang = 3
and the fact that there are three choices. My suggestion:my $choices = @choices;
In Perl,
$choices
and@choices
are different variables: the former is a scalar, and the latter is a list. The assignment above coerces the list into a scalar, and it does so by taking the number of elements in the list. (You used this technique in@choices[rand @choices]
.- Parentheses are optional for subroutine calls, and they are typically omitted for well-known functions such as
print
. - For maintainability, terminate the last
print
with a semicolon, even if you aren't required to. - As @glennjackman already told you,
say
would be better thanprint
, as it also outputs a trailing newline. Avoid super-long string literals by using a here document.
print <<"INTRO"; Welcome to the test script... There are $choices languages to choose from. @choices INTRO
Your logic is rather trusting: any input other than
"Ruby"
or"Python"
is treated as if it were"Perl"
.A better way:
use feature qw(say); ... chomp(my $choice = <STDIN>); if ($choice eq 'Perl') { say "You're already writing in Perl!! Let me choose for you:"; say @choices[rand @choices]; } elsif (grep { $choice eq $_ } @choices) { say "You have chosen $choice!"; }
A possible outcome is "You're already writing in Perl!! Let me choose... Perl". I consider that to be a logic bug.
-
\$\begingroup\$ I had no idea you could use
grep
in Perl?? I understand where you're saying there's a logic bug in the script. But can I make it so that it will not choose Perl..? \$\endgroup\$13aal– 13aal2015年11月10日 14:15:33 +00:00Commented Nov 10, 2015 at 14:15 -
1\$\begingroup\$ @LostBam
grep
in perl is function used to filter the contents of an array based on some user-defined criteria. It's not exactly like the /bin/grep command you're familiar with. Perl's grep is like Ruby's Array.select \$\endgroup\$glenn jackman– glenn jackman2015年11月10日 15:35:51 +00:00Commented Nov 10, 2015 at 15:35 -
\$\begingroup\$ @glennjackman Awh that makes a whole lot more sense, that's very good to know, I'm going to rewrite all the programs with all the new ideas I've learned, thank you all! \$\endgroup\$13aal– 13aal2015年11月10日 15:37:27 +00:00Commented Nov 10, 2015 at 15:37
def
to define a method; in Perl you usesub
to define a subroutine. Same idea, different keyword. \$\endgroup\$