Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
v3:subroutines [2022/01/21 21:59] – [Shadowing] shawnv3:subroutines [2024/07/30 22:43] (current) – [Overloading] neils
Line 3: Line 3:
 While you can use the [[GOSUB]] command in pair with [[RETURN]] to call parts of code as subroutines, the more sophisticated way of implementing subroutines is using the ''SUB ... END SUB'' block. While you can use the [[GOSUB]] command in pair with [[RETURN]] to call parts of code as subroutines, the more sophisticated way of implementing subroutines is using the ''SUB ... END SUB'' block.
  
-===== Defining subroutines =====+===== Defining Subroutines =====
  
 Subroutines are named routines that accept zero or more arguments. The simplest syntax to define a subroutine is the following: Subroutines are named routines that accept zero or more arguments. The simplest syntax to define a subroutine is the following:
  
-  SUB <rountine_name> (arg1 AS <type>, arg2 AS <type>, ...)+  SUB <rountine_name> ([arg1 AS <type>, arg2 AS <type>, ...])
     <statements>     <statements>
   END SUB   END SUB
  
-It is worth noting that a subroutine does not require argumentsIn this case you still must add the empty parentheses after the routine name, though, like so:+It is worth noting that the argument list is optionalIf you omit the arguments, you still must add the empty parentheses after the routine name, like so:
  
   SUB <routine_name> ()   SUB <routine_name> ()
Line 17: Line 17:
   END SUB   END SUB
  
-===== Calling subroutines =====+===== Calling Subroutines =====
  
 You can use the [[CALL]] keyword to call a subroutine. It behaves similarly to [[GOSUB]] with an important difference: ''CALL'' can pass arguments to the subroutine. Consider the following example: You can use the [[CALL]] keyword to call a subroutine. It behaves similarly to [[GOSUB]] with an important difference: ''CALL'' can pass arguments to the subroutine. Consider the following example:
Line 25: Line 25:
   END SUB   END SUB
      
-  CALL greet("Emily": REM will display: Hello, Emily +  CALL greet("Emily"will display: Hello, Emily 
-  CALL greet("Mark": REM will display: Hello, Mark+  CALL greet("Mark"will display: Hello, Mark
  
 The ''CALL'' command will evaluate the argument list in the parentheses, pass all arguments to the subroutine and then instruct the computer to continue the program at the top of the subroutine. The ''CALL'' command will evaluate the argument list in the parentheses, pass all arguments to the subroutine and then instruct the computer to continue the program at the top of the subroutine.
  
-===== Exiting subroutines =====+===== Exiting Subroutines =====
  
 The subroutine will be exited at the ''END SUB'' statement. If you want to exit a subroutine earlier, use the ''EXIT SUB'' command: The subroutine will be exited at the ''END SUB'' statement. If you want to exit a subroutine earlier, use the ''EXIT SUB'' command:
Line 39: Line 39:
   END SUB   END SUB
   CALL test(-1)   CALL test(-1)
-===== Local and global variables =====+===== Local and Global Variables =====
  
 Variables defined inside a subroutine are local variables, i. e. they are only accessible within that subroutine. Global variables (the ones defined outside subroutines) are visible from within all subroutines. Variables defined inside a subroutine are local variables, i. e. they are only accessible within that subroutine. Global variables (the ones defined outside subroutines) are visible from within all subroutines.
Line 53: Line 53:
 ==== Shadowing ==== ==== Shadowing ====
  
-A local variable may have the same name as a global variable. In such cases the local variable will be used inside the subroutine. Consider the following example:+A local variable may have the same name as a global variable. In such cases the local variable will be used inside the subroutine. This is know as a "shadow variable." Consider the following example:
  
   a = 42   a = 42
Line 64: Line 64:
  
  
-===== Static vs. dynamic =====+===== Static vs. Dynamic =====
  
-At this point it is important to understand how arguments can be passed to a subroutine. XC=BASIC offers two ways:+It is important to understand how arguments may be passed to a subroutine. XC=BASIC offers two methods:
  
-  * //Dynamic// arguments: the arguments are created dynamically in memory. Before the subroutine is called, a new area in memory - a //stack frame// - is allocated and this area holds the passed arguments. The advantage of dynamic memory allocation is that it allows recursive subroutine calls, i. e. the subroutine can call itself without messing up its data. However there is a penalty: dynamic arguments are operated much more slowlier+  * //Dynamic// arguments: the arguments are created dynamically in memory. Before the subroutine is called, a new area in memory - a //stack frame// - is allocatedand this area holds the passed arguments. The advantage of dynamic memory allocation is that it allows recursive subroutine calls, i. e. the subroutine can call itself without harming its data. Howeverthere is a penalty: dynamic arguments operate much slower than static arguments
-  * //Static// arguments: the arguments live in a pre-allocated memory area. When the subroutine is called, the arguments are simply copied to this area. This is way much faster than dynamic frame allocation but it doesn't support recursion.+  * //Static// arguments: the arguments are stored in a pre-allocated memory area. When the subroutine is called, the arguments are simply copied to this area. This is much faster than dynamic frame allocation but it doesn't support recursion.
  
-The default way of passing arguments is //dynamic//. If you'd like to pass arguments statically, append the ''STATIC'' keyword to the subroutine definition:+The default method of passing arguments is //dynamic//. If you'd like to pass arguments statically, append the ''STATIC'' keyword to the subroutine definition:
  
   SUB <subroutine_name> (arg AS <type>) STATIC   SUB <subroutine_name> (arg AS <type>) STATIC
  
 <adm note> <adm note>
-The ''STATIC'' keyword in a subroutine definition not only applies to its arguments but to all its local variables as well.+The ''STATIC'' keyword in a subroutine definition not only applies to the subroutine'arguments but to all its local variables as well.
 </adm> </adm>
  
Line 83: Line 83:
 </adm> </adm>
  
-==== Static variables inside dynamic subroutines ====+==== Static Variables Inside Dynamic Subroutines ====
  
 You can mix static and dynamic behaviour using the ''STATIC'' keyword instead of ''DIM'' to mark local variables static when a subroutine is otherwise dynamic. You can mix static and dynamic behaviour using the ''STATIC'' keyword instead of ''DIM'' to mark local variables static when a subroutine is otherwise dynamic.
Line 93: Line 93:
  
 <adm note> <adm note>
-Static local variables' values are preserved between subroutine calls. Upon entering a subroutine, static local variables have the same value as when the subroutine was last exited.+Static local variables' values are preserved between subroutine calls. Upon entering a subroutine, static local variables have the same value as when the subroutine last exited. They are not overwritten.
 </adm> </adm>
  
-If a subroutine is defined as ''STATIC'', all its local variables will be static, regardless whether you use the ''DIM'' or ''STATIC'' keyword to define them:+If a subroutine is defined as ''STATIC'', all its local variables will be static, regardless of whether you use the ''DIM'' or ''STATIC'' keyword to define them:
  
   SUB test (arg AS INT) STATIC   SUB test (arg AS INT) STATIC
Line 109: Line 109:
 ===== Overloading ===== ===== Overloading =====
  
-When passing arguments to a subroutinethe compiler will match the number of arguments in the ''CALL'' statement to the number of arguments in the subroutine declaration. If the number or arguments do not match, a compile-time error is shown.+Subroutine overloadingcommonly known as method overloading in object-oriented programming languages, refers to the ability to create multiple subroutines with the same name but different parameters. This feature allows a programmer to define different ways to call a subroutine based on the types and number of arguments passed.
  
-If the number of arguments matchthe compiler will compare the passed argument'type to what type the subroutine accepts. If the actual type can be converted to the accepted type, it will be silently converted. If however the types are not convertible (for example the subroutine accepts a numeric argument and you try to pass a string), compilation will fail with an error.+Overloaded subroutines have the same name but differ in the type, number, or both type and number of parameters.
  
-But what if you need subroutines that act differently when different number or type of arguments are passed? This is possible using overloading. A subroutine can have as many variations as you want. In this case the compiler will find the best match among the candidates for a call. For example:+==== Compile-Time Polymorphism ====
  
-  SUB test (AS INTSTATIC +The appropriate subroutine to call is determined at compile-time based on the arguments provided in the call. 
-    PRINT "a is an integer: "; a+ 
 +Consider the following example: 
 + 
 +  SUB PrintMessage(msg AS STRING * 16
 +      PRINT msg
   END SUB   END SUB
      
-  SUB test (AS STRING * 16) OVERLOAD STATIC +  SUB PrintMessage(msg AS STRING * 16, num AS INT) OVERLOAD 
-    PRINT "a is a string: "; a+      PRINT msg; " "; num
   END SUB   END SUB
      
-  CALL test(5+  CALL PrintMessage("Hello, XC=BASIC!"
-  CALL test("hello")+  CALL PrintMessage("The number is", 42)
  
 <adm warning> <adm warning>
-You have to use the ''OVERLOAD'' keyword when defining the second and subsequent overloaded variations of a subroutine. In this case the compiler will know that it'not by a mistake that you are using the same name+You must use the ''OVERLOAD'' keyword when defining the second and subsequent overloaded variations of a subroutine. This tells the compiler that the duplicate subroutine names are intentional overloads and not a programming mistake.
 </adm> </adm>
  
Line 133: Line 137:
 It is possible to overload the built-in XC=BASIC functions in your code, too. It is possible to overload the built-in XC=BASIC functions in your code, too.
 </adm> </adm>
-===== Forward declaration =====+===== Forward Declaration =====
  
 A subroutine can not be called before it was defined. This often makes it hard to organize your code in a clean and readable way. You may want to put subroutines at the end of your code and that's a perfectly valid requirement. A subroutine can not be called before it was defined. This often makes it hard to organize your code in a clean and readable way. You may want to put subroutines at the end of your code and that's a perfectly valid requirement.
  
-This is where forward declaration comes in handy. Forward declaration means that you declare a subroutine's all important properties (or the //header// of the subroutine) beforehands, and leave the actual implementation for later. The following example tries to illustrate this.+This is where forward declaration comes in handy. Forward declaration means that you declare a subroutine's all important properties (or the //header// of the subroutine) beforehand, and leave the actual code implementation for later. Consider the following example:
  
   REM -- the top of the program   REM -- the top of the program
Line 149: Line 153:
  
 <adm warning> <adm warning>
-The implementation must use the same number and type of arguments as the declaration. Overloading is possible though: you can declare overloaded variations of the subroutine and imlement each variation later.+The implementation of the subroutine later in the code must use the same number and type of arguments as the declaration. Overloading is still possiblethough: you may declare overloaded variations of the subroutine and implement each variation later on in the program.
 </adm> </adm>
-===== Subroutine visibility =====+===== Subroutine Visibility =====
  
-Subroutines, as well as variables can also be defined with different visibility levels. XC=BASIC offers two options:+Subroutines, as well as variables, may be defined with different visibility levels. XC=BASIC offers two options:
  
-  * //Global// visibility: the subroutine is callable from within the entire code module where it was defined.+  * //Global// visibility: the subroutine is callable from within the entire code module it was defined (but not outside the code module).
   * //Shared// visibility: the subroutine is callable from within all code modules.   * //Shared// visibility: the subroutine is callable from within all code modules.
  
Line 168: Line 172:
   END SUB   END SUB
  
-This way you make sure it is callable from within other code modules. Read more about [[code_modules|Code Modules here]].+This will ensure the subroutine is callable from within other code modules. Read more about [[code_modules|Code Modules here]].
  
 <- flowcontrol|Previous page ^ subroutines|Subroutines ^ functions|Next page -> <- flowcontrol|Previous page ^ subroutines|Subroutines ^ functions|Next page ->