09_Expression_Based

No Explicit Return Statements

What are Implicit Returns?

Functions automatically return the last evaluated expression without needing an explicit return statement.

/* Functions return the last expression automatically */
add : x y -> x + y;  /* Automatically returns x + y */
double : x -> x * 2;  /* Automatically returns x * 2 */

Why is This Esoteric?

Most programming languages require explicit return statements. Our language makes them implicit - the last expression is automatically returned.

Basic Examples

/* Simple functions with implicit returns */
add : x y -> x + y;
result : add 5 3;  /* 8 */

/* Single expression functions */
double : x -> x * 2;
increment : x -> x + 1;
square : x -> x * x;

/* All automatically return their last expression */
result1 : double 5;     /* 10 */
result2 : increment 5;  /* 6 */
result3 : square 5;     /* 25 */

Complex Functions

Even complex functions with multiple expressions return the last one:

/* Function with multiple expressions */
complex_function : x -> 
  doubled : x * 2;
  incremented : doubled + 1;
  squared : incremented * incremented;
  squared;  /* This is what gets returned */

result : complex_function 3;
/* Step 1: doubled = 3 * 2 = 6 */
/* Step 2: incremented = 6 + 1 = 7 */
/* Step 3: squared = 7 * 7 = 49 */
/* Result: 49 */

Conditional Returns

Functions with conditional logic return the last expression in the executed branch:

/* Function with conditional logic */
classify_number : x -> 
  when x is
    0 then "zero"
    when x % 2 = 0 then "even"
    when x % 2 = 1 then "odd"
    _ then "unknown";

/* Each branch returns its last expression */
result1 : classify_number 0;   /* "zero" */
result2 : classify_number 4;   /* "even" */
result3 : classify_number 7;   /* "odd" */

Nested Functions

Nested functions also use implicit returns:

/* Nested function definitions */
outer_function : x -> 
  inner_function : y -> y * 2;
  inner_function x;

/* The nested function returns its last expression */
result : outer_function 5;  /* 10 */

Table Operations

Table operations return the last expression:

/* Function that creates and modifies tables */
create_user_profile : name age -> 
  base_profile : {name: name, age: age};
  with_id : t.set base_profile "id" "user_123";
  with_timestamp : t.set with_id "created" "2024-01-01";
  with_timestamp;  /* Returns the final table */

result : create_user_profile "Alice" 30;
/* Result: {name: "Alice", age: 30, id: "user_123", created: "2024-01-01"} */

Function Composition

Implicit returns work seamlessly with function composition:

/* Functions that return functions */
create_multiplier : factor -> 
  multiplier : x -> x * factor;
  multiplier;  /* Returns the multiplier function */

/* Use the returned function */
double : create_multiplier 2;
triple : create_multiplier 3;

result1 : double 5;  /* 10 */
result2 : triple 5;  /* 15 */

Common Patterns

Data Transformation

/* Transform data with implicit returns */
transform_user_data : user -> 
  with_full_name : t.set user "full_name" (user.first_name + " " + user.last_name);
  with_age_group : t.set with_full_name "age_group" (
    when user.age < 18 then "minor"
    when user.age < 65 then "adult"
    _ then "senior"
  );
  with_age_group;  /* Returns the transformed user */

user : {first_name: "Alice", last_name: "Smith", age: 30};
result : transform_user_data user;
/* Result: {first_name: "Alice", last_name: "Smith", age: 30, full_name: "Alice Smith", age_group: "adult"} */

Validation Functions

/* Validation with implicit returns */
validate_user : user -> 
  name_valid : user.name != "";
  age_valid : user.age > 0 && user.age < 120;
  email_valid : user.email.contains "@";
  name_valid && age_valid && email_valid;  /* Returns boolean */

user : {name: "Alice", age: 30, email: "alice@example.com"};
is_valid : validate_user user;  /* true */

Configuration Builders

/* Build configuration with implicit returns */
build_config : base_config environment -> 
  dev_config : when environment is
    "development" then t.merge base_config {debug: true, log_level: "verbose"}
    "production" then t.merge base_config {debug: false, log_level: "error"}
    _ then base_config;
  dev_config;  /* Returns the final config */

base : {timeout: 30, retries: 3};
result : build_config base "development";
/* Result: {timeout: 30, retries: 3, debug: true, log_level: "verbose"} */

When to Use Implicit Returns

Implicit returns work well when:

  • Functions have a single, clear purpose
  • The return value is obvious from the function name
  • Functions are pure (no side effects)
  • Functions are used in composition chains
  • The logic is straightforward

Consider explicit structure when:

  • Functions have complex conditional logic
  • Multiple return paths are confusing
  • Functions perform side effects
  • The return value is not obvious

Key Takeaways

  1. Last expression returned - the last evaluated expression is automatically returned
  2. No return keyword - no explicit return statements needed
  3. Conditional returns - the last expression in the executed branch is returned
  4. Nested functions - nested functions also use implicit returns
  5. Composition friendly - works seamlessly with function composition

Why This Matters

Implicit returns make the language more functional and concise:

  • Concise syntax - less boilerplate code
  • Functional style - emphasizes expressions over statements
  • Composition focus - functions are treated as expressions
  • Mathematical thinking - functions are mathematical mappings
  • Readability - clear flow from input to output

This feature makes the language feel more like mathematical functions than traditional programming procedures! 🚀