Thread overview
Object as function argument
Mar 05, 2015
Chris Sperandio
Mar 05, 2015
w0rp
Mar 05, 2015
Chris Sperandio
Mar 05, 2015
Max Klyga
Mar 05, 2015
anonymous
Mar 05, 2015
Jonathan M Davis
Mar 05, 2015
Chris Sperandio
Mar 05, 2015
Adam D. Ruppe
March 05, 2015
Hi,

I'm a developer coming from C and I've a question about class instance as method or function parameter.
In the book "The D Programming Language", I read the instance was passed by reference to functions (in the opposite of structures). I understood that it was the same object in the function and the caller. But I'm think, I was wrong because when I print the addresses of an object before the function call and inside the function, they're not the same but the changes from the function are kept in the instance.
If I use the "ref" qualifier in the function declaration, the 2 addresses are the same.

How do the changes work in the function? Is there a copy ? Or a "magic" trick :) ?

Chris
March 05, 2015
On Thursday, 5 March 2015 at 19:35:35 UTC, Chris Sperandio wrote:
> Hi,
>
> I'm a developer coming from C and I've a question about class instance as method or function parameter.
> In the book "The D Programming Language", I read the instance was passed by reference to functions (in the opposite of structures). I understood that it was the same object in the function and the caller. But I'm think, I was wrong because when I print the addresses of an object before the function call and inside the function, they're not the same but the changes from the function are kept in the instance.
> If I use the "ref" qualifier in the function declaration, the 2 addresses are the same.
>
> How do the changes work in the function? Is there a copy ? Or a "magic" trick :) ?
>
> Chris

If you share your code, I'll be happy to take a look. Classes are reference types, so passing T for a class should pass the reference to the object.
March 05, 2015
On 2015-03-05 19:35:34 +0000, Chris Sperandio said:

> Hi,
> 
> I'm a developer coming from C and I've a question about class instance as method or function parameter.
> In the book "The D Programming Language", I read the instance was passed by reference to functions (in the opposite of structures). I understood that it was the same object in the function and the caller. But I'm think, I was wrong because when I print the addresses of an object before the function call and inside the function, they're not the same but the changes from the function are kept in the instance.
> If I use the "ref" qualifier in the function declaration, the 2 addresses are the same.
> 
> How do the changes work in the function? Is there a copy ? Or a "magic" trick :) ?
> 
> Chris

When you write `auto myObject = new MyObject();`
`myObject` is actually a pointer to object in GC memory. Its roughly equivalent to `struct MyObject *myobject` in C. So when you take a pointer you actually take a pointer to reference on the stack and thats why its different in the function - variable is higher up the stack.
`ref` qualifyer guaranties that you get the pointer to the same reference.

If you really need the actual pointer to object data you can use `*cast(void**)&myObject`. Compiler cannot cast object reference to `void*` but we can trick it ;)

March 05, 2015
Below the code:

module item;

import std.stdio;

class Item
{
  ulong count;

  static void call1(Item item)
  {
    writeln("(call1) Addr: ", &item);
  }

  static void call2(ref Item item)
  {
    writeln("(call2) Addr: ", &item);
  }

  static Item call3(Item item)
  {
    writeln("(call3) Addr: ", &item);
    return item;
  }

  static Item call4(Item item)
  {
    // Here, I change the count
    item.count = 100;
    return item;
  }
}


void main()
{
  auto item = new Item();
  writeln("(main) Addr item=", &item);
  Item.call1(item);
  Item.call2(item);

  auto res3 = Item.call3(item);
  writeln("(main) res3 item=", &res3);

  auto res4 = Item.call4(item);
  writeln("(main) res4 item=", &res4);

  assert(item.count == 100);

}

I get:

(main) Addr item=7FFF5D797818
(call1) Addr: 7FFF5D7977F8
(call2) Addr: 7FFF5D797818
(call3) Addr: 7FFF5D7977F8
(main) res3 item=7FFF5D797820
(main) res4 item=7FFF5D797828


On Thursday, 5 March 2015 at 19:48:38 UTC, w0rp wrote:
> On Thursday, 5 March 2015 at 19:35:35 UTC, Chris Sperandio wrote:
>> Hi,
>>
>> I'm a developer coming from C and I've a question about class instance as method or function parameter.
>> In the book "The D Programming Language", I read the instance was passed by reference to functions (in the opposite of structures). I understood that it was the same object in the function and the caller. But I'm think, I was wrong because when I print the addresses of an object before the function call and inside the function, they're not the same but the changes from the function are kept in the instance.
>> If I use the "ref" qualifier in the function declaration, the 2 addresses are the same.
>>
>> How do the changes work in the function? Is there a copy ? Or a "magic" trick :) ?
>>
>> Chris
>
> If you share your code, I'll be happy to take a look. Classes are reference types, so passing T for a class should pass the reference to the object.
March 05, 2015
On Thursday, March 05, 2015 19:35:34 Chris Sperandio via Digitalmars-d-learn wrote:
> Hi,
>
> I'm a developer coming from C and I've a question about class
> instance as method or function parameter.
> In the book "The D Programming Language", I read the instance was
> passed by reference to functions (in the opposite of structures).
> I understood that it was the same object in the function and the
> caller. But I'm think, I was wrong because when I print the
> addresses of an object before the function call and inside the
> function, they're not the same but the changes from the function
> are kept in the instance.
> If I use the "ref" qualifier in the function declaration, the 2
> addresses are the same.
>
> How do the changes work in the function? Is there a copy ? Or a "magic" trick :) ?

MyClass c;

is a reference to an object. So, if you do &c, you're taking the address of the reference, not the object. So, it's like if you had

MyClass* c;

in C/C++ and you did &c. So, if you have

void bar()
{
    auto c1 = new MyClass;
    foo(c1);
}

void foo(MyClass c2)
{
}

then c1 and c2 have different addresses just like if they would if they were explictly pointers. Changing foo to

void foo(ref MyClass c2)
{
}

means that you're passing the reference itself by ref, making it essentially equivalent to

void foo(MyClass*& c2)
{
}

in C++. So, c2's address is going to be the same as c1, because they're essentially the same reference/pointer at that point. If you want the address of the object itself rather than its reference, then you need to cast it to void*. e.g. this code will print the same value for c1 and c2:

import std.stdio;

class MyClass {}

void main()
{
    auto c1 = new MyClass;
    writeln(cast(void*)c1);
    foo(c1);
}

void foo(MyClass c2)
{
    writeln(cast(void*)c2);
}

- Jonathan M Davis

March 05, 2015
Ok... So, in D when I work with Object, it's like if I work with only pointers.
Thus, I can return null from a function which returns an Item instance.
Is it clean to write this code below ?

  static Item nullReturn(Item item)
  {
   // ...
   // and for some cases
    return null;
  }
March 05, 2015
On Thursday, 5 March 2015 at 20:08:08 UTC, Chris Sperandio wrote:
> Is it clean to write this code below ?

yup. Though remember all the downsides of null - if you try to use a null object like accessing a member, the program will be terminated.
March 05, 2015
On Thursday, 5 March 2015 at 19:51:09 UTC, Max Klyga wrote:
> If you really need the actual pointer to object data you can use `*cast(void**)&myObject`. Compiler cannot cast object reference to `void*` but we can trick it ;)

It can, actually. A class can define its own cast(void*) though, so the reinterpret way may be more robust. Also, I'm not sure if any of this is specified. So watch out for undefined (or underspecified) behaviour.