8 ms·
All my methods take 316 arguments, and I like it that way
- showell 17y agoThis seems like a wild exaggeration: "The behaviour of every function in a mutable, imperative environment is dependent upon the state of all of the other (variables|attributes|bindings|whatever) in your program at the time the function is invoked." You can write a function in an otherwise mutable and imperative environment like Python: pi = 3.15 # damn, typo for the value of pi! pi = pi * 15 # mutate it, wrongly again def sum(a, b): return a + b print sum(7, 8) Please tell me how sum() depends on pi. The program correctly prints 15.
- cemerick 17y agoOf course, the point is that a caller of any function in an imperative environment doesn't know what state its implementation depends upon.
- silentbicycle 17y agoIt doesn't. It is a wild exaggeration. It usually isn't the 300+ variables, just a few obscured by multiple levels of indirection that can cause unexpected inconsistencies. (It gets even worse when you drag in inheritance...) Each function only depends on the arguments passed in, and variables outside of its scope which are referenced. However, the same is true of every function called inside the function, and the dependency is transitive, so the impact of changes to variables that aren't explicitly threaded through leaks outside to functions that never mention them. That's the problem. Hidden state. It's also the kind of issue that usually looks incredibly contrived in small (say blog-post-sized) code samples, but isn't funny anymore when you have to deal with big lumps of spaghetti code. Global variables make reasoning about dataflow hard. Real problem, poor description.
- anonjon 17y agoIt is an exaggeration; but only a wild one if you are doing very simple examples. Imagine you have a 'mutable' program and I have a line that says something like this. (defun frob (a b) (+ (foo a) (bar b))) Not only is frob dependent on the definitions of foo and bar, it is also dependent on the the definitions of any mutable globals that are within foo and bar. If you imagine your program as a directed cyclic graph of functions, and pretend that mutable globals are really functions that set or get a position in memory, you can see that adding more globals to your program (and using them) increases the complexity of your graph mostly by adding cycles to it. (As well horizontal jumps across the entire graph). It is true that sometimes you need these cycles to write a program (vs. a program that causes your computer to heat up and do nothing), but it is not wildly inaccurate to say that using them all the time makes your program more complex. I'm not even sure that I'm on board with the supposition that global variables shouldn't be in the language; (saying 'shouldn't' exist at all to a language feature is entirely non-pragmatic). I think it is more accurate to say that they should be in the language, but they should have a cost greater than locals, and it should be best practice to use them as little as is reasonably possible.
- Jach 17y agoI see the main point, and I try not to use globals when I can, but I can't help but recall a quote I read from somewhere: "People who are afraid of globals are usually afraid of girls, spiders, etc."
- KirinDave 17y agoI wouldn't trust the person who told you that, anymore. Pretty much the last decade of software engineering has been a slow realization how how untenable the use of large amounts of global state is.
- Jach 17y agoYou're right, of course, but sometimes globals can be the magic sauce you need to hack out something quickly. (I find global hate to be similar to 'goto' hate.)
- cemerick 17y agoAh, the "I'm a big man, I code by writing bits to the platters with a magnet" argument. (Quick, prize to the first xkcd link here!)
- francoisdevlin 17y agohttp://xkcd.com/378/ http://xkcd.com/378/ You asked :)
- Jach 17y agoI found it an amusing quote, and I'm a strong believer in using the right tool for the right task. :)
- eru 17y agoAlso frob is dependent on the (mutable) definitions of foo and bar. Functions can be redefined in e.g. Python and Scheme. (And functions are variables, too.)
- olavk 17y agoClearly you can see in the implementation of the function that it doesn't rely on any globals. However if you look at the function as a black box, you cant really be sure what global state it relies on. This could be an issue if you use larger libraries you didn't write yourself (or in my case, if I use code I wrote more than two weeks ago!). In a language like Haskell the type signatures clearly indicates which global state the function (and other functions called by it) has access to, which makes it a lot easier to reason about side effects, even for code where you haven't read the source. Of course, this approach also have its downsides. If you decide for debugging purposes to add a logging function to an otherwise pure function deep inside a pure part of your program, you may have to change a whole lot of code.
- jrockway 17y agoHow do you know that "+" doesn't depend on pi? Oh. Now you see the problem.
- EricBurnett 17y agoIf you need 100% guarantees, then yes, do things in a purely functional way. However, I think the point is that in any sane program you can easily and safely make the assumption that + does not depend on pi in this situation. Yes, anything _can_ depend on any and all globals, but with proper practices, documentation, code reviews and what have you, one can make simplifying assumptions on what _will_ happen.
- jimbokun 17y ago"...but with proper practices, documentation, code reviews and what have you, one can make simplifying assumptions on what _will_ happen." Or you can leave out the practices, documentation, and code reviews and use a functional language and get the same result. Yes, those things are useful for other reasons, but the current argument is about avoiding the inherent dangers of global variables.
- KirinDave 17y ago"Sum" is written functionally, thus it is not dependent on the outside world. You used a functional stateless method to show that imperative stateful programming is safe.
- gecko 17y agoThis argument is absurd. All functional languages have mutable global variables. Most provide explicit support for mutable values (e.g., Scheme, OCaml), but even in the "pure" ones, there are the secretly global mutable values. Clojure gets them from its STM and from classes in the JVM. Erlang stashes them in ETS, DETS, and Mnesia. Haskell shoves them into the IO and State monads (among others) and hopes you won't notice. In all of these cases, the variable changes may be isolated, threadsafe, or internally consistent, or however you wish to describe it, but if that's not mutable state at a global level, I don't know what on Earth you'd call it. In all cases, this means that a function called twice in a row from the same point in a program may return two different values--and that's exactly what the author is saying is a flaw of imperative languages. Turning things around, while it's theoretically possible that any given function mutates global state in random ways, no good program is written that way. Instead, the relevant state is passed to a function in the form of a struct or class--exactly what you'd be doing in a functional language, as it happens. The only difference is that the function can, and sometimes does, mutate the structure passed to it, whereas the functional equivalent would likely return a slightly different version of that struct. But, again, a combination of passing things conservatively, naming functions well, and making heavy use of const/final/sealed/what have you to lock things down makes this problem largely absent in practice. I am not saying that functional programming can't a huge improvement for some things. I am utterly convinced that a multithreaded program should be written in a functional way, if not in a purely functional language. I likewise tremendously favor functional languages for algorithm-heavy applications, where the ease and safety with which I can backtrack and memoize can yield huge productivity gains. But saying that all imperative programs have hundreds of arguments, while functional languages have only those defined? Unless you do no output with the outside world, that claim is simply ludicrous.
- cemerick 17y agoSTM, agents/actors, et al. are not "mutable global variables" -- they are all ways of working with state within the bounds of defined semantics. Huge difference, and largely irrelevant to the current discussion. Who said anything about mutating global state in random ways? All you need is to have some state mutated in some way that you aren't aware of to make life hell in an imperative environment. Considering that that happens all the time, especially given the modern conveniences of large frameworks and libraries... > But, again, a combination of passing things conservatively, > naming functions well, and making heavy use of > const/final/sealed/what have you to lock things down makes > this problem largely absent in practice. This is flatly wrong, and equivalent to saying that you can write concurrent code in an imperative environment without a problem as long as you use locks just right.
- statictype 17y agoDoesn't this fit the definition of a strawman argument? It's entirely possible and very natural to write imperative programs that don't rely on every possible global variable your application has ever declared. True, if you're writing a library for consumption by others, then you would have to make it clear that your function depends on certain global variables being defined. But I would like to believe most people writing APIs for use by other programmers would know better than to rely on this type of behavior.
- olavk 17y agoIn Haskell you can easily fake an environment with a bunch of mutable global variables avaliable throughout the program, although this is frowned upon. Since global mutable variables are discouraged even in imperative languages, I agree that the argument is a strawman. There is however a nice property that Haskell makes it explicit in the type signature if global mutable state is available to the function. This makes it a lot easier to guarantee that large parts of a program is indeed side-effect free.
- nostrademons 17y agoI think a lot of people missed the article that this one is replying to: http://prog21.dadgum.com/54.html http://prog21.dadgum.com/54.html That article's main point was that functional programming doesn't work because deep in the bowels of two otherwise-pure leaf functions, you might want to make their behavior interdependent. In an imperative language, you can do this through adding a simple global variable. In a functional language, you have to change the signatures of all the callers to add this new parameter. A lot of people pointed out that in a real program, you're asking for massive maintenance headaches if you connect two independent leaf functions through a global variable and make their behavior interdependent. In that context, this isn't a strawman, because somebody actually did suggest structuring programs this way. Make a silly suggestion, get a silly reply. I think both authors would do well to focus less on individual languages or programming paradigms and more on writing actual large-scale software systems. Because the imperative, OO, and functional worlds basically converge on that point: don't do that. You don't want the behavior of apparently-pure functions to change based on hidden, undocumented state. And once you document it, you might as well add it to the function signature, which is your "executable documentation" anyway.
- dou001 17y agowelcome to visit: http://www.wowhotsale.com http://www.wowhotsale.com We are wholesaler of Nike Jordan and Other Shoes. We are a professional exporting company . We supply many kinds of Shoes, such as Nike Shoes, Jordan 1-23, Air Jordan, AF1, DUNK, Air max series etc. Most of them are in stock and can be supplied surely on time. All these shoes are packed with original-boxes and cards. ====> free shipping <==== ====>competitive price<==== ====>any size available<==== ====>accept Credit Card payment<==== HTTP://WWW.WOWHOTSALE.COM jordan air max oakland raiders $34--39; Ed Hardy AF JUICY POLO Bikini $25; Christan Audigier BIKINI JACKET $30; gstar coogi evisu true jeans $35-39; coach chanel gucci LV handbags $36; coogi DG edhardy gucci t-shirts $18; CA edhardy vests.paul smith shoes $32; jordan dunk af1 max gucci shoes $37; EDhardy gucci ny New Era cap $16; coach okely Adidas CHANEL DG Sunglass $18; HTTP://WWW.WOWHOTSALE.COM http://www.wowhotsale.com/productlist.asp?id=s81 http://www.wowhotsale.com/productlist.asp?id=s81 (Hoody) http://www.wowhotsale.com/productlist.asp?id=s17 http://www.wowhotsale.com/productlist.asp?id=s17 (Shox) http://www.wowhotsale.com/productlist.asp?id=n516 http://www.wowhotsale.com/productlist.asp?id=n516 (AF jacket) http://www.wowhotsale.com/productlist.asp?id=s32 http://www.wowhotsale.com/productlist.asp?id=s32 (women boot) http://www.wowhotsale.com/productlist.asp?id=s74 http://www.wowhotsale.com/productlist.asp?id=s74 (Tshirt) http://www.wowhotsale.com/productlist.asp?id=s79 http://www.wowhotsale.com/productlist.asp?id=s79 (Jean) http://www.wowhotsale.com/productlist.asp?id=s72 http://www.wowhotsale.com/productlist.asp?id=s72 (Handbag) http://www.wowhotsale.com/productlist.asp?id=s62 http://www.wowhotsale.com/productlist.asp?id=s62 (Tiffany_Ring)
- ajross 17y agoThis seems to be missing the point. Yes, it's true that the functional programming equivalent of functions with side effects is functions with lots of extra arguments to capture the equivalent state. Which is kind of the point: in an imperative language, you can capture all that complexity -- all 316 arguments, even -- with a few quick hacks to the side effect behavior of your functions. And that's a feature. It makes things simpler sometimes (obviously it can hurt, too -- tools can't substitute for taste). And it just can't be expressed in functional terms.
- jrockway 17y agoAnd it just can't be expressed in functional terms. Incorrect. Say you want to read some global state: a = do info <- ask return (info + 1) b = do info <- ask moreInfo <- a return (info + moreInfo) runReader b 42 -- ==> 42 + (42 + 1) ==> 85 This lets you weave information in as deeply as you want. If b doesn't need "info" but a does, and b calls a, that's still fine. You don't need to change b to make the information available to a. Just like a "global variable". You can also accumulate arbitrary information: fib :: Int -> Writer [String] Int fib 0 = tell ["fib 0"] >> return 1 fib 1 = tell ["fib 1"] >> return 1 fib x = do tell ["fib " ++ show x] a <- fib (x - 1) b <- fib (x - 2) return $ a + b runWriter (fib 4) ==> (5, ["fib 4", "fib 3", ...]) Again, very much like a global variable holding log data, but without many undesirable possibilities (like clobbering the log history accidentally, or performing IO during the computation) that are inherent in "global variables". And of course, you can read and write state, if you want: inc :: State Int Int inc = do old <- get let new = old + 1 put new return new fib 0 = inc >> return 1 fib 1 = inc >> return 1 fib x = do inc a <- fib (x - 1) b <- fib (x - 2) return $ a + b runState (fib 25) 0 ==> (121393, 242785) This is just like imperative programming, except easier and more fine-grained. Note how the number of times "fib" has been called is scoped to the "runState" invocation, and that we don't even need a "variable name". And as with Reader and Writer, if a called function needs the State, the calling function doesn't need to pass it in. So basically, many variations on the hacks that imperative programmers can be implemented easily in functional languages. Imperative programming languages give you a box to do with as you please, but functional programming languages can give you a box that you can prevent yourself from accidentally misusing. The best of both worlds.
- justin_vanw 17y agoI've got this car. It's absurdly easy to run over people. All you have to do is drive on the sidewalk. With a boat, this would be somewhere between completely re-engineering it and impossible.
- bad_user 17y agoOh, you should drive your boat near a beach on a hot day. Either way you can run over strangers ... however, in general if you want to be prepared for a specific target (in general), then it's more likely to get the job done with a car since not all people go to the beach or take a swim :) So while driving a boat is fun, keep that car nearby.
- Quarrelsome 17y agoCan we not just summarise this whole thing with the words: Shared state should be avoided, if possible and pragmatic. Now go do this in whatever language you wish.
- Psyonic 17y agoNo, because its not just about you. How can I as a developer know if a function I'm calling in C uses more than its inputs? That's the real issue.
- vidarh 17y agoExcept it hardly ever is an issue. I can't remember last time I came across a situation in any of the languages I use that support global variables where some function depended on some global variable without the docs making a huge fuss about it. It was certainly many years ago.
- cemerick 17y agoNone of this has to do with globals -- the key issue is accessibility of shared mutable state from within imperative functions. That is an inescapable constant outside of FP environments.
- cemerick 17y agoNo, because what language and environment you choose impacts your ability / likelihood of actually doing that.
- Quarrelsome 17y agoSorry, I meant mutable state.
- jules 17y agoTwisted thinking. He first mentions that functional programs have to thread state they use through the entire program by passing it as parameters to functions. Then he says that imperative procedures can depend implicitly on the global variables they use. The equivalent in a functional program is adding a parameter to all the functions that use the state, and to all functions that call these functions. He goes on to say this: > Would you ever intentionally write a method signature that takes 316 arguments? Would you use any library that contained such a function signature? No? Then why are you using tools that force such craziness upon you? So we're now expecting to get a conclusion, namely that functional programming is inferior to imperative programming, because you get functions with 316 parameters that thread the state through the program. But no, despite setting up an entire argument against functional programming he acts like he's arguing against imperative programming: > Of course, there is a place for mutable, imperative programming. I'm very confused.
- cemerick 17y agoYou need to read the post again. What you thought I was writing, were quotes from others.
- DougBTX 17y agoI'm very confused. I expected a different conclusion from the one you describe, so it didn't sound twisted to me. In the last question you quote, he refers to "tools". The question will only make sense if you understand that he is referring to imperative tools, not functional ones. because you get functions with 316 parameters that thread the state through the program. He assumes that you would never write a single function which depends on 316 different parameters, but that there could be 313 global variables. Now you have a function which takes three arguments. His argument is that to understand what this function depends on will require reading all the code in the function and all the code in every function which it calls, to work out which global variables it accesses. Without doing that, you have to assume that this simple function depends on all 313 of them, even though you would never write a function which explicitly took that many arguments. On the other hand, in a purely functional language, you would still have a function with only three arguments, and simply by reading the function signature, you can understand what it will depend on. The middle ground is to say, hey, but the function really did depend on some of those global variables, so in the real world the function will have more than three arguments. More than three, but less than 316, lets call it five. But you find yourself with six other functions which depend on the same two global variables, while nothing else does. So, you go off and make that explicit by having one class with two instance variables and a few methods, one of which takes three arguments. And then you ban global variables. Welcome to OOP.
- billjings 17y agoPart of the craft of programming is expressing a computation or interaction as simply as possible. Now, somehow the original point (http://prog21.dadgum.com/54.html http://prog21.dadgum.com/54.html) has missed its mark. The original point was this: that for certain kinds of interactions, an imperative solution with shared state solution is vastly less complicated and preferable to a purely functional solution. This is because in some cases the purely function solution will litter a whole hierarchy of function calls or an entire set of data structures with additional data, but the imperative, stateful solution will not. Now, obviously the problem with imperative is: "...that state gets threaded everywhere, and you can't look at any function individually and know how it will behave." But what is the problem with functional programming? That you can't look at any bit of state in the program unless some other part of the program has explicitly given it to you. Now, I'd say that 95% of the time I'd rather have that problem than the problems that come with state - like having to worry about call order semantics, reentrancy, etc etc. But dammit - 5% of the time I'd rather use the state and be done with it! And more generally speaking, 100% of the time I'd rather have a concrete example of something that is implemented simply today than an abstract idea of why something might be complicated in the future.
- stcredzero 17y agoReminds me of one day, when a Squeak Smalltalk newbie showed up on the mailing list, not understanding why his music-related program won't compile. He has his whole program in one method, and needs several hundred temporary variables to store all of his note objects. When informed of the 255 temp variable limit, he starts getting outraged.
- nerme 17y agoGraphical data flow languages like Max/MSP, Puredata, LabVIEW, and even Quartz Composer make a lot more sense for functional programing. Every time I see someone "explaining" what is going on in a functional language, it looks just like a Max patch! There are multiple inputs attached to multiple outputs. Of course, if you're well familiar with whatever textual based language you're working with, you are visualizing this process, but still, why aren't all functional languages moving in this direction? The great thing is you can still drop text-based code in to one of these graphical dataflow languages. I write a LOT of code in Max/MSP and Quartz Composer. Thankfully, both support Javascript, because some things are just plain easier if you can drop back in to a procedural, text-based language. Even writing your own compiled plugins/externals is pretty straightforward. Quartz uses Obj-C and Max/MSP uses C++, although I think you can mix in or use pure Obj-C as well. I haven't had to write any functionality in to Max that wasn't already available with the core package or from CNMAT, UBC Toolbox, etc. (yet!) Anyways, what I'm getting at is that there is a huge advantage in laying things out in a graphical way, especially for concurrent programming. What I find interesting is that there is very little support for these languages. There are no patterns, best-practices, etc... I've had to bring over the basic concepts from other text-based languages when I'm writing a larger project... and often when I'm looking at other people's patches I'm astonished at the lack of maintainability, the amount of code repetition, etc... it can easily turn in to a spidery mess if you're not used to what you're doing!
- eru 17y agoCan you do higher-order functions in Max?
- nerme 17y agoObviously not in the same manner... but I feel that proper use of patcher/bpatcher objects and utilizing the meta-programming capabilities of it's javascript environment by allowing you to dynamically generate objects and connections allow you to accomplish pretty much whatever it is that you need to do... while gaining my favorite benefits of higher-order functions, namely, tighter, more organized code with less redundancy and awesome interfaces. That being said, Max is still missing some very important aspects, however, such as iteration and recursion. Interestingly, Quartz Composer does have a method for iteration, one that I frequently use... it works really well, actually! I really like text-based programming, but I'm increasingly seeing the benefits of graphical programming.
- pwnstigator 17y agoIt's hard to avoid this, even in a functional language like OCaml (which has mutable ref cells). Haskell does a pretty good job, by requiring functions that have side effects to show it in their type signature. If you're doing Haskell right, the number of functions that have side effects is very small as a proportion of the number of functions you'll write in total, so most functions you write will be purely referentially transparent. Of course, I'd argue that this is true if you're using any high-level language properly, except possibly in GUI programming.
- tlb 17y agoCan someone point to a useful program written in a 99%+ functional style?
- eru 17y agoGHC is written in Haskell. Darcs may also be useful. You can also look at http://en.wikipedia.org/wiki/Haskell_(programming_language)#Applications http://en.wikipedia.org/wiki/Haskell_(programming_language)#... for some examples. It's hard to escape functional style in Haskell.
- eru 17y agoThere are also some interesting applications in Clean. They (used to) ship a jump-n-run game as an example with their compilers and IDE.
- deleted 17y ago[deleted]
- eru 17y agoFrom the article: > Of course, there is a place for mutable, imperative programming. The fellow who wrote the blog post to which I linked above appears to work on games, one of the few places where one could unapologetically use an imperative programming language with mutable state. Comtrast http://lambda-the-ultimate.org/node/1277 http://lambda-the-ultimate.org/node/1277 where the authors of Unreal point out that functional programs will be the future of game programming.
- cemerick 17y agoThanks for that pointer -- I added that link to the original post.
- fauigerzigerk 17y ago"The behaviour of every function in a mutable, imperative environment is dependent upon the state of all of the other (variables|attributes|bindings|whatever) in your program at the time the function is invoked." That's not true in general, but the problematic truth is that you don't know when it is true and when it is not true in any particular situation. That is, there are no formal guarantees that tell the caller of a function that the function does not depend on each and every mutable state in the program. The second issue is the fact that methods in object oriented code tend to depend on too much state held in the instance variables of their containing class. This is mostly due to bad design. But there must be something else if even the best programmers out there feel the need to make this design mistake over and over again when using OO languages. I am sympathetic to functional programming but for some of the code I write I have to carefully optimize the memory layout of my data structures. Adding an immutability requirement to very stringent memory usage and performance requirements is just not feasible in these situations.
- jfl 17y agoAll my methods take just a few argument, I learned to design carefully the state of my programs and manage adequatly how function access that state. Imperative programming works for me (and many others). You say I am doing it wrong and want me to do it your way. Proselytism ?
- KirinDave 17y agoNo one is going to argue that your program doesn't work when it seems to work. Unless you're using threads and locks. Then it's probably a safe bet that it will fail in ways you don't expect. ;)
- jfl 17y agoActually, my webapps are full of threads. Again, Imperative style is not the wrong way, and FP the right way. They are just different. Why not let people find their own way ? Just give the information they need to make up their mind. And why not be honest and tell them that learning Haskell is probably more painful that learning to deal with the mutable state.
- cemerick 17y agoThere is a reality out there, we're not arguing over pastels vs. chalk vs. pencils. You can write webapps in assembly if you're so motivated and tenacious.
- jfl 17y agoYes. But do you understand that every one has its own partial, subjective view of that reality. Your post is your own view, not an neutral, scientific study. Your point ("mutable state equals additionnal arguments to all functions") is at best a caricature or just plain wrong : a function can access only the part of the state it has in scope or for which it has a handle, most of the time by dereferencing its arguments, in a controlled fashion. I would love to find some good paper about new ways to tame the state of my program, how to manage the references that flow accross my call stack and get duplicated without my being aware of. Pointer uniqueness ? pointer adoption ? State partition by domain ? Nothing compelling so far. Unless you have to share state between threads, There is no problem using imperative style in a multithread environment. Threads allocated to incoming requests in typical webapps don't share state (they do it through the database). When it comes to FP, the tone is usually "you're doing it all wrong" and the message more or less "do without state". In other words, alleviate some pain by enduring some different kind of pain. My subjective view... Peace.
- ssp 17y ago316 arguments is clearly an exaggeration, but there's a reason programmers are admonished against global variables. For example many of the classic Unix utilities were built around a pile of global variables, and they could be quite difficult to understand. Sometimes you see people making fun of programmers who have eliminated the pile of global variables by passing around a pointer to a structure containing all the variables instead. But this actually is an improvement because the type signature of each function now indicates precisely what state can be modified.
- snorkel 17y agoAll my methods take 1 argument: the entire state of the universe and everything in it.
- cousin_it 17y agoLate to the party again. The way I see it, when you face a programming problem you mentally divide it into subtasks and use solve each one in the most natural, sweet-spot manner learned from experience. Have to parse a minilanguage? Use an FP approach. Control UI widgets? Do it in OOP style, that's what it was designed for. Keep track of global game state? Just write it imperatively and be done with it. As a professional you need to understand the good ideas in your field, but as a responsible worker you need the wisdom to avoid pushing those good ideas beyond their proven area of application. One day you'll read an article somewhere that will demonstrate how Haskell is a great fit for ragdoll physics simulations (for example), like it happened before with Parsec for parsing (another example). Until that day... don't rush in blindly believing that purity is better for every class of problem. It might be, but we don't have anything resembling a proof yet. So learn from experience, and subdivide.
- jamii 17y agoThe arguments here all seem to assume that you're writing the code yourself. I think the best argument against rampant global state is when dealing with other peoples code. An example from a couple of months back. I was using an open source library for parsing LaTeX code before it was added to a search index. After getting the alpha version up and running I ran into a subtle bug - malformed input such as "$$ \dot{C}O_2" would break every future parse of any mathematical input. So somewhere in this 20k loc library a global variable is not being reset after parsing. Since this is an imperative language there is no way to figure out which part of the call chain is calling which global variables so I potentially have to read every line of code of find it. After two days I managed to track it down by writing a script that reads the source code to identify every static global variable in the code and tracks their values between calls. This is not the ideal way to find bugs.