Skip to content

Emphasize that every returns true for empty arrays #28975

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from

Conversation

dfabulich
Copy link
Contributor

Description

every returns true for empty arrays. For example, this returns true:

[].every(() => false)
// true

Motivation

This gotcha was mentioned later in the description, but it deserves more emphasis, because many users of every will find this behavior counterintuitive.

This gotcha was mentioned later in the description, but it deserves more emphasis, because many users of `every` will find this behavior counterintuitive.
@dfabulich dfabulich requested a review from a team as a code owner September 6, 2023 23:11
@dfabulich dfabulich requested review from Elchi3 and removed request for a team September 6, 2023 23:11
@github-actions github-actions bot added the Content:JS JavaScript docs label Sep 6, 2023
Copy link
Member

@Josh-Cena Josh-Cena left a comment

Choose a reason for hiding this comment

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

Thanks, but we'd like to keep all caveats in the description, and this information is already entailed by "every array element". We shouldn't make it sound like it's a case to be separately considered.

It's not counterintuitive at all—it is how logic works. You would have to learn it, but without proper learning everything is guesswork :)

@Josh-Cena Josh-Cena closed this Sep 7, 2023
@dfabulich
Copy link
Contributor Author

[].every(()=>false)
// returns true

It's not counterintuitive at all

https://twitter.com/search?q=til%20every%20array%20true

Doing a quick search, half a dozen people disagree with you. What's counterintuitive to one person might be counterintuitive to another.

it is how logic works

every is how the for-all ∀ quantifier works, but that's a counterintuitive fact about that quantifier.

And furthermore, it's not a fact of pure logic how every is implemented. It could have returned a falsey value like null or undefined in that case. The fact that it does a surprising thing should be emphasized, even if it is in agreement with another mathematical construct.

without proper learning everything is guesswork :)

@Josh-Cena This response is not in keeping with the Mozilla Community Participation Guidelines. https://www.mozilla.org/en-US/about/governance/policies/participation/

Be inclusive of everyone in an interaction, respecting and facilitating people’s participation whether they are:

  • Remote (on video or phone)
  • Not native language speakers
  • Coming from a different culture
  • Using pronouns other than “he” or “she”
  • Living in a different time zone
  • Facing other challenges to participate

I filed this PR in good faith. I know what the ∀ quantifier does. All of those folks on Twitter surprised by the behavior of every had "proper learning." Your response here, criticizing someone who disagrees with you as "without proper learning," is actively disrespectful.

And, hey, even if I hadn't taken a college-level course in which I learned how to use logical quantifiers, that's no reason for MDN to be a place where only people with "proper learning" can benefit from the documentation.

You should reopen this PR, but, regardless of whether you agree with that, I really think you should apologize for your comment here.

@Josh-Cena
Copy link
Member

Josh-Cena commented Sep 7, 2023

My point is: "how some people guess how something works" is not the basis of how we should frame our docs. Without proper prior information, everyone will have a different guess at how something might work, and we will eventually populate our docs with various points on how "X doesn't work this way" and "X doesn't work that way". Instead, we document the behavior, as is, and point out some edge cases that may be interesting—which is why we have this special callout in the description. However, I maintain my stance that the "return value" be brief and composed of disjoint cases. If case A is entailed by case B, then we don't document case A as a special case, even if it's "interesting".

The problem with intuition is that few work to explain it. If you invite someone to share their mental model (or share your own) of how they may understand the problem differently, then we can specifically address why that mental model is wrong. For example, for the following statement:

And furthermore, it's not a fact of pure logic how every is implemented. It could have returned a falsey value like null or undefined in that case. The fact that it does a surprising thing should be emphasized, even if it is in agreement with another mathematical construct.

If every() does not special-case length === 0, then by any logical extension it will return true. For examples, here are some possible implementations:

function every(arr, cb) {
  return !arr.some(x => !cb(x));
}

function every(arr, cb) {
  return arr.reduce((acc, x) => acc && x, true);
}

function every(arr, cb) {
  return arr.find((x) => !cb(x)) === undefined; // Assuming the array doesn't contain undefined
}

function every(arr, cb) {
  for (const e of arr) {
    if (!cb(e)) return false;
  }
  return true;
}

If you understand every() using any of the mental models above, you would arrive at [] -> true.

I'm not assuming bad faith for you—I started my comment with an appreciation of your effort. By "proper learning", this means either "understanding of ∀" or "understanding of every()", as either can tell you how every() works. One can receive proper learning through our docs—one goes to the every() page, reads it from top to bottom, and should understand its behavior in every single scenario—if that's not the case, then a PR is welcome; but if we have to mention a single special case (that's not special at all, IMO) multiple times, then it's a waste of readers' time and just makes the docs repetitive overall.

@dfabulich
Copy link
Contributor Author

dfabulich commented Sep 7, 2023

∀ doesn't entail that the set is non-empty, but English terms like "every" and "all" do ambiguously imply that there's at least one (actually, at least two).

https://english.stackexchange.com/questions/23880/does-all-imply-one-or-more

If I told you in English that "everything in my backpack is awesome," and you later discovered that there was nothing in the bag, you'd rightly conclude that I'd played a trick on you, that I'd falsely implied that there was something awesome in the bag.

(Similarly, logicians prefer inclusive "or," but English "or" ambiguously implies exclusive "or," and, when writing in English, we often have to disambiguate.)

The documentation currently says:

true if callbackFn returns a {{Glossary("truthy")}} value for every array element. Otherwise, false.

The English word "every" doesn't logically entail what you want it to. It would in Lojban. It would if we used the for-all quantifier ∀. But MDN is written in English, and "every" customarily (but ambiguously) implies "at least one." MDN is intended to be used by everyone, including people who have never had a course in set theory.

I've provided multiple documented examples of actual people who were surprised by the behavior of every(). This isn't a wild, uneducated misinterpretation of the word "every." This is what most people think the word means.

If every() does not special-case length === 0, then by any logical extension it will return true.

function every(arr, cb) {
  let result = null; // or false, if you like, or undefined
  for (const x of arr) {
    result = cb(x);
    if (!result) return result;
  }
  return result;
}

By "proper learning", this means either "understanding of ∀" or "understanding of every()"

Yes, I understood you completely. I understand both ∀ and every() quite well. And I suppose you'd like me to believe that you weren't making fun of people without "proper learning" ":)"? That's where you crossed the line into a violation of the code of conduct.

MDN is for everyone, not just people who understand ∀.

If you're concerned about repetition, I'd be delighted to remove this paragraph:

every acts like the "for all" quantifier in mathematics. In particular, for an empty array, it returns true. (It is vacuously true that all elements of the empty set satisfy any given condition.)

This paragraph's mathematical jargon obscures more than it reveals. It is only useful to people who think that overeducation is "proper learning." :)

:(

@Josh-Cena
Copy link
Member

Josh-Cena commented Sep 7, 2023

English terms like "every" and "all" do ambiguously imply that there's at least one (actually, at least two).

"Every" and "all" are different. The SE you quoted reasoned "all" as implying "two or more" based o the fact that it's plural, but "every X" is singular.

If I told you in English that "everything in my backpack is awesome," and you later discovered that there was nothing in the bag, you'd rightly conclude that I'd played a trick on you, that I'd falsely implied that there was something awesome in the bag.

Being unsarcastic at all, I would not. On top of that, MDN is written in English but we use English terms to their precise logical and mathematical meaning, not ambiguous daily usage. If we tell you "every array element returns true" and you think it implies that the array is empty, then we've simply missed a case, but due to the knowledge that the return value section is always exhaustive with input cases, you would quickly come to the conclusion that "every" here does not place any presumptions about existence. This conclusion will be further supported by the description. And even if you do believe we've missed a case (for the understandable ambiguity of English), you wouldn't make assumptions about the output and should carry on reading, until we do mention this edge case in the description. There is still no misinformation.

This isn't a wild, uneducated misinterpretation of the word "every." This is what most people think the word means.

The search you shared brought 3 hits to me. I'll admit I've seen non-zero cases like this in the wild as well, but with every person that gets confused there are 5 people that understands in the first place, and in many threads like this, commenters educate the OP how it's actually the most reasonable. People who understand just don't tweet in the first place, so "most" is an overstatement.

I have to clarify again that "proper learning" does not mean a college maths course. A proper logic course can take you very far, for sure, but MDN docs is another source of proper learning. People who have neither are expected to be exposed to one of them in order to testify the effectiveness of the docs. I don't think there's anyone who, having read the doc in its current form, would still not understand how every() works. Those that do not probably haven't been exposed to either. Therefore this change:

  1. Does not add unique information that wasn't included
  2. Points out a special case in an unsuitable place

On which basis I closed because it does not add unique value.

This paragraph's mathematical jargon obscures more than it reveals.

MDN, and many other reference docs (note that you are reading a technical reference, and neither a tutorial nor a guide), often draw parallels to domain knowledge that some readers may be familiar with. Consider, for example, that we show the transformation matrices of CSS transforms. The idea is not to show off or to confuse readers. An experienced reader would learn to skip things they don't understand if they don't hinder further understanding (which is the case here), or to look it up and learn some bonus material. However it's proven helpful for people who do have the prior knowledge of these comparisons, as they can quickly gain a much deeper understanding of how it works.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Content:JS JavaScript docs
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants