Slashdot Mirror


Developer Argues For 'Forgotten Code Constructs' Like GOTO and Eval (techbeacon.com)

mikeatTB quotes TechBeacon: Some things in the programming world are so easy to misuse that most people prefer to never use them at all. These are the programming equivalent of a flamethrower... [But] creative use of features such as goto, multiple inheritance, eval, and recursion may be just the right solution for experienced developers when used in the right situation. Is it time to resurrect these four forgotten code constructs?
The article notes that the Linux kernel uses goto statements, and links to Linus Torvalds' defense of them. ("Any if-statement is a goto. As are all structured loops...") And it points out that eval statements are supported by JavaScript, Python, PHP, and Ruby. But when the article describes recursion as "more forgotten than forbidden," it begs the inevitable question. Are you using these "forgotten code constructs" -- and should you be?

409 of 600 comments (clear)

  1. Doing it wrong? by marc.pn.beaupre · · Score: 5, Insightful

    Honest question: Am I not supposed to use recursion? Am I missing something?

    1. Re:Doing it wrong? by j_kenpo · · Score: 5, Insightful

      I'm just as baffled by this. I wasn't aware that recursion went out of style. Just another tool in the algorithm and design pattern toolbox. Did I miss the memo that it was taboo as GOTO?

    2. Re:Doing it wrong? by Anonymous Coward · · Score: 1

      Well recursion incurs overheads such as pushing the current function's working values to the stack, passing the parameters onto the stack, then when the recursive call ends, it needs to pop stuff of the stack. The stack can grow big enough to crash the machine in some cases, and in most cases you can replace recursion with other means.

      Obviously if you're using it with a low number of levels it won't make much difference, it can make code neater and easier to understand, and in many cases the recursion itself can be optimized away (as in "tail recursion"). So it has uses but should only be applied to processes with a known, small number of steps/levels.

    3. Re:Doing it wrong? by Anonymous Coward · · Score: 1

      I thought it was widely recognized that recursion is often the most efficient solution. Then again, it should be widely recognized that gotos and evals are not evil, it is only terrible "programmers" who don't understand how computers work that shouldn't be allowed near them (because programmers already knew about if/switch/etc without linus having to say anything).

    4. Re:Doing it wrong? by Required+Snark · · Score: 2
      Without recursion, data structures like trees or graphs are useless. Kind of a problem if you have a directory tree structure, or you want to follows URL links for web scraping. Just on that alone, I would assume the rest of the article is crap.

      Does this horrible misrepresentation mean there are coders who don't realize that they are using a recursive algorithm? This lack of understanding could be a result of how some languages hide all the details of data structure implementation. Specifically, I'm thinking about Java. I saw a code example recently that was building a tree, but there were no obvious recursive calls anywhere. All the details were hidden in the data structure access interface. The way I knew what was going on was because "tree" was part of the object name.

      Given how "high-level" a lot of programming has become, I have a bad feeling that someone could be a working programmer and still have no idea what their data structures do. So if they do see recursive algorithms, they would call it a "forgotten code construct". Is this possible?

      --
      Why is Snark Required?
    5. Re:Doing it wrong? by Dog-Cow · · Score: 2

      You seem to have a poor understanding of programming.

      1) Hiding implementation, including algorithm selection, is a large part of what objects are for.
      2) It's possible to write any traversal algorithm using loops, without any recursion.

    6. Re: Doing it wrong? by PoopJuggler · · Score: 4, Interesting

      Recursion is undesirable because it doesn't scale - you run out of stack pretty quickly. There isn't really ever any need for recursion anyway as there's nothing you can do recursively that you can't do non-recursively.

    7. Re:Doing it wrong? by quenda · · Score: 5, Funny

      Honest question: Am I not supposed to use recursion?

      It depends. See https://developers.slashdot.or...

    8. Re: Doing it wrong? by gravewax · · Score: 5, Informative

      No but there are plenty of scenarios that require far more code an complexity when you don't use recursion, when the limits are well understood recursion is a valuable tool.

    9. Re: Doing it wrong? by religionofpeas · · Score: 2

      Sometimes recursion is appropriate, e.g. when walking binary trees, and a non-recursive solution requires just as much space to keep track of what you're doing. On big platforms with virtual memory, the stack will grow with as needed. On small platforms, the recursion doesn't need to go as deep.

    10. Re:Doing it wrong? by religionofpeas · · Score: 4, Insightful

      2) It's possible to write any traversal algorithm using loops, without any recursion.

      Sure, but if that requires building your own stack, you haven't really gained anything.

    11. Re:Doing it wrong? by jbolden · · Score: 1

      The article is a bit lite the summary on /. is worse. The article itself specifically mentions your use case: data structures where you want to convert a list of data into a list of actions as examples where recursion is often helpful.

    12. Re:Doing it wrong? by scamper_22 · · Score: 1

      I generally advise against it.

      This doesn't mean it should never be used.
      But a lot of the time, it doesn't NEED to be recursive and making it recursive complicates thing.

      I'll give a practical example. I worked on router firmware when I first graduated and got assigned this bug where a router in South Korea kept crashing. Really hard to debug it. After a lot of debugging, I found out it was related to the number of ACLs applied to a policy. Went through the code and the section that applies those ACLs was recursive.
      So when the number of ACLs got too high, this function was recursively called and it ended up blowing the stack on the firmware and crashing.

      Was there any reason for this to be recursive? Nope.
      A simply refactoring and I made it into a for loop. Problem solved.

      Recursion just introduces more ways things can screw up. I generally like the idea of it being cautioned against. If you really can't write it resonably in a loop, then go ahead.

    13. Re: Doing it wrong? by Anonymous Coward · · Score: 3, Insightful

      Elegance.

    14. Re:Doing it wrong? by Rockoon · · Score: 1

      Busting a hand-crafted software stack is far less problematic than busting the hardware stack that the cpu's call and return instructions directly use, and rapidly using a lot of stack brings in cache issues on many of the instructions compilers had expect to be low latency, significantly hurting performance.

      The fact is that recursion does not perform well on general purpose silicon. The performance degradation can be so significant that modern compilers are advertised to be able to perform an optimization that removes the recursion in some cases ("tail call optimization.")

      At least restrict your recursions to the cases of trees rather than lists.

      --
      "His name was James Damore."
    15. Re: Doing it wrong? by Cafe+Alpha · · Score: 1

      Uhm then you're using the wrong language.

      Lua and scheme have tail call optimization.

    16. Re: Doing it wrong? by hcs_$reboot · · Score: 2

      If the algorithm is well designed and its complexity well calculated no bad surprise is to be expected. And anyway most algorithms, based on recursion or not, do not dive very deeply (i.e. do not consume much stack), since the time complexity, depth wise, is usually exponential and too much depth implies too much time.

      --
      Slashdot, fix the reply notifications... You won't get away with it...
    17. Re: Doing it wrong? by Anonymous Coward · · Score: 1

      Listing every password of length n is a pain without recursion

      FYI: Looping with std::next_permutation() runs within a constant factor of the recursive solution.

    18. Re: Doing it wrong? by religionofpeas · · Score: 1

      Tail call optimization only works if you're actually doing a tail call, which isn't always the case. And if you're always doing a tail call, the recursion can be replaced by an iteration without too much trouble.

    19. Re: Doing it wrong? by Anonymous Coward · · Score: 1

      > just extents the stack as it would have with the heap if I had done the same with temporary objects

      This is why recursion should be forbidden: People don't even think about it or don't have a clue.
      OpenBSD used to have a stack limited to 64kB just a couple of years back.
      In a multithreaded environment, it is not even POSSIBLE to extend the stack as much as you want (as you will usually run into some other thread's stack REAL quick, 8 MB is the default in Linux).
      That results in code that works fine for the developer, then someone makes the architecture threaded and suddenly it crashes.
      There are also other issues, like that more data on stack usually means the program is much easier to exploit (this, among other things, was behind OpenBSD's restriction).
      These are the main reasons why recursion should be considered harmful (in C-like languages using the hardware stack):
      1) People implement it because it is "clean", but that is bought with them not even thinking 1 second about stack usage (otherwise they'd realize just how messy and complicated it actually is), so that the algorithm will randomly fail. Even if the recursion depth is fixed, adding a variable declaration can suddenly make your program crash. Algorithms using tail recursion don't suffer from that, but instead suffer from breaking if someone a bit carelessly adds code that breaks tail recursion.
      2) stack usage massively limits the possibility of threading (as a large number of threads means you need small stacks fit them all in the area the OS reserved for them).

      TL;DR: "Cleanliness" of recursion is usually bought via greatly reduced correctness and maintainability.

    20. Re:Doing it wrong? by Required+Snark · · Score: 1
      Claiming "It's possible to write any traversal algorithm using loops, without any recursion." is incorrect for both trees and graphs. The closest you can come is to maintain a stack structure and manually push and pop data and control flow information on the stack. It's ugly, and recursion is much easier to code and debug. Having done it both ways, I can say that coding your own stacks and using loops is not easy.

      Your reply has answered the final question I asked: it is possible to be a "coder" and not understand recursion or recursive data structures. If you had ever studied data structures in computer science you would know that just looping is not enough.

      To be even more pedantic, there are some recursive data structures, such as the threaded binary tree that allow tree traversal without recursion. This works by replacing null links in the tree structure with pointers to the next node for a specific traversal order. This is more expensive to build or modify then a general binary tree, and making it in the first place uses recursion. If you want to know what other similar tricks like this you can pull, look at The Art of Computer Programming volume 1 chapter 2.3.

      --
      Why is Snark Required?
    21. Re: Doing it wrong? by AmiMoJo · · Score: 2

      Yep. Embedded people avoid recursion like the plague because they have limited resources. Sometimes desktop guys use it, and it works okay until someone opens a big file and it needs 18GB of RAM...

      --
      const int one = 65536; (Silvermoon, Texture.cs)
      SJW, n: "Someone I don't like, and by the way I'm a fuckwit" - AC
    22. Re: Doing it wrong? by whopis · · Score: 2

      Read this post and it's replies. It is a good explanation of the issues with recursion.

      http://slashdot.org/comments.p...

    23. Re:Doing it wrong? by Z00L00K · · Score: 1

      Recursion is a very useful tool used right but very confusing for people trying to understand it if it's not well declared.

      Consider traversing a directory tree - that's a typical example of a "problem" that's solved with recursion.

      --
      If builders built buildings the way programmers wrote programs, then the first woodpecker would destroy civilization.
    24. Re: Doing it wrong? by Z00L00K · · Score: 4, Funny

      Whenever recursing, have a recursion counter and a termination condition that stops infinite recursions.

      --
      If builders built buildings the way programmers wrote programs, then the first woodpecker would destroy civilization.
    25. Re: Doing it wrong? by burnetd · · Score: 1

      You've not written stuff for browsers then. Some of them have had very strict limits on recursion, some of them still do.

      http://www.browserscope.org/us...

    26. Re: Doing it wrong? by Z00L00K · · Score: 1

      Just have a good exit criteria to avoid too deep recursions and it's not a problem on any system. Unless you code for a 4 bit processor or something other extremely small and weird.

      --
      If builders built buildings the way programmers wrote programs, then the first woodpecker would destroy civilization.
    27. Re:Doing it wrong? by jellomizer · · Score: 1

      I think we all missed the memo.
      Now there are some places where it is misused.
      1. Can make code too cryptic. When tracing code a recursive algorithm forces the observer to understand the full algorithm vs just the part which can make debugging an odd use case difficult.
      2. Limited stack space. So if you don't know how deep that routine will go. You could end up with some hard to fix problems.

      However some language like JavaScript really don't give you much of an option. Such as a lack of a sleep command and poorly implemented synchronize way to call data. Means using recursive method is necessary where one normally wouldn't.

      Then sometime there are problems where recursion is much more logical way to solve. While can be done with a loop but you need to make a stack by itself vs using the natural one that is in a recursion.

      --
      If something is so important that you feel the need to post it on the internet... It probably isn't that important.
    28. Re: Doing it wrong? by MagicMerlin · · Score: 1

      Ackerman can only be coded recursively...heh

    29. Re: Doing it wrong? by flux · · Score: 1, Informative

      You know, it might be a pretty good idea to not use recursion and just implement your own stack in many of those cases, because recursion locks you into one traversal algorithm, namely depth-first.

      If instead you collect the new nodes to visit to a list, you are able to choose whichever order to traverse those nodes easily. Such as in the order of "most promising prospect".

      With a list you can also wait until its size is larger than n and then split the list for multiple cores to execute, merge the resulting lists and gain some concurrency benefits this way.

      It's just a few lines of code to do the stack anyways in modern programming languages anyway.

    30. Re: Doing it wrong? by flux · · Score: 1

      Proper tail call optimizations also optimizes the case of not recursing to the same function That's a bit more difficult to make an iteration and you need to move all those functions involved into the same iterative loop.

    31. Re: Doing it wrong? by K.+S.+Kyosuke · · Score: 1

      Recursion is undesirable because it doesn't scale - you run out of stack pretty quickly.

      Tail calls, tail calls everywhere - at least in sane languages.

      There isn't really ever any need for recursion anyway as there's nothing you can do recursively that you can't do non-recursively.

      Modular compilation, actually. Coroutine-like transfer of control into places not known at compile time is very cumbersome. You need something like a trampoline. (Plus, recursion as a structural element of the program and recursion on the execution stack are two different things anyway.)

      --
      Ezekiel 23:20
    32. Re: Doing it wrong? by K.+S.+Kyosuke · · Score: 4, Insightful

      Every time you make a function call, some amount of bookkeeping data has to be stored on the stack

      Not necessarily, really, these days. But yes, if your compiler is really dumb, like in the 1970s, the difference can be significant.

      If you do "manual recursion", with a loop and a resizable container, then you can achieve lower overhead.

      Chances are that if you can do that easily, you should have done it in the first place, and if you can't, there was a reason for that.

      --
      Ezekiel 23:20
    33. Re: Doing it wrong? by K.+S.+Kyosuke · · Score: 2

      And if you're always doing a tail call, the recursion can be replaced by an iteration without too much trouble.

      Well, the good thing is that the compiler can do this automatically, so if you're writing a program from scratch and already know what it will do (which is often the case), these manual decisions are fine, but if you already have a working program and the desired logic changes a bit, switching between iterations and recursions by hand is much more involved now than just letting the compiler figure out the changed tail call positions.

      --
      Ezekiel 23:20
    34. Re: Doing it wrong? by religionofpeas · · Score: 1

      Embedded people avoid recursion like the plague because they have limited resources.

      You can't make blanket statements like that. It all depends on the recursion depth, your embedded platform, and the requirements of an alternative solution. You can have embedded platforms with 100 bytes or with 100 MB, with or without virtual memory and possible dynamically growing stacks. Also, if you need to build your own stack to avoid recursion, where are you going to store it ? Static memory is wasteful, and not all embedded platforms have heaps. And what are you going to do when your manual stack isn't big enough ?

      Sometimes desktop guys use it, and it works okay until someone opens a big file and it needs 18GB of RAM

      Never heard of paging ?

    35. Re: Doing it wrong? by Anonymous Coward · · Score: 1

      It's just a few lines of code in assembly on any architecture that can access memory with an address stored in a register.
      If it isn't trivial in a modern programming language it is probably very specialized for a specific type of problems. (See how I don't outright call it a bad language.)

      Unless you have decided that it is easiest to write your program in a functional language you are probably better off avoiding recursion.

    36. Re: Doing it wrong? by K.+S.+Kyosuke · · Score: 3, Insightful

      They can make the code look neat but that also hides horrible performance bombs and security issues.

      Then they're lousy abstractions. Abstractions are here to hide irrelevant details that you'd get wrong if you had to do stuff by hand identically in many places and correctly all the time. Doing something right just once is the exact opposite of having a security issue.

      Regarding stack allocation, that ought to be O(1), anyway.

      --
      Ezekiel 23:20
    37. Re: Doing it wrong? by N!k0N · · Score: 1

      Lua iterator construction is bordering on beautiful. I always feel like I've crafted something when I finish with lua code, not all languages do that.

      I feel the same about Java ... granted, that something would be right at home in the 9th circle of hell ...

    38. Re:Doing it wrong? by jenningsthecat · · Score: 1

      You seem to have a poor understanding of programming.

      1) Hiding implementation, including algorithm selection, is a large part of what objects are for...

      IANAP - I'm a hardware guy, more into analog and RF than digital. When I'm dealing with hardware that has a 'black box' module, or an IC I can't find data on, or even when I'm repairing a complete system for which I don't have schematics or even wiring diagrams, I'm working in the kind of 'hidden implementation' space you're talking about. And whenever I'm in that position, the first thing I try to do is gain an understanding of the design and the behaviour of the module, circuit, or whatever. It always makes the work easier, and sometimes it's necessary, as in I if I can't figure it out I can't fix it. And when I'm designing a circuit, I always like to know what's going on inside any 'black-box' items I'm thinking about using.

      I've also worked with programmers and heard them talking about the unexpected behaviour of some function or object. I totally get the purpose and power of objects in programing - but aren't there times when penetrating that abstraction will allow a programmer to write better code? And aren't there times when it's outright necessary for debugging the program?

      --
      'The Economy' is a giant Ponzi scheme whose most pitiable suckers are the youngest among us and the yet-unborn.
    39. Re: Doing it wrong? by angel'o'sphere · · Score: 4, Informative

      Stack frame allocation costs exactly: nothing.
      So why do you care?

      You fear an endless loop and running out of stack space?

      Well, most compilers convert most recursions into loops anyway: it is called tail recursion optimization.

      I don't remember when I saw recursion the last time in production code, likely decades ago, and you care about the raw cases where a manually written loop is "better" than recursion ... wow.

      --
      Cost free eBook I read (by iBook/Kobo/Amazon/ObookO/Gutenberg etc.): "The Green Odyssey" by Philip Jose Farmer.
    40. Re: Doing it wrong? by angel'o'sphere · · Score: 1

      And if you're always doing a tail call, the recursion can be replaced by an iteration without too much trouble.
      Yeah ... but why would anyone do that?

      --
      Cost free eBook I read (by iBook/Kobo/Amazon/ObookO/Gutenberg etc.): "The Green Odyssey" by Philip Jose Farmer.
    41. Re: Doing it wrong? by angel'o'sphere · · Score: 1

      Embedded people use C/C++ and mostly GCC wich means: it has tail recursion optimization just like any other modern language/compiler.

      No idea why people always spread myths about embedded programming. It is not different to other programming for most people involved.

      --
      Cost free eBook I read (by iBook/Kobo/Amazon/ObookO/Gutenberg etc.): "The Green Odyssey" by Philip Jose Farmer.
    42. Re: Doing it wrong? by religionofpeas · · Score: 1

      Yeah ... but why would anyone do that?

      Because you don't know always for sure that your compiler implements tail recursion optimization. I've worked on embedded projects, where the whole project was compiled with -O1 and tail recursion wasn't optimized. So, if the iterative solution isn't any more complex, I'd use that instead.

    43. Re: Doing it wrong? by angel'o'sphere · · Score: 1

      That is wrong.
      Every recursion can be expressed as a loop or nested loops.

      --
      Cost free eBook I read (by iBook/Kobo/Amazon/ObookO/Gutenberg etc.): "The Green Odyssey" by Philip Jose Farmer.
    44. Re: Doing it wrong? by religionofpeas · · Score: 1

      There are languages that do not optimise tail-recursion, such as C

      A good C compiler will do tail recursion.

    45. Re: Doing it wrong? by sg_oneill · · Score: 1

      Recursion is undesirable because it doesn't scale - you run out of stack pretty quickly.

      Badly designed recursion doesnt scale. However well defined problems that require it and have well understood limits, its fine and often optimal, particularly if the algorithm can be tail recursed.

      There isn't really ever any need for recursion anyway as there's nothing you can do recursively that you can't do non-recursively.

      Yes, but many algorithms will still require a stack and become incredibly more complicated and slow, such that there are literally no benefits.

      --
      Excuse the Unicode crap in my posts. That's an apostrophe, and slashdot is busted.
    46. Re: Doing it wrong? by AmiMoJo · · Score: 5, Interesting

      I am an embedded software engineer.

      You have to be extremely careful with recursion, because often you have a very small stack. We also try to avoid any dynamic memory allocation when possible, only using automatic variables. With some types of firmware, even automatics are not allowed, but I don't go that far.

      The danger with recursion is that even if you try to limit it, if you screw up it can be very bad. It can be much worse than, say, an infinite loop. The loop can be caught by a watchdog and if designed carefully shouldn't start corrupting other stuff. Recursion that grows the stack or allocates memory could end up overwriting things and causing all kinds of unpredictable behaviour. Remember that embedded systems typically don't have any memory protection or stack guarding, and only extremely simple memory management.

      Of course it does depend on the type of firmware too. My stuff often has to run for 5+ years without a reset, and is sealed so you can't just reset it if something does go wrong. If resetting is an option, you can take more risks. One option we considered was to do one reset every day by design, so that any issue which took longer than a day to emerge would never affect us.

      --
      const int one = 65536; (Silvermoon, Texture.cs)
      SJW, n: "Someone I don't like, and by the way I'm a fuckwit" - AC
    47. Re: Doing it wrong? by ShanghaiBill · · Score: 1

      a non-recursive solution requires just as much space to keep track of what you're doing.

      Nope. Recursion saves the instruction pointer on the stack, in addition to whatever other data is required. So a non-recursive equivalent will be slightly faster and use slightly less memory, at the cost of being slightly less understandable.

    48. Re: Doing it wrong? by religionofpeas · · Score: 2

      Maybe the tree is on an SD card, and the stack resides in a small RAM.

    49. Re: Doing it wrong? by angel'o'sphere · · Score: 1

      So you consider it easier to change perfectly running code (for what reason?) instead of fixing the compiler settings?

      --
      Cost free eBook I read (by iBook/Kobo/Amazon/ObookO/Gutenberg etc.): "The Green Odyssey" by Philip Jose Farmer.
    50. Re: Doing it wrong? by religionofpeas · · Score: 1

      if you screw up it can be very bad. It can be much worse than, say, an infinite loop.

      I'd rather have very bad effects in my embedded code than small and subtle effects that can stay hidden for a long time, but still have the potential to screw up the application.

    51. Re:Doing it wrong? by jcr · · Score: 1

      There are plenty of situations where recursion gets the job done with a minimum of code complexity. You just need to be aware of what the runtime costs might be.

      -jcr

      --
      The only title of honor that a tyrant can grant is "Enemy of the State."
    52. Re: Doing it wrong? by jcr · · Score: 1

      That would be good to know if, god forbid, I ever had to deal with C++ again.

      -jcr

      --
      The only title of honor that a tyrant can grant is "Enemy of the State."
    53. Re: Doing it wrong? by religionofpeas · · Score: 4, Insightful

      So you consider it easier to change perfectly running code (for what reason?) instead of fixing the compiler settings?

      Sometimes, yes. The project was for a medical application, with 99% of the code written by others. I'm not going to change global compiler settings and risk exposing some optimization error, when I can simply change a few lines of my code.

    54. Re:Doing it wrong? by geoskd · · Score: 3, Informative

      Am I not supposed to use recursion? Am I missing something?

      Recursion has a whole host of negative consequences that make it an undesirable programming construct. The most basic ones don't apply universally, but are nonetheless relevant.

      The number one reason not to use recursion is because it is very easy to exhaust the stack in system with more limited memory like embedded systems.

      The next most important reason to not use recursion is because it is slower. Iterative loops are easy for a compiler to optimize, and the branch instructions used for iterative loops are single cycle (or on some architectures less than 1 cycle) instructions. This makes them fast. Compare that with function calls which are always more than 1 cycle per call (at least 1 cycle for the call, and another one for the return). It is also extremely difficult for a compiler to unroll a recursive calling structure whereas loop unrolling is almost trivial. Compiler that can do recursion unrolling will hate you if the recursion depth is greater than about a thousand levels deep, as the compiler will eventually exhaust memory and fail.

      Recursion is a maintenance nightmare. Trying to ferret out what a recursive function is doing can be difficult even in relatively trivial implementations. The maintenance phase of the software lifecycle is more than half of the total effort, so give those guys a fighting chance and avoid "elegant" solutions unless you have an overriding reason, which you will never have when it comes to recursion.

      Recursion uses more memory. Each pass through the recursive function, you have to pile return vectors and function parameters into new locations on the stack. These data have nothing to do with your algorithm and represent pure overhead. iterative loops do not have this overhead penalty.

      In the end, recursion is one of those things that makes a great teaching tool, because it forces programmers to think about the consequences in non-linear program space. In practice it is a bad idea and will get you into trouble sooner or later. It is in fact so troublesome that recursion is expressly forbidden in safety critical systems.

      --
      I wish I had a good sig, but all the good ones are copyrighted
    55. Re: Doing it wrong? by Wuhao · · Score: 1

      I'm not sure what you mean when you say "you run out of stack pretty quickly." You run out of space in an 8-bit int "pretty quickly," but I still use those when the situation calls for it and I know I'm never going to need that much range. I don't get to use recursion often, but when I do, it improves readability and elegance. In most cases, I value those more than execution time or a restriction on domain that I was never going to exceed in the first place.

    56. Re: Doing it wrong? by geoskd · · Score: 1, Interesting

      You can't make blanket statements like that. It all depends on the recursion depth, your embedded platform, and the requirements of an alternative solution.

      Yes, you can make blanket statements like that. *Every* embedded software design standard expressly forbids recursion. There is 50 years of experience with these kinds of systems that pretty conclusively condemns recursion.

      You can have embedded platforms with 100 bytes or with 100 MB, with or without virtual memory and possible dynamically growing stacks. Also, if you need to build your own stack to avoid recursion,

      If you are building a stack to avoid recursion, then you haven't thought through the problem very well, and are just trying to emulate recursion without recursion. The problem space can always be transformed into one that does not require recursion, and it is that transformation that is critical, because it is what changes the problem from one that is effectively unbounded to one that is provably bounded. Embedded systems (especially safety critical systems) *must* be bounded. If you want to write programs without understanding the fundamentals of computer science then go be a windows programmer, but don't be too shocked when your software is bloated, slow, and prone to crash

      --
      I wish I had a good sig, but all the good ones are copyrighted
    57. Re:Doing it wrong? by luis_a_espinal · · Score: 1

      Honest question: Am I not supposed to use recursion? Am I missing something?

      In general, only for prototyping, describing problems or when using a language that has sufficient support for tail recursion. Otherwise, I'd say no.

      You have to understand it though, and understand it well. But if I see someone on the wild using a recursive solution from scratch, I'd be wondering wtf is going on.

      Honestly, I've only seen custom code recursive code, and it was a fuck up.

    58. Re: Doing it wrong? by Anonymous Coward · · Score: 5, Insightful

      Well, most compilers convert most recursions into loops anyway: it is called tail recursion optimization.

      Correction: *some* compilers will convert *some specifically structured* tail-recursive function calls into loops.

      There are lots of ways to make recursive function calls not tail-calls which renders them ineligible for compiler optimization.

    59. Re: Doing it wrong? by thsths · · Score: 1

      Exactly. Recursion is heavy on stack use, and you cannot be sure that your target system has enough stack space available.

      But it depends on how you use it. Binary recursion is usually considered ok, because you end up with a reasonably small number of levels (in the tens). Divide and conquer is a classic example, but even there you will usually find a loop implementation, because it is faster, and only marginally more difficult to code. Linear recursion on the other hand is complete madness, both in terms of stack use and in terms of performance.

      A decent functional language will unroll recursion into a more efficient loop implementation. C will not do that. So as always, you should understand your language and your compiler.

    60. Re: Doing it wrong? by Anonymous Coward · · Score: 1

      I defy you to name one compiler that doesn't at least store the return address - i.e. "some minimum amount of bookkeeping data" - on a stack-like structure in memory.

    61. Re:Doing it wrong? by ceoyoyo · · Score: 1

      I think they stopped teaching children what recursion is.

      They can all get off my lawn.

    62. Re: Doing it wrong? by Fragnet · · Score: 1

      Many uses of recursion aren't required to scale.

    63. Re: Doing it wrong? by Fragnet · · Score: 1

      because recursion locks you into one traversal algorithm, namely depth-first.

      What? No it doesn't.

    64. Re: Doing it wrong? by religionofpeas · · Score: 1

      *Every* embedded software design standard expressly forbids recursion

      My embedded software design standard doesn't.

      because it is what changes the problem from one that is effectively unbounded to one that is provably bounded

      Recursively searching a binary tree is bounded by the depth of the tree, just like many other recursive methods are naturally bounded by the data they work on. And If the original problem space is unbounded, your recursive code is crap, and needs to be fixed properly. Just changing it to a non-recursive method doesn't magically fix the problem, or make it bounded.

      If you want to write programs without understanding the fundamentals

      I do understand the fundamentals. That's why I can safely use recursion when the problem calls for it.

    65. Re: Doing it wrong? by religionofpeas · · Score: 1

      Recursion is heavy on stack use, and you cannot be sure that your target system has enough stack space available.

      Of course you can. You just figure out maximum recursion depth, and then check if there's enough stack space.

      C will not do that. So as always, you should understand your language and your compiler

      GCC has no problem identifying tail recursion and optimizing it away. I'm sure other modern C compilers do the same thing.

    66. Re: Doing it wrong? by TheRaven64 · · Score: 1

      This is true for a language like C, where you have strict constraints on the function call ABI. For languages that are designed with recursion in mind, it's common to transform a recursive call into a continuation passing representation. Called functions are then always tail called, but sometimes take a continuation as an extra argument (which they then tail call instead of returning). The last step prior to the back end will then turn some of these back into call-return structures to take advantage of the hardware's support for the stack.

      --
      I am TheRaven on Soylent News
    67. Re: Doing it wrong? by lgw · · Score: 1

      Well, most compilers convert most recursions into loops anyway: it is called tail recursion optimization.

      They don't though, is the problem. But that's a problem with compilers, not the concept.

      I've done "manual recursion" before -- creating a stack as a variable in order to use a loop -- in kernel space where the stack was too small to do otherwise. It's not a pleasant approach, but was still better than the alternatives.

      --
      Socialism: a lie told by totalitarians and believed by fools.
    68. Re: Doing it wrong? by lgw · · Score: 1

      That's true for trivial tail recursion, and refactoring that into a loop often makes sense, with no loss in clarity. But for something like a tree walk, the iterative approach (one that doesn't just make its own stack) is usually "too clever", the sort of code that breaks the first time a maintainer touches it.

      --
      Socialism: a lie told by totalitarians and believed by fools.
    69. Re: Doing it wrong? by TheRaven64 · · Score: 1

      Embedded is a term that ranges from 4- and 8-bit microcontrollers with under 1KB of RAM up to storage appliances with multi-core multi-GHz CPUs and hundreds of GBs of RAM. There are very few generalisations that are true for that entire space.

      --
      I am TheRaven on Soylent News
    70. Re: Doing it wrong? by lgw · · Score: 1

      You have to be extremely careful with recursion, because often you have a very small stack. We also try to avoid any dynamic memory allocation when possible, only using [the stack]

      You wot mate?

      When I did low-level programming last, we didn't use a stack, most memory used was either a fixed-sized data structure loaded with the code, or a fixed-size data structure passed by the caller (and, in turn, either loaded with it's code or passed by its caller).

      The limited dynamic allocation we did was all slab-allocated. E.g., the spec says we support 100 connections, and we pre-allocate a slab of 100 connection data structures, but allocate dynamically within that.

      --
      Socialism: a lie told by totalitarians and believed by fools.
    71. Re: Doing it wrong? by lgw · · Score: 1

      Meh, "manual recursion" is still recursion - allocating your own stack on the side isn't really changing the problem, just expressing it awkwardly in code.

      --
      Socialism: a lie told by totalitarians and believed by fools.
    72. Re: Doing it wrong? by prefec2 · · Score: 1

      Recursion is acceptable, but you may run out of stack space iff you get into endless recursion. However, this can be detected by a compiler under some conditions.

      GOTO however, is weaker in semantics than a loop or condition, as it can imply both.

      The article is stupid anyway. He only added recursion so that he can easily claim that it us useful and so is goto. That happens when.people stop reading Kuth and get their education from YouTube.

    73. Re: Doing it wrong? by prefec2 · · Score: 1

      Exactly. But it can be done by the compiler and I can specify the function much more elegant and readble.

    74. Re: Doing it wrong? by AmiMoJo · · Score: 1

      As I say, it depends on the system. In the stuff I'm working on we allow automatic variables and passing on the stack (although GCC always uses registers in all the code we have), but keep them small. Anything more than a few bytes gets statically allocated.

      If I were allowing 100 connections, I would statically allocate memory for 100 connections and then dynamically assign slots. I wouldn't use malloc() or it's kin, even with a limited size section.

      This is on devices with a few kilobytes of RAM. If memory pressure is an issue we do statically allocate everything. Sometimes twice, if we are concerned about RAM being corrupted.

      --
      const int one = 65536; (Silvermoon, Texture.cs)
      SJW, n: "Someone I don't like, and by the way I'm a fuckwit" - AC
    75. Re: Doing it wrong? by ziggystarsky · · Score: 1

      *Few* compilers would be more be even more correct.

    76. Re: Doing it wrong? by fahrbot-bot · · Score: 4, Informative

      Recursion is undesirable because it doesn't scale - you run out of stack pretty quickly. There isn't really ever any need for recursion anyway as there's nothing you can do recursively that you can't do non-recursively.

      While that's basically true, as a former LISP programmer, I can attest that recursion can be simpler and more elegant to code, understand and maintain. It's really good for prototyping and proof-of-concept work, where speed and scaling may not matter. For example, coding a tree search is about 3 lines of recursive code vs. 2 pages of non-recursive code. I sometimes even use a recursive version of a function to verify the operation of a non-recursive function.

      --
      It must have been something you assimilated. . . .
    77. Re:Doing it wrong? by zifn4b · · Score: 1

      Honest question: Am I not supposed to use recursion? Am I missing something?

      Nope. Recursion is incredibly useful for graph traversal.

      --
      We'll make great pets
    78. Re:Doing it wrong? by zifn4b · · Score: 1

      I'm just as baffled by this. I wasn't aware that recursion went out of style. Just another tool in the algorithm and design pattern toolbox. Did I miss the memo that it was taboo as GOTO?

      This article is incredible questionable as to its credibility and competence. Real programmers that have been in the business like myself for 30 years and have used many languages and styles of programming styles (procedural, functional, OOP, etc.) will tell you that recursion is still incredibly useful (especially for graph traversal) and functional programming languages also rely heavily on it. GOTO/GOSUB on the other hand have no practical use anymore. The only thing I might think you would consider using this for is for assembly language to optimize a particular piece of code for performance like in a device driver but most of the time these types of semantics are done via computer optimization like a compiler or perhaps something that is trying to optimize a circuit board design. If you compile something in any compile time language like C++ and decompile it, you will see lots of JMP's (the equivalent of a GOTO in assembler, go to this [memory address]). In fact I think you see that in JIT languages like java and C# too in the byte code as well. However, you should never be writing high level language code in this way because it turns into a spaghetti code mess that after awhile cannot be followed even by the best and brightest software engineers.

      --
      We'll make great pets
    79. Re: Doing it wrong? by zifn4b · · Score: 1

      Recursion is undesirable because it doesn't scale - you run out of stack pretty quickly. There isn't really ever any need for recursion anyway as there's nothing you can do recursively that you can't do non-recursively.

      If you're concerned about that then use a stack object on the heap to accomplish the same thing. It's still recursion just a different implementation.

      --
      We'll make great pets
    80. Re: Doing it wrong? by david_thornley · · Score: 4, Insightful

      Some algorithms are naturally recursive. For example, in-order traversal of a binary tree is easiest described as: deal with the left child, deal with this node, deal with the right child. Tower of Hanoi is easily solvable with: Move all disks above the one you want to move to the other peg, move the disk you want to move to the peg you want to move to, move the disks you moved earlier to on top of the disk you wanted to move.

      In these cases, if you use loops, you're going to be making up all the stuff recursion is good for, and you're going to be maintaining your own stacks. There's no advantage to doing this rather than using recursion. If you were going to get into a loop and recurse indefinitely, if you translate it into loops you're going to get into a loop and push indefinitely.

      --
      "When you have eliminated the unacceptable, whatever is left, however improbable, must be the truthiness" - Holmes
    81. Re: Doing it wrong? by tender-matser · · Score: 1

      Algorithms using tail recursion don't suffer from that, but instead suffer from breaking if someone a bit carelessly adds code that breaks tail recursion.

      I always wondered why nobody thought about implementing some sort of pragma / gcc-style attribute to mark a function call as a tail call (and let the compiler error out if it's not a tail call, or if it's just not able to optimize the outer frame away).

      2) stack usage massively limits the possibility of threading (as a large number of threads means you need small stacks fit them all in the area the OS reserved for them).

      That's one of the reasons why running the threads in separate address spaces would be such a great idea ;-)

    82. Re: Doing it wrong? by zifn4b · · Score: 1

      I don't remember when I saw recursion the last time in production code, likely decades ago, and you care about the raw cases where a manually written loop is "better" than recursion ... wow.

      It's not useful in most common programming situations especially in business software. Where it is useful is when dealing with non-linear graphs like binary search trees. Consider this application, we have a text adventure game and an actor is in one room and another actor is in a different room. Describe the general purpose algorithm to find the shortest path from actor A to actor B without recursion. In other words, implement a breadth first search of depth first search without recursion. You will find it's significantly more difficult to do without recursion.

      --
      We'll make great pets
    83. Re: Doing it wrong? by zifn4b · · Score: 1

      If you do "manual recursion", with a loop and a resizable container, then you can achieve lower overhead.

      Chances are that if you can do that easily, you should have done it in the first place, and if you can't, there was a reason for that.

      If the first thing that comes to mind when thinking about how to implement a recursive algorithm without using compile time function stack isn't using some type stack then you really don't know what you're talking about. Go back to Computer Science class.

      --
      We'll make great pets
    84. Re: Doing it wrong? by david_thornley · · Score: 1

      Yup. Programming with limited resources can result in hard-to-understand programs that would be easier to understand if the right abstractions were available, typically on a larger machine. PNGs at 11.

      --
      "When you have eliminated the unacceptable, whatever is left, however improbable, must be the truthiness" - Holmes
    85. Re: Doing it wrong? by david_thornley · · Score: 1

      Exactly. Recursion is heavy on stack use, and you cannot be sure that your target system has enough stack space available.

      If your solution involves a stack, it doesn't matter within a constant factor whether you use recursion or keep a stack manually. If it's recursing endlessly, it's going to blow either way.

      --
      "When you have eliminated the unacceptable, whatever is left, however improbable, must be the truthiness" - Holmes
    86. Re:Doing it wrong? by david_thornley · · Score: 1

      If you're working with cache constraints, recursion might be better than iteration. In different circumstances, different techniques can be better.

      --
      "When you have eliminated the unacceptable, whatever is left, however improbable, must be the truthiness" - Holmes
    87. Re:Doing it wrong? by david_thornley · · Score: 1

      Overall, it's generally impossible to say that, of two reasonable approaches to programming, one is always better. (It is possible to do this with unreasonable approaches to programming, such as generating random programs until one passes the acceptance test.)

      Abstractions can leak when they're used in unusual ways. As Joel Spolsky put it, TCP is an abstraction that makes it possible to maintain a continuous lossless two-way connection - until you find that the reason it isn't working is that your pet snake chewed through the Ethernet cable. At that point, you have to disregard abstraction of the hardware layer. Even in a world with snakes, though, it's almost always better to use TCP facilities when appropriate than to go to the bare metal.

      --
      "When you have eliminated the unacceptable, whatever is left, however improbable, must be the truthiness" - Holmes
    88. Re:Doing it wrong? by david_thornley · · Score: 1

      There are ways to avoid trees decaying into linked lists. As long as you have to treat it as a tree, though, you need to keep a stack, and a manually controlled stack can blow stack space itself.

      --
      "When you have eliminated the unacceptable, whatever is left, however improbable, must be the truthiness" - Holmes
    89. Re: Doing it wrong? by david_thornley · · Score: 1

      This is why recursion should be forbidden: People don't even think about it or don't have a clue.

      Eliminate every programming construct that careless people can misuse, and you've got nothing left.

      --
      "When you have eliminated the unacceptable, whatever is left, however improbable, must be the truthiness" - Holmes
    90. Re: Doing it wrong? by ShanghaiBill · · Score: 1

      I'd rather have very bad effects in my embedded code than small and subtle effects that can stay hidden for a long time, but still have the potential to screw up the application.

      That is the point. If you implement a recursive function to walk a tree, it will work fine as long as the tree is somewhat balanced ... and if random data is inserted, a tree will almost always be balanced. Almost. But not always. So one day, the tree is not balanced, and your recursion overflows the stack, trashing the very call chain that you need to figure out what went wrong. That can be a subtle bug that is hard to track down.

      There are several ways to avoid (or at least detect) this problem:
      1. Count the depth, and increment each time you recurse.
      2. Put a sentinel like "0xDEADBEAF" near the bottom of the stack space, and check it.
      3. During development, use a much smaller stack than in deployment. If your deployment will have a 2K stack, then use 1K in development. This will expose a lot of fragile algorithms.
      4. At each level of recursion, avoid storing unnecessary data in each stack frame. Instead, try to store data in static variables. For instance a depth counter does not need to be passed to a subfunction. It can be a static variable that is incremented when the subfunction is called, and decremented when it returns.
      So instead of this:

      void
      foo(int depth)
      {
            foo(depth + 1);
      }

      Do this:

      static int depth;
      void foo()
      {
          ++depth;
          foo();
          --depth;
      }

    91. Re:Doing it wrong? by david_thornley · · Score: 1

      If we're talking about an inherent recursive algorithm (tree traversal is an obvious example), we have to maintain a manual stack. Go through your earlier questions and ask them about the manual stack.

      As far as adding a 2MB array, I have a suggestion: test your code before you check it in.

      Also, problems you don't know a solution to may in fact have solutions, although you may not realize this due to Dunning-Kruger.

      --
      "When you have eliminated the unacceptable, whatever is left, however improbable, must be the truthiness" - Holmes
    92. Re: Doing it wrong? by jbolden · · Score: 1, Interesting

      The ones who use it a lot. I'd say most. Most use recursion schemes: maps, folds, catamorphism... to guarantee they are using tail calls.

    93. Re: Doing it wrong? by ShanghaiBill · · Score: 1

      C will not do that

      All modern C compilers will detect and optimize tail recursion. It is a very easy optimization to do, and is often a big win.

      So as always, you should understand your language and your compiler.

      Yes, you should.

    94. Re:Doing it wrong? by david_thornley · · Score: 1

      The number one reason not to use recursion is because it is very easy to exhaust the stack in system with more limited memory like embedded systems.

      If the algorithm is recursive, it probably requires you to maintain a stack if you don't use recursion. If the algorithm gets into unlimited recursion, it will blow either way. If you're working in tight embedded systems, you probably can't afford to make a stack without hard limits on it anyway, and again it doesn't matter (except that you can probably make the special-purpose stack take less memory than recursion).

      The next most important reason to not use recursion is because it is slower....Recursion uses more memory.

      Computers tend to be bigger and more powerful than we actually need, and sacrificing raw efficiency for things like readability, maintainability, etc., is completely standard in most cases. Modern software tends to be sufficiently complex that it would never get written without compromises like that.

      Recursion is a maintenance nightmare.

      Let's assume we have a binary tree with nodes like struct node { datapackage stuff; struct node * left, right; }

      where "datapackage" is a struct or class type. Now, for in-order traversal:
      void traverse (struct node * n) {
      if (left) traverse(left);
      process(stuff);
      if (right) traverse (right);
      }

      Now tell me how difficult this is to maintain. Now, write code to do the in-order traversal without using recursion and tell me how easy that is to comprehend at a glance.

      --
      "When you have eliminated the unacceptable, whatever is left, however improbable, must be the truthiness" - Holmes
    95. Re: Doing it wrong? by ShanghaiBill · · Score: 2

      There are languages that do not optimise tail-recursion, such as C .

      All modern C compilers optimize tail-recursion.

      computing the sum of the elements of a large array is efficiently done with a for-loop, whereas recursion would use excessive stack space.

      Only a total idiot would use recursion to sum an array. There are many other tasks, such as searching a tree, where a recursive algorithm makes much more sense.

      Anything that can be done iteratively, can be done recursively

      Anything that can be built with a hammer can be built with a rock.

    96. Re:Doing it wrong? by ShanghaiBill · · Score: 3, Funny

      In the book "C Traps and Pitfalls", on page 146 of the index it says "recursion 88, 146".
      The index also contains “pitfalls, see traps” and “traps, see pitfalls.”

    97. Re: Doing it wrong? by religionofpeas · · Score: 1

      or 5. Use an algorithm that keeps the trees (mostly) balanced.

    98. Re: Doing it wrong? by Thanatiel · · Score: 1

      Don't forget that the recursion will most likely save some register context you have no control of plus the call return address.
      Plus calling is not free.

      That being said, I find the drawback acceptable in most cases.
      If optimization is required, there is always time to do a more suitable implementation later.

      --
      Irrelevant news and morons using moderation to mod down what they disagree on. 2018 resolution: so long.
    99. Re: Doing it wrong? by allo · · Score: 1

      > you run out of stack pretty quickly
      Maybe in python. Other programming languages allow you to use a large stack, if you need to. And this isn't a bad thing. It may be a bad thing in python, because the call stack has overhead, but in C it is no bad thing.

    100. Re: Doing it wrong? by allo · · Score: 2

      Most modern C compilers, given certain constraints about return values.

    101. Re: Doing it wrong? by allo · · Score: 2

      Nope. You need to get the computer scientists point of view: Have a termination condition. And this is usually NOT a counter, but a condition, which needs to be fulfilled. i.e. you visited every node of a tree. This takes 1 mio steps? Yep, then it does. Your counter is arbitrary and/or hard to calculate and some measure for ppl who don't trust their code to have the right condition. Which is made easier by recursion, because functions tend to be more understable, as they are similiar to their math equivalents.

      The only thing to keep in mind: Don't recalculate values. Things like adding fib(n) and fib(n+1) shouldn't Take 2n+1 steps.

    102. Re: Doing it wrong? by allo · · Score: 1

      Tail OPTIMIZATION means, that your compiler moves the recursive call to the end, not you. You may do, because it often adds clarity, though.

    103. Re:Doing it wrong? by istartedi · · Score: 1

      It depends on the language. In Lisp dialects, it's practically required and IIRC compliant Scheme requires tail-call optimization so that it doesn't cause performance issues. My experience in C is that people prefer iteration. One time I did it in assembly and the professor marked me down, but I think it had to do more with combining self-modifying code *and* recursion. Dang, it was compact code though. You might even say it was elegant; but I get the lesson he was teaching and I would never do that now.

      --
      For all intensive purposes, "whom" is no longer a word. That begs the question, "who cares"?
    104. Re: Doing it wrong? by tepples · · Score: 2

      Who runs out of stack space on modern desktop computer platforms anyway unless you messed up your break condition or you've made very, VERY large data structures?

      People programming in languages that do not offer tail recursion optimization. For example, Guido van Rossum decided explicitly to exclude tail recursion optimization from Python because it would make the output from functions in the traceback module less clear.

    105. Re: Doing it wrong? by SharpFang · · Score: 1

      Try to process data in a tree structure without recursion. Say, scan all files in a directory tree for a string.

      Recursive approach:
      - iterate over every file and directory in current directory
      - if file, scan. If found, return the find, or add it to the list of found files.
      - if directory, open and restart self recursively with that directory as new root.

      Now if you want to do this iteratively, you're most likely to duplicate the recursive algorithm, except turning all the neat recursive calls the compiler normally makes for you into a hand-crafted monstrosity of storing current state on custom stacks.

      --
      45 5F E1 04 22 CA 29 C4 93 3F 95 05 2B 79 2A B2
    106. Re: Doing it wrong? by Z00L00K · · Score: 1

      Have fun with the linked directories in *Nix then... "ln /usr/local /usr/local/work/local"

      --
      If builders built buildings the way programmers wrote programs, then the first woodpecker would destroy civilization.
    107. Re: Doing it wrong? by PoopJuggler · · Score: 1

      It's not difficult at all. You just push nodes into a queue instead of using the system stack. Every iteration on the queue processes that set and possibly adds more nodes to the queue. Rinse and repeat. Recursion is a terrible solution to that problem because you've just limited the size of the trees that you can process.

    108. Re: Doing it wrong? by PoopJuggler · · Score: 1

      or you've made very, VERY large data structures

      Why do you think that's such an anomaly?

    109. Re: Doing it wrong? by allo · · Score: 4, Insightful

      That's a termination condition: If you ever visit a node, which was visited before, stop.

      You do not follow the symlink 1000 times and then abort. You follow it one time and the next time you see a mark "followed it" and stop. Without error as successful termination of a directory traversal.

      You think such a link would be an invalid condition, but it is actually not. And it isn't even a special case to the algorithm, which has the invariant "always take a node, which wasn't visisted yet until there are no such nodes".

    110. Re: Doing it wrong? by PoopJuggler · · Score: 1

      Just have a good exit criteria to avoid too deep recursions

      You've just crippled your processing ability.

    111. Re: Doing it wrong? by PoopJuggler · · Score: 1

      Or just don't use recursion

    112. Re: Doing it wrong? by Darinbob · · Score: 1

      It's undesirable only if you assume it scales. If you just call the same function a second time, then it's perfectly acceptable. It's no different than any other function call in that regard. Also note that all functional language programs are essentially highly recursive if written according to the language's style. Coming out and saying essentially "don't use this feature because there is a possibility of it being abused" means we can't use any computer language.

    113. Re: Doing it wrong? by Darinbob · · Score: 4, Funny

      There are people who think such things are beyond the ken of mortal man. Mere programmers should use libraries and only the gods themselves write the libraries.

    114. Re: Doing it wrong? by Darinbob · · Score: 1

      Gcc 4.8.4 does put the return address on the stack for everything but a leaf function.

    115. Re: Doing it wrong? by PoopJuggler · · Score: 1

      That's fine if it suits your needs, but to write robust and reusable code you avoid imposing limits like that if possible. Remember Y2K?

    116. Re: Doing it wrong? by Darinbob · · Score: 1

      Very often the amount of storage space used by a loop is as much or even more than using the stack. If you've got the stack space, then use it. Less memory used, less code space, less chance of leaked memory. I'm saying this as someone who works on very tiny systems. But too many programmers are stuck with superstitious nonsense, they refuse to use recursion because they heard it was bad but then go and make a huge array to do the same thing with a loop, or they refuse to use GOTO because it makes you go blind but they'll happily use break, return, throw, etc. They'll go and double the code size and make a confusing unmaintainable mess just to avoid some rule of thumb they heard once in school. Yes, the rules of thumb are very good things to follow, but they are not strict taboos they are meant to teach novices to beware of coding horrors like Fortran computed goto spaghetti code.

    117. Re:Doing it wrong? by tepples · · Score: 1

      However some language like JavaScript really don't give you much of an option. Such as a lack of a sleep command

      Of course there's a sleep command.

      setTimeout(function() { /* what to do after sleeping */ }, time_in_ms);

    118. Re: Doing it wrong? by Darinbob · · Score: 1

      If each call of a recursive function requires storage (state variables) then it will use a roughly similar amount of memory storage. Sometimes people avoiding recursion use MORE memory overall as they grab dynamically allocated memory from a heap which has a lot more overhead. Very often recursive programs with the right amount of stack space are smaller and faster than the non-recursive workaround.

      If you're on a unix like system, then you can assume your stack is very large, and the OS will allocate or free a new page when necessary, so these often work better than allocating a huge array. Sure, fibonacci in a loop will be more efficient (in C like languages, but in Scheme or Haskell it's more efficient recursively). But a tree walking or graph traversal function is very hard to make as efficient without recursion, and those types of problems are very common.

      (I've seen some people link all the nodes in a tree together with forwards/backwards links to avoid recursion even though it is harder to maintain and does not save memory, it's one of those silly tricks that sounds good at first but turns out to be something people will curse at when they try to debug it a few years down the road)

    119. Re: Doing it wrong? by Darinbob · · Score: 1

      A topic often overlooked by the average web programmer.

    120. Re: Doing it wrong? by Darinbob · · Score: 1

      Recursion does not lock you into depth-first traversal. What was your grade in algorithms class?

    121. Re: Doing it wrong? by Darinbob · · Score: 1

      Yes, those are more advanced algorithms. Sometimes you are forced to abandon the first readily elegant solution. But there are often other elegant solutions to investigate. Sorting algorithms for example, on mainframes most of the data would be on mag tapes and the RAM could not hold all that much, so you couldn't use quicksort or heapsort or most certainly not merge sort. But there are other types of sort and if you had a better sort for mainframes then you could make a ton of money (and they did).

    122. Re: Doing it wrong? by Darinbob · · Score: 1

      It also means that when you're using functional programming that the programmer with experience knows how to revise the loop to enable the optimization. It's one way you can spot the novice Scheme programmer.

    123. Re: Doing it wrong? by Darinbob · · Score: 1

      And yet it gets used in embedded systems with limited stack. Not arbitrary depth recursion of course. But calling the same function twice (with intervening fucntions) is often a convenient and efficient way to do some operations. Ie, start operation, go down a few calls, determine that some storage needs re-arranging before being able to continue, then recursively restart the original function (often optimized away with tail call optimization. I have seen code reviewer gag at that because they're afraid that recursion will go out of control despite the very obvious exit conditions that prove it won't, and they propose a complicated solution that doesn't save any additional memory. (generally the EE people freak out at recursion)

    124. Re: Doing it wrong? by Howitzer86 · · Score: 1

      So... if I can do it does that make me a master programmer? Recursion is great. I used it most recently for binary search. Yeah there's probably a library for that, but I had fun. I can also do heap sort.

      Can I work for Google now?

    125. Re: Doing it wrong? by Darinbob · · Score: 1

      I've seen cases where people follow their rules of thumb too rigidly. Ie, put all memory into pools, no exceptions. But then there's a case where I only need some temporary storage to live cross a couple functions, and there is absolutely without a doubt not enough memory if everything is pre-allocated during init. So I use the very tiny seldom used heap for this purpose, allocating the memory only for the duration of the operation. At which point someone complains that I should use a global buffer instead or malloc once only during init. Not because they thought about the issues and debated the various design choices, but because it was a knee jerk response to violating the "use memory pools" guideline.

    126. Re: Doing it wrong? by Lodragandraoidh · · Score: 1

      It's not a simple as that. If you are on a team of developers who are building applications on top of clearly defined APIs, all the heavy lifting from a systems perspective should already be done for you. This is to ensure the company doesn't end up with 15 different versions of the same code in each release that needs to be maintained in the future. I think mostly it comes down to the bottom line: a business doesn't want to spend money on building the same library over and over again.

      There are instances when low level systems programming is needed, and whoever is assigned that task should have the freedom to do what is needed to ensure the systems provided can perform at the desired level and provided whatever is necessary for security and so on. There is nothing canned that can do that, so you better have your best developers on that given the potential impacts to your customers and therefore to your bottom line.

      If you work for yourself - then do what you want since you're calling the shots.

      Policy choice is relative to your business risk/exposure. Ultimately whatever you choose to do with your own programming (if you work for yourself or you're just a hobbyist) will be proved out by your clients/users when they use (break) your software and systems. On the other hand, if you work for someone else as an employee, then you are bound to follow their rules, regardless of your views. You can try to change it, or you can find another job elsewhere.

      It's not simply a matter of these things being beyond anyone's ability, but it is also true that there are different levels of skills and experience that exist in a business environment. A good choice would be to partner your systems developer with your brightest applications developer to cross pollinate. Unfortunately, my experience also suggests that many companies don't do a good job of mentoring and growing talent within the company. People get assigned to silos and languish unless explicitly transfered to the group with a different focus. It really comes down to the philosophy of your employer.

      --

      Lodragan Draoidh
      The more you explain it, the more I don't understand it. - Mark Twain
    127. Re: Doing it wrong? by AmiMoJo · · Score: 1

      Can you describe a practical application of this where you couldn't just do the checks to see if the storage re-arranging first, or in a separate function that can then be re-called non-recursively? I can't think of one but I'm intrigued.

      --
      const int one = 65536; (Silvermoon, Texture.cs)
      SJW, n: "Someone I don't like, and by the way I'm a fuckwit" - AC
    128. Re: Doing it wrong? by Darinbob · · Score: 1

      Yes, IF you screw up. If you have very clear and unambiguous exit conditions then you don't screw up. The code is very clear, and yet a code reviewer may say "what if we run out of stack?" even though I proved it isn't a problem.

      I see the same thing with loops - programmer insists we must have a loop time out, even if it's reading hardware and the only reason for the loop is to handle clock syncing across domains, and the watchdog is active to handle the case of broken hardware.

    129. Re: Doing it wrong? by Lodragandraoidh · · Score: 1

      I think the real issue here is 'access to' versus 'elimination'.

      If you are your own boss, or you are a hobbyist, then this question is irrelevant. You can and should have access to every capability - it is up to you to manage based upon your own capabilities.

      In a business with a gaggle of programmers that is evolving over time, it is a different story. In that situation, you have developers of all different skill levels potentially, coming into and leaving the business if you are growing, and you have to take into consideration the risks associated with allowing poor code to impact your paying customers. In that case, I think it would make sense to create access limits for different programmers based upon their skill levels and areas of responsibility. You could also cross train and provide options for people without this access to prove they can be trusted to get higher level access to more of the 'shoot yourself in the foot' tools/constructs - which would expand your cadre without risking your business in the process.

      --

      Lodragan Draoidh
      The more you explain it, the more I don't understand it. - Mark Twain
    130. Re: Doing it wrong? by phantomfive · · Score: 4, Informative

      Most c compilers. Take this program: #include

      int recurse(int x) {
      if(x<=0) return 42;
      return recurse(x - 1);
      }

      int main() {
      return printf("%d\n", recurse(6502));
      }
      Then we compile it, adding -S so we can look at the assembly output:
      $ clang -S -O3 test.c The compiler recognizes that the printf() call is a tail call, and uses a jmp (which places nothing on the stack in x86), but it also recognizes that recurse() evaluates to a constant and returns that. I was going to post the assembly output for you to look at, but Slashdot said it had too many junk characters.

      There is a lot to complain about in terms of efficiency in clang and gcc, but tail recursion is a well-understood problem with a lot of research behind it, and they both do it well.

      --
      "First they came for the slanderers and i said nothing."
    131. Re: Doing it wrong? by ShanghaiBill · · Score: 2

      Or just don't use recursion

      A non-recursive algorithm to walk a tree structure still requires memory space proportional to the maximum depth of the tree, and still requires more memory for an unbalanced tree. You may need less memory than a call stack, since you don't need to store the instruction pointer or stack index pointer (BP register on an x86), but that is only a linear improvement.

    132. Re: Doing it wrong? by phantomfive · · Score: 1

      Searching through a tree is O(lg n), and that's how much space you're going to take on the stack, too. So, if you have a 1k stack (extremely small), and each function call places 10 bytes on the stack, then you're going to be able to search through 2^100 items in your binary tree before running out of stack in your search. If you have that many objects, you can probably afford to increase your stack size a bit.

      --
      "First they came for the slanderers and i said nothing."
    133. Re: Doing it wrong? by phantomfive · · Score: 1

      That sort of situation comes up, but in that case a B-tree is more appropriate. See also this comment. And this comment.

      --
      "First they came for the slanderers and i said nothing."
    134. Re: Doing it wrong? by allo · · Score: 2

      A tree has nodes and leafs. A leaf is where the algorithm terminates. A node has children, which can be followed.
      A search visits each node once, where links between nodes may alter when a node is visited first. When you visit a node, you mark it as visited and add the children (and links) to a queue or stack (depths first / breath first search).
      I do not see any need to visit a node twice, as you get no new information on the second visit.

    135. Re: Doing it wrong? by allo · · Score: 1

      Only if you don't know your data structures.

    136. Re: Doing it wrong? by Darinbob · · Score: 1

      Not easily without pulling out proprietary code, and I forget the details. Of course, things CAN be redesigned to avoid it. In this case it seemed more straight forward to just recursively call an earlier function in the call chain (exceptions with unwinding were not available and I think it would have helped in that situation). And it was known that the stack was ok with this case (it had just called a function with even more stack depth requirement). Nothing wrong with it except for the magic word "recursion".

    137. Re: Doing it wrong? by Megol · · Score: 1

      Most algorithms using recursion can use tail call optimizations, those that can't can be divided into those that would need temporary storage anyway and those that "wastes" space. An experienced programmer should be able to manage that.

      BTW why do you think that emulating recursion with a manually managed stack (or other storage) is any better? Because that's how one do many things non-recursively...

    138. Re: Doing it wrong? by Megol · · Score: 1

      So you don't use the hardware managed stack but create a software managed stack... You write unnecessary code with worse performance and claim that is better? If your trees overflow your stack then maybe you should use an OS that supports growing stacks?

    139. Re: Doing it wrong? by Megol · · Score: 1

      PNG?!? Get with the times dude - WebP is the cool thing!

    140. Re: Doing it wrong? by Megol · · Score: 1

      Of course, given a Turing machine one can port the algorithm to that too. But emulating a stack is still using a stack even if only on a higher level of abstraction.

    141. Re: Doing it wrong? by Darinbob · · Score: 1

      Embedded systems with a small chip. The default RTOS from the chip maker is often too large, the generic ones are inefficient, etc. For instance we have a demo board from a chip maker, we used their SDK to get things going and are now trying to clean stuff up. We ran out of code space already because their SDK used a nano-libc, brought in floating point, brought in a very bulky printf+console, etc. Writing out own drastically reduces memory usage. We can also use their registers directly and adapt the code into our style of device driver rather than using the somewhat bulky method that the chip maker had in their SDK. We also have to add details that most chip makers don't have in their libraries (low power states).

      Also when you're in control of the chip from reset until it gets to main(), you have to know the details of the runtime libary, especially if using C++.

      Silos can be a drawback. You often want to have an employee follow a project over its life. If you've got one guy only doing board bring up, then it gets tossed over the fence to application people, you often find a disconnect between competing needs. For example, the drivers used during testing mgiht not be the same drivers used in production which can lead to some subtle problems. Hhaving dealt with a hardware group that tosses boards over the walls and then scrubs their hands of it ("software can make a workaround for all problems") this is a major problem. This doesn't mean that everyone need to know everything, but it would be nice if everyone knew at least two things, or three even. In an *interview* you're going to be asked about things outside of the comfort zone for sure.

    142. Re:Doing it wrong? by jenningsthecat · · Score: 1

      Thanks for the clarification. I see the point and the value of working with the abstraction, instead of second-guessing its design and creating a non-standard, less well tested, and possibly less modular / portable substitute. I guess what I was questioning was not being able to see and understand the inner workings.

      --
      'The Economy' is a giant Ponzi scheme whose most pitiable suckers are the youngest among us and the yet-unborn.
    143. Re:Doing it wrong? by Megol · · Score: 1

      I'll just post the facts for Intel skylake, throughput (sustained in ideal case) and operations.

      push immediate
      push reg
      - 1/clock, 1 fused op (will execute as one store address + one store data operation)
      push mem
      - 1/clock, 2 fused ops (load + store address + store data)
      pop reg
      - 2/clock, 1 op (load)
      pop mem
      - 1/clock, 2 fused ops (load (stack), store address + store data)

      Compare this with the load/store operations of x86:

      mov [mem], reg
      - 1/clk, 1 fused op (store address + store data)
      mov reg, [mem]
      - 2/clk, 1 op (load)

      Push/pop instructions are small. They also (in all recent x86 processors) have a "free" stack pointer update that don't serialize dependent push/pop instructions (there will be overheads when manipulating the stack pointer though as that is done in the OoO execution stage while the update logic is done in the front end of the pipeline). The memory MOV instructions can use different address modes subset of [segment:basereg+indexreg*scale+offset] but are larger.
      I'll have to mention that x86 also support memory operands for most instructions (e.g. ADD reg, [mem]; SUB [mem], reg) however that doesn't change the general conclusion.

      In short stack operations are fast on mainstream processors. Tail call optimization is an optimization, just as a good compiler optimizes some kinds of complex loops it is another tool. But the main advantage of it isn't performance, it is avoiding blowing up the stack in a way that is unnecessary.

    144. Re: Doing it wrong? by K.+S.+Kyosuke · · Score: 1

      Chances are that if you can do that easily, you should have done it in the first place, and if you can't, there was a reason for that.

      If the first thing that comes to mind when thinking about how to implement a recursive algorithm without using compile time function stack isn't using some type stack then you really don't know what you're talking about. Go back to Computer Science class.

      Wow. No sequitur much? :-p Pray tell, how is that "easier" (or more natural)? Hey, two can play this fun game of yours: If the first thing that comes to mind when thinking about how to implement a recursive algorithm is to avoid the compiler's activation record stack and use some hand-crafted solution of yours, then you really don't know what you're talking about. Go back to Computer Science class.

      Anyway, my computer science class taught me that the one case for this when I need to replace the compiler-generated stack with something of my own is 1) when I have a non-deterministic program mapped onto some kind of interleaved execution or a program with complicated control flow transfers and 2) I don't have built-in continuations handy and/or the implementation doesn't use a programmer-manipulatable spaghetti stack.

      --
      Ezekiel 23:20
    145. Re: Doing it wrong? by K.+S.+Kyosuke · · Score: 1

      I'd be careful, however, with mentioning Common Lisp as one of the examples in that sentence, in case that the scope of the end of the sentence stretches to the beginning. While Lisps are generally recursion-friendly, Common Lisp is more of an ultimate imperative language: It has both a wide support for both basic (DOTIMES) and advanced (DO, DO*, LOOP) structured loops, and the ability to define new ones (such as ITERATE). CL is definitely not the first association that comes to my mind when a "give me examples of pervasive recursion" situation arises.

      --
      Ezekiel 23:20
    146. Re: Doing it wrong? by jbolden · · Score: 1

      Quite true but CL has tail recursions which was the questions. Schemes were more academic / functional in their feel.

    147. Re: Doing it wrong? by K.+S.+Kyosuke · · Score: 1

      Even in this case, a mere search can probably run in O(1) bounded stack space. Do you need the upper nodes after you're finished with the lower ones? If not, then tail-call.

      --
      Ezekiel 23:20
    148. Re: Doing it wrong? by K.+S.+Kyosuke · · Score: 1

      Perhaps a more correct claim would be that some CL implementations compile tail calls efficiently under some circumstances, while the language spec either doesn't say anything on that matter or implies that tail calls are not performed. It's not really better than what GCC does in terms of things you can rely on. It turns out that proper tail calls are necessary for the reason that when they're not guaranteed, some major expectations about program execution don't hold and one can't use them for these things at all. (It's similar to the DELAY/FORCE problem with some kinds of infinite streams in R5RS Scheme that was solved by adding a third operator in a SRFI.)

      --
      Ezekiel 23:20
    149. Re: Doing it wrong? by Pseudonym · · Score: 1

      All the Scheme and Haskell programmers. Every single one of them.

      --
      sub f{($f)=@_;print"$f(q{$f});";}f(q{sub f{($f)=@_;print"$f(q{$f});";}f});
    150. Re: Doing it wrong? by Pseudonym · · Score: 2

      I don't remember when I saw recursion the last time in production code, [...]

      See, I've worked in compilers, and software that has compiler-like components (e.g. input languages which resembles programming languages in some way) for a long time, and I see recursion all the time.

      Recursion is all over production code, you just don't work in those spaces.

      --
      sub f{($f)=@_;print"$f(q{$f});";}f(q{sub f{($f)=@_;print"$f(q{$f});";}f});
    151. Re: Doing it wrong? by Pseudonym · · Score: 1

      Recursion is undesirable because it doesn't scale - you run out of stack pretty quickly. There isn't really ever any need for recursion anyway as there's nothing you can do recursively that you can't do non-recursively.

      I once spent a week (a week) writing a non-recursive implementation of Tarjan's strongly connected components algorithm for precisely this reason. It was one of the most painful things I've ever done. (Before you ask: No, we could not use the "normal" iterative algorithm. The graph was too big for that.)

      You can do anything non-recursively, just like you can do anything in COBOL. But a lot of the time, you'd just be simulating the recursion stack anyway. Compilers are much better at this sort of thing than you are and have a lower hourly rate.

      --
      sub f{($f)=@_;print"$f(q{$f});";}f(q{sub f{($f)=@_;print"$f(q{$f});";}f});
    152. Re: Doing it wrong? by Pseudonym · · Score: 1

      Most modern C++ compilers can't because of all those modern C++ programmers who use RAII everywhere

      --
      sub f{($f)=@_;print"$f(q{$f});";}f(q{sub f{($f)=@_;print"$f(q{$f});";}f});
    153. Re: Doing it wrong? by Pseudonym · · Score: 1

      I would be willing to bet money that you don't need to compile any languages or diff any files or traverse any graphs on that CPU, though.

      --
      sub f{($f)=@_;print"$f(q{$f});";}f(q{sub f{($f)=@_;print"$f(q{$f});";}f});
    154. Re: Doing it wrong? by Wuhao · · Score: 1

      I don't believe that's true at all. The Y2K bug was an example of a problem that was foreseeable in the requirements of the program. Scientists in 1980 actually predicted that the year 2000 might happen in as little as 20 years.

      But if I have a problem where the upper bound on the number of calls to my recursive function that is much lower than the very large number of calls it would take to actually run out the stack, then there's no point in worrying about a stack overflow that is simply never going to happen. I'm not gonna buy 50 pounds of steak for a dinner party where I only invited 8 people.

    155. Re: Doing it wrong? by Pseudonym · · Score: 1

      Every recursion can be expressed as a loop or nested loops.

      Especially if you have a stack data structure too.

      --
      sub f{($f)=@_;print"$f(q{$f});";}f(q{sub f{($f)=@_;print"$f(q{$f});";}f});
    156. Re: Doing it wrong? by Pseudonym · · Score: 1

      I'm not sure what you mean when you say "you run out of stack pretty quickly."

      It depends what you're doing, as always.

      For many recursive algorithms (e.g. diff, balanced binary tree traversal, quicksort), unless you implement them stupidly, the maximum recursion depth is within a constant factor of the logarithm of the size of the problem. If the problem size is N, you will never have a call stack more than O(log N) calls deep. On a 64-bit machine, a 64-level-deep call stack is nothing. Hell, Mozilla or Unity 3D probably go 64 function calls deep on every key press.

      For other recursive algorithms (e.g. any graph algorithm based on depth-first search), the maximum recursion depth could be the size of the problem no matter what you do. If the problem size is N, a recursive algorithm might give you a call graph O(N) calls deep. That's not nothing, especially since stacks are typically smaller than they used to be because of multithreading.

      --
      sub f{($f)=@_;print"$f(q{$f});";}f(q{sub f{($f)=@_;print"$f(q{$f});";}f});
    157. Re: Doing it wrong? by Pseudonym · · Score: 1

      Of course you can. You just figure out maximum recursion depth, and then check if there's enough stack space.

      Your mission, should you choose to accept it, is to figure out the maximum recursion depth for Tarjan's strongly connected components algorithm given an arbitrary directed graph. It must be more efficient than just running the algorithm.

      --
      sub f{($f)=@_;print"$f(q{$f});";}f(q{sub f{($f)=@_;print"$f(q{$f});";}f});
    158. Re: Doing it wrong? by Pseudonym · · Score: 1

      Recursion can be good but can also easily be misused.

      I'm trying to think of a tool in the programmer's toolbox that this isn't true of, and I'm drawing a blank.

      --
      sub f{($f)=@_;print"$f(q{$f});";}f(q{sub f{($f)=@_;print"$f(q{$f});";}f});
    159. Re:Doing it wrong? by SeriousTube · · Score: 1

      It seems like the logical thing to use if for instance, you want to print the name of all of the files on a hard drive.

    160. Re: Doing it wrong? by pimproot · · Score: 1

      Are you sure you haven't seen any production code calling library or STL functions that are recursive? There are a lot of them out there.

    161. Re: Doing it wrong? by flux · · Score: 1

      My algorithm class was just fine. But just for sake of discussion, please convert this depth-first binary tree iteration to breadth-first:

              void visit(Node* node)
              {
                  if (!node) return;
                  printf("%d\n", node->value);
                  visit(node->left);
                  visit(node->right);
              }

    162. Re: Doing it wrong? by flargleblarg · · Score: 1

      *Every* embedded software design standard expressly forbids recursion

      My embedded software design standard doesn't.

      Thank you. GP is a fucking moron. As you go on to point out, many algorithms have natural limits on the recursion depth. A recursive mergesort, for example, can never go deeper than ceil(log2(n)) calls, where n is the number of elements to sort. If you have room on your stack for 30 calls deep, you can sort a list of a billion items. People who say recursion has no place in embedded software design either haven't thought their arguments through very carefully, or are very inexperienced programmers, or are just plain dumb.

    163. Re:Doing it wrong? by Tough+Love · · Score: 1

      GOTO/GOSUB on the other hand have no practical use anymore

      Beg to differ. In C/C++ if you need to break out of a loop from inside a switch statement your choices are: add an extra variable that obfuscates your code; otherwise obfuscate your code with organizational contortions; use an ugly but obvious goto. Another common use case for goto is, taking error handling out of line so it doesn't obfuscate the main algorithm. And here is one you will probably never run into given your rather limited "real programmer" perspective: implementing state transition networks. Very elegant with goto, the topology is exactly like the state transition diagram that you are hopefully using for reference.

      --
      When all you have is a hammer, every problem starts to look like a thumb.
    164. Re:Doing it wrong? by Tough+Love · · Score: 1

      It's possible to write any traversal algorithm using loops, without any recursion.

      If your algorithm pushes values onto a stack and modifies its control flow according to what it pops off the stack then it is still recursion. You meant "without native recursion". In general, arbitrary recursive data structures are impossible to traverse without recursion. For some theoretical background, look here.

      --
      When all you have is a hammer, every problem starts to look like a thumb.
    165. Re:Doing it wrong? by Tough+Love · · Score: 1

      if that requires building your own stack, you haven't really gained anything.

      True in many cases, however if you are sure of the maximum recursion depth than you may be better off allocating your stack on the stack. Also, not all recursion is about traversing trees. The fastest parsers are written iteratively, and have the ability to examine more than one stack level to make a decision. Examining data in caller stack frames using native recursion is not pretty at all.

      --
      When all you have is a hammer, every problem starts to look like a thumb.
    166. Re: Doing it wrong? by Darinbob · · Score: 1

      A few ways to do it. Not the easiest but they exist.
      - use an array based tree, which you would see a lot in early algorithm papers or books for languages without pointers. Ie, Node n's children are at 2n+1 and 2n+2. Yes it's cheezy.
      - use a counter of the depth you are at; print all nodes at depth 1, then all at depth 2, and so forth. Cheezy too and it's O(n^2).
      - add an extra queue, this is a common approach. If each node already has a next pointer then it's straight forward, but slightly cheezy as it assumes extra storage beyond the stack.
      - Use a functional language (where there isn't a "stack" per se), and there are some advanced algorithms. But hard to convert to C or Python style.

    167. Re: Doing it wrong? by flux · · Score: 1

      Yes, there are of course ways to do it as you can always convert an iteration to recursion. But, it's pretty much pointless unless you're working with a pure language. If you're going to use a queue, why not just iterate?

      In particular, a version that collects a queue is easily parametrized to work breadth first, depth first, or some alternative strategy.

              enum Mode { DepthFirst, BreadthFirst };

              void visit(Node* root, Mode mode)
              {
                      std::list work { root };
                      while (work.size()) {
                          Node* node = work.front();
                          work.pop_front();
                          if (node) {
                              printf("%d\n", node->value);
                              switch (mode) {
                              case DepthFirst: {
                                  nodes.push_front(node->left);
                                  nodes.push_front(node->right);
                              } break;
                              case BreadthFirst: {
                                  nodes.push_back(node->left);
                                  nodes.push_back(node->right);
                              } break;
                              }
                          }
                      }
              }

    168. Re:Doing it wrong? by jellomizer · · Score: 1

      Yes but that forces you to run a function. If you need to sleep in a loop then you need to change your function to be recursive

      --
      If something is so important that you feel the need to post it on the internet... It probably isn't that important.
    169. Re: Doing it wrong? by dolmen.fr · · Score: 1

      So "no recursion" is a strict rule for your environment.
      That's doesn't make it a general rule for programming.

    170. Re: Doing it wrong? by angel'o'sphere · · Score: 1

      You mean recursion inside of the compiler, right?

      That is not what we call "production code", even if it is strictly speaking production code.
      And: that code you usually don't see anyway. Unless someone is working in crafting compilers, like you :D

      My argument was not "against recursion" but for recursion as basically all arguments against it are either wrong, missleading or in appropriated. Perhaps you did not see my other posts.

      --
      Cost free eBook I read (by iBook/Kobo/Amazon/ObookO/Gutenberg etc.): "The Green Odyssey" by Philip Jose Farmer.
    171. Re: Doing it wrong? by Pseudonym · · Score: 1

      That is not what we call "production code", even if it is strictly speaking production code.

      Haha, well, the person who wrote the query optimiser in your database server would probably differ with that opinion... That was my job a long time ago.

      Perhaps you did not see my other posts.

      Of course. This is Slashdot.

      --
      sub f{($f)=@_;print"$f(q{$f});";}f(q{sub f{($f)=@_;print"$f(q{$f});";}f});
    172. Re:Doing it wrong? by dolmen.fr · · Score: 1

      Unless you write code directly in assembly, the stack is far from what you "the hardware stack".

      A recursive algorithm use the function call stack and the translation of that stack to the CPU stack is dependent on the compiler or the runtime environment. The limits of that stack is also dependent on the runtime environment, and the program may even have control of the size of that stack at runtime to raise the limits if necessary. The OS may also give control to the OS user on the size of that stack (man setrlimit) outside of your program (the program exhausts the stack? run again with a higher "ulimit -s").

      Computer resources (not just the stack) are always limited anyway. Using one algorithm or another is always a tradeoff on which resource you may exhaust first. The stack size is not always the first exhausted resource for a recursive algorithm. So "Never use recursion" should not be general rule.

      Unrolling a recursive algorithm to loops also has a cost: the code is often longer (in lines of code) and more complex (because you have to maintain the state that is handled in the stack in the recursive case), so may be harder to maintain and may have more bugs. You'll often have to write unit tests that compare the correctness of the unrolled implementation against the (simpler) recursive one.

    173. Re: Doing it wrong? by angel'o'sphere · · Score: 1

      Calling a library function probably yes, but that a programmer wrote a recursive function, can't remember that.
      OTOH, I'm not hunting for stuff like this.
      In other words: if I have not seen one, it does not mean there are none. It only means I did not run over it through code reviews or debugging etc.

      --
      Cost free eBook I read (by iBook/Kobo/Amazon/ObookO/Gutenberg etc.): "The Green Odyssey" by Philip Jose Farmer.
    174. Re:Doing it wrong? by dolmen.fr · · Score: 1

      There is no generic answer to this question. And that's why also there is no generic answer to the question "should I use a recursive function".
      As a programmer that's your responsibility to use the right tool for the job.

    175. Re: Doing it wrong? by jeremyp · · Score: 1

      In these cases, if you use loops, you're going to be making up all the stuff recursion is good for, and you're going to be maintaining your own stacks. There's no advantage to doing this rather than using recursion.

      Yes there is. If you use your own stacks, you have visibility over when the stack space is going to run out. It will also have a smaller memory footprint than recursing using the system stack since each stack frame has to contain the return address and the link pointer for the previous stack frame, as well as space to save local variables.

      I'm not advocating avoiding recursion but there are advantages to not using it when you expect a lot of levels of recursion.

      --
      All I want is a secure system where it's easy to do anything I want. Is that too much to ask ~~ Randall Munroe
    176. Re:Doing it wrong? by joboss · · Score: 1

      Perhaps they want you to just use a stack. It can be cheaper.

    177. Re:Doing it wrong? by holophrastic · · Score: 1

      I'm also stunned to see recursion in the list, but I can certainly agree that I almost-completely stopped using it about a decade ago.

      Now that we're discussing it, I can see why. Adding new functionality or debugging or even tracing recursive code is annoying. Like any really magical regular expression (which often gets executed recursively!) good recursion is tight-code that really blocks out a lot of diagnostics. For example, it's really annoying to dump your structure mid-recursion and understand what's happened and what's still to happen.

      It would seem that I replaced most of my recursion with task queues -- which basically just flattens recursion into iteration -- so each subtask can be done incrementally, making tracing and adding subtasks natural efforts.

      I'm in the business-application world, business-logic is rarely recursive because human tasks are rarely recursive. I'm sure it's different in a more science-application world.

    178. Re: Doing it wrong? by david_thornley · · Score: 1

      Hey, I was congratulating myself for not writing "GIFs at 11". Thing about getting with the times is that it never stops, I guess.

      --
      "When you have eliminated the unacceptable, whatever is left, however improbable, must be the truthiness" - Holmes
    179. Re: Doing it wrong? by petervandervos · · Score: 1

      Also embedded software engineer and don't like to use dynamic memory allocation.

      The only time to use recursion is when I have to print (to serial or something) a number in binary form and you can not use printf because your system is to small.

    180. Re: Doing it wrong? by JoeDuncan · · Score: 1

      it doesn't scale - you run out of stack pretty quickly

      LOL - Clearly you skipped out on the "Algorithms 101" lecture on "Tail Recursion"!!!

    181. Re:Doing it wrong? by geoskd · · Score: 1

      Computers tend to be bigger and more powerful than we actually need, and sacrificing raw efficiency for things like readability, maintainability, etc., is completely standard in most cases.

      That is absolutely not true. The difference between a 50 mips processsor and a 100 mips processor is about $0.50. If you are shipping a million units a year, that is half a million dollars a year you just wasted. I've worked places where co-workers were fired for wasting less money. I get paid *very* good money because I don't waste money. That "processor power is cheap" mentality is the reason why I have a desktop CPU that is 75x faster than the one I had 15 years ago, and everything runs *slower* today than ever as measured in the time it takes to perform basic tasks. Programmers need to get it through their heads that CPU cycles cost money, and wasting other peoples money is not a good way to run a business and by extension produce code for one. Some small degree of waste is acceptable, but wasting cycles by using a programming construct that is not as good, for reasons touching on ignorance is simply unacceptable, especially when there are any number of standards groups that have condemned recursion.

      --
      I wish I had a good sig, but all the good ones are copyrighted
    182. Re: Doing it wrong? by phantomfive · · Score: 1

      That's a toy program though. There's a lot of ways to screw up so that your recursive function is not eligible for tail recursion optimization.

      Show a program that screws it up, then.

      You should avoid recursion when you can imho.

      That's a really dumb rule, tbh. Make recursion your friend, get good at it, and then you won't be afraid of it anymore.

      --
      "First they came for the slanderers and i said nothing."
    183. Re: Doing it wrong? by spongman · · Score: 1

      if you're running out of stack on a 64-bit machine, then your OS's addressing scheme sucks.

      "8.1 exabytes should be enough for anyone" -- Bill Gates

    184. Re:Doing it wrong? by tender-matser · · Score: 1

      On newer browsers, you can sleep in a loop, or more generally, "return" from an asynchronous API.
      All you have to do is to wrap your code in a generator.

      function sleep(f, ms){ setTimeout(j=>f.next(), ms) }
      function wget(f, url){
              fetch(url).then(r => r.ok ? r.text().then(t => f.next(t)) : f.next())
      }
      var frame = function*(){
              for(var url in url_list){
                      code...
                      var text = yield wget(frame, url);
                      more code...
                      yield sleep(frame, 500);
                      more code...
              }
      }(); frame.next()

      It's a pity they managed to make it so awkward -- I don't understand why they have to take simple concepts from scheme or smalltalk and wrap them in obtuse abstractions (generators, iterators, factories, whatever).

    185. Re:Doing it wrong? by syntotic · · Score: 1

      Pardon me but: 1) GOTO is IRREPLACEABLE in the original BASIC; 2) GOTO is deemed harmful because it makes some compiler emission code and optimizations inefficient; 3) exception handling provides a GOTO mechanism where it was most useful, ie, bailing out of deep code unable to continue; and 4) following GOTO is less stylistically elegant and much less aesthetic MOST OF THE TIME than a full fledged deep branching-looping algorithm, including the mostly arbitrary goto tags, which usually go better into comments. Those are the reasons why GOTO is better avoided and why it is still included in parsing. I have used code twice to completely bail out of a complex algorithm in the meanwhile while I could come out of the mind boggling effort of producing the same code with branch exhaustion. Only temporarily to make ends meet, waiting for a further optimization effort, or for the other case, to test deep branches before engaging in code clutter by programming other deeply inner branches and calculating their foldings to become a one-time-pass algorithm. As for recursion... the problem with recursion is that you relinquish control of the execution stack to the language compilation and maybe OS support, so you DO lose control of your process while it is recursing. IT is more than OK for functions you know will execute short, like in Fibonacci you know will not be called beyond the tenth level. I have counted 200 recursions start becoming problematic, for instance... But the solution is simple, just implement recursion using your own pair of stacks, which can be encapsulated in a nice recursion class framework for total transparency.

    186. Re: Doing it wrong? by mcswell · · Score: 1

      I used it all the time in Prolog, it's really the only way to program in that language.

      Oh, yeah, I guess that was nearly two decades ago... Time flies when I'm having fun.

    187. Re: Doing it wrong? by mcswell · · Score: 1

      That's true of a tree, but it's not necessarily true of a Direct Acyclic Graph (DAG). In particular, it's not true of a DAG which is not a tree.

    188. Re: Doing it wrong? by mcswell · · Score: 1

      Smart compiler. What does it do to a program that calculates 64 (say) digits of pi?

    189. Re: Doing it wrong? by phantomfive · · Score: 1

      Don't know, do you have some sample source code I can try compiling?

      --
      "First they came for the slanderers and i said nothing."
    190. Re: Doing it wrong? by mcswell · · Score: 1

      It's sort of a joke. A *very* smart compiler would look at the code, determine that it was trying to calculate the digits of pi, and perform the optimization: substitute the value of pi to the requisite number of digits, calculated (if need be) at compile time. I'm sure I saw that somewhere, but a quick search didn't turn anything up. Just this:

      "Never put off until run time what you can do at compile time."

      - David Gries, in "Compiler Construction for Digital Computers", circa 1969.

    191. Re: Doing it wrong? by allo · · Score: 1

      Hmm, i think of the following algorithm:

      add a root node to a queue
      get an element from the queue
      when you visited the element, stop
      else process the element and add all linked elements to the queue
      mark all graph links (child directorys and symlinks) as visisted.

      complexity of a directory traversal O(n log n) where n is the tree depth
      complexity of "is marked": We use a tree. insertion is O(log m), lookup is O(log m) for the number of graph edges.
      The total complexity is then O(n log n + n log m) (which is another way to express n*log(max(n,m))), which is for normal directory structures (number of links proportional to number of directories) O(n log n)

      did i forget something in this algorithm? I did not test it, yet ;-).

    192. Re:Doing it wrong? by jellomizer · · Score: 1

      Still it is a recursive sleep algorithm just kinda hacked to give functionality of a normal sleep command.

      --
      If something is so important that you feel the need to post it on the internet... It probably isn't that important.
    193. Re: Doing it wrong? by psmears · · Score: 1

      A non-recursive algorithm to walk a tree structure still requires memory space proportional to the maximum depth of the tree,

      Not always, no. For example, if the nodes in the tree all have a reference to their "parent" nodes (which they may already have for other reasons), you can traverse the tree in O(1) space. That doesn't help if the nodes don't have parent references (adding them would increase the size of the tree by O(n) which is usually much bigger than O(max depth)), but if the tree is sorted (as it typically is) you can find the parent of a node in O(1) space, albeit in O(max depth) time.

  2. Intent by The+Evil+Atheist · · Score: 1

    Just use the one with the more clearer intent, unless it really affects performance.

    Just keep in mind that familiarity is not the same as clarity.

    --
    Those who do not learn from commit history are doomed to regress it.
  3. Re:Recursion is dead! by j_kenpo · · Score: 1

    I use JMP's if I'm messing around on some old micros, does that count?

  4. Re:Recursion is dead! by MichaelSmith · · Score: 1

    How is goto return better than just return?

  5. Combining two of them by johnw · · Score: 1

    Not sure about the idea of recursion being forgotten, but I used to work on a system (GEC 4000 series) which had no stack, making recursion slightly more difficult. The neat way of achieving it was by using a goto, back to the beginning of the function.

    1. Re:Combining two of them by Misagon · · Score: 1

      ... which is how compilers use to optimize a recursive function that calls itself at the end.

      --
      "We mustn't be caught by surprise by our own advancing technology" -- Aldous Huxley
    2. Re:Combining two of them by david_thornley · · Score: 1

      Pascal was originally implemented on a CDC 6600, which had no call stack. (The way to call a subroutine was a Return Jump, which jumped to a particular memory word and wrote a jump back in the word before the subroutine, so the subroutine jumped to its own location - 1 a the end.

      --
      "When you have eliminated the unacceptable, whatever is left, however improbable, must be the truthiness" - Holmes
  6. Poor article? by kwerle · · Score: 3, Informative

    Recursion is an easy way to implement solutions to a number of problems. But if you don't have a clearly finite depth then it can be dangerous. There is often a way to use a loop that doesn't pile on the stack the way recursion can.

    That said, it doesn't seem like it belongs in this list.

    Frankly, it doesn't seem like a great article. Yup, those things can be misused. Yup, if something can be misused, it will be. I use ruby, so I have access to at least 3/4 of these dark techs. Whatever.

    1. Re:Poor article? by grep+-v+'.*'+* · · Score: 5, Interesting

      Recursion is an easy way to implement solutions to a number of problems. But if you don't have a clearly finite depth then it can be dangerous.

      In '88 (90?) I had a copy of Unix Sort for PC (MS-DOS) complied in I believe a Lattice C compiler from LifeBoat. It worked fine but ran slow as a dog, and this was when IBM AT were fast. So I found the routine that did the actual in-memory sort and made it recursive. It easily worked over 5x as fast but had the slight problem of ABENDing when it ran out of stack space, which the old version didn't have.

      So I fixed it: I left the recursive sort in place but did a free space stack check on entry. If there was less than 4K (4K!) left I switched to the slower non-recursive routine. I was able to keep sort speed around 4x of the original slower program but still have the program always successfully complete.

      It was a simple fix, but I have to admit I was impressed with myself for implementing that.

      EVERYTHING can be misused. Add meaningful comments so they are not misunderstood. Write everything for your peers and their less-experienced colleagues. If you're a genius who writes working code that no one else understands, you're not a genius. But if the person following you really is a blithering idiot, then nothing you do will help.

      --
      If the universe is someone's simulation -- does that mean the stars are just stuck pixels?
    2. Re:Poor article? by TheRaven64 · · Score: 4, Informative

      Recursion used to be a lot faster on x86 then non-recursive solutions (to the extent that the Microsoft C++ compiler would turn iterative code into recursive) because stack pushes and pops were a lot cheaper than any other memory addressing mode (and are still single-byte instructions, so have good i-cache usage). On modern x86 chips, there's some fairly complex interaction between store forwarding and register rename logic that makes storing values relative to the stack pointer cheap, but manipulating the stack pointer expensive. Whether an iterative or recursive implementation will be faster depends a lot on the microarchitecture and it's generally not a big enough win to make the code less readable if one form is easier to understand than the other.

      --
      I am TheRaven on Soylent News
    3. Re:Poor article? by Lodragandraoidh · · Score: 1

      What if you get hit by a bus?

      --

      Lodragan Draoidh
      The more you explain it, the more I don't understand it. - Mark Twain
  7. Re:Kernels should only be in assembler by MichaelSmith · · Score: 1

    Well yeah the complex stuff should be in user land, as with Minix. But C is just an assembler language. There can't be may things you need to do in a kernel which can't be done in C.

  8. Re:Recursion is dead! by Anonymous Coward · · Score: 1

    IMHO just for cleanliness, and can help with debug later. It allows you to have a single exit point to a function, so in that case if you want extra debug/logging/whatever as to why its exiting at that point you can add it right in the goto instead of having to go to every return statement. Even though your most likely going to have logging at those error points anyway it provides one central location if you need to debug something

  9. Re:Recursion is dead! by Anonymous Coward · · Score: 3, Informative

    Also forgot to add to this, memory cleanup is another big one. Instead of having to free in every single possible 'if error return' block you can have it always do a check and free in the goto

  10. Re:Recursion is dead! by Anonymous Coward · · Score: 4, Interesting

    History lesson.

    https://en.wikipedia.org/wiki/Considered_harmful

    GOTO considered harmful, raised out of a generation of BASIC programmers that knew only too well that they were horrible to deal with. Early micros had RENUM so you could move line numbers around and attempt to preserve GOTOs. They were awful, but only on 8-bit micros.

    Later C used them in local jump structures using LABEL: which wasn't even remotely as bad as BASIC. Everyone is allergic to GOTO from BASIC so the whole idea got canned along with it - baby out with the bath water. This is why we say "GOTO considered harmful, considered harmful". The idea that a code construct is so repulsive that we've condemned it to never be used again.

    GOTO is useful. Certain forms of C exception handling code benefit from GOTO immensely. They make the code both more readable and more performant. Unfortunately we can't submit this code because in a code review...."GOTO considered harmful" circa 1990. Brainless dogma has won over thought. I've seen generations of programmers that would never consider GOTO to be a valid keyword. They won't consider it on the basis of a decades-old argument that was meant for a different language in a different age. As much as I might be right I won't pass a code review, so I don't use it.

  11. Re:Recursion is dead! by _merlin · · Score: 1

    People seem happy to hate on goto while using other things that are goto in all but name (break, continue, return, throw). Throw/catch is particularly useful as a non-local goto in places where you want to catch some kind of condition (usually an error) that can be detected in lots of places. C++ RAII eliminates most of the need for local gotos though - you can make local classes with destructors for cleanup, with the added benefit that it's exception-safe.

  12. Re:Goto by MichaelSmith · · Score: 1

    The whole point of recursion is to use the stack. If not some sort of while loop is probably called for.

  13. Re:Recursion is dead! by vux984 · · Score: 2, Insightful

    How is goto return better than just return?

    In C in particular, which is the ONLY place I'll use goto... i might have a pattern like something like...


    {
    a = malloc(something)
    if malloc failed goto e1
    b = malloc(something2)
    if malloc failed goto e2
    c = malloc(onemorething)
    if malloc failed goto e3 ...some code...
    open a file... if error happened goto e3 ...some code...
    some other error happened goto e3 ...some code... /*cleanup*/
    e3:
    free (a)
    e2:
    free(b)
    e3:
    return;
    }

    The goto sequence cleanly handles the memory free. Obviously you wouldn't want to just return after the 3rd malloc failed.

  14. Re:Kernels should only be in assembler by Anonymous Coward · · Score: 1

    Even if you have code that lives in the same address space as the kernel, it isn't necessarily part of the kernel. An optional set of modules is fine to load in the same address space if your architecture is one of the many that are bad at context switching between user and supervisor modes. Usually it's cache flushing related to page table updates that what burns you.

    C is definitely not assembler language. Maybe it was before ANSI got their hands on it. Most of the core routines that I consider important to kernel development cannot be done very effectively in C. The implementation is often long, tedious and inefficient when done in C. Saving and restoring contexts from an interrupt handler on ARM is a fine example, you need to embed some rather specific instructions to accomplish this. And sadly gcc still has subtle bugs when generating ISR returns if you do something silly like turn optimizations off.

    A small boot loader for a factory diags project took me about 1500 lines of C, but a little under 300 lines of assembler. That should be pretty shocking given that assembler tends to be pretty lengthy. The C had to do a lot of advanced gymnastics that my coworkers had trouble understanding and frequently would break, the assembler is nothing special and is pretty serviceable once there are sufficient comments. But full disclosure, my coworkers didn't bother modifying my assembler version of the boot loader. Because once it gets to a certain point it is able to load arbitrary binary blobs and execute those in a very DOS .COM file like way. The design was patterned more after CP/M than DOS, but on 64-bit ARMv8 instead of 16-bit x86 or 8-bit 8080.

  15. Obvious answer by aaribaud · · Score: 3, Insightful

    It depends.

    In some cases, you want to allow goto statements, for instance because they help manage failure handling without adding condition or exception constructs.

    In some case, you want none of these gotos, because you are using processes or tools which are (partly or entirely) not compatible with them, and you need these tools to work more than you need gotos.

    In some cases, you don't want recursivity because the contex does not favor them (think embedded SW with restricted stack size).

    In some cases you want recursion because it makes code simpler and closer to the principles behind it, thus more maintainable.

    In some cases, you want class-like constructs in C be don't want C++ because the legacy code, people involved, time alloted, or general context just does not allow you to rewrite the whole thing.

    Etc.

    1. Re:Obvious answer by jbolden · · Score: 1

      I don't agree with you. I use recursion all the time on infinite data structures where obviously the inner loops using recursion can't limit. That has to be handled by the out loops creating the evaluation context.

    2. Re:Obvious answer by david_thornley · · Score: 1

      Exceptions are for exceptional situations, and make handling them easier. (If they don't, don't use exceptions.) If people used goto only in exceptional situations, or only where it was clearer than the alternatives, Dijkstra would never have written against it.

      --
      "When you have eliminated the unacceptable, whatever is left, however improbable, must be the truthiness" - Holmes
  16. Re:Maintenance... by bool2 · · Score: 1

    That's not a reason to outlaw their use. If all you have are mediocre developers then no amount of coding standards will help you.

    Less experienced developers can learn from good code. Sure they will get it wrong as they find their feet - we have code reviews to deal with that - but we shouldn't seek to handicap them by taking away tools they can use to express themselves.

  17. Some things are better left alone by mridoni · · Score: 1

    Do what you want with your GOTOs, but do not bring ALTER back.

    1. Re:Some things are better left alone by tepples · · Score: 1

      We have ALTERable GOTOs in modern languages. They're called function pointers.

  18. Re:Recursion is dead! by sjames · · Score: 3, Informative

    It gives you a chance to unwind something (like taking a lock) before the return.

  19. I know what will happen one day. by LordHighExecutioner · · Score: 4, Insightful

    Somebody will publish a paper entitled: "Class statement considered harmful." and he will be applauded as the new IT guru!

    1. Re:I know what will happen one day. by johannesg · · Score: 3, Interesting

      That already happened; apparently some people now feel inheritance is bad. I've seen a few of their arguments (rants, really), and it seems to boil down to "you can get confused", "some inheritance trees are too deep", and a whole bunch of irrational ranting besides.

      I do agree that we've(*) suffered from an overload of policy factory manager producer singletons (which seems to be an important part of many of those rants), but actually inheritance is a tool that serves me well in many, many cases. It's certainly way better than having type-specific switch statements all over the place...

      (*) I say "we", but actually it seems like a fairly typical Java affliction, more than a general OO thing...

    2. Re:I know what will happen one day. by DrXym · · Score: 1
      Multiple inheritance of concrete classes generally is bad due to issues like diamond patterns. Single inheritance or multiple inheritance where only one class is concrete and the rest are interfaces is generally ok. That's assuming all the code resides in the same binary since fragile base classes can screw everything up.

      Stuff like virtual destructors, rule of three / five etc. in C++ demonstrate some pretty fundamental problems that can only be overcome with best practice. Inheritance in Java is much nicer.

    3. Re:I know what will happen one day. by cheesybagel · · Score: 4, Insightful

      IMO class inheritance is useless. Interfaces and properties are a good idea though.

    4. Re:I know what will happen one day. by DrXym · · Score: 1
      I wouldn't say it's useless. I'm writing a lot of Rust at the moment and lack of inheritance can be a pain in the ass especially when implementing some UML that expresses inheritance.

      The workaround is use composition. Make the base class (struct) a member of the things that "derive" from it and a trait that allows callers to call the composite and map the calls onto the base. It's a pain though and for more than one "subclass" involves macros to generate the boiler plate. It would be nice if Rust had a #[derive_composite(base)] that generated this boiler plate automatically.

    5. Re:I know what will happen one day. by rock_climbing_guy · · Score: 1

      I will applaud when they say "class statement considered harmful in Javascript because it reinvents the wheel"

      --
      Wh47 d1d j00 541, 31337 15n't t3h r0xor5 ne m0r3???
    6. Re:I know what will happen one day. by david_thornley · · Score: 1

      Inheritance in Java is also more limited than inheritance in C++. One of the design goals of Java seems to have been to produce a safer C++ at the cost of expressive power.

      --
      "When you have eliminated the unacceptable, whatever is left, however improbable, must be the truthiness" - Holmes
    7. Re:I know what will happen one day. by david_thornley · · Score: 2

      As someone who has worked with complicated C++ software for something like fifteen years, inheritance is very valuable. It keeps some of our core concepts understandable. It can clearly be overused, of course, but that's true of all language constructs.

      --
      "When you have eliminated the unacceptable, whatever is left, however improbable, must be the truthiness" - Holmes
    8. Re:I know what will happen one day. by david_thornley · · Score: 2

      Beware of arguments that seem rational and are not based on experience.

      --
      "When you have eliminated the unacceptable, whatever is left, however improbable, must be the truthiness" - Holmes
    9. Re:I know what will happen one day. by david_thornley · · Score: 1

      There's other patterns that work with multiple inheritance, such as only one superclass having superclasses of its own. This allows "mixin" classes, which provide one specific behavior. We make extensive use of these, and don't have problems with them.

      What you're finding more awkward in C++ inheritance has nothing directly to do with inheritance, but with C++ resource management. There's no problem with including a virtual destructor on every class you don't mark "final". The rule of three/five exists because a class may own resources that have to be cleared out or dealt with on destruction, and the C++ lack of a reference type distinction. With garbage collection and no destructors (finalizers are not destructors), Java makes cleaning up memory a lot easier and cleaning up anything else more difficult, but by removing resource management from the class structure it does make inheritance easier to get right.

      --
      "When you have eliminated the unacceptable, whatever is left, however improbable, must be the truthiness" - Holmes
    10. Re:I know what will happen one day. by ebvwfbw · · Score: 1

      That already happened; apparently some people now feel inheritance is bad. I've seen a few of their arguments (rants, really), and it seems to boil down to "you can get confused", "some inheritance trees are too deep"...

      In other words, it's bad because they are too stupid and get confused. I've run into people like that. It's fun to ask them how they would do it. This is often an exercise in "how to keep an idiot busy."

  20. Re:Recursion is dead! by MichaelSmith · · Score: 1

    char *a = NULL;
    a = malloc(something);
    if (a) free(a);

    and so on.

  21. Re:Recursion is dead! by Dutch+Gun · · Score: 1

    Gotos in C are like operator overloading in C++. It's a handy mechanism when used judiciously, in very specific circumstances. If GOTO is abused, used to jump all over the place (which it can literally do), yeah, of course it's bad. But then again, you can always name a function:

    int AddTwoNumbers(int x, int y);

    when it actually multiplies two numbers. Does this mean named functions are bad, because they could be misused? Why would you purposefully abuse the language like that?

    Generally speaking, the rule of thumb with GOTO seems to be to use it in exceptional circumstances, such as error handling. I don't see anything wrong with that. Honestly, it would be better if there were a more specific and constrained mechanism for doing that, but you use the tools you have.

    --
    Irony: Agile development has too much intertia to be abandoned now.
  22. Re:Recursion is dead! by johannesg · · Score: 4, Interesting

    Just like Linus, you seem to fail to understand the problem. Dijkstra argued against *unstructured* jumping around, since this made programs very hard to understand (look up some source from that era to get an idea of what he was arguing against. It wasn't just a single goto here or there, it was 'using goto for everything we now use structured constructs for, like loops, switch-statements, etc.). Dijkstra argued for replacing those goto's with structured jumps as much as possible. And guess what? By and large, the software world has done so, and become much better for it.

    I very much doubt he meant for his statement to become dogma in the way it has, and he certainly wasn't arguing for the complete removal of all forms of flow control, structured or not (as you and Linus seem to think). Goto, like everything else, is a tool. It has its place. You should not use it if a better tool is available, but you should also feel free to use it if it is the best you have. And the fact that assembly _only_ has goto is immaterial. The whole point is to allow reasoning over the language in the language itself.

    Dijkstra always struck me as a sensible, practical man. He wrote about an argument he had about driving printers. In his era, printers could only accept a character once every so often (because they were slow, mechanical beasts, without much in the way of buffering), so his colleagues wanted to intersperse printing code with other processing. Dijkstra didn't like this, and wanted to print using an interrupt that would signal when the printer needed a new character. His colleagues fought against that: not only were interrupts more costly than just interleaving printer output with normal code, but Dijkstra was 'throwing away' valuable information about printer timing that could be used to improve efficiency!

    His colleagues were, of course, completely right - right up until the moment when the hardware changed, and their programs no longer worked, that is...

  23. What the article says by jbolden · · Score: 5, Interesting

    The article talks about 4 features: goto, eval (run code from a string), multiple inheritance, and recursion. It discusses why the 4 get attacked by simplicity advocates:

    goto -- incomprehensible logic in programs
    eval -- security risks
    multiple inheritance -- breaks single responsibility since one module can have subtle impacts on how other modules acts in this context
    recursion -- article isn't clear though the comments above are mostly correct. In non-tail recursive languages recursion usually creates algorithms that are O(n) in memory. Even in tail recursive languages this can happen (and in fact in those languages because more complex recursions are encourages O(n^2) isn't uncommon when recursion isn't used carefully / well understood).

    It then mentions that these things should be used to avoid complexity in certain situations.
    goto -- error handling
    multiple inheritance -- is generally too useful to give up. implement with interfaces and be careful
    eval -- JSON, HTML, math...
    recursion -- trees, some list algorithms... recommend to implement imperative style mostly though (article assumes the language can't handle recursion)

    Now my opinion:
    Recursion is obviously the best understood of the 4. It is easily provable that there exists recursive algorithms which are both important and are not implementable as loops. Recursion classification is a still active research problem. Most imperative programers don't even bother to think deeply about their algorithms and not using design patterns from recursive features means the same bugs are introduced over and over again in code. IMHO there is no reason not to be abstracting loops away using built in functional design patterns in code.

    Multiple inheritance is too powerful to give up. Java was wrong here. Better safety than the C++ style seems to be needed though. For OO languages this should be an active area of experimentation.

    goto is today rarely used and when it is it often avoids complexity. I think we hit the right level of compromise here decades ago and this is a dead issue.

    Eval I think history has shown that without explicit evals developers end up having to create implicit evals where the code acts in complex ways on input. The code / data duality is not dead. Complex evaluation of input and layering aren't going away. Perl's concept of taint checking is likely the best approach: make it explicit and let the compiler check for accidental security risks.

    1. Re:What the article says by geggibus · · Score: 1

      Recursion is obviously the best understood of the 4. It is easily provable that there exists recursive algorithms which are both important and are not implementable as loops.

      Can you please provide a proof for this?

    2. Re:What the article says by Anonymous Coward · · Score: 2, Informative
    3. Re:What the article says by cheesybagel · · Score: 1

      It then mentions that these things should be used to avoid complexity in certain situations.
      goto -- error handling

      Exceptions do this better if your language supports them.

      multiple inheritance -- is generally too useful to give up. implement with interfaces and be careful

      Languages like Java don't support class multiple inheritance only interface multiple inheritance yes. For a reason. Class multiple inheritance is bonkers.

      eval -- JSON, HTML, math...

      It has its uses but it's a security hazard.

      recursion -- trees, some list algorithms... recommend to implement imperative style mostly though (article assumes the language can't handle recursion)

      Recursion can provide an easier to read algorithm which is good for prototyping but typically it uses too much stack memory and its better to manually handle the stack yourself if you need one. On modern pervasively MT architectures you should minimize the amount of per thread memory to keep the program running inside the processor caches and typically recursive algorithms are a bad idea because of this.

    4. Re:What the article says by jbolden · · Score: 2

      This is recursion theory. A tail recursive function f is expressible in loop form f' and visa versa (https://en.wikipedia.org/wiki/Tail_call#Relation_to_while_construct). Given any simple recursion that's not tail recursive you can use an explicit stack. So for example quick sort is much easier to implement recursively but it can be implemented with an explicit stack to make it into a loop. To get something that you can't avoid you need something for which the complexity / size of the explicit stack can't be computed.

      A church number (see link if you want more: https://en.wikipedia.org/wiki/...) is a function that takes two arguments one a function from a to a, the second of value of a.
      example three = f ( f ( f z ))) or f(f(f(z))) depending on notation

      three (+1) 0 == 3 as would expect.
      on the other hand
      if pred n = (\(a,b) -> b) (n (\(a,b) -> (succ a, a)) (zero, zero) where
      succ n f z = f (n f z)
      zero f z = z

      then you can define a subtraction function on church numbers.
      minus p q = q pred p
      with that definition for all church p,q and f, z.
      (minus (plus p q) q) f z == p f z

      That function minus is not expressible as a loop though it uses the recursive structure of the underlying church number q as you can see above.

    5. Re:What the article says by jbolden · · Score: 1

      See my response above. I mostly agree with you. Though you are over simplifying a bit. For full recursion to work you need infinite time and memory. There are functions which are computable in fixed time and memory recursively but not iteratively.

    6. Re:What the article says by jbolden · · Score: 1

      I'd actually say better still is to use a recursion pattern (map-reduce, more generic hylomorphism, paramorphisms....) which can then be optimized for the machine. There is no reason to believe a programmer is going to do a better job writing his own stack handling in most situations.

      As for multiple inheritance being bonkers. My car is a Honda and a vehicle registered in NJ. That's two hierarchies.

      As for exceptions I agree just citing the article.

    7. Re:What the article says by TheRaven64 · · Score: 2

      As for multiple inheritance being bonkers. My car is a Honda and a vehicle registered in NJ. That's two hierarchies.

      That's not an argument that multiple inheritance is needed, that's an argument that subtyping rarely fits real-world problem domains.

      --
      I am TheRaven on Soylent News
    8. Re:What the article says by jbolden · · Score: 1

      That's a good rebuttal AC. However from the standpoint of NJ i do throw away the car (i.e. it becomes an out of state car) when I register in NY.

    9. Re:What the article says by jbolden · · Score: 1

      Isn't that sort of the point of OO to model?

    10. Re:What the article says by jbolden · · Score: 1

      That's an interesting way to handle the problem via. delegation. IMHO you've basically picked up the complexity of multiple inheritance and moved it to the methods. I'm not seeing how that changes things from pure multiple. If you are following I'd love you to expand.

    11. Re:What the article says by TheRaven64 · · Score: 1

      No, the point of the OO model is that you should decompose a problem into smaller problems and the only thing that is sufficiently expressive to be able to represent the parts of the problem is a simple model of a general-purpose computer, which communicates with other simple models of general-purpose computers by message passing. Everything else is a later addition.

      --
      I am TheRaven on Soylent News
    12. Re:What the article says by david_thornley · · Score: 1

      There are recursive algorithms that are important and not implementable as loops without auxiliary stacks. The loop formulations of these algorithms tend to be harder to read.

      --
      "When you have eliminated the unacceptable, whatever is left, however improbable, must be the truthiness" - Holmes
    13. Re:What the article says by david_thornley · · Score: 1

      We use multiple inheritance on the basis that a certain size of block has specific processing, and different blocks can be made of different materials. It seems to do a great job of keeping the complexity under control in our particular use case.

      --
      "When you have eliminated the unacceptable, whatever is left, however improbable, must be the truthiness" - Holmes
    14. Re:What the article says by tepples · · Score: 1

      It has its uses but it's a security hazard.

      Is there a good way to feature-detect for ECMAScript 6 syntax support in a web browser without using eval, new Function, or anything treated as similarly unsafe by Content Security Policy?

    15. Re:What the article says by phantomfive · · Score: 1

      Multiple inheritance is too powerful to give up. Java was wrong here. Better safety than the C++ style seems to be needed though. For OO languages this should be an active area of experimentation.

      FWIW interfaces (like Java) plus "favor composition over inheritance" seems to solve this problem for most of my cases.

      --
      "First they came for the slanderers and i said nothing."
    16. Re:What the article says by TranquilVoid · · Score: 1

      As for multiple inheritance being bonkers. My car is a Honda and a vehicle registered in NJ. That's two hierarchies.

      Viewing inheritance via the 'is-a' model this does not work as strictly a car is not necessarily a Honda nor registered (although if your domain is a database of registered Hondas, rather than of generic cars, perhaps it is fine).

      In terms of class structure, having a base class of "thing made by Honda" isn't very useful. You're better off interpreting it as "has a manufacturer property whose value is Honda". The registration base class would fare a little better, assuming the system is a registration database, then you could inherit Car from RegisteredVehicle. Even so, such a database would be more concerned with RegisteredVehicle as the top-level object, not Car, and would probably want a VehicleType property rather than storing Car/Truck/Lorry objects that all inherit from RegisteredVehicle.

      This is why inhertiance has fallen out of favour to composition - composition is more flexible (if more verbose) as it effectively allows you inherit from an interface and change at runtime.

      That said, I do occasionally come across a situation where multiple inheritance makes sense, just can't remember at the moment :)

    17. Re:What the article says by Xest · · Score: 1

      Your car has a make, Honda, and a registration, that in turn has a registration state of New Jersey. Why do you need to inherit these things when you can just reference them?

      You're effectively saying that your car is a type of a brand (No. It has a brand, but it isn't a type of brand.) and that it's also a type of New Jersey (What?).

    18. Re:What the article says by jbolden · · Score: 1

      Yes of course my car is a type of Honda. "My car is an Accord" is a perfectly natural thing to say. Similarly among all registered entities in NJ my car is one particular type.

    19. Re:What the article says by Xest · · Score: 1

      But Honda is a brand, so by inheriting it you're saying it's a sub-brand of Honda, but a car isn't a brand, it's a car.

      You could say that Pepsi Max is a sub-brand of Pepsi, but not that a can of Pepsi Max is a sub-brand of Pepsi, it's not, it's a can, branded with the brand Pepsi Max.

      Time and time again most people that argue that we need multiple-inheritance from classes demonstrate that the real problem is that they're not that great at breaking down things into classes in a logically sound manner - you're falling into this trap here. I'm not trying to insult you with that, frankly there isn't an awfully high percentage of developers who are actually good at it - I've read your other comments here with interest, and you're genuinely knowledgeable on a whole lot of other stuff. No developer should feel defensive or embarrassed for not fully understanding absolutely everything because as soon as you go down that path you become immune to learning about anything, and that way lies redundancy in this fast moving market.

      You have to be quite pedantic about the English language to get it right, really when people say "My car is a type of Honda", what they're saying is merely shorthand for "My car is a type of vehicle made by the company with the brand Honda", because technically no, your car isn't a type of Honda, because Honda is a brand - your car has a brand, but it isn't a brand, again, it's a car. This pedantry is pointless and irrelevant when it comes to every day life because everyone looks at you like you're a dick when you make such pedantic statements about common usage of English, but it does help when you're trying to break some real world set of entities down into a high quality object oriented design.

      If you get good at that, then it rapidly becomes clear that multiple-class inheritance is entirely unnecessary, and that multiple interface inheritance is sufficient. I do personally believe that single class inheritance is helpful though as it can drastically decrease duplicate code - whilst I accept that the interface only approach has it's benefits in terms of implementing a clean design on paper, it doesn't in terms of code maintainability IMO.

    20. Re:What the article says by phantomfive · · Score: 1

      The big issue with that is when you have to do complex changes across the system and keep things in sync.

      I'm not sure how that relates to multiple inheritance at all, tbh. Complex changes across a large system are always going to be problematic.

      --
      "First they came for the slanderers and i said nothing."
    21. Re:What the article says by ebvwfbw · · Score: 1

      If I tell someone to "go to hell" they'll immediately understand the task.

      If I tell someone to "recurse to hell" they might never even get there!

      captcha: explains

      The stack would kill them first. The question is when they goto hell, would you send them with a Handbasket(small)?

    22. Re:What the article says by phantomfive · · Score: 1

      ok, so let me see if I understand what you're trying to say. Basically, if you have an API (which is basically a class with some public methods), then it's easier to modify the class without breaking the API when you have multiple inheritance?

      --
      "First they came for the slanderers and i said nothing."
    23. Re:What the article says by Xest · · Score: 1

      There's obviously quite a few ways of resolving that such as simply allowing a button to have a shape (i.e. a rectangle) which in turn allows it to be swapped out for a circle if you want round buttons for example. The danger with inheritance is that you're effectively fixing that behaviour.

      Clickable I'd argue is more suited to an interface, interfaces are quite good at representing behaviour.

      But in modern GUIs it's obviously become a lot more complex than all that, but in a good way - it means we have a steeper learning curve, but much more maintainable and testable code. We typically try to separate these things to a much greater degree now, as we really don't want visual design to impact on business logic. If you look at something like WPF you'll see that you basically have a button that inherits from a control, which in turn inherits from UI element (because not all UI elements need to be controls). The base UI element class has members that define how the element should be rendered - because in WPF you're not limited to rectangles, you may want a star shaped button or god knows what else if you're creating some weird UI for a game or something. It also has properties for things like size, width, font, colour, fade in/fade out effects and so on and so forth. Effectively the UI element class allows anything inheriting to look like anything, so an inheriting button class might implement some default behaviour, such as a rectangle, which in turn can be further overridden by a user, but ultimately it means that how the button looks slots in in a number of has-a relationships - has a colour, has a font, has a shape, has a size and so on and so forth.

      Things like clickable are simply exposed via events - a Control (which inherits from the above mentioned UIElement for display) will expose a number of common events such as OnClick and so forth, in C# events are basically just a form of callback, so effectively once you create a button you just assign callback handlers to those events which are again present in has-a relationships, so that a button has an on click event, a button has a resize event, and so on and so forth.

      What this means is that a button is really just an abstract concept for the most part - how that looks is really about how you set it's look and feel properties, how it behaves is really just defined by whatever you hook up to none, some, or all of it's many events.

      Now I'm not arguing that WPF is some example of perfect OO design, not by any measure, I'm citing it as an example of one way to design a GUI library without needing multiple inheritance. I believe that WPF's composition is actually quite messy - personally I think a UIElement should have a "visual style" and that in turn that visual style should encapsulate all the visual elements - if you look at the interface it's massive and messy, though to be fair a lot of this is because Windows is still dragging a fuck ton of legacy along behind it:

      https://msdn.microsoft.com/en-...

      For more simplistic designs you may just determine that all UI elements are in fact controls and just merge UI element and control into one base class (which is basically what you have in WinForms). Essentially the goal of WPF is to separate concerns - you don't have to worry about someone having checked the button out to write code defining how it looks whilst someone else wants to check it out to define what it does, because the button is just abstract - someone can define how it looks in one file, and someone else can define what it does in another. Only one of them has to wire it up without being concerned about the implementation details, and it kind of works. WPF has an XML GUI definition called XAML not too different to the way websites have their visual elements defined in HTML with the idea being that the whole interface can be defined by someone who doesn't even know code, whilst developers write the business logic behi

    24. Re:What the article says by jbolden · · Score: 1

      That's a very good answer. I'm going to digest it for a day or two and think about it. This forum doesn't lend itself to long conversations. But I'll see if it is still open for a response. My initial thinking is your argument seems strong.

      I guess the question then is, given your attitude above why do you think even single inheritance is useful? How does the above not argument equally apply in that case? In other words why not do what functional languages do and have polymorphic methods not tied to classes and get rid of base / parent classes entirely?

    25. Re:What the article says by Xest · · Score: 1

      On a conceptual level when talking about object oriented analysis I think the argument for single inheritance makes sense - I believe it's always the case that a thing is a sub-type of another thing and that remains true until you boil down to the fundamental building blocks of the universe - the base particles, which would, if you were building the entire universe in code presumably be our base classes (I'm not a physicist, I'm sure one might correct me :)).

      The difficulty with it is again in the mapping of figuring out what that parent type is, as we've seen it can be difficult when mapping casual English to an object oriented design that we run into problems, and so we have to be very careful about determining what that parent type actually is, rather than what we initially think it is, sometimes that parent type can be an entirely abstract concept - I would argue this is what we have in the case of Honda, it's a brand, but a brand in itself is just an abstract concept defined by a series of other items such as a trademark, a name, a logo and so forth. If we really wanted to get theoretical though we might choose to argue that a brand is actually just, say, an idea, and create an "Idea" parent type which is in turn just an organised set of thoughts, which are in turn just an organised set of electrical impulses in the brain and so on and so forth, so there nearly always seems to be something deeper you can parent type to that is individual. Even if we go back to the idea of particles, one might argue that element A is made of particle X and particle Y, so we just inherit those particles with multiple inheritance, but I think even here it's not an ideal solution because there's more to it than that, we probably need a more abstract concept of a class to inherit from instead such as a ParticleSystem, that defines not just the elements that comprise the element but their relation, the number of each (what if it's made up of two of particle X for example? - we can't inherit it twice).

      That's not to say there aren't examples where maybe multiple inheritance does make sense - if we invent a Car Plane then is it not reasonable to inherit from Car and Plane? That's probably a reasonable argument conceptually, practically this may cause issues though - the behaviour of wheels on the car, and wheels on the plane when taxiing may be completely different and confuse each other, so even here you'd probably be better off just implementing a new CarPlane type that inherits from vehicle. It of course gets messy if some of your planes are water planes and land on floats.

      Of course you're right though, there are other ways to solve these sorts of problems rather than single inheritance, and I don't want to make it sound like I'm pretending single inheritance is a magic bullet, it gets misused every day and junior devs still often struggle to properly understand it's use and associated keywords, especially when you're having to explain the difference between abstract and virtual and so on and so forth - they certainly don't follow that sort of thing conceptually as easy as something like the humble if statement.

      The real benefit of inheritance is that it allows encapsulation of reusable code, we're effectively saying that this code in the parent class is reusable, but only by certain other types - it's not relevant to everything, just these few things. This means we only have to write that code once, but it also means that it's not floating around for people who just don't care about those methods in that part of the application to see. It's of course not just methods we capture in this way, but properties/fields also.

      I have tried a no class inheritance route, using only interface as some profess is the ultimate clean design, and I inevitably find it just ends up resulting in more code duplication. In part this is probably more a limitation of various languages (C#, Java etc.) than it is an inherently intractable problem. So whilst I'm not inherently against the concept in principal, I

  24. Fuck ppl who hate goto but love exceptions by Anonymous Coward · · Score: 1

    People who hate goto but love exceptions drive me up the wall. You hate the cute little goto with the well defined label you can instantly fly to in any IDE from vi on up, but you love the goto that jumps across any number of functions and puts you in some code (std:terminate if you fucked up!) ? And don't forget that in C++ (and others I think), you aren't even sure if a given function can throw an exception except by inspection.

    Worst. Flow control. Evar.

    1. Re:Fuck ppl who hate goto but love exceptions by david_thornley · · Score: 1

      Exceptions do things that are hard to do without them. Most uses of goto can be better written as something else.

      --
      "When you have eliminated the unacceptable, whatever is left, however improbable, must be the truthiness" - Holmes
    2. Re:Fuck ppl who hate goto but love exceptions by K.+S.+Kyosuke · · Score: 1

      Some languages have somewhat smarter exceptions. Common Lisp and Smalltalk come to mind. But yeah, in C++, it's complicated.

      --
      Ezekiel 23:20
  25. Eval is a Beginners' Trap and a Huge Security Hole by mcpublic · · Score: 1

    Eval has been part of the Lisp programming language since the dawn of computing, but few experienced Lisp programmers ever used it outside of read-eval-print loops and software development tools (where its existence is a totally awesome gift). Eval is widely considered a beginner's trap. It is rarely "the right thing," typically because it is super inefficient. But my biggest concern is that it is a huge security hole, especially when the expression to be evaluated comes from the user. Think SQL injection attack. It is wise to require some sort of security credentials and/or filters to make sure the expression is within a "safe subset" of the language... at which point you might as well write the mini-interpreter you really need, instead of making the entire, underlying language and the application's entire data environment available for anyone to use or misuse.

  26. Re:Goto by johannesg · · Score: 1

    I believe you are missing the greater-than character, which also looks a bit like a letter "V" with the point facing to the right. Here's one now: >

    Oh, and the last time I worked with an 80-column screen was probably 30 years ago. My current screen comfortably displays at least double that number. I really don't see why we stick with that tired old convention.

  27. Avoid as a rule, apply with good reasoning by SpaghettiPattern · · Score: 1

    Any "dirty" style should be avoided as a rule and applied with good reasoning.

    My guilty pleasure is to return multiple return statements. The reasoning behind this is that it sometimes makes code better readable. Less nesting/fewer methods. Translating "avoid multiple return statements" to loops would result in avoiding break and continue statements.

    If one's self-critical enough, code will be cleaned up eventually. Cleanly avoiding multiple return statements -and too many avoiding break and continue statements- usually comes with a breakthrough in the functional decomposition of the problem at hand.

    --

    I hadn't the slightest objection to his spending his time planning massacres for the bourgeoisie... (P.G. Wodehouse)
    1. Re:Avoid as a rule, apply with good reasoning by swilver · · Score: 2

      There's absolutely nothing wrong with multiple returns, continue and breaks. Don't let some purist that got this added to your favourite "code checker" tool fool you that just because the rule is there, it must be good.

  28. Re:Kernels should only be in assembler by jbolden · · Score: 1

    You aren't going to win that debate easily. You are arguing for micro kernels. And of course you are right that micro kernels do allow for extensions much more easily. The problem is that they have notoriously horrible performance for operations that repeat too frequently because the wrapping and unwrapping of calls gets too expensive. Same thing that happens in user code at a high level. Linear efficiency matters. Speeding up every computer on the planet 20% is worth a lot of hassle to OS developers.

  29. Re:Goto by jbolden · · Score: 1

    You are wrong here. The whole point of recursion is to abstract away the details of how a loop executes and focus on what the loop does. Then later you use a recursion design pattern to abstract away the naive recursion. In a looping structure you end up having to decide immediately on bounds cases handling.

    Most languages that handle recursion well just translate most simple recursions into iterative loops during compilation anyway.

  30. Re:Recursion is dead! by vux984 · · Score: 2

    The point is that you have several mallocs to deal with, and more than one error condition (not just failing the malloc itself).

    So if you make 3 mallocs, and then there is an error opening the file... you still have to free all 3 mallocs.

    the use of 3 if(x) free(x) instead of multiple goto labels is fine, but you still need goto to get to the cleanup block from the various error points.

  31. Re:Recursion is dead! by vux984 · · Score: 1

    lol. on the upside it won't compile so no one will ever suffer them. :p

  32. Re:Recursion is dead! by james_gnz · · Score: 1

    GOTO is useful. Certain forms of C exception handling code benefit from GOTO immensely.

    Yes, goto is useful for exception handling, in languages that lack specific exception handling constructs, but have goto. This is a good reason to use goto in such languages, but I think it ultimately points to a deficiency in the language, rather than an argument in favour of goto as a language construct.

    IMHO, to argue for goto as a language construct, it is not enough to argue that there are a small number of specific well-defined ways in which it is reasonable to use goto in languages that lack control-flow constructs for particular purposes. This would better support an argument for the availability of suitable constructs for these purposes. Ultimately, to argue for goto as a language construct, I think it would be necessary to claim that is reasonable to use goto in ways that defy classification. AFAIK, this claim is seldom made.

  33. Re:Kernels should only be in assembler by religionofpeas · · Score: 1

    The problem with microkernels is not the wrapping and unwrapping of calls, or the cost of switching, or copying memory. The real problem is that different tasks in the microkernel do not have a synchronized view of the system state. As soon as you pass a message where you copy parts of the state, you have two different copies of that state, and as one task changes their copy, the other becomes outdated. Managing all of this becomes more complex than having a big kernel where different tasks share the same memory structures.

  34. Re:Recursion is dead! by Reemi · · Score: 1

    > I very much doubt he meant for his statement to become dogma in the way it has

    The original title Dijkstra gave his paper is 'A Case Against the Goto Statement'. It was a CACM editor who came up with the Considered Harmful version.

  35. Re:Recursion is dead! by _merlin · · Score: 1

    You've missed my point. The people I have a problem with are people who will avoid a goto at all costs, even doing things like this so they can say they didn't use a goto:

    do { ...
            if (exit_cond) break; ...
    } while (0);

    I really have seen that done in a popular piece of open source software. If a goto really is the cleanest way to achieve what you need to do, then just use a goto. Don't write code that does a goto while using some convoluted means to avoid the goto keyword.

    That said, in C++ there are many situations where you can do better than use a goto. For example cleaning up on error is better done with destructors as it will be exception-safe, and exceptions provide a structured goto that only lets you jump out, but lets you do so across multiple frames.

  36. Re:Recursion is dead! by Anonymous Coward · · Score: 4, Insightful

    You should read "GOTO considered harmful" before you bash it.

    "Most programmers have heard the adage "Never use goto statements", but few of today's computer science students have the benefit of the historical context in which Dijkstra made his declaration against them. Modern programming dogma has embraced the myth that the goto statement is evil, but it is enlightening to read the original tract and realize that this dogmatic belief entirely misses the point."
    http://david.tribble.com/text/...

    In the bad old days, all you had was goto, and every program looked like spaghetti. Now that we have if...then...else, loops, switch-case statements,
    goto should only be used as a last resort (and every use should be justified). I've been a professional programmer for twenty years; last year I used goto *twice*.

    And never forget https://xkcd.com/292/

  37. Honest answer by gargleblast · · Score: 1

    Pretty sure you're doing a lot better than the jackass who came up with the phrase "Forgotten code construct".

  38. Don't miss them. by MouseTheLuckyDog · · Score: 1

    Recursion is either so easy it is more of a trick than a useful tool, or it is more complex in which case it is generally much harder to get the terminal conditions right then it is to avoid recursion.

    I remember when I learned C, digging through K&R to find how to do goto. I also remember learning ruby and not even thinking about whether or not goto was supported. It really isn't needed and as Dikstra pointed out is mostly used for creating sloppy code.

  39. yea by AchiestDragon · · Score: 1

    it depends on the system environment , if your writing code to be used by a multi-thread o/s environment where use is discuraged as fearlessly as when you writing stand alone code for a embeded stand alone system where use of such can be expected , the other is the use of global vars

  40. Goto has its uses by DrXym · · Score: 2

    Sometimes code has to do multiple things and if any of those things fail, the whole lot has to be cleaned up. Using a "goto cleanup" is usually a lot more preferable way of cleaning up that nesting the code in conditionals rendering it unreadable or duplicating the cleanup in several places.

    1. Re:Goto has its uses by david_thornley · · Score: 1

      This is what destructors do in C++. Some languages have try...finally. In most modern languages, if your cleanup is freeing memory, you just leave it for the garbage collector.

      --
      "When you have eliminated the unacceptable, whatever is left, however improbable, must be the truthiness" - Holmes
  41. Re:Recursion is dead! by Dunbal · · Score: 1

    Try writing an assembly language program without using jump.... what is that, if not goto? Elevating the non use of GOTO to the level of a religion is just as crazy as any other religion. There's a right way and a wrong way to use it, just like there's a right way and a wrong way to use a pair of scissors. Safety scissors are smart in pre-school but an adult is expected to use regular scissors without killing themselves. Is your programming at infant or adult level?

    --
    Seven puppies were harmed during the making of this post.
  42. goto is useful in some situations by nateman1352 · · Score: 2

    When writing C code where exceptions are not available, I'll often use goto statements to perform error handling. Its useful because you only have to write any necessary memory de-allocation code once. Its pretty easy to simulate a try/finally block using them and its a way better and more readable way to write that sort of code then the other alternatives you have in C. All that said, I prefer exceptions, they more or less get the same job done, its easier to nest them, and IMHO are a bit more readable than the goto method. Only downside of exceptions is the execution overhead is often very bad compared to a goto.

  43. Devil is in the details by grumbel5969 · · Score: 1

    The problem with eval() is that it's incredible power can't be used safely in most languages, as whatever you eval() becomes part of the main program. If you could eval() code in a sandbox and apply memory and CPU cycle limits to it, it would be very useful, but most languages don't have such features making eval() little more than a dangerous toy that sometimes becomes useful for debugging.

    As for goto, the Linux kernel is full of it and quite readable because of it. But outside of C you tend to have other mechanism to deal with resource cleanup that make it no longer necessary (RAII in C++, 'with' statements in Python).

    Recursion again depends heavily on the details. In Python you quickly run into stack overflows when you use recursion to much (1000 is the default), so it's best avoided. In Haskell or Scheme it's the normal way of doing things, thanks to tail recursion support.

    Multi-inheritance I never found very useful, even single-inheritance is rarely a good solution and you are better of doing composition most of the time.

    1. Re:Devil is in the details by david_thornley · · Score: 1

      The problem with eval() is that it's incredible power can't be used safely in most languages,

      There are language constructs that should be used only in limited contexts. I'd look at an "eval" in application code as suspiciously as I'd look at "delete" in C++ application code. Both are commonly done by programmers who don't quite know how to use the language.

      Multi-inheritance I never found very useful, even single-inheritance is rarely a good solution and you are better of doing composition most of the time.

      Not in my experience, which may well be different from yours. There are situations where inheritance is exactly what you want (typically if you have a definite IS-A relationship with no gotchas which would violate the Liskov substitution principle*). Faking it with composition would be clumsy and unnecessary. You do need to have a good idea where inheritance is appropriate and where composition is. If most of your classes use other classes through inheritance, you're probably doing it wrong.

      *The Liskov Substitution Principle is a little technical, but the general idea is that, if B inherits from A, members of A have to be expressible as members of B. For example, a square is a rectangle, but you can't represent a 2x4 rectangle as a square, so having Square inherit from Rectangle would violate the LSP.

      --
      "When you have eliminated the unacceptable, whatever is left, however improbable, must be the truthiness" - Holmes
  44. Re:Recursion is dead! by thegarbz · · Score: 1

    Goto is bad.

    Goto is bad for people who can't code and people who can't read code. To consider a construct bad is to not understand it.

  45. Re: Kernels should only be in assembler by MagicMerlin · · Score: 1

    This is an age old debate. It comes down to this: monolithic kernels tend to be faster so they are in common use.

  46. Recursion by mrthoughtful · · Score: 1

    Recursion has never been dead.
    Tail recursion is an essential part of all modern efficiency in compilation.
    Many languages, especially functional languages, cannot really even begin without recursion.

    If you haven't got what I am saying, read this comment from the beginning.

    --
    This comment was written with the intention to opt out of advertising.
  47. Re:Recursion is dead! by fisted · · Score: 2


    {
    char *a = NULL, *b = NULL, *c = NULL;
    FILE *f = NULL;

    if (!(a = malloc(something)))
        goto fail;
    if (!(b = malloc(something)))
        goto fail;
    if (!(c = malloc(something)))
        goto fail;

    if (!fopen(f))
            goto fail;

    some code

    return 0;

    fail:
    if (f)
            fclose(f);
    free(c);
    free(b);
    free(a);
    return -1;
    }

    FTFY. mkay?

  48. GOTO is useful ... when you have nothing else by Misagon · · Score: 2

    In my opinion there are valid uses of GOTO where it could be used, but nowhere else, especially in C.
    Modern languages should preferably have constructs especially for those cases so that you wouldn't have to use GOTO, but many languages don't.

    The article already mentions error handling in languages without RAII or exceptions, where resources have to be deallocated. Note also that not all resources are objects on the heap: The function may need to close a file or a network connection etc.

    I find goto most useful for for breaking out of loops. Many languages have constructs especially for breaking out of nested loops to a scope that encloses the enclosing loop but there is one class of loop that is rarely supported: Loops for looking up an item in a data structure, you want to take a different code paths for when an item has been found to when the loop has run its course without a result.
    The only major language I know of that supports this with its own construct is Python in the form: for: ... break ... else: ..., where the else-block is taken only if you did not break out of the loop.
    In languages that allow nested break statements you could emulate that by enclosing the loop within an outer loop and breaking out of that but IMHO that would be even less readable than using GOTOs.

    --
    "We mustn't be caught by surprise by our own advancing technology" -- Aldous Huxley
    1. Re:GOTO is useful ... when you have nothing else by Goragoth · · Score: 1

      But there's nothing inherently unreadable about goto. In fact it is really obvious what it does and how it works, and I think a lot of code would be more readable if goto wasn't so demonised. The problem with goto is that it is easy to abuse, you can replace most other constructs (functions, loops, etc...) with creative goto usage and then you end up with unreadable spaghetti code. Using it to break out of a nested loop or to handle an error condition is perfectly fine and more readable than alternatives.

  49. Re:Eval is a Beginners' Trap and a Huge Security H by K.+S.+Kyosuke · · Score: 2

    It is rarely "the right thing," typically because it is super inefficient.

    In compiling implementations of programming languages, it's anything but inefficient.

    But my biggest concern is that it is a huge security hole, especially when the expression to be evaluated comes from the user.

    One of my favourite quotes in programming: "If you don't want to do something, just don't do that."

    at which point you might as well write the mini-interpreter you really need,

    Will you also rewrite the compiler, and the memory manager, and write a set of interfaces between your two separate kingdoms?

    --
    Ezekiel 23:20
  50. Re:Recursion is dead! by rkww · · Score: 1

    yeah except you've got e3 twice so it wouldn't even compile

  51. Re: Kernels should only be in assembler by religionofpeas · · Score: 1

    Not only faster, they are also simpler to get right, for everything except trivial cases.

  52. Eval by Tangential · · Score: 1

    Eval, properly used, can be extremely valuable and reduce a lot of code bulk. Improperly used it presents various nightmare scenarios for security and stability.

    In reality though, I don't see much more than a slightly nuanced difference between using eval and dynamically constructing any portion of a SQL statement for execution at runtime.

    Use it, but use it carefully.

    --
    Suppose you were an idiot. And suppose you were a member of congress. But then I repeat myself. -- Mark Twain
  53. Some of these things are not like the others by bradley13 · · Score: 2

    Goto: A way to enable lousy programmers to write impenetrable code. Are there extremely unusual circumstances, where a superstar might use a Goto in a good way? Yes, but the price - encouraging use by the incompetent - is not worth it.

    Multiple inheritance: Middle ground. In a few circumstances useful, but the conceptual complexity is too high for many programmers. On the other hand, those will not be the ones designing your architecture. Mixed feelings about this one.

    Recursion: Many algorithms can be implemented more cleanly with recursion than with iteration. If recursion were better supported, it would be more widely used. Unfortunately, the most widely used languages have poor implementations (C# and Java, to name two), making recursion horribly inefficient. Optimizing for tail-recursion is not hard (Scala does it on the JVM), so it's weird that this isn't done in all modern languages.

    --
    Enjoy life! This is not a dress rehearsal.
    1. Re:Some of these things are not like the others by religionofpeas · · Score: 1

      Goto: A way to enable lousy programmers to write impenetrable code

      I don't let lousy programmers touch my code. Problem solved.

    2. Re:Some of these things are not like the others by bradley13 · · Score: 3, Informative

      "I don't let lousy programmers touch my code. Problem solved."

      Nice thought, but that's not real life. As a cynical estimate, at least half of the people working as programmers are lousy. Companies hire them, because they're cheap, or because the company can't find anyone better, or because the company has no clue about programmer quality. There's more code to write than there are good programmers to write them, and that's not going to change any time soon.

      --
      Enjoy life! This is not a dress rehearsal.
    3. Re:Some of these things are not like the others by lgw · · Score: 3, Insightful

      goto is vital to safe C code. You want to be able to jump to your clean-up code from each place something might go wrong. The alternative is to add another layer of indentation under an "if" for each place something might go wrong, the stuff of nightmares.

      --
      Socialism: a lie told by totalitarians and believed by fools.
    4. Re:Some of these things are not like the others by R3d+M3rcury · · Score: 1

      As a cynical estimate, at least half of the people working as programmers are lousy.

      Well, by definition, 50% of programmers have below average skills. Of course, 50% have above average skills.

  54. You're probably using GOTO every day by scdeimos · · Score: 2

    Most language compilers are using goto constructs under the covers already. Disassemble some MSIL, for example, and you'll see how there are some in every single if-else or switch-case block.

    1. Re:You're probably using GOTO every day by Anonymous Coward · · Score: 3, Insightful

      Goto is considered harmful for humans. Who cares what happens under the covers. Hot liquids are harmful for humans. The fact that there are hot liquids under the covers when you drive your car is irrelevant.

    2. Re:You're probably using GOTO every day by angel'o'sphere · · Score: 1

      Wow, how insightful.
      How else should a compiler generate machine or byte code?

      --
      Cost free eBook I read (by iBook/Kobo/Amazon/ObookO/Gutenberg etc.): "The Green Odyssey" by Philip Jose Farmer.
  55. Stay away from the Knives, and the Stove too! by Anonymous Coward · · Score: 3, Insightful

    I'm tired of this mentality. I'd rather we favored those with skill rather than those with a lack of it. We as a people would go much farther.

    Do you cripple the use of bicycles by forcing everyone to ride with training wheels? Or do we in fact favor those who can ride and instead burden the new-comer with the difficulties around obtaining and installing training wheels on very poor low-end bicycles?

    Why should coding be any different? Sometimes people craft very complex and difficult pieces of software that tie together more than 20 libraries all which have their own quirks. I need the ability to share raw pointers, I need the ability to avoid ref-counting or shared_ptrs. I need to sometimes work with systems that have their own scheduler (Erlang, cough) and then bind C libraries into that ecosystem which doesn't allow blocking for more than 1ms. So I need crazy thread logic sometimes and odd code to support linking two separate mutex idioms from 2 different libraries so the lock works across the boundry....

    Sometimes I just wish to be left alone in a complex space where another soul's mere presence is essentially proof of their abilities and understanding of logic. Similar to how adults sometimes wish to leave behind children and mingle only with other mature adults, I desire this of a programming language. Something to scare away all the posers and poor misguided (but righteous and well meaning) individuals.... It's not elitist thinking just like Adults aren't really being rude when trying to mingle with other like-minded adults.... it's more of a time-saver for people who find that many "adults" are actually children in disguise and only after 30 minutes of talking can you determine they are fake. I grow tired of wasting my time and eventually wish to move to a place where it's harder for the fake to blend in. It was amazing going from finding 1-2 good people every 50 to instead finding 1-2 good every 10.

    For me that language has been C++ and simply put it's the most amazing thing I've ever discovered in my programming career. I also love how everyone still is scared to death of it and clamoring for it's deprecation while simultaneously using programs written in C++ to post these complaints.

  56. ShIt coders by Anonymous Coward · · Score: 1

    If you think a certain construct is somehow inherently bad, you are a shit coder. There is NOTHING wrong with goto, multiple inheritance, etc. They all have there uses. If you think they are bad. STOP. I deal with idiots like you all the god damned day, and I'm sick of it.

  57. The Recursion Cult by Zobeid · · Score: 2

    I think some time in the misty past (1970s?) recursion went through a fad phase, and it was hailed as the solution to every programming woe, not to mention the secret key to artificial intelligence. I can remember studying Logo (which is a variant of LISP) at one time. Logo composed every function call recursively: when it hit a key word that required arguments, then it would put that on hold and go looking for those arguments, some of which might be keywords that required their own arguments, etc. That's not unique among programming languages, but the syntax provided no clues or organization: no parenthesis, no brackets, no braces, just a string of words, and the only way to figure out which was an argument to what was if you already knew (or stopped to look up!) how many arguments each word takes. But supposedly you wouldn't need help reading it because it's recursive, and recursion is wonderful magic.

    Incidentally, Forth suffered from a similar readability problem, but at least it executed way way way faster.

    The other thing I remember about Logo and recursion was the textbooks and tutorials trying to teach me how every loop could be done using recursion -- and should be! Why would you do that? Because it's the Logo Way, of course. And because recursion is wonderful magic.

    It was overly complex and inefficient, to be sure. However. . . I happily use recursion for actually recursive tasks, such as traversing various kinds of tree structures.

    1. Re:The Recursion Cult by david_thornley · · Score: 1

      Incidentally, Forth suffered from a similar readability problem

      I always found well-written and reasonably documented Forth readable. By documented, I mean each word has an inline comment showing what it does to the stack, and everything has meaningful names. I thought Forth was a lot of fun, and where else do you find ": ? . ! ;" to be part of a language definition?

      --
      "When you have eliminated the unacceptable, whatever is left, however improbable, must be the truthiness" - Holmes
  58. Re:Recursion is dead! by jenningsthecat · · Score: 1

    Depends on their usage of goto... using it to jump backwards, or make loops, or basically any other usage, yea, those should be stricken

    So does that mean in C it's safe to use goto so long as I make sure I don't purposely or accidentally create recursion with it? ;-)

    --
    'The Economy' is a giant Ponzi scheme whose most pitiable suckers are the youngest among us and the yet-unborn.
  59. Iffy resources by fyngyrz · · Score: 2

    Here's a much better pattern for you, in a c-ish form:

    How to manage iffy resources in a structured manner

    You can generalize that pattern into almost any situation and it will work well. If you need details, then instead of true/false, pass can be a value or a bit mask, etc. and then the check at the end can be verbose about what exactly went wrong. Essentially still the same pattern.

    --
    I've fallen off your lawn, and I can't get up.
    1. Re:Iffy resources by vux984 · · Score: 1

      The thing I don't like about that pattern is that

      1) the nesting can get pretty deep. imagine you had to do a bunch of file operations and had to check for errors after each of them. You could easily be nesting 20+ deep.

      2) the nesting for the basic error checking totally obscures the logical structure of the actual code.

      You can't assume the resources are allocated at the front, and unwound at the end as you might only need some resources in certain conditions. So now you've got the real program logic mixed in with the success-test nesting. And the actual flow control logic becomes invisible, lost in a mess of library call 'success test' nesting.

    2. Re:Iffy resources by fyngyrz · · Score: 1

      It's only a basic pattern for the example case provided (which was, you will observe, all resources required up front.) You adjust as needed, or use something else as needed. It's programming, not rote behavior. :)

      --
      I've fallen off your lawn, and I can't get up.
  60. Re:Recursion is dead! by religionofpeas · · Score: 1

    C++ RAII eliminates most of the need for local gotos though - you can make local classes with destructors for cleanup, with the added benefit that it's exception-safe.

    But I wouldn't want throw exceptions in a linux kernel function. It introduces too many things going on behind the curtains that may not be safe in a particular situation.

  61. Absolutism is a problem by fyngyrz · · Score: 1

    You do realize there are CPUs with user stack pointer(s), right?

    You do realize there are cases where the recursion is limited in depth based on the nature of the problem, rather than the size of the data, right?

    You do realize there are languages where the amount of data involved in the levels of the recursion can be precisely controlled, right?

    It's not as black and white as "recursion bad, mkay?"

    --
    I've fallen off your lawn, and I can't get up.
  62. GOTO and the Wild West by Zobeid · · Score: 2

    To understand the revulsion some hold toward GOTO, you have to mentally turn back the clock to a time when it was used for almost everything. Back in the wild west days of computering, there were no conventions for organizing program code. There was no Structured Programming. Early languages provided simple branching tools (like IF-GOTO) but no guidance. A good programmer would soon figure out his own way of organizing his code, and he could become quite productive. The problem was, everyone had their own individual, eccentric methods, and looking at somebody else's code was often confusing. Then structured programming came along, and it provided (or some might say imposed at sword point) a common organizational methodology and a common vocabulary. Two programmers who were trained in the doctrine of structured programming could read one another's code much more easily.

    If you see the keywords and indentation of a WHILE-REPEAT loop, or a REPEAT-UNTIL loop, or an IF-THEN-ELSE condition, then you already have a clue, you already have a starting point to understand what the code is doing. If you see GOTO, then it communicates almost nothing. Then you have to look at the context. There may also be some code comments. It may not be a problem, and in today's environments there's no reason why it should be. This isn't the wild west anymore, and we don't use GOTO for everything. If it's there, somebody presumably had some reason for it.

  63. Re:Recursion is dead! by VernonNemitz · · Score: 1

    While a JMP is equivalent to a goto, keep in mind that conditional loops are a higher-level language construct than what is available to those early processors, which kind of means that JMP/goto had to be used everywhere on those systems. In my personal experience, having written spaghetti code with goto, and also having written vastly less tangled code without it, I'm quite aware of the software-maintenance benefits of avoiding goto whenever it is easy to avoid. But I'm also aware of situations, usually involving getting out from the inside of many nestings of conditions and loops, where goto is clearly the simplest and most elegant way to do that, and I will unhesitatingly use it for that purpose. Those situations are uncommon enough that its use need never be called "excessive".

  64. Re:Recursion is dead! by Rockoon · · Score: 1

    Do you understand that you are doing more work at runtime to solve an aversion to a source code construct?

    You understand how fucking dumb that is?

    --
    "His name was James Damore."
  65. Re:Goto by Rockoon · · Score: 1

    Most languages that handle recursion well just translate most simple recursions into iterative loops during compilation anyway.

    ...proving that recursion is inefficient.

    --
    "His name was James Damore."
  66. Re:Eval is a Beginners' Trap and a Huge Security H by willy_me · · Score: 1

    Same for MATLAB. In fact, the MATLAB documentation indicates that eval should be avoided.

  67. Re:Goto by religionofpeas · · Score: 1

    It's not inefficient if the compiler optimizes it away.

  68. Begs the question by chuckugly · · Score: 1

    In what way does it beg the question?

    1. Re:Begs the question by Skidge · · Score: 1

      I'm disappointed in you Slashdot readers. I had to scroll nearly all the way through the comment to find the first "Begs the question" complaint.

    2. Re:Begs the question by chuckugly · · Score: 1

      It was supposed to my day off watching for this stuff. Sorry.

    3. Re:Begs the question by Godwin+O'Hitler · · Score: 1

      To be fair, "to beg the question" is a particulary stupid way in this day and age of saying "to reason in a circle".
      And to be fair to both sides, "to beg" is a particularly stupid way of saying "to raise".
      Beg someone for something -- food, mercy -- yeah sure. Beg a question for something -- no, I'm not that desperate.

      --
      No, your children are not the special ones. Nor are your pets.
  69. Re: Doesn't care by hackwrench · · Score: 1

    Recursion isn't what allocates the stack frames. Limited compiler translate the recrsive algorithm into code that allocates the stack frames. I'm not sure, but I suspect that there is plenty of room for compiler optimization compared to what they are doing now, but I am not certain that they are still doing as you say they are.

  70. Re:Recursion is dead! by lucasnate1 · · Score: 1

    If you are using gcc, you can also use the "cleanup" attribute to achieve something similar. I have a feeling that one day this will become part of the C standard.

  71. Re: Your own stack by hackwrench · · Score: 1

    And what are you doing with that stack if still not recursion. You don't just magically make it 'not recursion' by implementing one element that you didn't even change the name of differently

  72. Re:Recursion is dead! by angel'o'sphere · · Score: 1

    There are much more errors, like fopen(f) :)

    --
    Cost free eBook I read (by iBook/Kobo/Amazon/ObookO/Gutenberg etc.): "The Green Odyssey" by Philip Jose Farmer.
  73. Sorry, but "creative use" of any feature ... by Ihlosi · · Score: 2
    Sorry, but "creative use" of any feature of a programming language might impress your geek buddies, but it will also make your code utterly hard to comprehend and maintain for anyone - including yourself - in a matter of a few months.

    (And I'm not saying 'goto' is a bad thing. Using it to uncreatively break out of multiple nested loops or do error handling is easier to understand than the alternative. Also, in about every programming language, there are pretty much always several ways to achieve a certain behavior. The one that is easiest to understand should be chosen unless there are pressing reasons for one of the other ways.)

    Disregard my rant about maintainability if you code one-shot things that no one - including you - will look at again once you're done.

  74. Re: What reason by hackwrench · · Score: 1

    Internal company politics, probably.

  75. GOTO and the arguments for it by angel'o'sphere · · Score: 1

    I don't get why people defend the usage of GOTOs with claws and teeth.

    In modern languages, and that includes C, the question if to use or not to use a GOTO never was an issue!

    The phrase 'GOTO considered harmful' comes from times where the predominate language was FORTRAN!!!

    In FORTRAN you easily see a 1000 lines program with 1 or 2 dozens of GOTOs, where the same program written in proper C or Pascal (and any other modern language) has zero.

    Furthermore, the example of 'good use of goto' given in the linked article is bollocks. I would fire (or educate) a programmer giving me code like that.

    --
    Cost free eBook I read (by iBook/Kobo/Amazon/ObookO/Gutenberg etc.): "The Green Odyssey" by Philip Jose Farmer.
    1. Re:GOTO and the arguments for it by lgw · · Score: 1

      How on earth would you write "safe C" without goto? Deeply, deeply nested if blocks, adding a layer of indentation below every function call? That's the stuff of nightmares. Heck, the MS compiler added the goofy __try, __leave, and __finally statement just to encourage proper use of goto in C code, by calling goto something different.

      --
      Socialism: a lie told by totalitarians and believed by fools.
    2. Re:GOTO and the arguments for it by __aaclcg7560 · · Score: 1

      In FORTRAN you easily see a 1000 lines program with 1 or 2 dozens of GOTOs, where the same program written in proper C or Pascal (and any other modern language) has zero.

      For a while I was converting old BASIC games that I never got to work as a kid in the 1980's into Python scripts. Some BASIC games had an elaborate "fall through" decision structure at the end of the program that made it difficult to trace all the GOTOs going in and out. The behavior was in some ways similar to a SWITCH statement. Of course, Python has no SWITCH statement. Rewriting these GOTOs into function calls was an education in itself.

    3. Re:GOTO and the arguments for it by angel'o'sphere · · Score: 1

      I don't know.
      I never needed to write such code.

      I doubt it exists :D

      And that was not the point anyway.

      Neither Djikstra no any one else is arguing against "proper use" of GOTOs but against ABUSE, perhaps you want to reread my post you answered to.

      --
      Cost free eBook I read (by iBook/Kobo/Amazon/ObookO/Gutenberg etc.): "The Green Odyssey" by Philip Jose Farmer.
    4. Re:GOTO and the arguments for it by angel'o'sphere · · Score: 1

      Interesting. Did not know about the lack of a switch in Python.
      This is interesting: http://stackoverflow.com/quest...

      --
      Cost free eBook I read (by iBook/Kobo/Amazon/ObookO/Gutenberg etc.): "The Green Odyssey" by Philip Jose Farmer.
    5. Re:GOTO and the arguments for it by lgw · · Score: 1

      Well, your claim of "I don't get why people defend the usage of GOTOs with claws and teeth." was rather broad. People defend proper use of goto in C fiercely, because of the constant stream of idiots who've never worked with that sort of code, but are sure it must be wrong, because they read that somewhere.

      --
      Socialism: a lie told by totalitarians and believed by fools.
    6. Re:GOTO and the arguments for it by angel'o'sphere · · Score: 1

      People defend proper use of goto in C fiercely
      Then reread my post.

      The defend it fiercely because they don't understand the meaning of "GOTO considered harmfull".

      Again: the resonating phrase was coined in a context where roughly every 20th statement was a GOTO. It never was meant to abolish GOTOs in situations where it is the straight forward solution.

      because of the constant stream of idiots who've never worked with that sort of code, but are sure it must be wrong
      I don't think such idiots exist. I never met one and I definitely did not meet one in this discussion on /.

      Or to close the circle: I would not distinguish between "those idiots" and the "idiots who immediately jump on the bandwagon of pointing out rare situations where a GOTO is appropriated" ... both are the same idiots for me. Both don't grasp the historical context of the phrase.

      --
      Cost free eBook I read (by iBook/Kobo/Amazon/ObookO/Gutenberg etc.): "The Green Odyssey" by Philip Jose Farmer.
    7. Re:GOTO and the arguments for it by lgw · · Score: 1

      Again: the resonating phrase was coined in a context where roughly every 20th statement was a GOTO. It never was meant to abolish GOTOs in situations where it is the straight forward solution.

      Almost no one in the industry today understands that context. C programming standards around the world ban goto thoughtlessly. That's about like demanding all your devs use VI - of course there's a fierce holy war as a result.

      --
      Socialism: a lie told by totalitarians and believed by fools.
    8. Re:GOTO and the arguments for it by angel'o'sphere · · Score: 1

      In my over 30 years of software development:
      1) I never had a coding standard where gotos were banned
      2) I never saw a goto in any C or C++ code ... except on internet forums where it was attempted to be justified (usually very bad examples)

      But again: I'm not a zealot against gotos.
      I'm rather a zealot against discussing gotos ... sounds like a waste of time, seeing 1) and 2)

      --
      Cost free eBook I read (by iBook/Kobo/Amazon/ObookO/Gutenberg etc.): "The Green Odyssey" by Philip Jose Farmer.
  76. Re: Doesn't make it not recursion by hackwrench · · Score: 1

    Using your own stack doesn't make it 'not recursion'.

  77. GOTO is dead.We live in COMEFROM age. by 140Mandak262Jamuna · · Score: 3, Insightful
    I wonder what Djikstra would say about the modern development API and the GUI. He railed against unstructured GOTO statements, back in 1968.

    But the entire modern GUI API is based on "event driven" programming. Replete with "OnRightButtonDown()" , "OnWindowClose()" ... . These are nothing but COMEFROM statements. COMEFROM could be as harmful or even more harmful than GOTO. With a good design based on a valid state machines and object oriented code we not only handle these with east, we are successfully developing incredibly complex code.

    So, no. We did not forget GOTO just because some authority figure railed against it. We replaced it with a better concepts like event loop, event dispatching, object orientation.

    --
    sed -e 's/Chuck Norris/Rajnikant/g' joke > fact
    1. Re:GOTO is dead.We live in COMEFROM age. by phantomfive · · Score: 1

      He wasn't rigidly against GOTO. He liked programs to be structured in a way that they can be proven correct if necessary.

      --
      "First they came for the slanderers and i said nothing."
    2. Re:GOTO is dead.We live in COMEFROM age. by ChrisMaple · · Score: 1

      Typical GUI code is write-only. They are mostly indecipherable messes, although this may be due to the way libraries like Gtk and Qt are put together.

      Anyway, "comefrom" is useful for GUI and interrupt handling, but is inapplicable to the areas where the real work is done - any sort of complicated math or data analysis. There, goto can be useful.

      Object Orientation is related to goto the same way balloons are related to spiders - that is, there's no relation.

      --
      Contribute to civilization: ari.aynrand.org/donate
  78. Really? by John.Banister · · Score: 1

    And, after this, we'll see and article titled "Developer argues for unilateral editor switch" that ends in "it begs the inevitable question. Are you ditching emacs in favor of vi -- and should you be?"

  79. Re:Recursion is dead! by mysticgoat · · Score: 4, Informative

    I was there.

    Circa 1980, GOTOs in early BASIC and also 6502 Assembly were appropriately used to maximize the limited resources of early desktop computers. A particularly elegant technique on the Apple II was to POKE instruction codes into the keyboard buffer and GOTO it (the Lamb technique IIRC). While the KB buffer was only something like 128 bytes, it was long enough that a GOTO to a computed destination could be built in it and, wowsa, suddenly Applesoft BASIC had a very powerful CASE emulation.

    Naked GOTOs were no longer needed when disk drives replaced tape drives, and RAM grew from 4, 8, or 16 kilobytes to the incredible size of 640 kilobytes. We still used GOTOs that were clothed within Structured Programming constructs (IF-THEN, DO-UNTIL, WHILE-DO, etc) but those were tamed GOTOs. The wild, naked GOTOs became much more rare and good programmers charged with maintaining legacy software would savagely hunt them down and destroy them.

    Meanwhile, Gee-Whiz BASIC (arguably the only really good thing to ever come out of Microsoft) let us replace line numbers with labels and brought about the Business BASIC revolution circa 1985.

    Dijkstra first used the phrase "GOTO considered harmful" in 1968, only 3 years after BASIC was written and about 7 years before BASIC was widely used (the costs associated with moving from Big Iron using centralized card and tape readers to minicomputers with networks of remote terminals slowed BASIC's adoption.) He was talking about FORTRAN and COBOL practices. His work was part of the slowly dawning recognition that it was not sufficient to write a program that solved the problem; that you also had to write it in such a way that you could maintain it or repurpose it next month or next year. That was the dawning of what became known as structured programming practice.

    Bringing this back to the present, using recursion makes a great deal of sense when time to production, long term costs of code maintenance, or repurposing are things that need to be considered.

    Obviously if the code is one-off throw-away, like a tool that will be used in converting the accounting system database from warehouse inventory to just in time purchasing, then maintenance is not a consideration but neither is efficiency. Slap together whatever will work and get on to something else asap; don't take time to rework a recursion into something faster or more robust unless the software breaks on a pre-production trial run. And then look for a quick and dirty fix.

    But if the code is likely to still be in use five years in the future, then write it so the poor bastard whose got to maintain it can understand it as quickly as possible. That could well mean using recursion. The same goes if chunks of the code might be re-used in some other way, say for example taking chunks from an inventory application to build a library system for maintenance manuals.

    Also keep in mind that today's hardware limitations will not apply to tomorrow's problems. It is perfectly acceptable to use a recursion that you know will fail on the 20th iteration if you also are assured that there will never be a need for more than 19 iterations in the next 5 years. In other words, don't waste yourself trying to fix tomorrow's problem, which may no longer be a problem when tomorrow rolls around.

  80. Re:Recursion is dead! by alexo · · Score: 1

    Goto is for quiche eaters. Real men use setjmp/longjmp.

  81. Re:Recursion is dead! by OneSmartFellow · · Score: 1

    goto is for people who can't understand nested code.

  82. Re:Recursion is dead! by TheRaven64 · · Score: 1

    In this example, you get much cleaner code from inverting your if conditions so that they're checking for success, not failure, and the proceed version is inside the next indentation level. You can then cleanly see what failure condition corresponds to which cleanup, in both directions, using the indentation level. Linux developers are allergic to this for two reasons. The first is that they set their tab width to 8 and have an 80-column maximum line width, so code written with this kind of structure quickly runs out of horizontal space. The second is that GCC 1.x generated much better code from the goto version (since 3.0, probably 2.x but I've not actually tested it) it will generate byte-for-byte identical code from both.

    --
    I am TheRaven on Soylent News
  83. Re:Kernels should only be in assembler by fisted · · Score: 1

    While you're free to want your OS written in assembler, I prefer mine to be written in compiler.

  84. Re:Recursion? Forgotten? by lgw · · Score: 1

    It's only the first thing you learn to do in SICP.

    Not even MIT still uses SICP, sadly.

    --
    Socialism: a lie told by totalitarians and believed by fools.
  85. Re:Recursion is dead! by TheRaven64 · · Score: 1
    There's a difference between the break and a goto: the break target can only go up an exact number of scoping depths. With goto, you can do horrible things like jump over the declaration of a variable. Consider this code:

    if (b)
    goto x;
    int y = 1;
    x:
    return y;

    Clang and GCC won't even warn when you do this, but if b is true then this code contains undefined behaviour (the initialisation of y is not reached - even though the initialisation is inline with the declaration). In contrast, the standard explicitly prohibits jumping over a declaration in other contexts. If you restructure the above example to use a switch statement to jump over the declaration of y, then you'll see the code rejected at compile time.

    --
    I am TheRaven on Soylent News
  86. Re:I miss multiple inheritance in Java .... by lgw · · Score: 1

    regularly. About every other month. It's kind of eerie how reglarly it happens that I'm saying 'this is an A and a B with some new stuff but I can't do this can I" to my java IDE.

    Java added back multiple inheritance via "default implementation of interface methods". It's awkward, but that's java for you.

    --
    Socialism: a lie told by totalitarians and believed by fools.
  87. Re:Recursion is dead! by colinrichardday · · Score: 1

    Maybe not better than return, but goto might be better for breaking out of deeply nested code.

  88. Re:Recursion is dead! by Spazmania · · Score: 1

    I've been coding in C professionally for a quarter of a century now. I still haven't run in to a situation where I thought, "Wow, that guy's use of goto makes things so much cleaner." Run in to plenty where I thought, "WTF is going on here?"

    Goto breaks the pattern for control flow through a program. When you need to debug the program, goto makes it needlessly hard to figure out how you reached that piece of code.

    And frankly, if you can't write a clean, efficient program without goto, you're not very good at programming.

    --
    Moderating "-1, Disagree" is simple censorship. Have the guts to post your opinion.
  89. Like Terry Pratchett said by chthon · · Score: 1

    "It's sometimes better to light up a flame thrower than to silently curse in the dark"

  90. Do *not* spider web with recursive function calls by raymorris · · Score: 1

    > Without recursion, data structures like trees or graphs are useless. Kind of a problem if you have a directory tree structure, or you want to follows URL links for web scraping.

    I would say web scraping is a good example of when you should NOT use a recursive function. My first web scraper looked like this:

    scrape_page(url) {
          links = get_links(url);
          foreach(link in links) {
                  scrape_page(link);
            }
    }

    On a site like Slashdot, which has many pages (on for eaxh comment posted), that fails wonderfully.

    My i improved version, which has been running successfully for many years, looks like this:

    scrape_page(url) {
          links = get_links(url);
          foreach(link in links) {
                  add_to_queue_database(link);
            }
    }

    Note scrape_page no longer calls itself, it's not a recursive function. It's driven by this main() function:

    while (url = get_url_from_queue_database() ) {
            scrape_page(url);
    }

    The queue is held in a database which can easily store hundreds of thousands or millions of urls, There is no recursive function and it doesn't die when spidering a forum. It also doesn't lose all its queue when stopped and restarted.

    Some people would point out this solves a recursive and say it's therefore a recursive algorithm. The algorithm isn't recursive by definition because no function calls itself, even indirectly.

  91. Limitations for bad programmers by bussdriver · · Score: 1

    Good programmers may not be commonplace and that in itself might be to reason to ban freedom and make everything as constrained and idiot proof as possible... I'm not one of those people... I am for formal language "modes" where you can specify your skill level. Then GOTOs can be forbidden except for those who have an approved skill level.

    As we should all know, loop and if constructs are merely specialized use cases for GOTO. Not every situation has been abstracted into a safe language construct. C lacks the ability to break out of nested loops, same with C++. One has to work around the language constraints adding complexity and performance loss. Now adding an argument maybe a label could have provided another abstraction for another GOTO use case for specifying the loop to jump to.

    Exception handling is another abstraction use case for GOTO. Along with the "come from" event model we use which is especially awkward in async and parallel situations. These continue to have poor abstractions that add complication trying to do things that a GOTO or an evolved GOTO would address. I'm saying we should leave power tools around for those who know how to use them so that better abstractions can be created for the lesser programmers. Exceptions being a great example which really couldn't be done without an evolved GOTO but behind the scenes language programmers did all the difficult work. For async event callback coding we currently have kind of a mess everywhere with Java 8 being an impressive hack but only to bring it into the same mess.

    How about call back closure situations where you flip the situation and have the code block until the async completes but it jumps to a function or up the call stack for the idle running code. Quite often you have the a where you just want to spawn async tasks and the response to the async task belongs right next to it (hence the popularity of closures.) So now you don't have closures, it just blocks and life is easier "the fork in execution" instead is jumping to the idle code instead of jumping to the callback code. Do I make myself clear? The OS does this already for processes-- your process blocks without any concerns and the OS shifts processing elsewhere.

  92. GOTO is fine! by Murdoch5 · · Score: 1

    Developers who speak out against GOTO, show their amateur or assumed armature level or experience. `I had a prof in University who spoke out strongly against it, even going to lengths such as costly loops and costly checks to get around using a simple GOTO, his code was made worse because he refused to use it. If you honestly feel GOTO is an unexceptionable statement in programming, then please write a program in ASM and NEVER use JMP!

  93. Re:Recursion is dead! by fahrbot-bot · · Score: 1

    History lesson.

    https://en.wikipedia.org/wiki/Considered_harmful

    Future history lesson: Mostly Harmless

    --
    It must have been something you assimilated. . . .
  94. Re:Recursion is dead! by TheRaven64 · · Score: 1
    You never had this constraint in standard C. You did, until C99, have to declare the variables at the start of a block, but this was still valid C even then:

    if (b)
    goto x;
    {
    int y = 1;
    x:
    return y;
    }

    Even without the corner cases related to declarations, being able to enter a block anywhere other than the start makes reasoning about control flow harder than it needs to be.

    --
    I am TheRaven on Soylent News
  95. "a much better pattern" by bool2 · · Score: 1

    That's a bit subjective. I think I would call it an alternative pattern.

    I have seen it work well but more often than not I have seen create code that looks like an arrow. In real life, outside of trivial snippets, arrow code can be horrible to read and maintain. That's not always the case though hence I don't say it's a "worse" pattern - just an alternative.

  96. Re:Recursion is dead! by vux984 · · Score: 1

    Its not really cleaner though if you are doing a lot of operations that check for errors. You could be doing a bunch of file io, for example, and need to check for errors after pretty much every line.

    Nesting 50 levels deep for success checking is not 'cleaner' and it obscures any actual conditional logic and structuring you've got.

  97. Re:Recursion is dead! by david_thornley · · Score: 1

    Memory cleanup is a nonissue in many languages. A lot use GC to dispose of memory, and C++ uses destructors. Putting cleanup code at the end of a function is somewhat fragile, particularly in a language with exceptions.

    --
    "When you have eliminated the unacceptable, whatever is left, however improbable, must be the truthiness" - Holmes
  98. Re:Recursion is dead! by ChrisMaple · · Score: 1

    There are situations where multiple if(a) free(a); results in cleaner and more compact source code.

    --
    Contribute to civilization: ari.aynrand.org/donate
  99. Re:Recursion is dead! by david_thornley · · Score: 1

    You might want to free your memory and close your open file on success also. Now, if you were using C++ and unique_ptr, everything would automatically be freed and you wouldn't have a memory leak if you add an allocation and don't put the free() in at the end.

    --
    "When you have eliminated the unacceptable, whatever is left, however improbable, must be the truthiness" - Holmes
  100. Re:Recursion is dead! by ChrisMaple · · Score: 1

    Nested code is for people who can't understand goto.

    --
    Contribute to civilization: ari.aynrand.org/donate
  101. Re:Recursion is dead! by david_thornley · · Score: 1

    In C and C++, "break" usually replaces "goto" for leaving loops, but when you need to break out of multiple loops there's really nothing better than a goto with a nice descriptive target label.

    --
    "When you have eliminated the unacceptable, whatever is left, however improbable, must be the truthiness" - Holmes
  102. Re:Recursion is dead! by david_thornley · · Score: 1

    One of the reasons I use higher-level languages is that abstracting away the details works a lot better than paying attention to them. If I use a break; in a for loop, I know at a glance what it's doing. If I substitute a "goto", I have to pay attention to the target line. Switches work more like if...else constructs than gotos, unless you're using something like Duff's device.

    --
    "When you have eliminated the unacceptable, whatever is left, however improbable, must be the truthiness" - Holmes
  103. Re:Recursion is dead! by fisted · · Score: 1

    Sigh.

  104. Re:Recursion is dead! by david_thornley · · Score: 1

    That's twisted. My own instinctive way to do it would be the first ..., then if (!exit_cond) ....There's no reason to use a "goto" here.

    --
    "When you have eliminated the unacceptable, whatever is left, however improbable, must be the truthiness" - Holmes
  105. Re:Recursion is dead! by ChrisMaple · · Score: 1

    I designed an audio DSP processor that had to always run exactly 1024 instructions and then start again at instruction number 0. There was no jump instruction. Instead, when conditional operation was required, the next N instructions could be prohibited from writing or setting condition codes.

    --
    Contribute to civilization: ari.aynrand.org/donate
  106. Re:Goto by david_thornley · · Score: 1

    You're missing the point of language abstractions. Ideally, we write our program in an easy-to-understand manner, and the compiler makes it run efficiently. In practice, this doesn't work as well as we'd like, but we're specifically talking here about a compiler that does what we really want.

    --
    "When you have eliminated the unacceptable, whatever is left, however improbable, must be the truthiness" - Holmes
  107. Forgotten? by allo · · Score: 1

    Maybe if you use some new hipster frameworks. Real programmers know their constructs and when to use them.

  108. Python is the wrong language by tepples · · Score: 2

    By your criteria, Python is the wrong language, and this is intentional. See Guido van Rossum's explanation: part 1 and part 2.

    1. Re:Python is the wrong language by Pseudonym · · Score: 1

      To be fair, Python is the wrong language.

      --
      sub f{($f)=@_;print"$f(q{$f});";}f(q{sub f{($f)=@_;print"$f(q{$f});";}f});
  109. Re:Eval is a Beginners' Trap and a Huge Security H by david_thornley · · Score: 1

    Eval is not something to be used casually, but it's vital to how some languages work. My general rule is that, if you use it while writing application code, it's probably a mistake, but it can be very useful in libraries to do things and the like. Much like C++ template metaprogramming: very powerful, and most people should leave it for someone else to write.

    --
    "When you have eliminated the unacceptable, whatever is left, however improbable, must be the truthiness" - Holmes
  110. Re:Recursion is dead! by Thanatiel · · Score: 1

    Please do not do this.

    Do one allocation of the sum of the 3, taking alignment into account (ie: 8) and divide the allocated block to the relevant objects.

    One NULL test.

    One free.

    I understand you were making a point, but we are speaking about "good ways" and this itches so much I had to reply -_-;;;

    --
    Irrelevant news and morons using moderation to mod down what they disagree on. 2018 resolution: so long.
  111. Re:Recursion is dead! by fisted · · Score: 1

    No, I prefer things to be simple and portable.
    Besides, what you're doing is premature optimization, the well-known root of all evil in programming.

  112. Re:Kernels should only be in assembler by ChrisMaple · · Score: 1

    Carry flag. Sign flag. Overflow flag. Zero flag. Fucking flag.
    if(fucking) goto fubar;

    --
    Contribute to civilization: ari.aynrand.org/donate
  113. Re:Recursion is dead! by Rockoon · · Score: 1

    Translation: Its best at least once! Therefore its always best!

    Both your lack of knowledge and lack of logic skills do not surprise me.

    --
    "His name was James Damore."
  114. Re:Goto by Rockoon · · Score: 1

    You're missing the point of language abstractions.

    You mean like the "low level" C abstract machine?

    There is a reason the abstraction is similar to how hardware handles memory.

    Conclusion: We do not choose our abstractions based on human needs alone.

    --
    "His name was James Damore."
  115. Re:Recursion is dead! by vux984 · · Score: 1

    taking alignment into account (ie: 8)

    Full disclosure... I wrote the bug ridden sloppy pseudocode to make a point. Fisted cleaned up pretty nicely into something that essentially did what i was showing in a cleaner way.

    I kind of wish he'd preserved the multiple goto labels but they weren't needed in my example, although there are cases where they would be... where you want specific error handling for certain errors. Here is some hopefully less awful pseudocode.


    {

    /*allocate resources */

    if [allocate resources1] fails goto: errorhandler1
    if [allocate resources2] fails goto: errorhandler2

    /*do something */

    code to do something useful with the resources
    result = 0
    goto:cleanup

    /* error handling */

    errorhandling1:
    do something in response to 1
    result = -1
    goto: cleanup

    errorhandling 2:
    do something in response to 2
    result = -2
    goto: cleanup

    /*cleanup*/

    cleanup:
    if resource1 is allocated free it
    if resource2 is allocated free it

    return result;

    }

  116. Re:Recursion is dead! by james_gnz · · Score: 1

    Yes, goto is useful for exception handling, in languages that lack specific exception handling constructs, but have goto.

    No, not just there. In quite a few cases it would be "in languages that lack efficient exception handling constructs". And that's almost all of them.

    Okay, but I still think this points to a deficiency in the language with regard to error handling constructs, rather than being an argument in favour of goto as a language construct (other than as a stop-gap measure).

  117. Re:Do *not* spider web with recursive function cal by Megol · · Score: 1

    I'd say that's still recursive however with a buffer.

    Map the data flow and you should see why I think it's still recursive...

  118. Re:Do *not* spider web with recursive function cal by JesseMcDonald · · Score: 1

    Some people would point out this solves a recursive and say it's therefore a recursive algorithm. The algorithm isn't recursive by definition because no function calls itself, even indirectly.

    The algorithm is still recursive; the recursion is just built in to the language in the form of predefined iteration constructs like "foreach" and "while". Any time you have an iterative program of the form "first do X, and then repeat the process for the remaining input", that's recursion: one of the steps in the process (the repetition) is defined in terms of the process itself.

    Some recursive algorithms can run in constant space, while others (such as most operations on trees) inherently require more space to process larger inputs—even when implemented "iteratively". The space used does not depend on whether the recursion is implemented with explicit function calls or loops, but rather on the quality of the compiler, including, but not limited to, tail-call optimization. Far from being complex wizardry, this optimization is really just the correction of a common implementation flaw wherein a function's stack frame remains allocated until the function returns, rather than being freed once it is no longer needed. This simplifies the compiler slightly at the cost of forcing the programmer to distinguish between implicit and explicit recursion, thus impairing the readability of naturally recursive algorithms and sparking endless debates over what ought to be a trivial difference of coding style with no runtime effect.

    --
    "The state is that great fiction by which everyone tries to live at the expense of everyone else." - Bastiat
  119. Re:Eval is a Beginners' Trap and a Huge Security H by K.+S.+Kyosuke · · Score: 1

    It may be very well advisable for Matlab's eval, especially since Matlab itself is better avoided. In other languages, you can often use COMPILE instead of EVAL anyway. (Chances are that this is what you actually want to do in many cases.)

    --
    Ezekiel 23:20
  120. Re:recursion is "forgotten" now? by K.+S.+Kyosuke · · Score: 1

    Because non-hardware stacks on your computer use some special kind of physical or virtual memory that is somehow magically more plentiful than the memory your computer uses for hardware stacks?

    --
    Ezekiel 23:20
  121. Re:Recursion? Forgotten? by K.+S.+Kyosuke · · Score: 1

    Technically, MIT does still use SICP. I believe the class is called "Advanced Symbolic Systems" or something like that.

    --
    Ezekiel 23:20
  122. Re:Do *not* spider web with recursive function cal by raymorris · · Score: 1

    Arguments might be avoided by saying it's not a recursive FUNCTION - no function calls itself, can't run out of stack space. It *is* a lot like what happens when you start with a tail-call recursion then remove(?) the recursion. If somebody wants to call it a recursive algorithm I feel no need to really argue about it, though I will ask you a question or two.

    > Any time you have an iterative program of the form "first do X, and then repeat the process for the remaining input", that's recursion: one of the steps in the process (the repetition) is defined in terms of the process itself.

    Care to point to which step "is defined in terms of the process itself"? I don't see that anywhere.

    It's very similar to recursion, but my understanding of the definition of recursion is that the definition/implementation of X must reference X. I don't see that in my code anywhere.

  123. Definition: X defined using X by raymorris · · Score: 1

    What's your definition of recursion? My informal definition:

    X is recursive if and only if X is defined / implemented by calling X, directly or indirectly.

    One dictionary definition is similar:
    A routine, function etc in which a part is defined in terms of the whole.

    Just because the output of a function X(a) may be, at some later time, be passed to another seperate instance of X(b) doesn't make it recursive, imho, if X(a) TERMINATES before X(b) begins, because X() makes no reference to itself.

  124. Re:Recursion is dead! by fisted · · Score: 1

    I kind of wish he'd preserved the multiple goto labels

    But eliminating those was the whole point of the cleanup. Having to maintain (and get right) the per-failure jump targets is, IMO, more of a mess than just doing the cleanup right away without jumping.

    And if it's just about returning a failure-specific exit code, you could implement that without multiple labels by assigning to a variable before jumping.

  125. Alternative definition by raymorris · · Score: 1

    Here' s an alternative definition:

    A recursive algorithm is defined as any algorithm which is recursive. ;)

  126. Can't go without Recusion, needbe must goto recurs by manojkg · · Score: 1

    Goto does ease redability of complex logical jumps .. and would still be a prefer choice. Recursion bit difficult(or impossible) to replace -- it may change in syntax, and may be called something else, but at core recursion does exist -- whether in parser, far known leaf node traversal, email parts parsing etc etc.... They both are neat and clean ... I always support them, and use them as and when necessary.

  127. Re:Recursion is dead! by james_gnz · · Score: 1

    Yes, goto is useful for exception handling, in languages that lack specific exception handling constructs, but have goto.

    Goto is useful even in languages with exception handling. Exceptions isn't really a good way to deal with errors. It encourages grouping several errors together with a single error handling routine for all of them. That is one of the reasons exceptions are frown upon in embedded and/or safety critical applications.

    I didn't intend for "exception handling" to mean anything more specific than "some way of dealing with errors". I think the term can be used with this general meaning, although I suppose it is also commonly associated with a specific mechanism. In any case, if the mechanism for dealing with errors in a programming language is broken, I think the best solution would ultimately be to fix it, rather than forever working around the problem.

  128. "GOTO considered harmful" considered harmful by DutchUncle · · Score: 1

    A chainsaw don't know the difference between a log and a leg. But sometimes it's the right tool.

    http://web.archive.org/web/200...

  129. Re:Goto by david_thornley · · Score: 1

    Something like a decade ago, I tried throwing out everything I'd been taught about program optimization and just optimizing for cache use. The speedup was remarkable.

    --
    "When you have eliminated the unacceptable, whatever is left, however improbable, must be the truthiness" - Holmes
  130. Re:Recursion is dead! by david_thornley · · Score: 1

    Elevating anything in software development to the level of a religion (except vim over emacs) is as crazy as any other religion. Similarly, saying that a developer should use a language construct where inappropriate because it might be appropriate in another application is crazy. Obviously, you're going to use jumps in assembly code, but you need to examine them to make sure they're doing what they should. In C, most applications of goto should be replaced by appropriate control structures that make it obvious what they're doing and reduce the chance of mistakes.

    --
    "When you have eliminated the unacceptable, whatever is left, however improbable, must be the truthiness" - Holmes
  131. Re:Recursion is dead! by david_thornley · · Score: 1

    If a is a pointer, if(a) tests a against the null pointer. This is unnecessary because free(NULL) works. It's also deceptive since a non-null pointer doesn't have to point to anything useful, and free(a) doesn't set a to the null pointer. I've seen heavy use of macros in C, where the macro executes free(a);a = NULL;.

    --
    "When you have eliminated the unacceptable, whatever is left, however improbable, must be the truthiness" - Holmes
  132. Re:Kernels should only be in assembler by david_thornley · · Score: 1

    C is definitely not assembler language. Maybe it was before ANSI got their hands on it.

    The 1989 ANSI standard didn't remove any functionality, but made the language cleaner. If it would be awkward in C89, it would be awkward in K&R C.

    --
    "When you have eliminated the unacceptable, whatever is left, however improbable, must be the truthiness" - Holmes
  133. Y2K overstated by hawk · · Score: 1

    What most people miss on Y2K is that given the constraints at the time most of those programs were written, the cost of avoiding the problem would have been roughly triple (in real terms, discounted dollars, etc.) as ultimately fixing it was.

    Yes, economists went back and actually measured, estimated, etc. Also, most of the code from the era did not, in fact, make it to Y2K, and would have incurred the costs without receiving a benefit.

    Although the resources would be negligible today, we are talking about the extra labor to punch two more digits on each and every 72 column card, the limited number of digits on those punch cards, memory for which it was a break thought when the *rental* price dropped down to a buck a byte a month, the extra processing time to handle three or four digits, etc.

    It also didn't help that so many (a strong majority?) coded in the year ending in 00 exception to leap years without including the divisible by 400 exception to the exception . . . other attempts to accommodate 2000 might have had similar blunders.

    hawk

  134. Re:Recursion is dead! by michael_wojcik · · Score: 1

    Dijkstra first used the phrase "GOTO considered harmful" in 1968

    Not even then, actually. The title of the letter, as published in CACM, is "Go To Statement Considered Harmful"; and that title was added by the editor. I just skimmed through it again, and unless I missed it, he never even uses the word "harmful".

    He does say that "go to" (boldface in the original) is "too primitive", and refers to its "undesirability" and "disastrous effects" and "(logical) superfluousness".[1]

    But the passive construction "considered harmful" is, just as its most natural interpretation would have it, an indication that someone other than the writer considers it harmful. That someone was Dijkstra; and while he cites others in support of his position, it would have been rather unlike him to step back and crouch behind the passive voice. The man was a first-order curmudgeon, bless 'im.

    [1] Prolepsis: Dijkstra's "(logical)" here is meant to indicate that yes, he is perfectly aware that Von Neumann machines implement all branches with some form of "go to". That it must be available to the machine, and thus will typically be available in assembly language, does not mean it has to appear as an arbitrary branch construct in higher-level languages.

  135. Re:Eval is a Beginners' Trap and a Huge Security H by tepples · · Score: 1

    It is rarely "the right thing," typically because it is super inefficient.

    In compiling implementations of programming languages, it's anything but inefficient.

    More and more platforms have begun to establish Data Execution Prevention (W^X) policies that give third-party applications no way to flip a page from writable to executable. These include iOS, Windows Runtime, and current-generation game consoles and gaming handhelds. Thus all compilation to native code must be either done ahead of time before packaging or done by an operating system component, such as WebKit JavaScript in iOS.

  136. Forgotten? Forbidden? by drolli · · Score: 1

    (Exclude recursion here - i think he talks about the examples given in school for recursion, which often are not good in terms of resource usage)

    About the rest: Bullshit. These are not forgotten, and they are forbidden in most coding guidelines for a reason. His musing about that goto is only bad if you jump "backwards" is borderline funny.

    There is a reason that goto should only be used in extremely rare occasions (and i would agree that some of these *may* be for kernel programming). The examples of this "programmer" are excellent examples why for people like him these should be forbidden. Any of his examples are better off without goto, and if you don't see a more efficient, clearer and safer solution without his shit, you should not program any high-level language.

    Eval is another piece of cake (I exclude python here because it seems to get eval right). My practical experience is that i is rather overused by inexperienced programmers. Filtering a string that should be evaled in a way that it has a predictable outcome is as difficult as writing an eval. Typically my recommendation would be that evals need to be a) sanctioned by a senior developer (just to make sure nobody uses these out of pure incompetence) b) encapsulated in a function (e.g. for the dection of a laguange feature/level) c) filtered carefully if they accept user input.

  137. I've used them by Stubbyfingers · · Score: 1

    GOTO was kinda special...It was to either completely exit a procedure when the input conditions were just TOO F'd up.
    Quite often the jump was to the equivalent of a "Halt and Catch Fire" sorta error processing.

    GOD, I LOVED recursion. Of course, I slung a boat load of LISP code in my younger days.

  138. How about infinite loops? by lbates_35476 · · Score: 1

    Some would say this is bad programming, but if you are programming a pacemaker, heart monitor or the like, an infinite loop is EXACTLY the construct you want. I've written some pretty ugly code (breaking out of deeply nested loops) when a simple GOTO would have cleaned things up a lot. They are all tools that have a place and time to be used.

  139. Re:Do *not* spider web with recursive function cal by JesseMcDonald · · Score: 1

    Care to point to which step "is defined in terms of the process itself"? I don't see that anywhere.

    It's part of the compiler's internal definition of the loop construct, and does not appear in the source code. In the object code it can be identified as the opcode that branches back to the beginning of the loop.

    This becomes more obvious if you consider programming languages where iteration is not a built-in construct, and loops are written in terms of explicit recursion. In Haskell, for example, a simplified C "while" keyword (disregarding "break", "continue", etc.) could be implemented as the following recursive function:

    while :: Monad m => m Bool -> m () -> m ()
    while cond body = cond >>= \c -> when c (body >> while cond body)

    Or using the fixpoint operator, without referencing the current definition by name:

    while cond body = fix (\loop -> cond >>= \c -> when c (body >> loop))

    Building on the fixpoint example above, would you call this a recursive function?

    void f(void (*g)(), int c) {
    if (c < 10) g(g, c + 1);
    }

    Sometimes it isn't so simple. The body of f() does not refer to f(). However, what happens if you call f(f, 0)? The function might be recursive, or it might not be, depending on the arguments. It all depends on that function pointer.

    Arguments might be avoided by saying it's not a recursive FUNCTION - no function calls itself, can't run out of stack space.

    It's not a recursive function, since it's not the entire function that's repeated. It would be more accurate to say that it contains a recursive function, though that inner function is hidden behind the loop construct. Barring the use of alloca() or similar it won't run out of space on the function-call stack, since alloca() / variable-length arrays and function calls are the only ways to allocate from the function-call stack, but the iterative version of the function still needs to track the same data and can still run out of memory given large enough inputs—just not stack memory. Sometimes that distinction is important, but more often it isn't, especially given the stack sizes available to programs running on most virtual memory based operating systems, ranging from several megabytes to "malloc() would fail first". (After all, some languages allocate stack frames from the heap.)

    Anyway, the fact that (unoptimized) tail calls use stack space while iteration constructs ordinarily do not is nothing but an artifact of poor compiler implementation, and easily corrected through tail-call optimization. It's really no different from the way some languages with simplistic garbage-collection algorithms (e.g. Perl) fail to collect sets of objects with cyclic references. You can either take pains to avoid cyclic references (tail recursion), or just switch to one of the many modern languages which don't cause arbitrary runtime errors when you write code in the most natural style. Given a reasonable guarantee of tail-call optimization, function calls in general may allocate additional function-call stack space, but a call in tail position won't, so tail recursion is exactly the same as iteration in terms of expected stack use.

    --
    "The state is that great fiction by which everyone tries to live at the expense of everyone else." - Bastiat
  140. Does not need to track parent, not 500 instances by raymorris · · Score: 1

    > but the iterative version of the function still needs to track the same data

    It seems to me that it does not. Looking at the actual state information of my program after running for three years appears to confirm that.

    In a moment, you may wish to refer to my code posted above, but we'll start by talking about the clearly recursive version.

    Some years ago, I pointed my spider at a large, deep directory of urls with many links. Imagine dmoz.org. Since then, it's followed links several million deep. Were it recursive (in the traditional sense), there would now be several million copies of the function *running*, each with a stack pointer to its parent. For the URL it's currently spidering, we'd have the full history of how it got there, the url that linked to it, all on the stack. Also any other variables local to the function would still be live in memory - millions of instances because millions of instances of the function are still running.

    Using the iterative algorithm I posted above, I think you can see that we do NOT track any data whatsoever about how we got to the current URL. All of the information about past pages, which would be on the stack in a recursive algorithm, do not exist in my program. So in fact it does *not* "track the same data" and your idea that it "can still run out of memory" is disproven by the fact that it's been running for years, millions and millions of iterations, and it's still using the same 3MB of RAM that it started with, plus a few MB for the queue.

    You are certainly correct that you *can* simulate iteration by using recursion. That doesn't mean you must.

    The key point, to me, is that at least what I mean by "recursive" is that there is a parent and a child. The parent doesn't return/exit until its child does - and its child, and its child, and its child, and its child ...
    With the iterative algorithm, one completes, and releases all of its memory, then another one starts. There is only one instance running at any given time, and therefore only one copy of the variables. There is no "parent", only "previous", which has no other relation to the currently running code - the previous URL isn't even the one that linked to the current url!

  141. Re:Does not need to track parent, not 500 instance by JesseMcDonald · · Score: 1

    Using the iterative algorithm I posted above, I think you can see that we do NOT track any data whatsoever about how we got to the current URL. All of the information about past pages, which would be on the stack in a recursive algorithm, do not exist in my program. So in fact it does *not* "track the same data"...

    You're comparing apples and oranges. The iterative version of your program is not using the same algorithm as the recursive version. You replaced a depth-first search with a breadth-first search, which makes your example completely irrelevant for comparing iterative vs. recursive implementations of the same algorithm. Among other things, the order in which your web crawler visits pages is very different in the iterative version. To maintain the original order you would need to restore the depth-first search algorithm, which would imply tracking the chain of pages you came from—exactly like the recursive implementation, though you could store that information on the heap or in a database rather than on the stack. (Note that a tail-recursive implementation would also store that information on the heap or in a database... this isn't a matter of recursion vs. iteration.)

    You are certainly correct that you *can* simulate iteration by using recursion.

    The tail-recursive implementation is not "simulating" iteration. It is iteration. Expressing the same algorithm with a loop construct rather than an explicit function call would not make it any less recursive; the loop implies a built-in fixpoint operator. If this trivial difference of style makes any difference in how much stack space your function uses, that's a bug in your toolchain.

    The key point, to me, is that at least what I mean by "recursive" is that there is a parent and a child. The parent doesn't return/exit until its child does - and its child, and its child, and its child, and its child ...

    That is not what "recursion" means. Moreover, how would that definition even account for something like tail-recursion, where the "parent" is replaced by the "child"? Logically, the "parent" still does not exit until the "child" does, but in the meantime it occupies no space on the stack and the return from the innermost "child" is also the return from all of the "parents". No matter how deep the tail-calls become, the stack use remains constant. Recursion only requires additional stack space when there is more for the function to do after the call, i.e. when it is not tail-recursion. Such cases cannot be converted to iteration (using the same algorithm) without shifting all the data required by the continuation from the function-call stack into some other data structure.

    --
    "The state is that great fiction by which everyone tries to live at the expense of everyone else." - Bastiat
  142. The web isn't a tree, it's a network by raymorris · · Score: 1

    When we started this discussion, that quote at the bottom of the Slashdot page was James Baldwin
    --
    Those who say it can't be done are usually interrupted by others doing it.
    --

    > The iterative version of your program is not using the same algorithm as the recursive version.

    Okay so you acknowledge there are iterative algorithms, there are recursive algorithms, and not all iterative algorithms are recursive, right? That's an important point.

    > You replaced a depth-first search with a breadth-first search

    In fact it's (mostly) depth-first.

    > the depth-first search algorithm would imply tracking the chain of pages you came from

    Let's try a little experiment. Clear your browser history, then try clicking a link. Amazingly, you can go forward (in depth) without knowing your full history of where you came from! This isn't theoretical, as I said, I've spidered millions and millions of pages, by roughly following the first unvisited link on each page. If I were in the mood, I'd give you a core dump from my spider and you'd notice that nowhere in the core does it have the starting page from several years ago. (Unlike a recursive tree walk, which would have that data.) "But how do you get back, to follow another branch?", you may ask.

    The first thing apparent is that once you've spidered a page, you're not going to spider the same page again, so you can forget all about it! There is no need to track all the parents. You need only remember some *unvisited* pages, none of the visited pages. So no, it's not correct to say "depth-first search algorithm would imply tracking the chain of pages you came from". Rather, you must track the head of the branch you did NOT come from. That'll be where you go next if you end up on http://hmpg.net/ (check out that page).

    Further, we're discussing spidering the web, which is first a network, not tree. You seem to be thinking in terms of a tree. More importantly, the web is a real practical, thing, for which I gave an algorithm that's actually been at work for many years, as opposed to walking some theoretical tree. Because of the nature of the web, as a real network, you can discard 99.999% of the information which you would need for a complete walk of a theoretical tree. No need to remember *every* link you didn't visit, you'll never spider every page on the web anyway, and if you wanted to try you could always start back at dmoz.org or *any* large list of links. The network (the actual www) is such that there are many nodes (sites) which connect indirectly to ~every other available site. So the actual working algorithm doesn't know where it came from. What it *does* remember is a list of 1,0000 URLs it can go TO next. That's all it needs to know - where to go next, not where it came from. It ends up being depth-first because I made the list of "next URLs" a 1,000 element LIFO. I've also run it breadth-first by simply working the other end of the list, FIFO.

  143. MySQL Requires Eval by brian.stinar · · Score: 1

    MySQL will not allow table names to be passed in as parameters to a stored procedure [1] [2] [3]. Without eval, there is no way to dynamically use a stored procedure to operate over multiple, different, tables without enumerating all the tables. The code needed for the "safe" approach is massively bigger, n * m, where m is the body of your stored procedure and n is the set of tables you want to operate over. It also requires such a massive degree of code duplication to make it significantly less safe.

    We have a reporting system called MyDBR that requires everything to be done in MySQL or JavaScript. Likely, a stored procedure isn't the best answer for my problems, but it's better than JavaScript. Probably the "safest" answer is to throw away MyDBR and use an actual programming environment to accomplish what I'd like (sane reporting.)

    The entire premise of this article seems odd to me. Who would forget these techniques, unless they never really learned them in the first place? And why would the author want to revisit them? I think because it was a slow news day.