We learned loops back in school. But enumerators and iterators are the next generation.
TL;DR: Don't use indices while iterating. Prefer Higher level collections.
Problems
Encapsulation
Declarativeness
Solutions
Favor foreach() or high order iterators
You will be able to use yield(), caches, proxies, lazy loading and much more when you hide your implementation details.
Sample Code
Wrong
for (i = 0; i < colors.count(), i++) {
print(colors[i]);
}
Right
foreach (color of colors) {
print(color);
}
//Closures and arrow functions
colors.foreach(color => print(color));
Detection
Linters can find this smell using regex.
There might be false positives. See exceptions below.
Exceptions
If the problem domain needs the elements to be bijected to natural numbers like indices, the first solution is adequate.
Remember all time to find real world analogies.
The One and Only Software Design Principle
Maxi Contieri ・ Oct 13 '20
Tags
- Declarative
Conclusion
This kind of smell do not ring the bell to many developers because they think this is a subtlety.
Clean code is full of this few declarative things that can make a difference.
Relations
More info
Credits
Photo by Elena Mozhvilo on Unsplash
If you get tired of writing for loops, take a break and continue later.
David Walker
Software Engineering Great Quotes
Maxi Contieri ・ Dec 28 '20
Original twitter thread by @Matt Moll
This article is part of the CodeSmell Series.
How to Find the Stinky parts of your Code
Maxi Contieri ・ May 21 '21
Last update: 2021/06/13
Top comments (15)
The Right JS code is kind of wrong syntax wise and stuff. This would be the correct code:
Or in this case it could have been simplified even further to:
Nice!
I don't use js and this confused the hell out of me at first sight :) i was expecting color to be an element in colors but it is used as an index? I think I prefer the c++ way
in
is damn confusing.of
notin
.corrected! thank you!
I also prefer to hide explicit iteration. Still, I had to use the first style for chunking.
The second style (
for ... of
) is for awaiting inside, orfor await ... of
.The third style, I generally use
map
because of performance, but grammatically, it would be for each. Also,map(async () => ...)
can be used withPromise.all
(orPromise.allSettled
).In my opinion chinking should be hidden at iteration level.
That is, if a convenient library function exists.
of
with iterators,in
is for string keys of objects (including inherited).for in
andfor of
syntax in js looks likefor (const ident of expression)
(whereconst
could belet
orvar
andof
could bein
))
in the last statementconsole.log
Array
method is calledforEach
(capitalization)so, all in all:
if for some reason you have to use
in
to iterate over values of an object, it's typically done like this (to avoid iterating over inherited keys)however you should prefer the new iterators, such as
Object.keys()
,Object.values()
andObject.entries()
.As such, the above becomes:
Finally, if you see yourself operating on keys of an Object generically like this, you might instead be looking for Map, which naturally iterates by "entries", and supports non-string keys.
See also Set, WeakMap, WeakSet
Wow!
How many detaill!
I will make your corrections
Nevertheless i use many different languages on all my code smells and i like to think them as pseudo code without entering any language details. Your solution is clearly a better one but it is too tied to a particular language.
What other languages do you use?
see my code smells
up to now:
javascript
pyhton
php
golang
java
ruby
Language is accidental
Code smells are not related to any particular language
I write code snippets as examples but I think them most as pseudocode