1

I've created a subroutine named "MENU" with a label named "INIT_MENU" at the top of the subroutine, but when i call this label i got a error : Can't goto subroutine outside a subroutine at program.pl line 15

Here is an example:

sub MENU {INIT_MENU: print "blah blah";}

and here is the line 15:

goto &MENU, INIT_MENU;

Sorry if it is a duplicated question, i searched in all possible places and even in the official site of Perl

Makyen
  • 31,849
  • 12
  • 86
  • 121
  • Doesn't look like there is enough information is available. Try to see if you can create a small example. – kangaroo_cliff Oct 22 '17 at 03:28
  • Here is the [complete source code of the example](https://pastebin.com/UWENBXZp), a simple program. –  Oct 22 '17 at 03:41
  • I'm not sure why you want to do this, you can just remove the block label and call your `MENU().` Unless you know what you are doing (and why), you probably don't ever need to use a `goto` in typical perl code. – xxfelixxx Oct 22 '17 at 04:43
  • i want to call an specific block label in the MENU without making another useless functions... –  Oct 22 '17 at 06:00
  • The "specific block" can't be selected via function parameter ? – ulix Oct 22 '17 at 08:24
  • Perhaps a better idiom to use would be a dispatch table: https://hop.perl.plover.com/book/pdf/02DispatchTables.pdf – xxfelixxx Oct 22 '17 at 10:10
  • 4
    Usually when I see a `goto` in someone's perl code, I think its either genius or madness, but I cannot tell which. – xxfelixxx Oct 22 '17 at 10:11
  • Since when did `goto` take two parameters? – Borodin Oct 22 '17 at 12:52
  • 1
    @xxfelixxx All geniuses are mad anyway. When I see a goto, I think the programmer either doesn't understand the structure of the data or does not know the best representation of the data inside a program. Taking time to figure out what is going on will remove any goto. – shawnhcorey Oct 22 '17 at 12:53
  • 2
    Please don't make more work for others by vandalizing your posts. By posting on the Stack Exchange (SE) network, you've granted a non-revocable right, under the [CC BY-SA 4.0 license](//creativecommons.org/licenses/by-sa/4.0), for SE to distribute the content (i.e. regardless of your future choices). By SE policy, the non-vandalized version is distributed. Thus, any vandalism will be reverted. Please see: [How does deleting work? …](//meta.stackexchange.com/q/5221). If permitted to delete, there's a "delete" button below the post, on the left, but it's only in browsers, not the mobile app. – Makyen Sep 13 '19 at 01:07
  • @Makyen In this particular case, there is an answer, so deleting is probably not possible. Otherwise, I completely agree: Vandalism is not permitted on SO. –  Sep 13 '19 at 01:10
  • 1
    @Chipster The comment is intended to cover both situations where the OP has the capability to delete and those situations where the OP won't be able to delete the post. In this case, the OP won't be able to delete this question due to multiple criteria preventing it. The Q&A I linked in my first comment provides a much more detailed description of what is possible for the Op and the post within the SE system wrt. deleting. – Makyen Sep 13 '19 at 01:23
  • FYI we typically don't delete Q&A that's perceived to be useful by the community (which this evidently is), even if the original poster requests it. – EJoshuaS - Stand with Ukraine Sep 13 '19 at 01:53

1 Answers1

5

The goto expects a single argument, so this code first executes goto &MENU and then after the comma operator it evaluates the constant INIT_MENU in a void context (drawing a warning).

The purpose of goto &NAME is to replace the subroutine in which it is encountered with subroutine NAME; it doesn't make sense calling it outside of a subroutine and this is an error. From perldiag

  • Can't goto subroutine outside a subroutine

(F) The deeply magical "goto subroutine" call can only replace one subroutine call for another. It can't manufacture one out of whole cloth. In general you should be calling it out of only an AUTOLOAD routine anyway. See goto.


A comment on the purpose of this.

A lot has been written on the harmfulness of goto LABEL. Not to mention that INIT_MENU: cannot be found when hidden inside a routine. The upshot is that there are always better ways.

A sampler

  • Call the function and pass the parameter

    MENU(INIT_MENU);
    
    sub MENU {
        my $menu = shift;
        if ($menu eq 'INIT_MENU') { ... }
        ...
    }
    
  • If, for some reason, you want to 'hide' the call to MENU use goto &MENU as intended

    sub top_level {   # pass INIT_MENU to this sub
        ...
        goto &MENU;   # also passes its @_ as it is at this point
    
        # the control doesn't return here; MENU took place of this sub
    }
    

    This altogether replaces top_level() with MENU() and passes on its @_ to it. Then process input in MENU as above (for example) to trigger the chosen block. After this "not even caller will be able to tell that this routine was called first," see goto. Normally unneeded

  • Why even have MENU()? Instead, have menu options in separate subs and their references can be values in a hash where keys are names of options. So you'd have a dispatch table and after the logic (or user choice) selects a menu item its code is run directly

    my %do_menu_item = ( INIT_MENU => sub { code for INIT_MENU }, ... );
    ...
    $do_menu_item{$item_name}->();
    
  • Menu systems tend to grow bigger and more complex with development. It would make sense to adopt OO from start, and then there are yet other approaches for this detail

If you find yourself considering goto it may be time to reconsider (some of) the design.


See for instance this post and this post. It's (even) worse than that in Perl since there are specific constructs (and restrictions) for situations where goto can be argued acceptable, so there is even less room for it. One example is jumping out of nested loops: there are labels in Perl.

zdim
  • 64,580
  • 5
  • 52
  • 81