Callbacks in EasyBite
Callbacks let you pass functions as parameters to other functions, enabling deferred execution, event handling, and highly flexible code structures. In this guide, we’ll unpack callbacks step‑by‑step, with clear examples and detailed explanations—even if you’ve never worked with callbacks before!
Table of Contents
Why Callbacks Matter
Callbacks are a cornerstone of modern programming because they let you:
- Decouple logic: Write general-purpose functions that call back to user‑supplied code.
- Handle events: Respond to actions (like button clicks or data arrival) by passing a handler function.
- Control flow: Delay or sequence operations without hard‑coding every step.
With callbacks, you can build libraries and utilities that other parts of your program—or even other developers’ code—can customize by providing their own functions.
Conceptual Overview
A callback is simply a function passed as an argument to another function, which then “calls back” that function at the appropriate time. Think of it like ordering room service: you give the hotel your room number and a callback function (the bell). When your food arrives, they ring the bell to notify you.
Key points:
- A callback is a first‑class function value.
- You pass it just like any other parameter.
- Inside the caller, you invoke it by using its name and parentheses (e.g.,
callback(data)
).
Callback Syntax in EasyBite
Callbacks look like ordinary parameters in EasyBite. Here’s the generic form:
function doSomething(param1, callback)
// inside, call the callback when ready
callback(param1)
end function
callback
is just a parameter name.- You call it with
callback(...)
as if it were a normal function.
You can also give it a default:
function doSomething(param1, callback to defaultHandler)
callback(param1)
end function
If no callback is passed, EasyBite will use defaultHandler
.
Defining and Passing Callbacks
-
Define a callback function just like any other:
function logger(message)
show "[LOG] " + message
end function -
Define a function that accepts it:
function processData(value, callback)
// do some work
set result to value * 2
// notify via callback
callback(result)
end function -
Pass the callback by name (without parentheses):
processData(5, logger)
This passes the
logger
function itself. InsideprocessData
, callingcallback(result)
invokeslogger(result)
.
Example: Simple Callback
A minimal example to illustrate the flow:
function greetUser(name)
show "Hello, " + name + "!"
end function
function welcome(callback, userName)
show "Welcome!"
callback(userName)
end function
// Call 'welcome', passing 'greetUser' as the callback
welcome(greetUser, "Alice")
// Output:
// Welcome!
// Hello, Alice!
welcome
prints “Welcome!” then callsgreetUser("Alice")
.- The callback allows
welcome
to remain generic.
Example: Using Callbacks for Filtering
Build a reusable filter utility that takes a list and a predicate callback (a function returning true/false):
from array import length
function filterList(items, predicate)
declare result
set result to []
set i to 1
repeat while(i <= length(items))
if predicate(items[i])
append result with items[i]
end if
set i to i + 1
end repeat
return result
end function
function isEven(n)
return (n % 2) = 0
end function
set myNumbers to [1, 2, 3, 4, 5]
set evens to filterList(myNumbers, isEven)
show evens // Displays: [2, 4]
filterList
doesn’t care how you decide to filter—it just callspredicate
for each item.- You can pass different predicates (like
isOdd
,isPrime
, etc.) to reusefilterList
.
Example: Simulating Asynchronous Callbacks
Although EasyBite doesn’t have true threads or timers built‑in, you can simulate asynchronous behavior by structuring code with callbacks:
function fetchData(url, callback)
// Simulate a delay (this is conceptual)
delay 2 // wait 2 seconds
set data to "Data from " + url
callback(data)
end function
function displayData(result)
show "Fetched: " + result
end function
// Start fetch, and supply displayData as callback
fetchData("http://api.example.com", displayData)
// After ~2 seconds:
// Fetched: Data from http://api.example.com
- Here,
fetchData
“returns” via callingdisplayData
. - This pattern underlies real-world APIs like event handlers and network requests.
Callbacks with Recursion
You can combine recursion with callbacks for tasks like tree traversal:
from array import length
function traverse(node, visit)
visit(node)
set i to 1
repeat while(i <= length(node.children))
traverse(node.children[i], visit)
set i to i + 1
end repeat
end function
function printNode(n)
show "Node: " + n.name
end function
// Example tree:
declare root
set root to { name: "A", children: [ { name: "B", children: [] }, { name: "C", children: [] } ] }
traverse(root, printNode)
// Output:
// Node: A
// Node: B
// Node: C
traverse
is a recursive function that calls thevisit
callback for each node.
Common Pitfalls
Pitfall | Symptom | Fix |
---|---|---|
Passing a call instead of function | Callback executes immediately | Pass the function name without () : processData(5, logger) |
Forgetting parentheses when calling back | No callback execution or error | Invoke with callback(arg) inside the caller function |
Callback parameter naming collision | Confusing code | Use clear names like onSuccess , onError , visit , predicate |
Not checking callback before calling | Runtime error if nil | Use default or check: if callback <> nil then callback(data) |
Tips & Best Practices
- Name callbacks descriptively:
onComplete
,handleResult
,validateItem
rather than genericcb
. - Provide defaults: Use default arguments for callbacks to avoid nil checks.
- Keep callback signatures consistent: Decide on few parameters (e.g.,
(error, result)
) for event-like callbacks. - Avoid deep nesting: Chain callbacks with care to prevent “callback hell.” Consider breaking logic into named functions.
Conclusion
Callbacks in EasyBite unlock powerful patterns:
- Customization: Let callers plug in their own behavior.
- Reusability: Write utilities (like
filterList
) that work for many cases. - Control flow: Sequence and delay actions elegantly.
Experiment by writing small utilities that accept callbacks—then pass in different functions to see how they shape your program’s behavior. With callbacks mastered, you’ll build more dynamic and maintainable EasyBite code!