This RFC proposes an alternative syntax for single-expression functions using the =
operator instead of curly braces and explicit return
statements.
This syntax provides a concise way to declare simple functions without the overhead of traditional function body syntax.
This RFC introduces a shorthand syntax for functions that consist of a single return statement.
The proposed syntax uses the =
operator to denote that the function directly returns the result of the expression.
Modern codebases typically contain numerous entities, models, forms, data transfer objects (DTOs), and value objects (VOs) with many getter and setter methods. These methods are usually simple one-liners that create significant cognitive overhead with minimal functional value.
Concise syntax makes it easier to associate function names with their return values, reducing mental parsing overhead.
PSR-compliant syntax requires multi-line formatting:
function getName() { return "Name"; }
Even compact syntax contains redundant elements:
function getName() { return "Name"; }
When reading traditional function syntax, developers mentally process:
function getName() { return "Name"; }
The brain performs this parsing:
function
- skip (boilerplate)getName
- identify function purpose()
- note no parameters{
- skip (boilerplate)return
- skip (expected keyword)"Name"
- identify return value;
- skip (boilerplate)}
- skip (boilerplate)Effectively, the brain extracts:
getName() "Name"
This syntax directly represents the mental model: function maps to value, making the code more readable and reducing the cognitive load required to understand simple getter/setter methods.
function functionName(parameters): returnType = expression;
This is functionally equivalent to:
function functionName(parameters): returnType { return expression; }
Basic function:
// Short syntax function getVersion(): int = 1; // Equivalent traditional syntax function getVersion(): int { return 1; }
Function with parameters:
// Short syntax function add(int $a, int $b): int = $a + $b; // Equivalent traditional syntax function add(int $a, int $b): int { return $a + $b; }
Class methods:
class Calculator { // Short syntax public function multiply(int $a, int $b): int = $a * $b; // Equivalent traditional syntax public function divide(int $a, int $b): float { return $a / $b; } }
This proposal deliberately uses =
instead of =>
to avoid confusion with existing arrow function syntax (fn() => expression
). The key differences are:
=
are regular named functions with global scopefn
)function
keyword, not fn
Getter methods:
class User { public function __construct( private string $name, private string $email ) {} public function getName(): string = $this->name; public function getEmail(): string = $this->email; public function getDisplayName(): string = ucfirst($this->name); }
Simple calculations:
function calculateTax(float $amount): float = $amount * 0.18; function isEven(int $number): bool = $number % 2 === 0; function formatCurrency(float $amount): string = '$' . number_format($amount, 2);
Delegation methods:
class Service { public function __construct(private Repository $repo) {} public function findById(int $id): ?Entity = $this->repo->find($id); public function count(): int = $this->repo->count(); }
The implementation is purely lexical—during parsing, the short syntax is transformed into the equivalent traditional syntax before further processing. This ensures:
This change introduces no breaking changes. The proposed syntax would currently result in a parse error, making it safe to implement.
The original Short Functions RFC proposed using =>
, but this creates confusion with arrow functions:
// Confusing - looks like an arrow function function add(int $a, int $b): int => $a + $b; // Clear distinction function add(int $a, int $b): int = $a + $b;
// multiline function handle(string $input): string = func1($input) |> func2(...) |> func3(...) |> func4(...) ; // oneline function handle(string $input): string = func1($input) |> func2(...) |> func3(...) |> func4(...);
class Point { public function __construct(private int $x, private int $y) {} public function withX($x): static => clone($this, ["x" => $x]); public function withY($y): static => clone($this, ["y" => $y]); }
class Point { public function __construct(private int $x, private int $y) {} public function withX($x): static { return clone($this, ["x" => $x]); } public function withY($y): static { return clone($this, ["y" => $y]); } }
fun add(a: Int, b: Int): Int = a + b fun getVersion() = 1 fun isEven(n: Int) = n % 2 == 0
let add a b = a + b let getVersion () = 1 let isPositive x = x > 0
fn add(a: i32, b: i32) -> i32 = a + b; fn get_version() -> i32 = 1; fn add(a: i32, b: i32) -> i32 { a + b }
add :: Int -> Int -> Int add a b = a + b getVersion :: Int getVersion = 1
func add(_ a: Int, _ b: Int) -> Int = a + b func getVersion() -> Int = 1
public int Add(int a, int b) => a + b; public string FullName => $"{FirstName} {LastName}"; public int GetVersion() => 1;
int add(int a, int b) => a + b; String get fullName => '$firstName $lastName';
def add(a, b), do: a + b def get_version, do: 1
const add = (a, b) => a + b; const getVersion = () => 1;
This feature could potentially be extended to:
function
keyword to declare a function – class member