Thread overview
Is it's correct to say that ALL types that can grow are place on heap?
Sep 08, 2018
Suliman
Sep 08, 2018
Ali Çehreli
Sep 11, 2018
Timoses
Sep 11, 2018
drug
Sep 12, 2018
Timoses
Sep 12, 2018
drug
Sep 12, 2018
rikki cattermole
Sep 12, 2018
Timoses
Sep 12, 2018
rikki cattermole
September 08, 2018
Is it's correct to say that ALL types that can grow are place on heap and types that not growing (int, char, pointer) are place on stack?

Or there is some exceptions?

Is there any tools that can visualize place of data in memory?
September 08, 2018
On 09/08/2018 02:19 AM, Suliman wrote:
> Is it's correct to say that ALL types that can grow are place on heap
> and types that not growing (int, char, pointer) are place on stack?

The question is not that simple. :)

First, there is also the area used for objects that are static and object that are defined at module scope. That is different from both the call stack and the heap. Let's ignore them...

There are automatic objects like local variables inside a function and function parameters. They normally live on the stack. (However, the compiler may pass some parameters in CPU registers without allocating any memory at all.)

As you say, whenever memory is dynamic in nature e.g. we don't know the size before hand, the memory is normally allocated from the heap. However, heap can be used for allocating even an int:

import std.stdio;

void main() {
    auto p = new int(42);
    writeln(p);
    writeln(*p);
}

Although the memory used for the elements of a dynamic array is on the heap, the slice itself is usually on the stack:

import std.stdio;

void main() {
    auto arr = [ 42 ];
    writeln("Local slice variable is at       ", &arr);     // stack
    writeln("The elements of the array are at ", arr.ptr);  // heap
}

Then there are member variables of a user-defined type: Obviously, those variables are wherever the actual object lives.

> Or there is some exceptions?
>
> Is there any tools that can visualize place of data in memory?

I think there are some debuggers that visualize data like that but I don't have experience with those.

Ali

September 11, 2018
On Saturday, 8 September 2018 at 22:51:17 UTC, Ali Çehreli wrote:
> On 09/08/2018 02:19 AM, Suliman wrote:
> > Is it's correct to say that ALL types that can grow are place
> on heap
> > and types that not growing (int, char, pointer) are place on
> stack?
>
> The question is not that simple. :)
>
> First, there is also the area used for objects that are static and object that are defined at module scope. That is different from both the call stack and the heap. Let's ignore them...
>
> There are automatic objects like local variables inside a function and function parameters. They normally live on the stack. (However, the compiler may pass some parameters in CPU registers without allocating any memory at all.)

Is this why it is said that passing parameters by value can be more efficient?
Cause for a ref parameter it would require passing the address which would require to be allocated?

Aww, I really would love some insights into function parameter passing. Why is it said that passing by value can be more efficient at times?
Since it is also said that passing large structs by value can be expensive, why then would it not be cheaper to ALWAYS pass everything by reference? What mechanism is behind the scene that follows one to reason that sometimes passing by value is less expensive?

I get that passing an int by reference would cause indirections which need to be resolved whereas passing the int by value is just one copy (I guess).


This topic kinda seemed fit for my question that I was carrying around for some time.


September 11, 2018
11.09.2018 13:11, Timoses пишет:
> 
> Is this why it is said that passing parameters by value can be more efficient?
> Cause for a ref parameter it would require passing the address which would require to be allocated?
> 
> Aww, I really would love some insights into function parameter passing. Why is it said that passing by value can be more efficient at times?
> Since it is also said that passing large structs by value can be expensive, why then would it not be cheaper to ALWAYS pass everything by reference? What mechanism is behind the scene that follows one to reason that sometimes passing by value is less expensive?
> 
> I get that passing an int by reference would cause indirections which need to be resolved whereas passing the int by value is just one copy (I guess).
> 
> 
> This topic kinda seemed fit for my question that I was carrying around for some time.
> 
> 

If data size is less or equal to total size of available registers (that can be used to pass values) than passing by value is more efficient. Passing data with size less than register size by reference isn't efficient because you pass pointer (that has register size) and access memory using it.
September 12, 2018
On Tuesday, 11 September 2018 at 12:07:14 UTC, drug wrote:
>
> If data size is less or equal to total size of available registers (that can be used to pass values) than passing by value is more efficient. Passing data with size less than register size by reference isn't efficient because you pass pointer (that has register size) and access memory using it.

Thank you!
So if I pass by reference it will ALWAYS use the address in memory to fetch the data, whereas passing it by value enables the (compiler?..) to use the register which has already loaded the data from memory (stack for example)?
September 12, 2018
On 9/11/18 3:11 AM, Timoses wrote:
> Aww, I really would love some insights into function parameter passing. Why is it said that passing by value can be more efficient at times?
> Since it is also said that passing large structs by value can be expensive, why then would it not be cheaper to ALWAYS pass everything by reference? What mechanism is behind the scene that follows one to reason that sometimes passing by value is less expensive?

So consider that accessing a struct from the function is cheaper when it is passed by value -- you have one offset from the stack pointer, and that's it. Vs. going through the stack pointer to get the reference, and then dereferencing that.

In addition, passing a large struct by value can be as cheap or even cheaper if you can construct the value right where it is going to be passed. In other words, you don't need to make *any* copies. This can be true for rvalues that are passed by value, but not lvalues.

So in addition to register passing, there are other benefits to consider.

-Steve
September 12, 2018
12.09.2018 15:14, Timoses пишет:
> On Tuesday, 11 September 2018 at 12:07:14 UTC, drug wrote:
>>
>> If data size is less or equal to total size of available registers (that can be used to pass values) than passing by value is more efficient. Passing data with size less than register size by reference isn't efficient because you pass pointer (that has register size) and access memory using it.
> 
> Thank you!
> So if I pass by reference it will ALWAYS use the address in memory to fetch the data, whereas passing it by value enables the (compiler?..) to use the register which has already loaded the data from memory (stack for example)?

Honestly, I'm not an expert in this domain, but I think so.
September 13, 2018
On 13/09/2018 2:34 AM, drug wrote:
> 12.09.2018 15:14, Timoses пишет:
>> On Tuesday, 11 September 2018 at 12:07:14 UTC, drug wrote:
>>>
>>> If data size is less or equal to total size of available registers (that can be used to pass values) than passing by value is more efficient. Passing data with size less than register size by reference isn't efficient because you pass pointer (that has register size) and access memory using it.
>>
>> Thank you!
>> So if I pass by reference it will ALWAYS use the address in memory to fetch the data, whereas passing it by value enables the (compiler?..) to use the register which has already loaded the data from memory (stack for example)?
> 
> Honestly, I'm not an expert in this domain, but I think so.

Recently used areas of the stack will be available in the cache in most cases. The issue with passing by reference is it increases the indirection (number of pointers) that it must go through to get to the raw bytes.

This is why classes are bad but structs are good. Even if the struct is allocated on the heap and you're accessing it via a pointer.
September 12, 2018
On Wednesday, 12 September 2018 at 14:46:22 UTC, rikki cattermole wrote:
> On 13/09/2018 2:34 AM, drug wrote:
>> 12.09.2018 15:14, Timoses пишет:
>>> On Tuesday, 11 September 2018 at 12:07:14 UTC, drug wrote:
>>>>
>>>> If data size is less or equal to total size of available registers (that can be used to pass values) than passing by value is more efficient. Passing data with size less than register size by reference isn't efficient because you pass pointer (that has register size) and access memory using it.
>>>
>>> Thank you!
>>> So if I pass by reference it will ALWAYS use the address in memory to fetch the data, whereas passing it by value enables the (compiler?..) to use the register which has already loaded the data from memory (stack for example)?
>> 
>> Honestly, I'm not an expert in this domain, but I think so.
>
> Recently used areas of the stack will be available in the cache in most cases. The issue with passing by reference is it increases the indirection (number of pointers) that it must go through to get to the raw bytes.
>
> This is why classes are bad but structs are good. Even if the struct is allocated on the heap and you're accessing it via a pointer.

This sounds like classes should never be used.. I don't recall right now what issues I'm usually encountering with structs that make me switch to classes (in D).

So passing by reference is generally only applicable (logical) to structs and non-reference types + only makes sense when the function being called is supposed to change the referenced value without returning it.

Except, as Steven pointed out in his post when dealing with large lvalue structs.

This all seems quite complicated to "get right" when writing code. I'm sure there are compiler optimizations run on this? Or is that not possible due to the nature of difference in ref and value passing.


Anyhow, thanks for the answers! I bet it's possible to write books on this topic.. Or just mention ones that already were written : ~D.
September 13, 2018
On 13/09/2018 3:22 AM, Timoses wrote:
> On Wednesday, 12 September 2018 at 14:46:22 UTC, rikki cattermole wrote:
>> On 13/09/2018 2:34 AM, drug wrote:
>>> 12.09.2018 15:14, Timoses пишет:
>>>> On Tuesday, 11 September 2018 at 12:07:14 UTC, drug wrote:
>>>>>
>>>>> If data size is less or equal to total size of available registers (that can be used to pass values) than passing by value is more efficient. Passing data with size less than register size by reference isn't efficient because you pass pointer (that has register size) and access memory using it.
>>>>
>>>> Thank you!
>>>> So if I pass by reference it will ALWAYS use the address in memory to fetch the data, whereas passing it by value enables the (compiler?..) to use the register which has already loaded the data from memory (stack for example)?
>>>
>>> Honestly, I'm not an expert in this domain, but I think so.
>>
>> Recently used areas of the stack will be available in the cache in most cases. The issue with passing by reference is it increases the indirection (number of pointers) that it must go through to get to the raw bytes.
>>
>> This is why classes are bad but structs are good. Even if the struct is allocated on the heap and you're accessing it via a pointer.
> 
> This sounds like classes should never be used.. I don't recall right now what issues I'm usually encountering with structs that make me switch to classes (in D).

Nah, this is cycle counting aka don't worry about it if you're not doing anything super high performance.