Popup YouTube Video
Sheerpower Logo

Routine Parameters in Detail


A Detailed Understanding of Routine Parameters

Sheerpower routines can handle up to 32 parameters in total, split into two categories:

  • Up to 16 parameters can be passed into routines.
  • Up to 16 parameters can be returned from routines.

The with clause names the parameters passed into the routine, and the returning clause names the parameters returned from it.

Design Rationale: Why defaulting to dynamic-then-fixed parameters?

  • Low ceremony to start: You can call routines without predeclaring types, which speeds up prototyping and keeps call sites simple.
  • Early, clear failures: After first use establishes the type, mismatches become compile-time errors (not runtime surprises).
  • Optimizable paths: Once the type is known, the runtime is able to treat it as static for faster code paths.
  • Business safety: Prevents subtle data drift (e.g., strings replacing reals) in long-lived large apps.
  • Escape hatch remains: If you need ongoing flexibility, pass an argument explicitly declared as dynamic to keep it open.

Contrasting Methods
  • Always dynamic (e.g., scripting): maximal flexibility, but errors can surface later.
  • Always static (e.g., classical compiled): maximal safety, but verbose upfront.
  • Sheerpower hybrid: start flexible, then lock for safety and speed.


In short, Sheerpower parameters begin flexible but quickly become disciplined — favoring both developer speed and business safety.

Parameter Passing

Parameters Passed into a Routine

By default, all WITH parameters in Sheerpower are passed into a routine by reference and are treated as read-only. This means the routine works directly with the original data, rather than a copy. As a result, parameter passing is highly efficient, no matter how large or complex the data being passed.

Parameter Types and Runtime Flexibility

Dynamic Parameters by Default

Unless explicitly given a type, routine parameters are initially dynamically typed. A dynamic parameter can accept any supported type: STRING, REAL, BOOLEAN, INTEGER, or a custom type. The first time the parameter is used in an expression or operation, the system infers and fixes its type for all subsequent uses within the program. The exception is when the argument passed in was explicitly declared as dynamic; in that case, the parameter remains dynamic across all uses.

Specifying Data-Typed Parameters

To enforce a specific type, declare the type name followed by the parameter names. Types are sticky: once a type appears, it applies to the listed parameter and any that follow until another type is given.

routine do_it with string a, b, c

In this example, a, b, and c are all fixed as STRING parameters.

Quick Summary

  • No type given → parameter is dynamic, and its first use fixes its type (unless the passed-in argument is declared dynamic, in which case it stays dynamic).
  • Type given → declaration is sticky and applies to following parameters until another type keyword appears.

Important:

Bare parameter names are type-flexible, not type-fixed. Once a parameter's type has been determined, it cannot change. If a different type is later passed to the same parameter, Sheerpower will generate a compile-time error:

?? Inconsistent argument types were used. -- Argument "DO_TAXES$AMOUNT": Expected Real, got String

This prevents accidental misuse and ensures program consistency.

Example: Dynamic Parameters

routine display_value with input_data print "Value: "; input_data print "Type: "; typeof$(input_data) print end routine ! Calls with different data types declare dynamic x x = "Hello World" display_value with input_data x ! STRING x = 123.45 display_value with input_data x ! REAL

Type Detection with typeof$()

routine format_output with data, returning formatted_result$ select case between$(typeof$(data), "Dtype:", " ") case "String" formatted_result$ = "Text: " + data case "Real", "Integer" formatted_result$ = "Number: " + str$(data) case else formatted_result$ = "Unknown type: " + typeof$(data) end select end routine

Returning Parameters

By default, values returned from a routine are copied into the named returning parameters. Returning the same string multiple times is optimized internally, so performance remains fast.

Clusters as returning parameters are passed by reference. This lets routines add rows to cluster arrays or update existing fields directly. Any changes made inside the routine are reflected in the original cluster.

For Legacy Code: In older Sheerpower programs, routines sometimes modified with parameters directly. This was allowed back when the default calling method was by value. To preserve this behavior, enable OPTION LEGACY at the top of your program. With this option turned on, all with parameters are passed by value (copied), so they could be changed locally without affecting the caller's original arguments.

OPTION LEGACY also preserves the old omitted-parameter behavior: a call may leave out a parameter that has no default value, and the parameter simply keeps its value from the previous call. (Without the option, such an omission is a compile-time error — see Default Parameter Values below.) Parameters that do have defaults still fill in as usual.

Advantages of Named Parameters

  • Clarity: Parameters clearly document their purpose.
  • Order Independence: They can be passed in any order.
  • Self-documenting Code: Inline documentation reduces comments.
  • Maintainability: Explicit names make refactoring easier.
  • Error Reduction: Reduces risk of mixing up parameters.

Tip: For clarity, use variable names that match the routine's parameter names. This allows you to call the routine with just the variables, in any order, and Sheerpower will automatically match them.


Example of Named Parameter Usage

routine calculate_tax with income, tax_rate, returning tax_amount tax_amount = income * tax_rate end routine calculate_tax with income=50_000, tax_rate=0.2, returning tax_amount result print "Tax Amount: "; result ! Using implied parameter values income = 50_000 tax_rate = 0.2 calculate_tax with income, tax_rate, returning tax_amount print "Tax Amount: "; tax_amount

Routines can also be called without any parameters. This is typical for global routines. Private and scoped routines almost always take parameters.

profit = 1234 tax_rate = 6.5/100 calculate_tax_due with amount profit, rate tax_rate, returning due tax_due print 'Tax due: '; tax_due private routine calculate_tax_due with amount, rate, returning due due = amount * rate end routine

There can be up to 16 parameters in the with clause and up to another 16 in the returning clause. For maintainability, keep the number of parameters small. When large amounts of data must be exchanged, use cluster parameters (see next tutorial).

Performance Benefits of Pass-by-Reference

Research Insight: Industry studies show 15—20% of code defects in languages like C++ are due to parameter handling errors. Sheerpower's design removes this risk by defaulting to pass-by-reference with compile-time safety checks, eliminating the need to choose between reference vs. value behavior.

Passing large data (like a 4 MB file or an entire Bible text) is as fast as passing a single number, because only a reference is passed, not the data itself.

routine analyze_bible_text with bible_content$, returning word_count word_count = elements(bible_content$, " ") end routine

Performance Summary

Sheerpower's parameter model combines the speed of pass-by-reference with compile-time safety, making it ideal for large-scale business applications that demand both performance and reliability.

Simplifying Routine Calls

There are three increasingly concise ways to pass parameters:

! Full syntax calculate_tax_due with amount=myamount, tax_rate=myrate, returning due mydue ! Without "=" calculate_tax_due with amount myamount, tax_rate myrate, returning due mydue ! Implied parameters calculate_tax_due with amount, tax_rate, returning due

All three are equivalent—the last version being the simplest.

Default Parameter Values

There is one more step in concision: a with parameter can declare a default value, and callers simply omit it. Callers that pass the parameter override the default:

routine send_alert with message$, priority$ = "normal" print priority$; ": "; message$ end routine send_alert with message$ "Backup complete" send_alert with message$ "Disk almost full", priority$ "urgent"

The default is an expression, evaluated at every call that omits the parameter — not once when the routine is defined. That means defaults can do real work:

! a module variable is read fresh at every call routine fetch_page with url$, timeout = net_timeout ! a built-in runs per call: every event gets its own timestamp routine log_event with event$, stamp$ = fulltime$ ! a default can even reference an EARLIER parameter: ! omit the width and you get a square routine rec_area with length, width = length, returning area area = length * width end routine print rec_area(length = 10) ! 100 -- square by default print rec_area(length = 10, width = 4) ! 40

Order matters when one parameter's default uses another: declare the parameter being referenced before the parameter that uses it — length first, then width = length. Names in a default expression are resolved left to right, so if a default names a parameter that only appears later in the list, Sheerpower quietly uses the module variable of that name instead. That is not a compile error — just a different value than you meant — so keep referenced parameters on the left.

Defaults work the same whether the routine is called as a statement or as a function:

routine calc_tax with amount, tax_rate = 0.12, returning tax tax = amount * tax_rate end routine calc_tax with amount 200, returning tax due ! due = 24 total = 1000 + calc_tax(amount = 1000) ! 1120, default rate total = 1000 + calc_tax(amount = 1000, tax_rate = 0.5) ! 1500

Parameters Without Defaults Are Required

If a parameter has no default, every call must pass it. Omitting it is a compile-time error, reported at the exact call site:

?? Routine CALC_FEE, Parameter RATE -- was not passed and has no default value

This check protects you from a subtle bug: without it, an omitted parameter would silently keep its value from the previous call. A routine whose parameters all have defaults can be called bare, with no with clause at all.

Rules at a Glance

  • The default may be a literal, a constant, a module variable, a built-in function, or an expression combining them — including an earlier parameter in the same list (the referenced parameter must be declared first). It may not call a routine.
  • Defaults are evaluated only when the parameter is omitted — after the explicitly passed parameters are bound, in declaration order.
  • returning parameters cannot have default values.
  • Override any subset of defaults, in any order — parameters are named, so there is no “trailing parameters only” restriction.

Function Parameters — Passing a Function into a Routine

A routine can take a function as one of its parameters. This lets the code that calls the routine choose which function to use. You write the function keyword and empty parentheses, then call it inside the routine like any other function:

routine apply_number with n, function fn(), returning result result = fn(n) end routine

When you call the routine, you pass the function the same way — the function keyword and the function name with ():

apply_number with n 16, function sqr(), returning result r print r ! 4 (sqr() is a square root, so this is the root of 16)

A String Example

The same idea works for text. This routine uses whatever string function you give it:

routine apply_text with text$, function fn(), returning out$ out$ = fn(text$) end routine word$ = "Hello World" apply_text with text$ word$, function ucase$(), returning out$ shouted$ print shouted$ ! HELLO WORLD

A routine that returns one value can also be called as a function, or with the pipe. So the same routine works in all three ways:

apply_text with text$ word$, function ucase$(), returning out$ a$ ! statement form b$ = apply_text$(text$ = "quiet") ! function form -> QUIET c$ = "loud words" |> apply_text$() ! pipe -> LOUD WORDS

Your Own Functions, Too

The function you pass can be one of your own routines, not just a built-in. It can take one value, or several. This routine takes two values and passes them to whatever function you give it:

routine apply_pair with a, b, function cmp(), returning result result = cmp(a, b) end routine routine difference_of with first, second, returning diff diff = first - second end routine apply_pair with a 30, b 10, function difference_of(), returning result r print r ! 20

You can put function fn() anywhere in the parameter list. Both with a, b, function cmp() and with function cmp(), a, b work. And when you call a routine as a function, the first value may skip its name: apply_pair(30, b = 10) means the same as apply_pair(a = 30, b = 10).

Where This Is Handy

Passing a function lets you write a routine once, then let the code that calls it decide one step. Two everyday examples:

Build a line of output, and let the caller choose how to style the value:

routine show_field with label$, value$, function fmt(), returning line$ line$ = label$ + ": " + fmt(value$) end routine show_field with label$ "name", value$ "sara", function ucase$(), returning line$ ln$ print ln$ ! name: SARA

Or do a fixed calculation, and let the caller choose how to round the result:

routine price_with_tax with amount, function adjust(), returning total total = adjust(amount * 1.08) ! add 8% tax, then adjust end routine price_with_tax with amount 19.99, function ceil(), returning total t print t ! 22 (ceil rounds up)

In both, the routine holds the fixed work — building the line, adding the tax — and the function you pass fills in the one part that changes.

The rules, in short

  • You can pass a built-in function (like sqr(), ucase$(), or trim$()) or one of your own routines. It can take one value or several. Inside the routine you call it the normal way: fn(x), or fn(a, b) for two values.
  • Position does not matter. You can write function fn() first, last, or in the middle of the parameter list.
  • One function per routine. A routine can have only one function parameter, and every call must pass the same function. To use a different function, write a second routine.
(Show/Hide Routine Parameters Takeaways)
Hide Description

    

       


      

Enter or modify the code below, and then click on RUN

Looking for the full power of Sheerpower?
Check out the Sheerpower website. Free to download. Free to use.