Ref parameter: intended behavior or bug?

Regan Heath regan at netmail.co.nz
Wed Aug 22 03:18:50 PDT 2007


Mike Parker wrote:
> Bill Baxter wrote:
>> Mike Parker wrote:
>>> I knocked up a sample program to demonstrate reference parameters, 
>>> then got a result that wasn't at all what I expected:
>>>
>>> ====================================
>>>
>>> import std.stdio;
>>>
>>> struct MyStruct
>>> {
>>>     ubyte[] contents;
>>> }
>>>
>>> class MyClass
>>> {
>>>     ubyte[] contents;
>>> }
>>>
>>> void structDefault(MyStruct ms)
>>> {
>>>     writefln("Struct default: %d", ms.sizeof);
>>> }
>>>
>>> void structRef(ref MyStruct ms)
>>> {
>>>     writefln("Struct ref: %d", ms.sizeof);
>>> }
>>>
>>> void classDefault(MyClass mc)
>>> {
>>>     writefln("Class default: %d", mc.sizeof);
>>> }
>>>
>>> void main()
>>> {
>>>     MyStruct ms;
>>>     MyClass mc = new MyClass;
>>>         structDefault(ms);
>>>     structRef(ms);
>>>     classDefault(mc);
>>> }
>>> ==================================
>>>
>>> Here's the output:
>>>
>>> Struct default: 8
>>> Struct ref: 8
>>> Class default: 4
>>>
>>> The first and last are what I thought they would be, but I expected 
>>> the Struct ref line to output 4, since it's supposed to be a ref 
>>> parameter. I assume this to be a bug, but want to make sure there's 
>>> not something intended going on.
>>
>> 'ref' is not a type constructor in D, it is a storage class.
>> .sizeof gives the size of the type.  The storage class shouldn't 
>> affect that.
> 
> But it's a bit inconsistent, is it not?   Consider this function:
> 
> void structPtr(MyStruct* ms)
> {
>     writefln("Struct ptr: %d", ms.sizeof);
> }
> 
> This will print 4. 

Of course, you're asking for the size of a pointer here and a pointer on 
a 32 bit system is _always_ 32 bits or 4 bytes.

> Why should the behavior of 'ref' be any different 
> than that of '*'? 

Because 'ref' is not '*'.  To turn it around;  Why should the behaviour 
of 'ref' be the same as '*'?

Is the only point of having 'ref' to allow you to pass variables without 
& at the call site?

I believe the main reason for 'ref' was/is to allow you to modify the 
variable being passed.

So what advantage does 'ref' have over '*'?

If you ask me, in D, 'ref' has perhaps 1 small advantage, and 1 large 
liability.

The advantage:
   void foo(ref int a) {  a = 5; }  //cleaner syntax
   void foo(int* a)    { *a = 5; }

Consider a struct however:
   struct Foo { int a; }
   void foo(ref Foo f) { f.a = 5; }
   void foo(Foo* f)    { f.a = 5; } //identical syntax

Granted you still have:
   struct Foo { int a; }
   void foo(ref Foo f) {  f = <some other Foo>; }  //cleaner syntax
   void foo(Foo* f)    { *f = <some other Foo>; }

However, the liability (IMO):

   Which of these functions modifies 'foo'?

   Foo foo;
   bar(foo);
   baz(foo);

You can't tell without inspecting the function signatures. Whereas with 
pointers:

   Foo foo;
   bar(&foo);
   baz(foo);

It's quite clear, unless of course baz is passing by reference ;)

 > If I want the size of the type, I would use
> MyStruct.sizeof.

I think the concept of passing by reference is that when you pass by ref 
the parameter _is_ the original variable in every possible way.  The 
compiler might be using a proxy object to implement this, it might not 
be, IANACW.  As such when you ask for the size of a ref parameter you're 
asking for the size of the original variable, which in this case is the 
size of the struct itself.

Regan


More information about the Digitalmars-d-learn mailing list