I agree that this is premature optimization and for a simpler reason: This use case can't be a hot-path because you always will have a small list and even in the case that it is a hot-path you will end up using a database if the list grows too much, so by that time you won't be using hard-coded variables anyway.
But I'd like to point out (not for you, but anyone reading this) that 'includes' itself time complexity IS linear O(n), as described in the spec (Step 10, tc39.es/ecma262/#sec-array.prototy... ):
Let O be ? ToObject(this value).
2. Let len be ? LengthOfArrayLike(O).
3. If len is 0, return false.
4. Let n be ? ToIntegerOrInfinity(fromIndex).
5. Assert: If fromIndex is undefined, then n is 0.
6. If n is +∞, return false.
7. Else if n is -∞, set n to 0.
8. If n ≥ 0, then
a. Let k be n.
9. Else,
a. Let k be len + n.
b. If k < 0, set k to 0.
10. Repeat, while k < len,
a. Let elementK be ? Get(O, ! ToString(𝔽(k))).
b. If SameValueZero(searchElement, elementK) is true, return true.
c. Set k to k + 1.
11. Return false.
It just happens to be constant in this case because our data initialization: the array is hard-coded, so it is a fixed constant (as you noted in your article), but the algorithm of the method by itself is O(n) in the scope of the algorithm (and because the worst case for the algorithm is not fixed data initialization I would still say that this is O(n) in a wider scope IMO, just in case we change our data initialization in the future which is not that uncommon).
I just wanted to clarify that to avoid any distracted developers reading this to misleadingly think that 'includes' is O(1) because it uses some kind of hash table.
Easy on yourself, easy on the code: All other things being equal, notably code complexity and readability, certain efficient design patterns and coding idioms should just flow naturally from your fingertips and are no harder to write than the pessimized alternatives. This is not premature optimization; it is avoiding gratuitous pessimization.
Early optimization is the root of all evils," Knuth said, but on the other hand, "belated pessimization is the leaf of no good," according to Len Lattanzi.
Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design Patterns Applied", Small Object Allocation, p.77, 2001.
Programmers know the benefit of everything and the tradeoffs of nothing.
V8 is an amazing piece of technology but its heuristics are so complex that the smallest thing can derail JavaScript performance, so it's very inconsistent — at least when compared to languages that are compiled prior to deployment. From that perspective it makes sense to feed it code where is doesn't have to "guess" too much.
Both JavaScript and WebAssembly have the same peak performance. They are equally fast. But it is much easier to stay on the fast path with WebAssembly than it is with JavaScript. Or the other way around. It is way too easy sometimes to unknowingly and unintentionally end up in a slow path in your JavaScript engine than it is in the WebAssembly engine.
And finally in the face of the continued proliferation of low-power / low-end / low-spec / small-core devices it seems foolish to rely on the JIT having access to the necessary CPU cycles to reliably optimize the code in a reasonable amount of time at runtime (perhaps we need profiling transpilers - but establishing representative "real-world" operational profile(s) can be a challenge in itself).
If I had to choose between making my code readable and optimizing for a particular browser's proprietary JS engine, I would always choose the former.
Attitudes like that play right into Apple's hands if you believe that the "state of Safari" reflects a desire to deemphasize the importance and relevance of the web.
Then for a web professional that mindset is equivalent to "sawing off the branch you're sitting on".
There is a difference between "efficient coding idioms" and "premature optimization" and those two should not be confused.
Alex Russell
@slightlylate
@kore_sar Mobile reset everything. Latest update on the state of play here:
And how is giving Safari users an adequate UX playing into Apple's hands? Apple doesn't benefit if you actually poly- and ponyfill Safari's inadequacies as you help to keep the web working. Most iOS user's don't realize that iOS Chrome is just Safari with a paint job so if the web is doing poorly on their flagship device it must be the web's fault, not Apple's.
You've completely lost sight of what matters and have gone off on a tangent.
The issue is the difference between "efficient coding idioms" vs. "premature optimizations".
If your application has to only work over a cooperate intranet with a strictly standardized web browser it's easy to determine what works and what doesn't. Over the public web matters are much more complicated and much less predictable especially when JavaScript is involved. So the blanket
These kinds of performance optimizations don't matter. At all
without consideration of any type of context is entirely inappropriate. For example the iteration mechanism that is consistently performant across the majority of situations is the plain for loop. Does that mean bad things will happen if you prefer array functions? Not likely but context matters. As always — it depends.
The other issue is that current benchmarks don't typically cover memory pressure.
I agree that this is premature optimization and for a simpler reason: This use case can't be a hot-path because you always will have a small list and even in the case that it is a hot-path you will end up using a database if the list grows too much, so by that time you won't be using hard-coded variables anyway.
But I'd like to point out (not for you, but anyone reading this) that 'includes' itself time complexity IS linear O(n), as described in the spec (Step 10, tc39.es/ecma262/#sec-array.prototy... ):
It just happens to be constant in this case because our data initialization: the array is hard-coded, so it is a fixed constant (as you noted in your article), but the algorithm of the method by itself is O(n) in the scope of the algorithm (and because the worst case for the algorithm is not fixed data initialization I would still say that this is O(n) in a wider scope IMO, just in case we change our data initialization in the future which is not that uncommon).
I just wanted to clarify that to avoid any distracted developers reading this to misleadingly think that 'includes' is O(1) because it uses some kind of hash table.
And yeah, this is premature optimization.
Edit. Fix spec link.
Hmm you are correct, people who built these performance metrics aren’t smart. !!
It's also exhausting how often claiming "premature optimization" is used to justify sloppy thinking.
Don’t pessimize prematurely:
Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design Patterns Applied", Small Object Allocation, p.77, 2001.
Stated differently:
Rich Hickey:
V8 is an amazing piece of technology but its heuristics are so complex that the smallest thing can derail JavaScript performance, so it's very inconsistent — at least when compared to languages that are compiled prior to deployment. From that perspective it makes sense to feed it code where is doesn't have to "guess" too much.
WebAssembly for Web Developers (Google I/O ’19):
And finally in the face of the continued proliferation of low-power / low-end / low-spec / small-core devices it seems foolish to rely on the JIT having access to the necessary CPU cycles to reliably optimize the code in a reasonable amount of time at runtime (perhaps we need profiling transpilers - but establishing representative "real-world" operational profile(s) can be a challenge in itself).
Meanwhile the self-improvement industry is pushing for aggregation of marginal gains - which is all about eliminating pessimization.
In the meantime real-life users have to deal with this.
Attitudes like that play right into Apple's hands if you believe that the "state of Safari" reflects a desire to deemphasize the importance and relevance of the web.
Then for a web professional that mindset is equivalent to "sawing off the branch you're sitting on".
There is a difference between "efficient coding idioms" and "premature optimization" and those two should not be confused.
PS: Then again maybe it's Chrome that is the real problem: Breaking the web forward.
Saying it works on Chrome is the web equivalent of "it works on my machine" — and fundamentally fails to recognize the nature of the web — there is no web platform, there’s an immensely varied collection of web platforms so lots of common wisdom from the backend doesn't directly apply.
And how is giving Safari users an adequate UX playing into Apple's hands? Apple doesn't benefit if you actually poly- and ponyfill Safari's inadequacies as you help to keep the web working. Most iOS user's don't realize that iOS Chrome is just Safari with a paint job so if the web is doing poorly on their flagship device it must be the web's fault, not Apple's.
The issue is the difference between "efficient coding idioms" vs. "premature optimizations".
If your application has to only work over a cooperate intranet with a strictly standardized web browser it's easy to determine what works and what doesn't. Over the public web matters are much more complicated and much less predictable especially when JavaScript is involved. So the blanket
without consideration of any type of context is entirely inappropriate. For example the iteration mechanism that is consistently performant across the majority of situations is the plain for loop. Does that mean bad things will happen if you prefer array functions? Not likely but context matters. As always — it depends.
The other issue is that current benchmarks don't typically cover memory pressure.
+1
99% of the times O(1) level optimization is not required. So maintainability of the code should be preferred.