...or is it just a practice?
I\'m asking this because of an argument with my professor: I lost credit for calling a function recursively on the basis that we did not cov
Regarding the specific question, is recursion a feature, I'm inclined to say yes, but after re-interpreting the question. There are common design choices of languages and compilers that make recursion possible, and Turing-complete languages do exist that don't allow recursion at all. In other words, recursion is an ability that is enabled by certain choices in language/compiler design.
Supporting first-class functions makes recursion possible under very minimal assumptions; see writing loops in Unlambda for an example, or this obtuse Python expression containing no self-references, loops or assignments:
>>> map((lambda x: lambda f: x(lambda g: f(lambda v: g(g)(v))))(
... lambda c: c(c))(lambda R: lambda n: 1 if n < 2 else n * R(n - 1)),
... xrange(10))
[1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880]
Languages/compilers that use late binding, or that define forward declarations, make recursion possible. For example, while Python allows the below code, that's a design choice (late binding), not a requirement for a Turing-complete system. Mutually recursive functions often depend on support for forward declarations.
factorial = lambda n: 1 if n < 2 else n * factorial(n-1)
Statically typed languages that allow recursively defined types contribute to enabling recursion. See this implementation of the Y Combinator in Go. Without recursively-defined types, it would still be possible to use recursion in Go, but I believe the Y combinator specifically would be impossible.