9 ms·
This article brings up an interesting question. Since much of programming is based on simply making something easier for humans to read, create and design with,
by RobertRoberts 9y ago
This article brings up an interesting question. Since much of programming is based on simply making something easier for humans to read, create and design with, is there a trade off with functional programming in regards to debugging?
I really appreciate some aspects of both styles, but I am not a die hard either way, my limited experience with functional programming has never lead me into the depths of debugging like discussed in the article. So the article actually makes me wary of going further.
I would liken this effect to a form of technical debt similar to a framework. Upfront development is faster, but when there's a problem, it's much harder to fix or work around, and problems can be more obscure.
Is this concern valid?
- ShaneWilton 9y agoI've found that it really varies based on the language and the tooling it offers. I code Erlang and Elixir on a daily basis, and I've never used such a full-featured debugging environment before. I can trace messages across a distributed system, connect to production nodes to set breakpoints or tracepoints, and I can render a live visualization of all the supervision trees in my application and watch as processes spawn and are killed. And of all that is just scratching the surface of what you can do. I also remember Racket having pretty powerful debugging capabilities, including the ability to step through programs and see how each expression is evaluated. Some languages have worse tooling than others, but I don't think it's a problem endemic to functional programming.
- tathougies 9y agoThere are perfectly good debuggers for functional languages, but honestly, it's not as useful as it is for imperative languages in my experience. More useful is profiling information -- both execution and heap.
- willtim 9y agoFunctional programming actually opens up more opportunities for debugging, as we are better able to both reason about and transform programs. The caveat is that often we need to build domain-specific debuggers, to effectively debug our high-level domain-specific code. Even in imperative languages like C++ and Java, the standard word-at-a-time debugger gets increasingly less useful as abstractions are piled up. Multiple threads really throw a spanner in the works. Here's an example functional debugger that can step forwards and backwards in time, as well as modify code at any time: http://debug.elm-lang.org http://debug.elm-lang.org
- seanmcdirmid 9y agoBackward step debuggers aren’t limited to just functional languages, they’ve been available for imperative languages as well (e.g. via gdb).
- willtim 9y agoThat's quite a bold promise, when in theory any statement could "launch the missiles". Just like software transactional memory, this idea, AFAICT, really needs pure functional programming to work well.
- seanmcdirmid 9y agoNo way, I’ve implemented a few of them myself (my research area is in love programming), and none of the languages I’ve done were functional. All you need to do is checkpoint, which is true for non trivial FP programs as well.
- naasking 9y agoCheckpointing is more fine-grained and yet, essentially free in pure functional languages though. The tooling has got to be simpler for that reason alone.
- deleted 9y ago[deleted]
- seanmcdirmid 9y agoYou should no better than that. It is only free in pure functional languages if they keep every single world around, then the overhead of checkpointing is nil because they are basically doing it already! So choose between "save the world because that's what we already do" or "save the world after the fact," it is pretty much the same.
- 9y ago
- rdtsc 9y ago> is there a trade off with functional programming in regards to debugging? I have looked and large and hairy C++/Java/C#/Erlang/Python programs. I think overall Erlang are the easiest to debug. Two reasons are: state is most likely to be passed in explicitly, and data is immutable. Compare to, say, looking at a class instance in an OO language, which inherited from a bunch of other classes, and then had some methods called on it, modifying its internal state, and now you're and asking yourself "hmm, this seems broken, but how did we even get to this point?". vs looking at function like "update_state(State, NewData, ...) -> ... NewState.". In the second case it is clear what is happening, what the old state was, what the new is. If the bug happens on a live system, it is easy to attach a trace that would trigger only when NewData matches something or old state matches, or both match.