6 ms·
doseq isn’t imperative because it doesn’t support break or continue? That doesn’t make sense.
by dkersten 6y ago
doseq 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!
- didibus 6y agoYup, we're in agreement. My point is actually that using higher level abstractions, such as how Clojure does it, leads to safer code, i.e., less prone to bugs and security vulnerabilities. I also personally think it often yield better readability as well, once you get used to the abstractions. And that, when needed, such as for raw performance, there are still escape hatches if need be. > 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 Definitely immutability is a big one. Though I think depending what you compare it against, the loops help as well. Like languages where the only iteration is through while or for-loop (the kind that takes a condition). Or those that lack higher level declarative constructs like filter, any?, every?, partition, etc. Also, related to immutability, it kind of implies loops must be recursive, cause if you think about what a standard for-loop is: for(i = 0; i < 10; i++) {} If your language doesn't have (or discourages) mutable variables, how does i work?