29 ms·
What if you couldn’t program with loops?
- sk5t 7y agoSo, I was sort of expecting this article to use recursion instead of a regular loop, but it was not to be, as the author went ahead and used a for-loop anyway and abstracted a bit of logic into a separate function. Silly premise overall.
- csours 7y agoI was hoping for GOTO or JMP
- setr 7y agoReally its the same kind of thing as teaching people to "run the code in their heads" when trying to debug -- an extremely primitive yet necessary skill... but not a utility interesting enough to bother running by HN IMO
- bctnry 7y agoI was hoping for APL/J-style stuff or something like using `map` and `forEach` but no. That's a big letdown.
- necovek 7y agoI would consider those "some kind of loop".
- squiggleblaz 7y agoI was hoping for a massive parallel solution! You just run the same function on a million cores at once, with different inputs. But I think there's a big difference between a language that lets you expect that iteration b will happen after iteration a, vs a language that merely gives you guarantee the result is derived from application of the function onto the necessary inputs. The latter can be correctly parallelised, but the former can only ever be executed in serial. `map f [1,2,3]` (in Haskell) can be solved in parallel or in serial. `[1,2,3].map(f)` (in modern JS) must be executed in serial, since f might be the result of `() => { var j = 0; return (i) => { j += i; return j }}`.
- myhf 7y agoFor some clarification of the "loopless" terminology in J: https://code.jsoftware.com/wiki/Vocabulary/Loopless https://code.jsoftware.com/wiki/Vocabulary/Loopless
- akavi 7y ago`map` is strictly less "powerful" than a "loop", so I'd argue that's misleading. Which I'd also argue is a good thing. Using the least powerful construct available both communicates to future readers of the code, and allows higher level optimization (eg, `map` is trivially parallelizable, an arbitrary loop is not)
- thaumasiotes 7y agoBut `map` is not a primitive. It's just a function implemented with... a loop. It's hard to argue that that doesn't make it "some kind of loop".
- jonathankoren 7y agoI agree. Honestly, I thought he was going to be using Scheme, and maybe derive a for loop by using recursion. But honestly, I hate the misleading title of this post, because it completely misdirects what the post is about, which is just breaking logic up into a functions. Typically, you'd teach this by explaining the concept of functions, rather than focusing on loops, which is completely irrelevant to the proper use of functions.
- deleted 7y ago[deleted]
- hawski 7y agoI was hoping for something about how eBPF verifier does not allow loops.
- deaddodo 7y agoI agree. The correct solution (given javascript as the language of choice) is something along the following lines: let highlightProducts = (products, index = 0) => { if(index >= products.length) { return; } product = products[index]; if(product.name.indexOf('mountain') !== -1) { products[index].highlighted = true; } else if(product.stock > 100 && product.price < 5) { products[index].highlighted = true; } else if(product.category == 'outdoors' && product.price < 35 && product.price > 20) { products[index].highlighted = true; } highlightProducts(products, index+1); } Personally, I think this exercise is completely fruitless except to teach recursion.
- dan-robertson 7y agoI was expecting the answer to look something like: products.forEach((p) => p.highlighted = ( /mountain/.test(p.name) || (p.stock > 100 && p.price < 5) || (p.category == 'outdoors' && 20 < p.price && p.price < 35))) And if one wants the (implicitly hidden) behaviour that highlighted products stay highlighted forever, just add the condition p.highlighted to the disjunction above.
- dhbradshaw 7y agoWant a job? ;-D
- deaddodo 7y agoforEach is a loop, so this doesn't answer the basic question OP presented.
- dan-robertson 7y agoThe standard doesn’t specify whether or not forEach is a “loop” or not. One could implement it using tail recursion. FWIW I would claim that such recursion should also be called a loop, because the control flow goes in a loop.
- 7y ago
- deleted 7y ago[deleted]
- regecks 7y agoThere are real life situations where you must program without loops, and eBPF programs are an example. They also have an program size and various other limitations (http://www.brendangregg.com/ebpf.html#bccprogramming http://www.brendangregg.com/ebpf.html#bccprogramming). When I was writing an ACME (Let's Encrypt) TLS-ALPN client that ran in-kernel with an eBPF tc program, it led to some pretty silly looking code: https://dpaste.de/82aZ https://dpaste.de/82aZ
- lalos 7y agoI could see this as an effective pedagogical tool when learning to program.
- helloiloveyou 7y agoThank you! That's really what this post is about :) Facing the loop's body so many times forces you to analyze if something better can be done
- necovek 7y agoIn real world, factoring out a function that's only ever used once is usually not the smartest thing to do early. You'd do that if you eg. do TDD. The article is a false "tip": author explicitely decides not to extract the entire loop body (why?) into a function but only a part of the logic. They've chosen the factoring approach despite no loop, not thanks to it. Their intrinsic reasoning that led to deciding what to split out would have been more useful, and then we could argue if it was good design tip or not.
- jchw 7y agoI was sort of wondering if the conclusion would be to use map/filter/etc, but instead... it was to use an ordinary loop. I am aware that there is a programming practice for writing “branchless” code. I was expecting this to be more along those lines.
- jonathankoren 7y agoJust because the loop is put in a function, the loop is still there. I would be very disturbed if someone said, "Let's not use a loop!" and then used a normal map(). Now, if they had implemented their own map() that used tail recursion, then we'd have something.
- jchw 7y agoWell, I agree it’s still imperfect. The thing is, though, in JS the fact that map uses a “loop” is an implementation detail; Array.prototype.map is a native function. Since the point of this experiment is to constrain the code to emphasize other details, I can see why it might make sense to limit use of just native JS loop control flow, though it is unclear that using map/filter/forEach/etc. would lead to better code than a simple for loop. (In this case it might be alright, but I do get annoyed when there’s a mess of functional operations going on with complicated transformations that would’ve been really mundane with imperative control flow.)
- exabrial 7y agoWhy not though? Generally our CPUs are based around jumps
- diego 7y agoI'd use functional programming, which is what I'd thought this post would be about. It seems the author is not familiar with the concepts of mapping, reducing and filtering. This is just a map() command.
- Msurrow 7y agoIf you were a programming language designer, would you implement a map, filter or reduce command?
- lagadu 7y agoGod yes. As a .net developer, it's extremely rare for a day to go by where I don't put them to use (via linq). They get so much stuff done.
- diego 7y agoyes, of course. And obviously I would do it with loops, so you don't have to. Ultimately a Turing machine needs to have loops somewhere. The best you can do is abstract them.
- KhoomeiK 7y agoThis is sort of what Microsoft's new/experimental Bosque language is supposed to be about—a paradigm shift to "Regularized Programming", similar to the advent of Structured Programming in the 1960's. Here's the paper: https://www.microsoft.com/en-us/research/uploads/prod/2019/04/beyond_structured_report_v2.pdf https://www.microsoft.com/en-us/research/uploads/prod/2019/0...
- fouc 7y agoIt ends up being a form of mapping. It's a good idea/exercise for developers to engage in occasionally in order to improve their ideas on how to organize their code.
- helloiloveyou 7y agoExactly, thank you! I believe it is a very good exercise for when you are teaching a programming class. Another possible exercise is to not use ifs. The way to navigate around that would be to use double dispatch. Not because of any reason of performance gain with the branch predictor like other comments mentioned, but because it adds another tool to your toolbelt
- glangdale 7y agoA strange emphasis. I imagined old-school GPGPU (only with loops with fixed bounds). Programming without branches of any kind (loop branches or otherwise) is a fun diversion; I've enjoyed it sufficiently to have put my blog at branchfree.org - will be more on branch free programming when my superoptimizer is more mature.
- whatshisface 7y agoEveryone in this comment section was expecting some kind of programming language trickery, but that's not what this post is about. The author is illustrating a refactoring technique.
- Sahhaese 7y agoHalf the people here are discussing the headline not the article because people don't read articles, they read the headline and jump to the comments. In this case it drowns out discussion of the article because the article is terrible. It doesn't start with the code as it would look like with loops, but instead says "Let's pretend you don't have loops" and then refactors the logic which has nothing to do with loops, then puts the loop back in. The same refactoring would be just as clear with loops, and in fact the version without the refactor might be even more clear. A static function which is only called from a single place isn't always more clear than having the logic inside the loop, especially if all that is left from the original function is the loop.
- ssully 7y agoI think calling the article terrible is a little harsh. It's clearly meant for people just starting with programming, and it utilizes a teaching technique that can be very powerful. It isn't meant to teach you how to do things in the best possible way, but to artificially constrain you so that you approach the techniques you know from many different angles to reach a better understanding.
- el_cujo 7y ago>Half the people here are discussing the headline not the article This often happens with articles that have really snappy title. If the title was just "Using refactoring instead of loops" it would probably generate more on topic discussion, but probably less interest overall. I wouldn't go as far as to call this particular title "clickbait", it's at least clickbait-adjacent.
- yjhoney 7y agoI teach a JS coding class and I had the luxury of creating the curriculum. To the horror of my peers, I decided that coding with loops was not necessary for beginners and got rid of loops altogether from our curriculum. I thought OP was proposing the same thing, but I was wrong. the refactoring was good, but my students will probably end up with the following result (more in line with your no loops title): ``` function highlightProducts(aListOfProducts, i=0){ if (i === aListOfProducts.length) return null if(productShouldBeHighlighted(product)){ product.highlighted = true } return highlightProducts(aListOfProducts, i + 1) } ``` The added benefit of the above approach is that debugging is easier! If you want to debug the last 5 items, you can simply call the function like this: highlightProducts(aListOfProducts, aListOfProducts.length – 5) Ultimately, though, everyone should be using higher order functions (map, reduce filter, find, etc.)
- helloiloveyou 7y agoHey! you are the one from the blog comment :) It must be pretty fun to create those curriculums!! I agree with you that the restriction of not using loops can also direct you to apply recursion. However do you believe recursion makes it easier to debug certain parts of the array when you can adjust the starting and stoping points in the guard of the for loop?
- yjhoney 7y agoUltimately, everyone should use higher order functions. In your case (as other commenters have said), map or forEach should have been used. I don't really want to make a statement that recursion makes debugging easier because I don't code like that at work. I use utility functions (map, reduce, filter, etc.)
- BalinKing 7y agoThis seems a bit worrying to me as a general principle, since Javascript's lack of tail call optimization (TCO) means that you can blow the stack pretty easily by manually recursing. Just my two cents :-)
- 7y ago
- patrickhogan1 7y agoThe example calls indexOf instead of calling a loop directly and indexOf uses a loop under the hood. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
- jplayer01 7y agoIs the goal to remove all for loops at all levels of code or to abstract them away to some benefit?
- chaosite 7y agoI don't know! The goal seems to be to restrict yourself for the sake of restricting yourself, as a way to induce creativity. So, hiding the for-loop away in a library function does seem like cheating...
- cozzyd 7y agoKind of like matlab or numpy? (If you don't want it to be super slow).
- molticrystal 7y agoI was thinking it would be an essay on computational completeness and memory or functionality without the ability to loop, which is as fundamental as moving the tape head left or right on a Turing machine. I suppose the title of the article overly encourages what one might interpret it to be about. The upvotes and comments here provide evidence that the article is useful, just not what everybody might be expecting.
- fvilers 7y agoNot that hard, a loop is just an "if" and a "jump" instructions.
- deanCommie 7y agoIt's really hard to teach clean code to beginners. Concepts like SOLID principles feel like meta-academic overkill, and get in the way of "getting things done". Juniors don't click in to the value of well structured well modularized code until they handle the pain of refactoring code that isn't, and introducing unintentional bugs into it. Your only hope, as a senior engineer, who's been through it already, is that they have enough trust in you that when you leave code review feedback that says "It would be more clear and maintainable if you refactor that into a function/make the function return the value instead of mutating it as a side effect/etc etc etc" they trust you, even if they don't yet feel the real value of it) I can't tell if this blog post helps or not. I need to ask one of my juniors.
- stinos 7y agoConcepts like SOLID principles feel like meta-academic overkill, and get in the way of "getting things done". For small programs, certainly. But I've witnessed the effects of not applying any kind of SOLID principle at all to larger scale software and it was never pretty. Your only hope, as a senior engineer, who's been through it already, is that they have enough trust in you that when you leave code review feedback that says "It would be more clear and maintainable if you refactor that into a function/make the function return the value instead of mutating it as a side effect/etc etc etc" they trust you, even if they don't yet feel the real value of it) This sounds kinda pessimistic. Why would you not hope for the best i.e. for a junior understandting what you're saying and most importantly why you're saying it, and why the refactored version is better? I mean, in the end that's what's supposed to happen. And even if that doesn't work out, I'd rather have them questioning my reasoning than just blindly trust me. I'm much more satisfied with a junior showing critical thinking, even if they just don't understand the matter, than just blind trust.
- indigochill 7y agoIn fact, I'd even say blind trust is the "mutate as side effect" of human understanding. It may work in small, isolated incidents, but apply it at scale and everything goes wrong. A junior who learns engineering dogma from his seniors and repeats it without understanding it is a liability, since when his code goes wrong, he won't know why because he doesn't understand the principles at work. So it's the responsibility of the mentor to not settle for blind trust, but ensure his protege does actually understand the principles.
- Agentlien 7y agoThe title of this article reminded me of that one time when I found a small programming app for android with a very limited language. It had some basic variables, if statements and a drawing routine for solid colour circles. It contained no function calls and I don't think it allowed for loops. What it did have was timers which took a piece of callback code and could be set to repeat that code with a given frequency. It was all very simplistic and restricted, so I spent an evening making a breakout clone in it, just to see if I could. That was a lot of frustrating fun.
- dig1 7y agoIn Scheme, the only way to loop is via recursion. In Clojure, all high level functions and looping macros (for/doseq) are implemented via recursion as well (loop/recur). Yes, it requires significant paradigm shift when you start to use these languages, but after a while, you start to appreciate high level functions (map, reduce) instead of language looping constructs (for, while) - they can be easily composed, parallelized, scaled over cluster, refactored... Even code looks much cleaner. You like it even more if you are mathematician, because things looks more "natural" :D
- mratsim 7y agoWhen you need efficient parallel map or reduction you often go back to low-level C loops wrapped in a pretty map/reduce/array package like numpy or R. I'd argue that Einstein Summation like `C[i, j] = A[i, k] * B[k, j]` is much more natural than any composition of map reduce you may use to describe the loops of matrix multiplication.
- dan-robertson 7y agoEinstein summation for matrix multiplication isn’t really a great example because we have a perfectly good way to describe matrix multiplication without loops or sufficies or anything else: C = AB Rate is multiplication (and matrix-vector multiplication) is easy to denote. Tensor multiplication (well really tensor contraction) is annoying to denote and that is the point of summation notation. Notation is easier when there is less to denote: - Matrix multiplication: only one thing you can do (well you can add to but this distributes) - Tensor multiplication: all you can do is add, tensor product, and contract. First two are easy, last one you add extra notation for. This notation can also express permuting indices but this is the same as multiplication by a particular tensor and contraction so ok to do. - map,reduce,fold,etc. These can do quite a lot but not everything (eg processing multiple and in particular different data structures is often annoying. Processing things out of the usual order is often annoying. Processing eg consecutive elements is often annoying). One gets convenience for common things by making it impossible/hard to express uncommon things. If you see something that looks like map(f,x), you know the size of the input is the same as the size of the output and (hopefully) f acts independently on each element. - loops/tail recursion these give you more power to do things so looking at a loop there are many things that could possible happen and one must look carefully to find which.
- ChrisSD 7y agoUse Rust's `const fn`. In its current state you can't do any looping, Nor any other control flow. Fun times. Doing recursion works easily enough but the hard part is stopping.
- alecmg 7y agoJust recently was rminding myself good numpy practices and honestly thought this was also an article about broadcasting and vectorization. Look Ma, No For-Loops: Array Programming With NumPy https://realpython.com/numpy-array-programming/ https://realpython.com/numpy-array-programming/ Which is powerful and enables multicore execution even on notorious Python GIL
- pmlnr 7y agoIf you program in C, try MISRA C and it's requirements/restrictions.
- harimau777 7y agoI primarily program in JavaScript and between Lodash and the built in iterator functions I don't see any reason to use loops other than the while loop. I often use recursion rather than while loops; however, I find that is often difficult to do in a way that is readable and that uses tail recursion. What I really wish is that something like "forUntil", "mapUntil", and "reduceUntil" would be added to the core language. Maybe the forEach, map, and reduce could be made generic functions that operated on any iterable rather than being defined as methods of Array.
- rthomas6 7y agoFunctional programming is the answer. In python the answer is just this: def action(thing) ... map(action, array_of_things) I'm sure there's some similar solution in Javascript.
- rejschaap 7y agoAgreed, that is a much better direction to go. In this particular case you could combine map with filter instead of hiding the filter inside "action"
- doc_gunthrop 7y agoBetter yet just combine map and filter into a list comprehension: def action(thing): ... return [func(x) for x in thing if func2(x)]
- ldd 7y agoyup. const action = (thing) => ... array_of_things.map(action)
- IceDane 7y agoI agree, but I think it's worth pointing out that this abstraction costs more in a language like python. Unless I'm mistaken, I don't believe python has any way to fuse these higher order operations into a single pass.
- fnord123 7y ago[action(x) for x in array_of_things if x > 7] Action is the function you are applying. `for x in ...` will pull an iterator from a generator which could be doing a lot of interesting stuff. And `if x > 7` is the filter.
- raiflip 7y agoI think its a bit of a misnomer to say functional programming is the answer because you can call a function instead of doing a loop, because all you're doing is shifting responsibility to the function you're calling to implement the iteration (which is probably done via tail recursion in FP language). Really the answer to avoiding loops via FP is to use tail recursion, but tail recursion is not always more natural than a loop.
- thb567 7y agoYou could just get the thing going running an external file/script. And stop it with an if condition. It's a classic structure from very noob admins.
- pcstl 7y agoWhile the article is a cute way to introduce the loop body extraction refactoring, I think it is a disservice to talk about not using loops without mentioning recursion. I am quite often shocked at the number of programmers who, even after years of experience, are not able to use recursion properly. (Not saying this is true of the article's author - but they should have mentioned recursion)
- brighter2morrow 7y agoAny languages don't implement tail-call optimizations though which makes using recursion expensive.
- asimpletune 7y agoPretty easy to implement tail recursion though. Sometimes it’s hard to know if a language that automatically compiles to tail recursion will even always do it.
- JD557 7y ago> Sometimes it’s hard to know if a language that automatically compiles to tail recursion will even always do it. I wish more languages that do not always compile to tail recursive methods had something similar to Scala's `@tailrec` annotation (which forces the compilation to fail if the tail calls cannot be optimized). It's not a very elegant solution, but at least it works.
- 0xcde4c3db 7y agoI even convinced a C++ compiler (don't recall whether it was g++ or clang++; it might have been during a FreeBSD fling) to do TCO at one point, but I don't remember exactly how I did it and don't think the requirements are documented anywhere. It probably involved functions declared "static" (i.e. internal linkage) and with the same signature.
- dleslie 7y ago
- leshow 7y agoI really thought the blog post would end with recursion, and found no mention of it anywhere.
- zadkey 7y agoI think you would just use recursion to implement loops.
- lincpa 7y agoIn the pure function pipeline data flow, no loop is required. I wrote a 100k lines of pure clojure language project, no loop is used, and tail recursion is only used once. Most of them use high-order functions for dataflow processing or data driving. [The Pure Function Pipeline Data Flow](https://github.com/linpengcheng/PurefunctionPipelineDataflow https://github.com/linpengcheng/PurefunctionPipelineDataflow)
- fnord123 7y agoSee also: http://reactivex.io/ http://reactivex.io/
- lincpa 7y agoI read the documentation on the URL you provided, and the pure function pipeline data flow is essentially different from Rx: 1. The essential difference between programming methods is the inherent thoughts and models. The idea and model of pure function pipeline data flow are highly consistent with integrated circuits. 2. The pure function pipeline data flow emphasizes the data flow, Rx emphasizes the asynchronous event flow, and does not mention or emphasize the data flow. 3. The pure function pipeline data stream is composed of only 5 components, and the model is much simpler than Rx. 4. Pure function pipeline data flow emphasizes the sequential structure (series of pipeline components), and the maintenance (code reading, expansion, debugging, etc.) is simpler. 5. The asynchronous event flow of the pure function pipeline data flow is simpler than Rx. I wrote an asynchronous event flow in my project, it is just a queue processing, so it is not necessary to specifically mention it. 6.The clojure language doesn't require Rx at all.
- fnord123 7y agoThanks for summarizing the differences. I think anyone interested in function pipeline data flows will also be interested to know about Rx and RxClojure as they both allow programs to be structured to work over a stream of data in many other languages as is available in Rx.
- deleted 7y ago[deleted]
- taffer 7y agoSince no one has mentioned SQL yet: SELECT * FROM products WHERE (stock > 100 AND price < 5) OR (price BETWEEN 20 AND 35 AND category = 'outdoors') OR name ILIKE '%mountain%';
- vincent-toups 7y agoNo stinking loops link: http://nsl.com/ http://nsl.com/
- cr0sh 7y agoIIRC, Mel, The Real Programmer, didn't need loops... https://news.ycombinator.com/item?id=9913835 https://news.ycombinator.com/item?id=9913835 --- I'm going to expand on this - the author of the article doesn't mention a couple of things that you can do if you don't use loops, or don't have them for some reason, but it is understandable that it wasn't mentioned - because the author is working in javascript, not in something lower level. However, that may change with WASM coming into its own; depending on if anyone takes the challenge up of hand coding WASM (that actually isn't an "if" - I am certain people are doing it as I type this). Those two commonly known (well, used to be - less so today, maybe, outside of embedded programmers of 8 and 16 bit controllers - and the retro and demo scene) methods: 1. Self-modifying code 2. Overflows Number 2 could be seen as a subset of number 1, depending on how an overflow is exploited. It's been decades since I've played with either of them - and really only at a "toy" level, but they were common techniques for those well versed in assembler (for whatever processor or architecture), as they could be used to write both more efficient and smaller code for a given routine. Especially in the old 8-bit realm and before, when memory was precious and expensive, and not very large, such techniques could allow for more functionality than what might seemingly fit into memory space available. They were used for everything, particular games on 8-bit machines, as well as more mundane software. The downside is that the code created was often very "opaque" in the sense that you really had to understand how potentially the whole system was working in order to understand how the technique worked and was being used in context. This worked to the advantage of some developers - namely those writing old-school viruses/trojans/malware - as the ability to have self-modifying code meant they could easily hide themselves from a malware detector, and do other nefarious (and honest, sometimes quite interesting) techniques. It's less a thing today, but back in the day, there were some amazing bits of code floating around that scene. The guy who wrote about Mel understood all this - or came to understand it - very well. Mel did it mainly because he didn't trust compilers to make fast code (which they probably didn't back in his day - even today, there are edge cases that fall thru the cracks - it's just code, it can't do everything - yet) - so he hand coded everything; he also had the advantage that he knew precisely how the system worked, especially the drum memory of that system, and by precisely timing things, and deft use (abuse?) of certain registers - well, he was able to do seemingly wizard-like tasks. I can't say he didn't use any loops - he did in fact use one; it looked like an endless loop with nothing inside it; in fact, it should just cause the machine to hang. But the author of Mel's story found that the machine, stepping through the code, would pass right thru this seemingly endless loop. Well - he explains how Mel did it, and it really is a thing of wonder, combining both register manipulation, overflow techniques, and self-modifying code to the utmost. Read the story to find out more (Mel - as far as can be determined, was likely a real person; there is a picture of him out there that was dug up. No one knows for certain whether that Mel is The Mel - but most believe the person depicted probably is). Also google around on such techniques to learn how they work; you likely won't be able to apply them to your day-to-day (unless you work in assembler or something like that), but you might learn something useful for your toolbag. Oh - one other thing - I kinda lied about how these tricks can only apply to a low-level; that's not completely true. There are certain techniques that can be done with higher level languages (and not using exploitable bugs). I won't go into detail here, though. Maybe you can work it out on your own?
- Mugwort 7y agoI have a much harder time reasoning with loops than using map, reduce, recursion etc. I'll just say the whole truth, I can't program with loops, I get a headache and I'm forced to quit.
- cr0sh 7y agoAs an alternative, what if you didn't have (or didn't want to use) common structured programming techniques, and you wanted to implement a state machine? Like, you could use if-then, but not while, loop, do, etc? But goto was allowed (argh?). About a decade ago I was in a discussion with someone on this, and his technique changed my mind on where, when, and how goto could be acceptable in a real code base; some of you may or may not agree - but I thought I would show you, warts (on my part) and all. Here's the thread: https://www.electro-tech-online.com/threads/state-machine-in-mcu.113718/ https://www.electro-tech-online.com/threads/state-machine-in... ...also, here's the state machine (as implemented in C); the original post of the image on the forum, I think, requires a login to see, thus this copy: http://i.imgur.com/JkND1Av.png http://i.imgur.com/JkND1Av.png Read the thread to understand the arguments for and against, but it ultimately (I think) comes down to implementation readability and maintainability. This is a more critical thing in an embedded hardware system, of course, but I think similar techniques, or at least the mindset behind them, could be an advantage. It's kinda like how learning Golang, much later, forced me to rethink the idea of error handling. In Go, there's the concept of using "guard statements" at the top of functions/methods to essentially exit out as soon as possible if something untoward occurs or is passed as an argument incorrectly. Basically a bunch of simple if-then statements at the beginning, then your code proper. It was one of those things I recall as being something I railed against at first, but I quickly came to understand the reasoning behind doing it that way, rather than nested if-then statements or other constructs within the logic. It produced simpler, easier to follow code - but at first, it felt very "wrong" to me for some reason. It was one of many "golang-isms" I had to come to terms with, before I really appreciated the whys and whats of the language. Which ultimately is what these techniques are all about - the author touches upon this: Restriction of your toolset can lead to fascinating solutions, and in some or many cases, this simplification is reflected in the code as well; things can become easier to understand, since less is being used. It's also one of the reasonings behind such "demo competition" contests such as the 256 byte challenge, or 1K intros, etc. Also behind such things as pixel-art, especially tile art using only 8 colors (or even just black and white!) with only an 8 x 8 grid-space to work in. Some amazing art comes out of that, operating within such restrictions. I've heard/read that great programmers are those who are able to remove more code than they add for a given change (aka - simplifying the code). These techniques and everything else may all be a part of that idea.
- robomartin 7y agoAt the risk of inspiring a violent reaction (virtually, of course): Sorry folks, this is silly. Go solve real problems. Does a patient care if the ML code that discovered a malignant tumor used an explicitly written loop? As a silly test: What would be the value in rewriting the Facebook, Google, Amazon, etc. codebases to avoid loops? What’s the ROI? Kindly provide a few examples at scale (not academic oddities) where this might actually matter? You can’t avoid loops. Any time you are doing the same thing repeatedly, you are using a loop, whether you explicitly wrote it or not. Sure, sure, there are corner cases. I have unrolled loops in assembly in real time embedded code where every microsecond counted. That is far from the norm and, frankly, should be avoided with absolute passion. I have also worked with APL for ten years. You can do amazing things with the language while seemingly not looping. In reality nearly everything you do with APL includes heavy looping behind the curtains, and you better be well aware of this if performance is important. Don’t get me wrong, the academic question is interesting. However, if you live and work in the real world there are far more interesting and pressing issues to be concerned with.
- hkai 7y agoIn fact, you can set up an eslint rule banning any loops from your code.