5 ms·
Clojure's "for" is really a list comprehension function, but Clojure's "doseq" is more or less what you'd expect from a for loop (like Python's anyway or any ot
by dkersten 6y ago
Clojure's "for" is really a list comprehension function, but Clojure's "doseq" is more or less what you'd expect from a for loop (like Python's anyway or any other range-based for).
- didibus 6y agoPython's for isn't a for-loop either, it's a for-each loop also sometimes called a for-in loop. In that sense, neither Python nor Clojure have real for-loops. But Python gets much closer, because Clojure's doseq is similar to its while, it is actually syntax sugar for a recursive loop, and not an imperative loop. While Python's for is an imperative for-each loop, which supports the statements break, continue and return inside it.
- dkersten 6y agodoseq isn’t imperative because it doesn’t support break or continue? That doesn’t make sense.
- didibus 6y agoOh sorry, I meant to say iterative, not imperative. Basically all loops in Clojure are implemented in terms of recursion (loop/recur) and not jumps. Which is why there's no break, continue or return statements. Whatever categories you assign them in, I was more trying to show the differences between Python's for and Clojure's doseq. And also show that neither are your classic for-loop.
- dkersten 6y agoIt is iterative too, though: it iterates through an input sequence. > Whatever categories you assign them in, I was more trying to show the differences Fair enough. I take your overall point, I just don't think that not being a classic for-loop matters so much in practice, certainly not "most of the time" anyway.
- didibus 6y ago> It is iterative too, though: it iterates through an input sequence. I don't think these words have supper formal definitions to be honest. I'm using iterative to contrast it against recursive. So in that respect, Clojure's doseq is recursive. You can also see it as iterating over a sequence and thus say it is iterative, but the way it loops over the sequence is through recursion, which is where doseq differs with Python's for. Maybe it's clearer if I say that doseq is recursive while Python's for isn't and just not mention iterative at all haha. > Fair enough. I take your overall point, I just don't think that not being a classic for-loop matters so much in practice, certainly not "most of the time" anyway. I don't know what you mean by "matter", but with regards to the article I'm discussing I'd say it does. A classic for-loop is prone to easy to make bugs that are well known, such as "off by one errors", and "overflows". So the fact that the language has you use this higher level abstraction for looping over collections can help prevent a certain amount of such errors and thus provide additional program safety. Now I don't know if the further differences between Clojure doseq and Python for would also result in safer code. I guess the question is: is the use of break and continue a common source of defect? And is forcing branching instead a safer alternative? Personally I don't know, I'd say maybe not. That said, Clojure also favours the use of its immutable for or reduce over doseq, and that is arguably much safer, because mutable state inside a for-each loop is also a known source of common defects, like changing the sequence as you loop over it, and especially if concurrency is involved. So that's another relevant practical difference in my mind.
- dkersten 6y ago> So in that respect, Clojure's doseq is recursive. The implementation is recursive, but the user facing interface isn't really. > I don't know what you mean by "matter" I mean that in any real world code, at least any that I've encountered in ten years of Clojure and ~20 of Python, the difference has not impacted any actual code that I've written. Sure, in Python I have seen and used "break" but in Clojure it has never been necessary. > A classic for-loop is prone to... Ok, so you're actually arguing in favour of non-classic for loops? I certainly agree. Even in C++, I try to avoid traditional loops in favour of range-based loops or the standard library abstractions like std::for_each, std::transform etc. I think maybe we're on the same page, I thought you were arguing that the lack of classic for-loops was a deficiency and I was just saying that in Clojure it doesn't actually matter that its loops aren't the classic ones. > Now I don't know if the further differences between Clojure doseq and Python for would also result in safer code. Probably not. I think Clojure does result in safer code, but for other reasons than the differences between doseq/for, as you say yourself. I don't think break is a common source of defect, personally, but I also don't find the lack of break a problem in Clojure: you only use doseq when you need side-effects, why would you need to break/continue? Typically you'll already have filtered the list before calling doseq anyway. > Personally I don't know, I'd say maybe not. I agree, I don't think its a big deal either way. > Clojure also favours the use of its immutable Yes, I think that (at least in my own experience), Clojure tends to be safer and less error prone, but the reasons are not its loops, they're mainly due to its immutable-by-default nature. I think that over all, we are more or less in agreement. But I did overlook that doseq doesn't support break/continue in my original comment, so thanks for pointing that out!