Live data from Hacker News

Code Smells: Iteration

blog.jetbrains.com

81–90 of 95 posts

Re: Code Smells: Iteration

#81
To say that iteration should be "considered a code smell" is not a good thing to do for the programming community.

Present-day CPUs operate on structures by iterating. On a typical high-level programming language, they are at some point done by either (a) iteration or (b) recursion. If the compiler does not do automatic tail call optimization; then (b) recursion can't be made as optimal (in terms of speed and resources) than (a). The latest Java compiler does not perform tail call optimization and probably never will be able to do it. I mention Java because the article is targeted to the Java crowd.

Thus, iteration IS a very important tool for enhancing performance, and real-world (production) systems might have very important performance requirements.

Iteration, in a code, should just be considered... iteration. No kind of smells.

In the past, there was a very important computer scientist called Edsger Dijkstra wrote a paper called "Goto Statement Considered Harmful", GOTO being considered a "code smell": Dijkstra is a very important guy; an unit of measure, the nanoDijkstra, was named in his honor.

However, even afterwards, new programming languages did include a GOTO statement (or some form), because there are special cases when they are needed for higher performance or (believe it or not!) producing more readable code.

Re: Code Smells: Iteration

#82

Earlier quoted context omitted.

Agree. I think we're all Stringly-typed developers. We use strings everywhere. We throw strings across system boundaries at will.

If you're just using objects to represent groupings of strings and encapsulate behavior around converting them back to strings for output at some point, why not just operate on the strings instead of all the serialization / deserialization? Maybe enough of the quick stuff I do isn't enough to warrant more complex data structures, but I get pretty far into a problem with just dicts (in Python) and generally get annoye…

This is one of the major reasons why I love Lisp so much. Serialization problems disappear in homoiconic languages. It eliminates an entire class of issues.

Re: Code Smells: Iteration

#83
post #44

Earlier quoted context omitted.

Agree. I think we're all Stringly-typed developers. We use strings everywhere. We throw strings across system boundaries at will.

"We use strings everywhere." That's bad. "We throw strings across system boundaries at will." That's neither good nor bad, it's just inevitable. The point of not using "strings" is that strings generally do not have the semantics of whatever it is you are really dealing with, because strings are just raw sequences of bytes and are generally too permissive for the specific type. For instance, if you have a URI, that c…

Tight coupling ... or just s-expressions ;)

Re: Code Smells: Iteration

#84
post #13

Earlier quoted context omitted.

It's worse than that. We have met the Enemy and the Enemy is us. Java, as introduced, claimed that nearly everything was an Object. What we got instead was nearly everything is a String. The Real WTF in this code is that all of the important information is passed around as Strings. The iterator and its source hint at this but she fixes the wrong problem. Ever has this been the way with Java. Despite having a statical…

Unix started it.

Linux /proc and /sys were the epicenter

Re: Code Smells: Iteration

#86
post #61

Earlier quoted context omitted.

One reason for this is the tight coupling in developers' minds between what I'd call "types" and "representations" (these terms are very overloaded, so others may use them in different ways). Just because, say, a function name and a string are represented in memory the same way, that doesn't mean they are the same type; in particular there are many strings which aren't function names, and there are many operations (e…

You can go further with the type/representation dichotomy. An obvious example is printing: All of a sudden, you need to convert an object of that type to a representation that can be read. Read by what? Humans? Other code? Both to some extent? The representation is dependent upon both the original type and the intended recipient. (In Lisp, "readable" means "acceptable to the read function, which parses Lisp expressio…

Regarding things like serialising/deserialising, I don't think there's much issue 'philosophically': in the case of Lisp's `read`/`write`, we can spot the ambiguity and deal with it by writing separate functions, for example:

- `serialise`/`deserialise` to produce/consume machine-readable data; must be mutually inverse (which rules out your example of functions).

- `pretty-print` for human consumption; has no inverse.

As a MVP, these could just be wrappers around `read` and `write` (macros would prevent any runtime overhead); the names convey the intended meaning. Later on we could start enforcing some checks, but since Lisp is dynamically typed, we'd have to do runtime tag-checking (e.g. "if type of 'X' is 'function', throw an error"). A static type system/checker would be better.

More generally, each application should be responsible for parsing its input into a domain-specific model, with machine-checked types. A pair of communicating applications may choose to delegate that responsibility to some common library, but they should not assume that their input can be trusted since it's 'coming from that other system'; e.g. they shouldn't pass around a `String` of input as if it were a domain object, and mangle it by pull out particular characters, concatenating things, etc. That `String` should be parsed into its components ASAP, and those should be passed around.

You're right that "apps hungarian" is another possible approach: slightly better than just documentation, but still not manchine-checked. I think the history of apps hungarian degenerating into systems hungarian is another example of this type/representation conflation.

Re: Code Smells: Iteration

#87

Earlier quoted context omitted.

> If you see collection.map(...) you know that each iteration is simply a pure function from original element to transformed element, which is an immense help when reading the code. You'd think so, but I've had colleagues who managed to fuck that up and use map or list comprehension solely for side-effects.

Even Excalibur can be used to mince garlic, and even a supercomputer can be used to play Zork.

Yeah I mean my point is "trust but verify", I love restricted iteration construct, but just because they're being used does not mean they're being used "properly" unless the language ensures it.

Re: Code Smells: Iteration

#88
post #44

Earlier quoted context omitted.

"We use strings everywhere." That's bad. "We throw strings across system boundaries at will." That's neither good nor bad, it's just inevitable. The point of not using "strings" is that strings generally do not have the semantics of whatever it is you are really dealing with, because strings are just raw sequences of bytes and are generally too permissive for the specific type. For instance, if you have a URI, that c…

Tight coupling ... or just s-expressions ;)

S-expressions are irrelevant to my point. S-expressions are just a serialization format; the use of S-expressions does nothing to synchronize semantics between two programs. Labeling a string as a "uri" with an s-expression does nothing to solve the problem I mentioned about mismatched semantics between two programs. In fact, it does nothing to solve (uri "::::::////SUPERINVALID"). Behold the fundamental problem with semantics and why the semantic web has never worked out as its advocates hoped; labeling is the easy part of the problem.

Re: Code Smells: Iteration

#89

Reading this article, I got a bit bothered. I agree with the sentiment: people repeat entirely too much code. There are very few cases where a for-loop is the right thing to write. Using generic methods which can be tested and shipped in isolation is basically always better. But the article seems to imply there are performance concerns in some cases with its talk of using "a data structure". This irked me, because it…

> There are very few cases where a for-loop is the right thing to write. I'm trying to get my head around that, do you mean any for loop is bad or many nested loops?

Indexed loops are just a bad problem waiting to happen. They introduce arithmetic bugs, are the least efficient way to traverse most any data structure but a sequential memory segment, maximize the opportunity for error, and are often harder for compile-time optimizers to work through (since it's harder to prove what they do in situ).

Abstracting away your iteration is important.

Re: Code Smells: Iteration

#90
post #88

Earlier quoted context omitted.

Tight coupling ... or just s-expressions ;)

S-expressions are irrelevant to my point. S-expressions are just a serialization format; the use of S-expressions does nothing to synchronize semantics between two programs. Labeling a string as a "uri" with an s-expression does nothing to solve the problem I mentioned about mismatched semantics between two programs. In fact, it does nothing to solve (uri "::::::////SUPERINVALID"). Behold the fundamental problem with…

S-expressions are much more than a serialization format.
Post reply on HN