How to explain callbacks in plain english? How are they different from calling one function from another function?
How to explain callbacks in plain English? How are they different from calling one function from another function taking some context from the calling function? How can their power be explained to a novice programmer?
I am going to try to keep this dead simple. A "callback" is any function that is called by another function which takes the first function as a parameter. A lot of the time, a "callback" is a function that is called when something happens. That something can be called an "event" in programmer-speak.
Imagine this scenario: you are expecting a package in a couple of days. The package is a gift for your neighbor. Therefore, once you get the package, you want it brought over to the neighbors. You are out of town, and so you leave instructions for your spouse.
You could tell them to get the package and bring it to the neighbors. If your spouse was as stupid as a computer, they would sit at the door and wait for the package until it came (NOT DOING ANYTHING ELSE) and then once it came they would bring it over to the neighbors. But there's a better way. Tell your spouse that ONCE they receive the package, they should bring it over the neighbors. Then, they can go about life normally UNTIL they receive the package.
In our example, the receiving of the package is the "event" and the bringing it to the neighbors is the "callback". Your spouse "runs" your instructions to bring the package over only when the package arrives. Much better!
This kind of thinking is obvious in daily life, but computers don't have the same kind of common sense. Consider how programmers normally write to a file:
fileObject = open(file)
# now that we have WAITED for the file to open, we can write to it
fileObject.write("We are writing to the file.")
# now we can continue doing the other, totally unrelated things our program does
Here, we WAIT for the file to open, before we write to it. This "blocks" the flow of execution, and our program cannot do any of the other things it might need to do! What if we could do this instead:
# we pass writeToFile (A CALLBACK FUNCTION!) to the open function
fileObject = open(file, writeToFile)
# execution continues flowing -- we don't wait for the file to be opened
# ONCE the file is opened we write to it, but while we wait WE CAN DO OTHER THINGS!
It turns out we do this with some languages and frameworks. It's pretty cool! Check out Node.js to get some real practice with this kind of thinking.
Often an application needs to execute different functions based upon its context/state. For this, we use a variable where we would store the information about the function to be called. According to its need the application will set this variable with the information about function to be called and will call the function using the same variable.
In javascript, the example is below. Here we use method argument as a variable where we store information about function.
function processArray(arr, callback) {
var resultArr = new Array();
for (var i = arr.length-1; i >= 0; i--)
resultArr[i] = callback(arr[i]);
return resultArr;
}
var arr = [1, 2, 3, 4];
var arrReturned = processArray(arr, function(arg) {return arg * -1;});
// arrReturned would be [-1, -2, -3, -4]
How to explain callbacks in plain English?
In plain English, a callback function is like a Worker who "calls back" to his Manager when he has completed a Task.
How are they different from calling one function from another function taking some context from the calling function?
It is true that you are calling a function from another function, but the key is that the callback is treated like an Object, so you can change which Function to call based on the state of the system (like the Strategy Design Pattern).
How can their power be explained to a novice programmer?
The power of callbacks can easily be seen in AJAX-style websites which need to pull data from a server. Downloading the new data may take some time. Without callbacks, your entire User Interface would "freeze up" while downloading the new data, or you would need to refresh the entire page rather than just part of it. With a callback, you can insert a "now loading" image and replace it with the new data once it is loaded.
Some code without a callback:
function grabAndFreeze() {
showNowLoading(true);
var jsondata = getData('http://yourserver.com/data/messages.json');
/* User Interface 'freezes' while getting data */
processData(jsondata);
showNowLoading(false);
do_other_stuff(); // not called until data fully downloaded
}
function processData(jsondata) { // do something with the data
var count = jsondata.results ? jsondata.results.length : 0;
$('#counter_messages').text(['Fetched', count, 'new items'].join(' '));
$('#results_messages').html(jsondata.results || '(no new messages)');
}
With Callback:
Here is an example with a callback, using jQuery's getJSON:
function processDataCB(jsondata) { // callback: update UI with results
showNowLoading(false);
var count = jsondata.results ? jsondata.results.length : 0;
$('#counter_messages').text(['Fetched', count, 'new items'].join(' '));
$('#results_messages').html(jsondata.results || '(no new messages)');
}
function grabAndGo() { // and don't freeze
showNowLoading(true);
$('#results_messages').html(now_loading_image);
$.getJSON("http://yourserver.com/data/messages.json", processDataCB);
/* Call processDataCB when data is downloaded, no frozen User Interface! */
do_other_stuff(); // called immediately
}
With Closure:
Often the callback needs to access state
from the calling function using a closure
, which is like the Worker needing to get information from the Manager before he can complete his Task. To create the closure
, you can inline the function so it sees the data in the calling context:
/* Grab messages, chat users, etc by changing dtable. Run callback cb when done.*/
function grab(dtable, cb) {
if (null == dtable) { dtable = "messages"; }
var uiElem = "_" + dtable;
showNowLoading(true, dtable);
$('#results' + uiElem).html(now_loading_image);
$.getJSON("http://yourserver.com/user/"+dtable+".json", cb || function (jsondata) {
// Using a closure: can "see" dtable argument and uiElem variables above.
var count = jsondata.results ? jsondata.results.length : 0,
counterMsg = ['Fetched', count, 'new', dtable].join(' '),
// no new chatters/messages/etc
defaultResultsMsg = ['(no new ', dtable, ')'].join('');
showNowLoading(false, dtable);
$('#counter' + uiElem).text(counterMsg);
$('#results'+ uiElem).html(jsondata.results || defaultResultsMsg);
});
/* User Interface calls cb when data is downloaded */
do_other_stuff(); // called immediately
}
Usage:
// update results_chatters when chatters.json data is downloaded:
grab("chatters");
// update results_messages when messages.json data is downloaded
grab("messages");
// call myCallback(jsondata) when "history.json" data is loaded:
grab("history", myCallback);
Closure
Finally, here is a definition of closure
from Douglas Crockford:
Functions can be defined inside of other functions. The inner function has access to the vars and parameters of the outer function. If a reference to an inner function survives (for example, as a callback function), the outer function's vars also survive.
See also:
- http://javascript.crockford.com/survey.html
- http://api.jquery.com/jQuery.when/
- http://api.jquery.com/jQuery.getJSON/
- http://github.com/josher19/jQuery-Parse
I'm stunned to see so many intelligent people failing to stress the reality that the word "callback" has come to be used in two inconsistent ways.
Both ways involve the customization of a function by passing additional functionality (a function definition, anonymous or named) to an existing function. ie.
customizableFunc(customFunctionality)
If the custom functionality is simply plugged into the code block, you have customized the function, like so.
customizableFucn(customFunctionality) {
var data = doSomthing();
customFunctionality(data);
...
}
Though this kind of injected functionality is often called a "callback", there is nothing contingent about it. A very obvious example is the forEach method in which a custom function is supplied as an argument to be applied to each element in an array to modify the array.
But this is fundamentally distinct from the use of "callback" functions for asynchronous programming, as in AJAX or node.js or simply in assigning functionality to user interaction events (like mouse clicks). In this case, the whole idea is to wait for a contingent event to occur before executing the custom functionality. This is obvious in the case of user interaction, but is also important in i/o (input/output) processes that can take time, like reading files from disk. This is where the term "callback" makes the most obvious sense. Once an i/o process is started (like asking for a file to be read from disk or a server to return data from an http request) an asynchronous program doesn't wait around for it to finish. It can go ahead with whatever tasks are scheduled next, and only respond with the custom functionality after it has been notified that the read file or http request is completed (or that it failed) and that the data is available to the custom functionality. It's like calling a business on the phone and leaving your "callback" number, so they can call you when someone is available to get back to you. That's better than hanging on the line for who knows how long and not being able to attend to other affairs.
Asynchronous use inherently involves some means of listening for the desired event (e.g, the completion of the i/o process) so that, when it occurs (and only when it occurs) the custom "callback" functionality is executed. In the obvious AJAX example, when the data actually arrives from the server, the "callback" function is triggered to use that data to modify the DOM and therefore redraw the browser window to that extent.
To recap. Some people use the word "callback" to refer to any kind of custom functionality that can be injected into an existing function as an argument. But, at least to me, the most appropriate use of the word is where the injected "callback" function is used asynchronously -- to be executed only upon the occurrence of an event that it is waiting to be notified of.
In non-programmer terms, a callback is a fill-in-the-blank in a program.
A common item on many paper forms is "Person to call in case of emergency". There is a blank line there. You write in someone's name and phone number. If an emergency occurs, then that person gets called.
- Everyone gets the same blank form, but
- Everyone can write a different emergency contact number.
This is key. You do not change the form (the code, usually someone else's). However you can fill in missing pieces of information (your number).
Example 1:
Callbacks are used as customized methods, possibly for adding to/changing a program's behavior. For example, take some C code that performs a function, but does not know how to print output. All it can do is make a string. When it tries to figure out what to do with the string, it sees a blank line. But, the programmer gave you the blank to write your callback in!
In this example, you do not use a pencil to fill in a blank on a sheet of paper, you use the function set_print_callback(the_callback)
.
- The blank variable in the module/code is the blank line,
-
set_print_callback
is the pencil, - and
the_callback
is your information you are filling in.
You've now filled in this blank line in the program. Whenever it needs to print output, it will look at that blank line, and follow the instructions there (i.e. call the function you put there.) Practically, this allows the possibility of printing to screen, to a log file, to a printer, over a network connection, or any combination thereof. You have filled in the blank with what you want to do.
Example 2:
When you get told you need to call an emergency number, you go and read what is written on the paper form, and then call the number you read. If that line is blank nothing will be done.
Gui programming works much the same way. When a button is clicked, the program needs to figure out what to do next. It goes and looks for the callback. This callback happens to be in a blank labeled "Here's what you do when Button1 is clicked"
Most IDEs will automatically fill in the blank for you (write the basic method) when you ask it to (e.g. button1_clicked
). However that blank can have any method you darn well please. You could call the method run_computations
or butter_the_biscuits
as long as you put that callback's name in the proper blank. You could put "555-555-1212" in the emergency number blank. It doesn't make much sense, but it's permissible.
Final note: That blank line that you're filling in with the callback? It can be erased and re-written at will. (whether you should or not is another question, but that is a part of their power)