Javascript – Is it a bad idea to return different data types from a single function in a dynamically typed language

dynamic-typingjavascriptstatic-typing

My primary language is statically typed (Java). In Java, you have to return a single type from every method. For example, you can't have a method that conditionally returns a String or conditionally returns an Integer. But in JavaScript, for example, this is very possible.

In a statically typed language I get why this is a bad idea. If every method returned Object (the common parent all classes inherit from) then you and the compiler have no idea what you're dealing with. You'll have to discover all your mistakes at run time.

But in a dynamically typed language, there may not even be a compiler. In a dynamically typed language, it's not obvious to me why a function that returns multiple types is a bad idea. My background in static languages makes me avoid writing such functions, but I fear I'm being close minded about a feature that could make my code cleaner in ways I can't see.


Edit: I'm going to remove my example (until I can think of a better one). I think it's steering people to reply to a point I am not trying to make.

Best Answer

By contrast to other answers, there are cases where returning different types is acceptable.

Example 1

sum(2, 3) → int
sum(2.1, 3.7) → float

In some statically typed languages, this involves overloads, so we can consider that there several methods, each one returning the predefined, fixed type. In dynamic languages, this may be the same function, implemented as:

var sum = function (a, b) {
    return a + b;
};

Same function, different types of return value.

Example 2

Imagine you get a response from an OpenID/OAuth component. Some OpenID/OAuth providers may contain more information, such as the age of the person.

var user = authProvider.findCurrent();
// user is now:
// {
//     provider: 'Facebook',
//     name: {
//         firstName: 'Hello',
//         secondName: 'World',
//     },
//     email: 'hello.world@example.com',
//     age: 27
// }

Others would have the minimum, would it be an email address or the pseudonym.

var user = authProvider.findCurrent();
// user is now:
// {
//     provider: 'Google',
//     email: 'hello.world@example.com'
// }

Again, same function, different results.

Here, the benefit of returning different types is especially important in a context where you don't care about types and interfaces, but what objects actually contain. For example, let's imagine a website contains mature language. Then the findCurrent() may be used like this:

var user = authProvider.findCurrent();
if (user.age || 0 >= 16) {
    // The person can stand mature language.
    allowShowingContent();
} else if (user.age) {
    // OpenID/OAuth gave the age, but the person appears too young to see the content.
    showParentalAdvisoryRequestedMessage();
} else {
    // OpenID/OAuth won't tell the age of the person. Ask the user himself.
    askForAge();
}

Refactoring this into code where every provider will have its own function which will return a well-defined, fixed type would not only degrade the code base and cause code duplication, but also will not bring any benefit. One may end up doing horrors like:

var age;
if (['Facebook', 'Yahoo', 'Blogger', 'LiveJournal'].contains(user.provider)) {
    age = user.age;
}
Related Topic