Skip to content

Why Modern Languages Use `fn` and `func`: The Greppability Advantage

Purpose

This post explains why modern programming languages use explicit function keywords like fn and func, and how this design choice makes searching code easier.

The Problem

When I tried to find all function definitions in a C codebase using grep, I ran into this problem:

Terminal window
$ grep -r "calculate" src/
src/calc.c:int calculate(int a, int b) {
src/calc.c: return calculate(a + b);
src/calc.c:// TODO: fix calculate() for negative numbers
src/utils.c:typedef int (*calculate)(int);

I got four matches. But I only wanted the function definition on line 1. The other results were:

  • A function call
  • A comment
  • A function pointer type declaration

This makes code search noisy and frustrating.

Why This Happens

C and C++ have ambiguous function syntax. Look at these examples:

calculator.c
// Function definition
int calculate(int a, int b) {
return a + b;
}
// Variable declaration
int calculate;
// Function call
int result = calculate(3, 4);
// Function pointer
int (*calculate)(int);

The word calculate appears in all four patterns. When you grep for it, you get everything mixed together.

You cannot tell if something is a function definition until you look at the next character or line. This ambiguity makes text-based search tools less useful.

The Modern Solution

Languages like Go and Rust fix this with explicit keywords:

calculator.go
// Function definition
func Calculate(a, b int) int {
return a + b
}
// Function call
result := Calculate(3, 4)
calculator.rs
// Function definition
fn calculate(a: i32, b: i32) -> i32 {
a + b
}
// Function call
let result = calculate(3, 4);

Now you can grep for just function definitions:

Terminal window
# Find all function definitions in Go
$ grep -r "^func " src/
src/calc.go:func Calculate(a, b int) int {
src/calc.go:func main() {
# Find all function definitions in Rust
$ grep -r "^fn " src/
src/calc.rs:fn calculate(a: i32, b: i32) -> i32 {
src/calc.rs:fn main() {

The pattern ^func or ^fn matches only function declarations. It skips calls, comments, and variables.

Why Greppability Matters

You might think: β€œWhy not just use an IDE?”

Here are real scenarios where grep-based search is better:

1. Quick code review on remote servers

Terminal window
$ ssh production-server
$ grep "^func [A-Z]" /app/api/ | head -20
func CreateUser(user User) error {
func UpdateUser(id int, user User) error {
func DeleteUser(id int) error {

I can see all public API functions in seconds without loading the project in an IDE.

2. Counting functions in a file

Terminal window
# Go - easy
$ grep -c "^func " handlers.go
12
# C - inaccurate
$ grep -c "^[a-zA-Z_].*(" handlers.c
47 # Includes if statements, while loops, etc.

The Go count is accurate. The C count includes control flow statements.

3. Finding specific implementation

Terminal window
# Find where CalculateTotal is defined
$ grep -r "^func CalculateTotal" .
src/billing/calculate.go:func CalculateTotal(items []Item) int64 {
# C version returns noise
$ grep -r "CalculateTotal" .
src/billing/calculate.c:int CalculateTotal(Item* items) {
src/billing/calculate.c: total += CalculateItem(&items[i]);
src/main.c: grand = CalculateTotal(all_items);
src/test/test.c: assert(CalculateTotal(test_items) == 100);

When This Helps Most

Terminal-based development

  • SSH sessions on remote servers
  • CI/CD pipelines checking code structure
  • Quick inspection without opening a full IDE
  • Analyzing code without project setup

Learning a new codebase

  • Find all public functions instantly
  • Understand code structure quickly
  • No need to parse the whole project

Simple code analysis tools

  • Generate documentation automatically
  • Count functions per module
  • Find security-related functions
  • Track API changes

Real Examples

Scenario: Finding entry points in a Go project

Terminal window
$ grep "^func [A-Z]" main.go
func HandleRequest(w http.ResponseWriter, r *http.Request) {
func ProcessOrder(order Order) error {
func SendEmail(to string, content string) error {

I see three exported functions at a glance. In C, this would require complex regex or a full parser.

Scenario: Debugging on production

Terminal window
$ ssh production-server
$ grep "^func.*Error" /app/handlers.go
func HandleTimeoutError(err error) {
func HandleDatabaseError(err error) {

I can see all error handling functions in one command.

The Design Philosophy

This is about explicit vs implicit syntax:

ApproachProsCons
C/C++ (implicit)Less typingHarder to grep, more ambiguous
Go/Rust (explicit)Clearer syntax, easier toolsMore typing

The trade-off favors tools and readability over brevity.

Go’s creators chose func specifically to improve code search. Rust chose fn for brevity while keeping the explicit keyword.

Common Grep Patterns

Here are useful patterns for Go and Rust:

Find all functions:

Terminal window
grep -r "^func " . # Go
grep -r "^fn " . # Rust

Find public functions:

Terminal window
grep "^func [A-Z]" . # Go (capitalized names)
grep "^pub fn " . # Rust

Find functions containing specific text:

Terminal window
grep "^func.*Auth" . # Find auth-related functions in Go
grep "^fn.*auth" . # Find auth-related functions in Rust

Count functions per file:

Terminal window
for file in *.go; do echo "$file: $(grep -c "^func" "$file")"; done

Summary

In this post, I explained why modern languages use fn and func keywords. The key point is that explicit function keywords make code search easier and more accurate.

When you grep ^func Calculate in Go, you get only the function definition. In C, you get mixed results including calls, comments, and other declarations.

This design choice helps terminal users, simplifies code analysis tools, and makes learning codebases faster. Even with modern IDEs, explicit keywords remain useful for quick searches and automated tools.

Final Words + More Resources

My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me

Here are also the most important links from this article along with some further resources that will help you in this scope:

Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!

Comments