21

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?

  • 14
    It's probably just trying to show you how to define your own functions. – Doval Oct 2 '14 at 0:00
  • 4
    I would never write code in such a way to obfuscate it - code is for the programmer to read easily, not the other way around. Use an obfuscater for obfuscation. – rhughes Oct 2 '14 at 5:45
  • 32
    The benefit is that it wraps a function with parameters. This way if you later want to make your app spanish, you only have to change "Hello" to "Ola" in one place. – Pieter B Oct 2 '14 at 6:59
  • 9
    @PieterB actually, "Hola" – rev Oct 2 '14 at 13:43
  • 29
    @PieterB - And if you discover you misspelled "Hola" you only have to fix it in one place. – Daniel R Hicks Oct 2 '14 at 23:48
60

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.

  • 3
    window.alert is also often used as a placeholder during development until a nice modal/popup can be designed/implemented, so, same as the language issue, it can be switched out much more easily. Or if you already have one, a design update a few years down the line might require similar changes. – Izkata Oct 2 '14 at 16:22
34

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");
 }
19

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.

  • I like this answer. Often design is the foremost reason for these functions, especially OO design where you want objects responsible for behaviour to execute functions of other objects with specific behaviour. Imaging your car, more particularly you shifting gears. You shift your gear up by "telling" your stick to shift up. In turn it forwards this call to your gearbox. But in addition it first checks you can shift up from your current position. – Eric Oct 2 '14 at 10:10
  • 3
    The other reasons are good but +1 for mentioning abstraction levels. Using clear abstractions and good function names can make it much easier to read and maintain old code. At the point where sayHello() is called, you're not necessarily concerned with how it's implemented, you just want to understand what is the intention of this line of code. And a function name like sayHello() makes that obvious. – kkrambo Oct 2 '14 at 13:06
  • Also +1 for mentioning abstraction levels: it can happen that the implementation of a function at one abstraction level consists of one call to another function of a lower abstraction level. So what? – Giorgio Oct 3 '14 at 6:49
7

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.

2

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.

2

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.

-1

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.

  • You seem to be advocating against OOP here, where the fundamental principle is "tell, don't ask". Following the advice here is what normally leads to code riddled with useless "getFoo", "setFoo" and "execute" calls. OOP is about combining data and behavior, not separating them. – Aaronaught Oct 4 '14 at 3:26
  • @Aaronaught It's true that I'm against OOP, but I certainly wouldn't recommend setFoo calls, since that implies mutable data. Altering the contents of variables/properties is an effect, which causes all calculations using that data to become impure. I wouldn't recommend execute calls per se, but I would recommend runFoo procedures for executing actions based on their arguments. – Warbo Oct 4 '14 at 21:17
-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)

  • @downvoter(s) - care to share your knowledge with the rest of us. Is my post simply wrong, badly written or what? – paul Oct 6 '14 at 4:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.