0

The below code snippet works perfectly and reverses the string "abc", recursively, and gives us the correct output as "cba". If the method ReverseString was static, instead of non-static, we would have called the method ReverseString from Main(), without having to create an instance of Program - and we would have simply called it as: string reversed = Program.ReverseString("abc"); In that scenario (when the method ReverseString were static), the method ReverseString and all it's local variables would reside on the Stack-memory and, Activation Records (call stacks) for ReverseString would build up on the Stack-memory. But for the case when ReverseString is non-static, and we instantiate the class Program, the non-static method ReverseString would lie on the Heap. And when we do prog.ReverseString, the pointer prog on the Stack will call the method ReverseString on the Heap. And ReverseString on the Heap will call itself in a recursive way on the Heap. Is my understanding correct? I believe I am wrong when I say recursion is happening on the Heap, in the below code snippet. I will be highly grateful, if you could tell me what exactly goes on the Stack and the Heap, in the code snippet below. And what would go on the Stack and the Heap if ReverseString were static and we called ReverseString from Main() as: string reversed = Program.ReverseString("abc");

internal class Program
{
    static void Main(string[] args)
    {

        Program prog = new Program();
        string reversed = prog.ReverseString("abc");
    }

    public string ReverseString(string input)
    {
        if (input == string.Empty)
            return string.Empty;
        else return ReverseString(input.Substring(1)) + input[0];
    }
}
Vikram Singh
  • 435
  • 2
  • 10
  • 2
    why do you care for stack and heap at all? In C# there's little demand for differing between those, unless you make some pointer-arithmetic in an `unsafe`-context. – MakePeaceGreatAgain Apr 03 '23 at 04:02
  • 3
    You're going to want to read [The stack is an implementation detail](https://learn.microsoft.com/en-us/archive/blogs/ericlippert/the-stack-is-an-implementation-detail-part-one) by @ericlippert – Flydog57 Apr 03 '23 at 04:05
  • @MakePeaceGreatAgain, I just wanted to know what goes under the hood. Are recursion calls ever made on the Heap? Thanks a lot for your answer! – Vikram Singh Apr 03 '23 at 04:09
  • 1
    All `new` class types are on the heap. Local variables are (probably) on the stack, but if they are reference types, that's just a pointer to the heap. And some C# language features will promote values from the stack to the heap. – Jeremy Lakeman Apr 03 '23 at 04:15
  • Your actual question makes an assumption that is just nonsense. The only difference between static and non-static, is the existence of an implicit `this` reference as a method argument. Local variables are still local variables on a thread stack. – Jeremy Lakeman Apr 03 '23 at 04:28
  • @JeremyLakeman, in the code snippet that I have provided, does the recursion happen on the Heap? I believe I am wrong that recursion happens on the Heap? Can you provide some insight into how the recursion happens in the code snippet that I have provided? Thanks! – Vikram Singh Apr 03 '23 at 04:37
  • 2
    "does the recursion happen on the Heap?" that question is nonsense. All method calls allocate space for local variables on the stack. How would you imagine that any method call could "happen on the Heap?" – Jeremy Lakeman Apr 03 '23 at 04:41
  • @JeremyLakeman, so what is the difference between calling the method as string `reversed = prog.ReverseString("abc");` And, `string reversed = Program.ReverseString("abc");` (the second invocation is for the case when the `ReverseString` method is `static`). Thanks! – Vikram Singh Apr 03 '23 at 04:48
  • 1
    there is none in the meaning of heap and stack. However there's a huge difference when it comes to object-orientation, which is *semantics*, rather than *mechanics*. See the [`static`-keyword](https://learn.microsoft.com/dotnet/csharp/language-reference/keywords/static). – MakePeaceGreatAgain Apr 03 '23 at 04:51
  • 1
    JeremyLakeman has already metioned the only difference between static method and non-static method is non-static method has an implicit this parameter. – shingo Apr 03 '23 at 05:19
  • 1
    or in other words: `myInstance.MyFunction` is essenitally equivalent to `TheClass.MyFunction(myInstance)`. – MakePeaceGreatAgain Apr 03 '23 at 06:20
  • @JeremyLakeman maybe tone it down a bit. It's not totally out of this world to ask such questions and one can imagine a runtime storing stack frames on the heap (e.g. that's how resumable coroutines [were implemented in C++](https://lewissbaker.github.io/2017/09/25/coroutine-theory)). – Good Night Nerd Pride Apr 03 '23 at 11:34
  • 1
    [SharpLab](https://sharplab.io/#v2:EYLgxg9gTgpgtADwGwBYA0AXEUCuA7AHwAEAmABgFgAoUgRmuoEs8MYo8BDAGwAJS/aAdmoBvajwkCkfFDwCyHZgAoitMgG0Aujw5QA5gGcAlOMliqpyZNWCeABygQ9PALw88MAO4DBSowG5LKwEyHlgANzYDGAATV3tHPQA6ACUYSKhogGUMKGY9JQAiDmAwQoCgq0rrEgBWByc0HmLSwqaIqNiKqisAXwYe6wBmEJ40jOzc/JU1HmY7HAwTQYlzYMlGADMeJXnF1zdVMiSAUQBbOwwAT2X19aJbI9OL68CV4JguaL5bcc6cvJ4Ap7DBJLI4YBHJS0IxGHgAajmeAWGHUZE0bz61F6QA===) does not show the recursion stack frames but can tell you where locals are allocated. – Good Night Nerd Pride Apr 03 '23 at 11:36

1 Answers1

1

The c# language does not really specify things like stack or heap, they are implementation concepts, separate from the language itself. But in practice they will be used by most implementations.

It does not matter if the method is static or not, method parameters and local variables will always be stored on the stack for the thread that executes the method. Your method will in in principle be rewritten to something like

public static string ReverseString(Program this, string input){...}

With all references to fields prefixed with this..

Note that the actual code for the method will neither be on the stack nor the managed heap, it will instead be stored in a separate code segment. But that is totally up to the compiler and runtime, and there are few cases where you have to care about where the code is stored.

Since string is a reference type all the strings will be stored in the heap. So the stack in this case will just contain string references and things like return address etc.

In your specific case, at the point where the recursion ends, you will have 4 stack frames for ReverseString, each frame will contain a reference to a string that is stored on the heap, or possibly a data segment in cases where the compiler will 'intern' the string.

Note that the jitter is allowed optimize things as long as the behavior remain the same. It can pass parameters in registers, or just inline entire method calls.

Also note that the terms used will depend on the point of view. In .Net 'heap' usually refers to the managed heap, i.e. the part where managed objects are stored. The OS will have its on definition of 'heap memory', and that will include memory managed by the runtime for various internal purposes, like jitted code etc.

JonasH
  • 28,608
  • 2
  • 10
  • 23
  • Oddly enough, .NET specification *also* doesn't specify stack or heap (except for the logical stack within CIL instructions). My private conforming implementation of .NET stores data on the Moon which is made of cheese, and the stack is made of pizza boxes with hand-written notes stuck on. – Charlieface Apr 03 '23 at 11:35