A tutorial (for Javascript) I’m doing suggests we write a function like this one:
function sayHello() {
//Some comments explaining the next line
window.alert("Hello");
}
Other than obfuscation are there benefits to writing something like this in real life? If so, what are the benefits?
8
Please pardon my memory if I have this incorrect… Javascript isn’t my preferred implementation language.
There are several reasons why one would want to have a no arg function wrap another function call. While the simple call to window.alert("Hello");
is something that you could imagine just instead calling directly instead of sayHello()
.
But what if there is more to it? You’ve got a dozen places where you want to call sayHello()
and have written window.alert("Hello");
instead. Now you want it to do a window.alert("Hello, it is now " + new Date())
. If you wrapped all those calls as sayHello()
you change it one place. If you didn’t, you change it in a dozen places. This touches on Don’t Repeat Yourself. You do it because you don’t want to have to do it a dozen times in the future.
I worked with an i18n / l10n library in the past that used functions to do client side localization of the text. Consider the sayHello()
function. You could have it print out hola
when the user is localized to a Spanish language. This could look something like:
function sayHello() {
var language = window.navigator.userLanguage || window.navigator.language;
if(language === 'es') { window.alert('Hola'); }
else { window.alert("Hello"); }
}
Though, this isn’t how the library worked. Instead, it had a set of files that looked like:
# English file
greeting = hello
# Spanish file
greeting = hola
And then the library would detect the browser language setting and then create dynamic functions with the appropriate localization as the return value for a no-arguemnt function call based on the appropriate localization file.
I’m not enough of a Javascript coder to say if that is good or bad… just that it was and can be seen as a possible approach.
The point being, wrapping the call to another function in a function of its own is often quite useful and helps with the modularization of the application and may also result in easier to read code.
All that bit aside, you are working from a tutorial. It is necessary to introduce things as simply as possible at the start. Introducing varargs style function calls from the start can result in some very confusing code for a person who is unfamiliar with coding in general. It is much easier to go from no argument, to arguments, to varargs style – with each building on the previous examples and understanding.
1
I think its useful sometimes for hiding implementation.
function sayHello() {
window.alert("Hello");
}
And this gives you the flexibility to change it later
function sayHello() {
console.log("Hello");
}
Other than obfuscation are there benefits to writing something like this in real life? If so, what are the benefits?
-
centralization: although the implementation is a single line long, if it is a line that changes often, you probably prefer to change it in a single place, than wherever sayHello is called.
-
minimizing/hiding of dependencies: your client code no longer needs to know there is a window object, and you may even change the whole implementation without affecting client code at all
-
contract fulfillment: client code may expect a module that has a sayHello function. In this case, even if trivial, then function must be there.
-
consistence of abstraction levels: if client code uses high level operations, it is in your interest to write client code in terms of ‘sayHello, sayBye’ and some other ‘sayXXX’ function(s), instead of window objects. Infact, in client code you may not even want to know there is such a thing as a ‘window’ object.
3
Amazing that not a single other person has mentioned testing.
The particular “wrapped” line that you picked, window.alert('hello')
, is actually a perfect example of this. Anything involving the window
object is really, really painful to test. Multiply that by 1000 times in your application and I guarantee that the developers will eventually give up on testing. On the other hand, it’s pretty easy to just clobber the sayHello
function with a spy and test that it got called.
A more practical example – because really, who actually uses window.alert(...)
in production code? – is checking the system clock. So for example, this would be wrapping DateTime.Now
in .NET, time(...)
in C/C++, or System.currentTimeMillis()
in Java. You really want to wrap those in a dependency that you can inject, because they are not only (almost) impossible to mock/fake, they are read-only and non-deterministic. Any test covering a function or method that makes direct use of the system clock function is extremely likely to suffer from intermittent and/or random failures.
The actual wrapper is a 1-line function – return DateTime.Now
– but that’s all you need in order to take a poorly-designed, non-testable object and make it a clean and testable one. You can substitute a fake clock for the wrapper, and set its time to whatever you want. Problem solved.
As Doval said, this example is probably just trying to introduce you to functions. I’m general, though, it is useful. Especially by specifying some but not all do the arguments, and passing the other ones through, you can make a more case-specific function from a more general function. As a somewhat trivial example, consider a sorting function that takes an array to sort and a comparator function to sort with. By specifying a comparator function that compares by numerical value, I can make a sortByNumericalValue function, and calls to that function are much more clear and concise.
The thinking behind your question seems to be: “Why not just write alert("Hello");
directly? It’s pretty simple.”
The answer is, in part, because you don’t really want to call alert("Hello")
– you just want to say hello.
Or: Why store contacts on your phone, when you can just dial phone numbers? Because you don’t want to remember all those numbers; because dialing numbers is tedious and error-prone; because the number might change, but it’s still the same person at the other end. Because you want to call people, not numbers.
This is what’s understood by terms like abstraction, indirection, “hiding implementation details”, and even “expressive code.”
The same reasoning applies to using constants instead of writing raw values everywhere. You could just write 3.141592...
every time you need π, but thankfully there’s Math.PI
.
We might also look at alert()
itself. Who cares how it constructs and displays that alert dialog? You just want to alert the user. Between you writing alert("Hello")
and the pixels on your screen changing, there’s a deep, deep stack of code and hardware, with each layer telling the next what it wants, and that next layer taking care of details until the deepest possible layer flips some bits in the video memory.
You really don’t want to have to do all that yourself just to say hello.
Programming – well, any task, really – is all about breaking complex problems into manageable chunks. Solving each chunk gives you a building block, and with enough simple building blocks, you can build large things.
It’s algebra.
It’s a good idea to keep calculation of values (expressions) separate from execution of actions (statements). We want precise control over where and when actions will be taken (like displaying messages), but when calculating values we’d rather work at a more abstract level and not have to care about how those values are being calculated.
A function which only calculates a return value, using only the arguments it’s given, is called pure.
A “function” which performs an action is actually a procedure, which has an effect.
Any effects caused during the calculation of a value are called side-effects, and it’s better to avoid them where possible (“I just needed that string, I didn’t know it would hammer the database!”).
To minimise the chance of side-effects, we should avoid sending too much data to our procedures, or putting any calculation in them; if some calculation needs to be performed beforehand, it’s usually better to do it separately in a pure function, then pass only the required result to the procedure. This keeps the purpose of the procedure clear, and reduces the chance that it’ll be re-used by later as part of a calculation (the pure function can be re-used instead).
For the same reason, we should avoid processing results inside a procedure. It’s better to return the result (if any) our our action, and perform any subsequent processing with pure functions.
If we follow these rules, we might end up with a procedure like sayHello
, which doesn’t need any data and doesn’t have a result. Hence the best interface for it is to have no arguments and not return a value. This is preferable to, for example, calling “console.log” in the middle of some calculation.
To reduce the need for effects during calculation, we can have calculations which return procedures; eg. if we need to decide on an action to take, we can have a pure function choose a procedure and return it, rather than executing it directly.
Likewise, to reduce the need for calculation during procedures, we can have procedures take other procedures as parameters (possibly the result of a function); eg. taking an array of procedures and running one after another.
2
I would say it is a combination of the answers given by @MichaelT and @Sleiman Jneidi.
Perhaps there are a number of places in the code where you want to greet the user with a Hello message so you pack that idea in a method. In the method you can translate it or expand on a simple ‘Hello’ by displaying a longer text. Also you might want to use a nice JQuery dialog in place of an alert.
The point is that the implementation is in one place. You just need to change the code in one place. (SayHello() is perhaps a too simple example)
1