Return statements#
Code Example
Runnable Example in Jac and JacLib
# Return Statements
def return_value -> int {
return 42;
}
def return_expression -> int {
x = 10;
return x * 2;
}
def return_none {
print("executing");
return;
}
def no_return {
print("implicit None return");
}
def conditional_return(x: int) -> int {
if x > 0 {
return x;
} else {
return 0;
}
}
def early_return(flag: bool) {
if flag {
return;
}
print("after early return check");
}
def multiple_returns(val: str) -> int {
if val == "high" {
return 100;
} elif val == "medium" {
return 50;
} elif val == "low" {
return 10;
} else {
return 0;
}
}
with entry {
print(return_value());
print(return_expression());
print(return_none());
print(no_return());
print(conditional_return(5));
print(conditional_return(-3));
early_return(True);
early_return(False);
print(multiple_returns("high"));
print(multiple_returns("low"));
print(multiple_returns("unknown"));
}
Jac Grammar Snippet
Description
Return Statements
Return statements exit a function or method and send a value back to the caller. They are fundamental to function-based programming and control flow in Jac.
Returning a Value
Line 4 demonstrates the simplest form: return 42;. This exits the return_value function immediately and sends the integer 42 back to the caller. The function signature on line 3 includes -> int, indicating the function returns an integer type. Line 49 calls this function and prints the returned value.
Returning an Expression
Lines 7-10 show returning a computed value. Line 9 evaluates x * 2 (which is 10 * 2 = 20) and returns the result. The expression is evaluated before the function exits, and the calculated value is sent to the caller. Line 50 demonstrates calling this function.
Return without a Value
Lines 12-15 demonstrate return; with no expression. Line 14 shows the bare return statement, which exits the function and implicitly returns None. This is useful for early exits when you don't need to provide a return value. Line 51 calls this function, which returns None.
Implicit None Return
Lines 17-19 show a function without any return statement. Line 18 executes print, then the function ends, implicitly returning None. Functions without explicit return statements automatically return None when they reach the end. Line 52 demonstrates this behavior.
Conditional Returns
Lines 21-27 show return statements in different conditional branches:
| Condition | Line | Return Value |
|---|---|---|
x > 0 (true) |
23 | Returns x |
x > 0 (false) |
25 | Returns 0 |
Line 53 calls with argument 5 (positive), taking the first branch and returning 5. Line 54 calls with -3 (negative), taking the else branch and returning 0. This pattern ensures all code paths return a value.
Early Return Pattern
Lines 29-34 demonstrate using return for early exit. When flag is True, line 31 executes return; and the function exits immediately, never reaching line 33. When flag is False, the early return is skipped and line 33 executes. Lines 55-56 demonstrate both cases.
graph TD
A[Function entry] --> B{flag == True?}
B -->|Yes| C[return - exit immediately]
B -->|No| D[print statement]
D --> E[Function ends, returns None]
This pattern is valuable for: - Guard clauses validating inputs - Handling special cases before main logic - Avoiding deep nesting in conditionals - Simplifying complex control flow
Multiple Return Paths
Lines 36-46 show a function with multiple return statements across different branches:
| Input | Line | Returns |
|---|---|---|
| "high" | 38 | 100 |
| "medium" | 40 | 50 |
| "low" | 42 | 10 |
| Other | 44 | 0 |
Lines 57-59 demonstrate calling with different arguments, each taking a different return path through the function.
Return Statement Execution
Key behaviors to understand:
- Execution stops immediately at the return statement
- No code after the return in that code path will execute
- The expression is evaluated before exiting
- Return values should match the function's type annotation
- Functions without explicit returns implicitly return None
- Unlike report, return can only execute once per function call
Return Type Annotations
The examples show different return type patterns:
| Line | Function | Return Type | Meaning |
|---|---|---|---|
| 3 | return_value |
-> int |
Returns an integer |
| 7 | return_expression |
-> int |
Returns an integer |
| 12 | return_none |
(none) | No type specified, returns None |
| 17 | no_return |
(none) | No type specified, implicitly returns None |
| 21 | conditional_return |
-> int |
Returns integer from either branch |
| 29 | early_return |
(none) | Returns None |
| 36 | multiple_returns |
-> int |
Returns integer from any branch |
Common Patterns
Return statements enable several important programming patterns demonstrated in this example:
- Value computation (lines 3-5): Calculate and return a result
- Early exit (lines 29-34): Return early from guard clauses
- Branching logic (lines 21-27): Return different values based on conditions
- Multiple exit points (lines 36-46): Handle different cases with appropriate returns
- Explicit None (lines 12-15): Use bare
return;to exit without a value
Complete Example Flow
Lines 48-60 in the entry block call all the example functions in sequence, demonstrating each return pattern: - Simple value return - Expression evaluation return - Explicit None return - Implicit None return - Conditional returns with different arguments - Early return with different flags - Multiple return paths with different inputs