Search code examples
perlnestedsubroutine

Return value from nested Subroutine Perl


We've received an assignment from school, where we're supposed to make our own small n' simple Perl application. I thought I'd make a ATM simulator. So far, it's been going great; I've created a menu (Withdraw, Balance, Transfer), by using subroutines. This is my code so far:

#! /usr/bin/perl
#Written by: Tobias Svenblad, h15tobsv@du.se, Digitalbrott & e-Säkerhetsprogrammet (2015)
#PerlLab03-2c.plx

use warnings;
use strict;
use Term::ANSIColor;
use Text::Format;

my $firstname;
my $lastname;
my $acc_balance = 2451.26;
my $acc_withdraw;
my $clr_scr = join( "", ( "\033[2J", "\033[0;0H" ) );    #This variable will clear the screen and jump to postion 0, 0.

my $atm = Text::Format->new;
print color('green');
print $atm->center("ATM v. 1.20");
print color('reset');

#Create account message.
my $crt_acc_msg = <<"END_MSG";
\nDear Sir or Madam,\n
We're very happy you've chose us as your bank.
Before we proceed, we need to set-up your account.\n
END_MSG

print $crt_acc_msg;

&acc_create;
&acc_choose;

sub acc_create {
  ACC_BEGINNING:

    #First name:
    print "\nYour first name: ";
    $firstname = <STDIN>;
    chomp $firstname;

    #Last name:
    print "\nYour last name: ";
    $lastname = <STDIN>;
    chomp $lastname;
    if ( defined($firstname) && $firstname ne "" ) {
        if ( defined($lastname) && $lastname ne "" ) {
            goto ACC_PASS;
        }
    }
    else {
        print "You didn't fill in first or last name. Try again. \n";
        goto ACC_BEGINNING;
    }
  ACC_PASS:
    print "Please wait while the system loads.\n\n";

    #sleep(2);
    print $clr_scr;

    print color('green');
    print $atm->center("ATM v. 1.20");
    print color('reset');

    print "\nWelcome ", $firstname, " ", $lastname, "!\n\n";
}

sub acc_choose {

    sub acc_balance {
        print $clr_scr;

        print color('green');
        print $atm->center("ATM v. 1.20");
        print color('reset');

        print "\nYour balance is: ";
        print color('green');
        print $acc_balance;
        print color('reset');
        print " SEK\n\n";
        &acc_choose;
    }

    sub acc_withdraw {

      ENTER_AMOUNT:
        print $clr_scr;

        print color('green');
        print $atm->center("ATM v. 1.20");
        print color('reset');

        print "\nEnter how much you'd like to withdraw: \n";
        my $acc_balance_withdraw = <STDIN>;

        if ( $acc_balance_withdraw > $acc_balance ) {
            print "Insufficient funds.";
            goto ENTER_AMOUNT;
        }
        $acc_balance -= $acc_balance_withdraw;
        print "\nYour current balance is now: ";
        print color('green');
        print $acc_balance;
        print color('reset');
        print " SEK\n\n";
        &acc_choose;
    }

    sub acc_transfer {
      ENTER_AMOUNT:
        print $clr_scr;

        print color('green');
        print $atm->center("ATM v. 1.20");
        print color('reset');

        print "\nEnter how much you'd like to transfer: \n";
        my $acc_balance_withdraw = <STDIN>;

        if ( $acc_balance_withdraw > $acc_balance ) {
            print "Insufficient funds.";
            goto ENTER_AMOUNT;
        }

        print "\nYour current balance is now: ";
        print color('green');
        print $acc_balance - $acc_balance_withdraw;
        print color('reset');
        print " SEK\n\n";
        &acc_choose;
    }
  ACC_CHOOSE:
    print "[ ";
    print color('cyan');
    print "1";
    print color('reset');
    print " ]";
    print "Account Balance\n";
    print "[ ";
    print color('cyan');
    print "2";
    print color('reset');
    print " ]";
    print "Withdraw\n";
    print "[ ";
    print color('cyan');
    print "3";
    print color('reset');
    print " ]";
    print "Transfer\n";
    my $choice1 = <STDIN>;
    chomp $choice1;

    if ( $choice1 == 1 ) {
        &acc_balance;
    }
    elsif ( $choice1 == 2 ) {
        &acc_withdraw;
    }
    elsif ( $choice1 == 3 ) {
        &acc_transfer;
    }
    else {
        print "You entered an invalid option. Try again. \n";
        goto ACC_CHOOSE;
    }
    return ();
}

The problem I face is when I try to return the $acc_balance value to the other subroutines. I've tried to implement return($acc_balance ); underneath the nested subroutines, but that'll just prompt me to end the application. So basically, what I'm trying to do is to update $acc_balance every time I make a withdrawal or transfer (they are both currently the same thing in this code), but whenever I try to do that, it either doesn't update the value or it'll just show the classic "Press any key to continue..." message.

Any help is greatly appreciated! Thanks!


Solution

  • I think you shouldn't be using subroutines for this assignment. But it worries me that someone has told you to use an ampersand & when you call a subroutine and has explained how to use labels and goto. That's inappropriate for a modern computer language and you can do much better

    For instance, here's how I would write your subroutine acc_create

    sub acc_create {
    
        while () {
    
            print "\nYour first name: ";
            chomp (my $firstname = <STDIN>);
    
            print "\nYour last name: ";
            chomp (my $lastname = <STDIN>);
    
            last if $firstname and $lastname;
    
            print "You didn't fill in first or last name. Try again.\n";
        }
    
        print "Please wait while the system loads.\n\n";
    
        print
            $clr_scr,
            color('green'), $atm->center("ATM v. 1.20"), color('reset');
    
        print "\nWelcome $firstname $lastname!\n\n";
    }
    

    There's a lot more I could say, but Stack Overflow isn't the place for a tutorial