The thing that stops you from doing data-flow freely in C or assembly is ownership of memory.
In a GCed language, you can freely your parameters into a complex returned structure; without GC, you can't mix up ownerships without a separate accounting system.
Consider:
struct some_struct *f(int x, char *y)
{
struct some_struct *result = malloc(sizeof *result);
if (x < 0)
result->value = "negative";
else
result->value = y;
return result;
}
If you're writing functional code, the return values of your routines will normally be a function of the parameters, which often means wholesale inclusion. Without GC, you need to do a lot more preemptive copying, and freeing the resulting data structures is much more painful.Alternative accounting systems can be used, e.g. arena or marker based allocation (freeing everything allocated when control returns to earlier points on the stack), or something else more involved. But it's not free.