Please create an account to participate in the Slashdot moderation system

 



Forgot your password?
typodupeerror
Programming IT

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

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?
This discussion has been archived. No new comments can be posted.

Developer Argues For 'Forgotten Code Constructs' Like GOTO and Eval

Comments Filter:
  • Doing it wrong? (Score:5, Insightful)

    by Marc Beaupré-Pham ( 4860011 ) on Sunday February 05, 2017 @03:40AM (#53805719)
    Honest question: Am I not supposed to use recursion? Am I missing something?
    • Re:Doing it wrong? (Score:5, Insightful)

      by j_kenpo ( 571930 ) on Sunday February 05, 2017 @03:50AM (#53805745)

      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?

      • Re: Doing it wrong? (Score:5, Interesting)

        by PoopJuggler ( 688445 ) on Sunday February 05, 2017 @04:54AM (#53805899)
        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.
        • Re: Doing it wrong? (Score:5, Informative)

          by gravewax ( 4772409 ) on Sunday February 05, 2017 @05:02AM (#53805913)
          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.
        • 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.
          • by Z00L00K ( 682162 ) on Sunday February 05, 2017 @07:14AM (#53806205) Homepage

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

            • by allo ( 1728082 )

              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 equivalen

        • Re: (Score:3, Insightful)

          by Anonymous Coward

          Elegance.

        • Uhm then you're using the wrong language.

          Lua and scheme have tail call optimization.

          • By your criteria, Python is the wrong language, and this is intentional. See Guido van Rossum's explanation: part 1 [blogspot.com.au] and part 2 [blogspot.com.au].

        • 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.
        • by AmiMoJo ( 196126 )

          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...

        • Re: Doing it wrong? (Score:5, Informative)

          by fahrbot-bot ( 874524 ) on Sunday February 05, 2017 @02:37PM (#53807623)

          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.

    • Poor article? (Score:4, Informative)

      by kwerle ( 39371 ) <kurt@CircleW.org> on Sunday February 05, 2017 @03:55AM (#53805761) Homepage Journal

      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.

      • Re:Poor article? (Score:5, Interesting)

        by grep -v '.*' * ( 780312 ) on Sunday February 05, 2017 @08:18AM (#53806329)

        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.

        • Re:Poor article? (Score:5, Informative)

          by TheRaven64 ( 641858 ) on Sunday February 05, 2017 @01:23PM (#53807227) Journal
          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.
    • 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 thin

      • by Dog-Cow ( 21281 )

        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.

        • Re:Doing it wrong? (Score:5, Insightful)

          by religionofpeas ( 4511805 ) on Sunday February 05, 2017 @05:07AM (#53805921)

          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.

          • 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 optimizatio
      • by jbolden ( 176878 )

        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.

    • by quenda ( 644621 ) on Sunday February 05, 2017 @04:56AM (#53805901)

      Honest question: Am I not supposed to use recursion?

      It depends. See https://developers.slashdot.or... [slashdot.org]

    • 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 re

    • Pretty sure you're doing a lot better than the jackass who came up with the phrase "Forgotten code construct".
    • Read this post and it's replies. It is a good explanation of the issues with recursion.

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

    • Re:Doing it wrong? (Score:4, Informative)

      by geoskd ( 321194 ) on Sunday February 05, 2017 @12:05PM (#53806955)

      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.

  • 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.
  • 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.

  • Obvious answer (Score:4, Insightful)

    by aaribaud ( 585182 ) on Sunday February 05, 2017 @04:29AM (#53805845)

    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.

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

  • by LordHighExecutioner ( 4245243 ) on Sunday February 05, 2017 @04:41AM (#53805871)
    Somebody will publish a paper entitled: "Class statement considered harmful." and he will be applauded as the new IT guru!
    • by johannesg ( 664142 ) on Sunday February 05, 2017 @05:27AM (#53805979)

      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...

  • by jbolden ( 176878 ) on Sunday February 05, 2017 @05:14AM (#53805941) Homepage

    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.

  • 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 st

    • by swilver ( 617741 )

      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.

  • by DrXym ( 126579 ) on Sunday February 05, 2017 @06:14AM (#53806089)
    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.
  • by nateman1352 ( 971364 ) on Sunday February 05, 2017 @06:58AM (#53806185)
    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.
  • by Misagon ( 1135 ) on Sunday February 05, 2017 @08:36AM (#53806359)

    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.

  • by bradley13 ( 1118935 ) on Sunday February 05, 2017 @09:36AM (#53806499) Homepage

    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.

  • by scdeimos ( 632778 ) on Sunday February 05, 2017 @09:37AM (#53806503)
    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.
    • Re: (Score:3, Insightful)

      by Anonymous Coward

      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.

  • by Anonymous Coward on Sunday February 05, 2017 @09:40AM (#53806513)

    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.

  • by Zobeid ( 314469 ) on Sunday February 05, 2017 @09:48AM (#53806527)

    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.

  • by Zobeid ( 314469 ) on Sunday February 05, 2017 @10:13AM (#53806577)

    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.

  • by Ihlosi ( 895663 ) on Sunday February 05, 2017 @11:57AM (#53806921)
    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.

  • by 140Mandak262Jamuna ( 970587 ) on Sunday February 05, 2017 @12:20PM (#53807011) Journal
    I wonder what Djikstra would say about the modern development API and the GUI. He railed against unstructured GOTO statements, [homepages.cwi.nl] 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.

There are no games on this system.

Working...