In general it is naive, often dangerous, and an inefficient space/time trade-off.
I have been writing software for several decades... does that make one less insightful or more biased?
https://youtu.be/pmu5sRIizdw?feature=shared&t=31
=)
There may be use cases where it's insecure or has performance concerns, but those are the exception. Most of the time, it's fine.
We don't generally tell programmers that loops are naive, often dangerous, and risk locking up the program. They certainly can, but most just... don't.
Just like loops, recursion can make code much simpler to write, read, and maintain. Every modern language under the sun supports it for very good reasons. Use it.
Parsers are far from immune to these issues.
I think we will have to "agree to disagree" here... =)
with open('lulz.json') as ayy_lmao:
oops = json.load(ayy_lmao)
If you parse arbitrary json bytes from the Internet (for example, if you have some public Python API with no auth) then you have given the world a fun little stacktrace generator, and a way to lessen your server room's heating bill.EDIT: btw you can do the same thing in rust's serde_json if the type you're deserializing into somehow supports the nesting, but you'd have to work for it.
EDIT2: the only (decent) way I can think to mitigate this in the python app's case is to enforce a sufficiently restrictive Content-Length at the edge, which obviously isn't possible of you expect blobs O(100Kb) uncompressed. Or you could pre-parse to detect nesting.
[1] EDIT3: on my machine in ipython right now it's 1485:
import json
def nest(d):
return '{"k":' + str(d) + '}'
def make_mess(n):
v = 1
for _ in range(n):
v = nest(v)
return v
json.loads(make_mess(1485)) # boomYou'll want to cap the maximum allowed nesting depth. Even if not using recursion, you probably don't want untrusted input to be able to make your stack data structure allocate arbitrary amounts of memory.
If you do put a nesting limit in, you can do that equally well using an actual stack or recursion. (For example, I believe v8 still uses recursive descent for parsing JSON and JavaScript. It detects and handles stack overflows to ensure that untrusted input can't blow the stack and crash. I'm not sure if it's using a hardcoded nesting limit or actually trapping the stack/heap collision somehow.)
I've run into similar issues with recursive code in java. The story gets better in C or rust, but there wre still sharp edges. I guess there are sharp edges everywhere though...
Shouldn't you stick to a depth-first branch reply limit until moving to the next fork.
I want to respect your beliefs. =)
And yeah, recursion is avoided in some shops for good reasons.
def isRecursionOk(problem)
for (subProblem in (breakDownIntoSubProblems(problem))
if ! isRecursionOk(subProblem) return false
return trueMakes more sense to do it as breadth-first with only one return value:
from collections import deque
def isRecursionOk(problem):
q = deque(problem)
while q:
problem = q.popleft()
q.append(list(breakDownIntoSubProblems(problem)))
return trueThere are safer hobbies available like snake juggling =)
I currently have open in my editor a code formatter that I maintain that uses at least half a dozen recursive algorithms to traverse syntax trees and other data structures. This program is used by almost every user of our language, invoked on every save, and probably executed billions of times a day.
Recursion is fine.