Skip to content

Rule: Do not use || for defaulting#590

Open
adrienverge wants to merge 1 commit intoairbnb:masterfrom
adrienverge:rule/do-not-use-or-for-defaulting
Open

Rule: Do not use || for defaulting#590
adrienverge wants to merge 1 commit intoairbnb:masterfrom
adrienverge:rule/do-not-use-or-for-defaulting

Conversation

@adrienverge
Copy link
Copy Markdown
Contributor

Defaulting omitted variables using || is like using == instead of ===. If a function's argument is falsy (0, false, null, ''...), it will be defaulted while it shouldn't be.

Example:

// bad
function f(arg, optionalArg, opts = {}) {
    const message = optionalArg || 'not set';  // what if arg === ''?
    const rate = opts.rate || 0.1;             // what if arg === 0.0?
}

// bad
const useUnicode = ENV['USE_UTF8'] || true;    // what if arg === false?

// good
function f(arg, optionalArg = 'not set', opts = {}) {
    const rate = opts.rate !== undefined ? opts.rate : 0.1;
}

// good
const useUnicode = ENV['USE_UTF8'] !== undefined : ENV['USE_UTF8'] || true;

More reading: http://www.codereadability.com/javascript-default-parameters-with-or-operator/

@ljharb
Copy link
Copy Markdown
Collaborator

ljharb commented Nov 24, 2015

It's good to avoid the footgun of a falsy non-undefined value when using || - however, in the case of your example, where "port" needs to be a positive integer, opts.port || 80 is actually more accurate than your "good" example, although nowhere near as precise as it should be.

Separately, is there an eslint rule that would enforce this?

@goatslacker
Copy link
Copy Markdown
Collaborator

Does this rule not handle this case?

@ljharb
Copy link
Copy Markdown
Collaborator

ljharb commented Nov 24, 2015

@goatslacker that talks about reusing function argument names, which deopts in v8 and hurts readability, but this PR seems to be talking about use of || for defaulting any value, even to a new var.

@adrienverge adrienverge force-pushed the rule/do-not-use-or-for-defaulting branch from 1ee18bd to dd90d55 Compare November 24, 2015 22:38
@adrienverge
Copy link
Copy Markdown
Contributor Author

Thanks for feedback @ljharb @goatslacker.

in the case of your example, where "port" needs to be a positive integer, opts.port || 80 is actually more accurate

That's true, port was not a good a example. I've updated it.

Does this rule not handle this case?

Rule 7.7 mentions that using || is a bad practice, but is about the default parameter syntax. The rule I want to add applies to any var in general (including opts arg: opts.optionalKey).

README.md Outdated
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a syntax error

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My bad, sorry. I'm correcting it.

@adrienverge adrienverge force-pushed the rule/do-not-use-or-for-defaulting branch 2 times, most recently from 82aaf0d to 30ec484 Compare November 24, 2015 22:56
Defaulting omitted variables using `||` is like using `==` instead of
`===`. If a function's argument is falsy (`0`, `false`, `null`,
`''`...), it will be defaulted while it shouldn't be.

Example:

```javascript
// bad
function f(arg, optionalArg, opts = {}) {
    const message = optionalArg || 'not set';  // what if arg === ''?
    const rate = opts.rate || 0.1;             // what if arg === 0.0?
}

// bad
const useUnicode = ENV['USE_UTF8'] || true;    // what if arg === false?

// good
function f(arg, optionalArg = 'not set', opts = {}) {
    const rate = opts.rate !== undefined ? opts.rate : 0.1;
}

// good
const useUnicode = ENV['USE_UTF8'] !== undefined : ENV['USE_UTF8'] || true;
```

More reading:
http://www.codereadability.com/javascript-default-parameters-with-or-operator/
@adrienverge adrienverge force-pushed the rule/do-not-use-or-for-defaulting branch from 30ec484 to 81c7c53 Compare November 24, 2015 23:02
@adrienverge
Copy link
Copy Markdown
Contributor Author

Separately, is there an eslint rule that would enforce this?

I did not see any rule like that. It would be hard to enforce, since || is legitimate in certains cases (boolean operations).

@ljharb
Copy link
Copy Markdown
Collaborator

ljharb commented Nov 30, 2015

It seems like an eslint rule could look for assignments where the right hand side contained a ||? There very well may not be an existing rule though.

@justjake
Copy link
Copy Markdown
Collaborator

@ljharb then we have to tell if the values involved in the right-hand side are nullable or something -- it is possible to have this sort of check with Flow or some other null-aware type system but I don't think you could write a heuristic in ESLint that did anything but cause sadness.

eg const shouldRun = isOnline() || (isOffline() && isIsomporphic()) should be allowed

@ljharb
Copy link
Copy Markdown
Collaborator

ljharb commented Nov 30, 2015

@justjake the idea would be to always disallow || in assignments, not just nullable values.

@adrienverge
Copy link
Copy Markdown
Contributor Author

the idea would be to always disallow || in assignments, not just nullable values.

Actually what I proposed was less strict: disallow || for defaulting, i.e. do not use || for non-boolean values.

eg const shouldRun = isOnline() || (isOffline() && isIsomporphic()) should be allowed

I agree.

@ljharb
Copy link
Copy Markdown
Collaborator

ljharb commented Dec 1, 2015

@adrienverge that means there's no way we could enforce a lint rule then, because there's no way to tell at compile time that isOffline, for example, is a boolean.

@adrienverge
Copy link
Copy Markdown
Contributor Author

@ljharb Absolutely. But in my opinion, not being able to enforce it does not mean we shouldn't recommend it.

@jonmarkprice
Copy link
Copy Markdown

#188 generalizes this to include &&.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants