Scope/Function names and labels

From Rosetta Code
Scope/Function names and labels is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

The task is to explain or demonstrate the levels of visibility of function names and labels within the language.

For levels of scope relating to visibility of variables see Variables. For scope modification facilities see Scope modifiers.

AWK

In awk function names are always global and can be referenced in sections of code appearing before the definition:

<lang awk># This program outputs a greeting BEGIN {

 sayhello()    # Call the function defined below
 exit

}

function sayhello {
  print "Hello World!"    # Outputs a message to the terminal
}</lang>

Note that the awk extraction and reporting language is data driven and does not support arbitary line labels.

BASIC

Line numbers are used instead of labels. These are also immediately accessible as soon as the line is entered, even if the program is not run:

<lang basic>GOTO 50: REM THIS WILL WORK IMMEDIATELY</lang>

The visibility of functions depends on the implementation. Most versions of basic will allow a function to be referenced from a point in the code prior to its definition. However, other implementations may require the function definition to be run, before it can be used:

<lang basic>10 DEF FN S(A)=A*A 20 PRINT FN S(2): REM THIS WILL WORK 30 PRINT FN C(2): REM CALLING A FUNCTION PRIOR TO DEFINITION MAY NOT WORK 40 GOSUB 9000 50 PRINT FN C(2): REM THIS WILL WORK 60 END 9000 DEF FN C(A)=A*A*A 9999 RETURN</lang>

Perl 6

First a little hand-wavey exposition. The lines are rather blurry in Perl 6 between subroutines, methods, operators and functions. Methods are associated with an object and are inheritable. Subroutines and operators are not. Other than that though there is a lot of overlap. "A function" doesn't really have a specific definition, but is more of a generic term used when talking about code reference type of things.

Methods don't have a separate scope from the object they are attached to. If the object is in scope, the method will be.

A subroutine is really just another type of object. It has a code reference and has ROUTINE semantics attached to it. The same holds for operators. Operators are really just subroutines with a funny calling convention. That being the case, scoping for subroutines very closely follows scoping rules for any other Perl 6 variable type.

In general, subroutines are "my" variables by default (if you don't specify, the "my" is implicit), meaning scoping is lexical to the enclosing block and flows inward. A subroutine defined within a block will be visible to everything inside that block, even other blocks within that block. However, any inner block can define its own subroutine with the same name and that will be used in preference to the routine from an outer block. That implies you can easily override / redefine core functions from the Perl 6 setting. The setting is the collection of built in functions supplied by Perl 6, typically and somewhat incongruously referred to as "CORE" even though technically it is the outermost scope. ( SKIN? BARK? CRUST? ... oooo! EXOSKELETON! :-) )

Alternately, subroutines may be declared as an "our" variable making it a package global, visible anywhere in the packages' namespace. That is somewhat discouraged though as it pollutes the namespace and reduces the granularity of control.

There are several ways to modify the relative scope of a subroutine (any item in the symbol table really) by adding modifiers to the name.

CALLER    # Contextual symbols in the immediate caller's lexical scope
OUTER     # Symbols in the next outer lexical scope
UNIT      # Symbols in the outermost lexical scope of compilation unit
SETTING   # Lexical symbols in the unit's DSL (usually CORE)
PARENT    # Symbols in this package's parent package (or lexical scope)

<lang perl6>

  1. call a routine before it has been defined

say log(); # prints: outer

  1. define a subroutine that overrides a CORE function

sub log { 'outer' }; {

   # redefine the subroutine in this block
   sub log { 'inner' };
   {
       # redefine the subroutine yet again
       sub log { 'way down inside' };
       
       # call it within this block
       say log();                 # prints: way down inside
       
       # call it from the block one level out
       say &OUTER::log();         # prints: inner
       
       # call it from the block two levels out
       say &OUTER::OUTER::log();  # prints: outer
       
       # call it from the outermost block
       say &UNIT::log();          # prints: outer
       
       # call a subroutine that is post declared in outermost scope
       outersub()
   }
   {
       # subroutine in an inner block that doesn't redefine it
       # uses definition from nearest enclosing block
       say log();      # prints: inner
   }
   # call it within this block
   say log();          # prints: inner
   
   # call it from the block one level out
   say &OUTER::log();  # prints: outer

}

sub outersub{

   # call subroutine within this block - gets outer sub
   say log();          # prints: outer
   
   # call subroutine from the scope of the callers block
   say &CALLER::log(); # prints: way down inside
   
   # call subroutine from the outer scope of the callers block
   say &CALLER::OUTER::log(); # prints: inner
   
   # call the original overridden CORE routine
   say &CORE::log(e);  # prints: 1 ( natural log of e )

} </lang>


Labels are less interesting and are typically useful only for control flow in looping constructs. They generally follow the same scoping rules as "my" variables. There is nearly always easier ways to do control flow though, so they aren't heavily used.

REXX

In REXX, labels (which are also the name of in-stream subroutines (or functions) are identified by:

  • (optional blanks)
  • a REXX symbol
  • (optional blanks)
  • a colon   (:)

Labels   (and therefore subroutines/functions/procedures)   are global in scope   (but local to the REXX program) and can be referenced from earlier in the code than than they occur. <lang rexx>/*REXX program demonstrates use of labels and a CALL. */ zz=4 signal do_add ttt=sinD(30) /*this REXX statement is never executed.*/

do_add: /*coming here from the SIGNAL statement.*/

say 'calling the sub add.2.args' call add.2.args 1,7 say 'sum=' result exit /*stick a fork in it, 'cause we're done.*/

add.2.args: procedure; parse arg x,y; return x+y</lang>

ZX Spectrum Basic

Functions are visible as soon as they are entered, even if the program is not run. Line numbers are used instead of labels. These are also immediately accessible as soon as the line is entered, even if the program is not run:

<lang zxbasic>9000 REM The function is immediately visible and usable 9010 DEF FN s(x)=x*x

PRINT FN s(5): REM This will work immediately GOTO 50: REM This will work immediately</lang>