Out parameters and initialization

Unknown W. Brackets unknown at simplemachines.org
Sun Feb 26 16:22:43 PST 2006


Given the following example:

class X
{
    int bar;
}

int foo(out X var)
{
    var.bar = 5;

    assert(var.bar == 5);
}

Look at that, an out parameter - being read?  Amazing, I've done the 
unthinkable.

If a variable is a pointer, it should be a pointer.  Classes, as 
reference types, are clear because they are always pointers.  However, 
consider the following:

import std.stdio;

int main()
{
	int x;
	test(x);

	return 0;
}

void test(out int x)
{
	writefln(typeid(typeof(x)));
}

This code clearly identifies x as an int.  If it is an int, it should be 
an int, and it should always be an int.  I mean, that's just common 
sense.  If an animal is a moose, it should not be a giraffe.  We learn 
this in kindergarten.

In every other way, out and inout parameters are treated as moose.  ONLY 
when they receive a default parameter are they being treated as giraffe. 
  This is inconsistent.  They should only ever be treated as one animal: 
as a giraffe, or as a moose.  There is no girmooffe.

I've really grown quite tired with your patronizing and condescending 
tone, and you are reminding me exactly what I dislike about this 
newsgroup and therefore D; the people who seem to surround it.  The 
language seems okay but I honestly remember why I don't use it as often 
every time I get in a conversation with one of you people.

-[Unknown]


> On Sun, 26 Feb 2006 14:44:57 -0800, Unknown W. Brackets 
> <unknown at simplemachines.org> wrote:
>> Yes, but this is a topic about a bug.  We are no longer really talking 
>> about the bug.
>>
>> If you used your workaround, you would have:
>>
>> 1. Extra global variables somewhere in memory, which may not be 
>> desirable.
> 
> True, however you can use the same default global for every parameter of 
> the same type provided the 'out' contract of the function does not check 
> them (which is something you will know and can work around), eg.
> 
> int dontCare;
> int test(out int a = dontCare, out int b = dontCare, out int c = 
> dontCare) { ... }
> 
> You can do this because the dummy globals are never 'read' by anything 
> at any time.
> 
>> 2. Uninitialized variables, from what I can tell (out parameters are 
>> normally initialized to their default state at the beginning of the 
>> function.) This may cause unexpected/hard-to-reproduce bugs.
> 
> 'out' and dummy globals do not prevent the init of the out parameter:
> 
> import std.stdio;
> 
> int global = 5;
> 
> void test(out int a = global) {
>   writefln(a);
> }
> 
> void main()
> {
>     writefln(global);
>     test();
> }
> 
> Output:
> 5
> 0
> 
>> 3. Requirements to use synchronized blocks around accesses to the 
>> variables
> 
> Why? Given that value of an 'out' variable is never 'read' by anyone at 
> any time it does not matter what value it has at any given time, or even 
> that it has any sensible value at all.
> 
> The same cannot be said for 'inout' however. For 'inout' you would need 
> to protect access to the global. For 'inout' your points above are 
> valid. You would need to protect access to the global, but, as Ivan 
> mentioned that may be exactly what you want.
> 
> In the end are we arguing about the utility of each set of behaviour or 
> the logic of it?
> 
> If we're arguing about the logic, my opinion remains that the current 
> behaviour is logical given the following rules:
>   "out and inout _always_ alias/reference the parameter passed"
>   "a default parameter is passed when no parameter is given explicitly"
>   "a constant cannot be passed by reference"
> 
> In order to implement inout how you describe (as 'in' sometimes) you'd 
> need to break rule #1, making the behaviour illogical and inconsistent 
> with other instances of 'inout'.
> 
> The problem seems mainly to be the perception that a default parameter 
> is a default initializer and that is simply incorrect in the general 
> case. It is only true for value types passed as 'in' parameters. Take 
> for example:
> 
> void test(int* a = 5) {} //cannot implicitly convert expression (5) of 
> type int to int*
> 
> you would never expect that to work, right?
> 
> This is essentially identical to:
> 
> void test(inout int a = 5) {}
> 
> Regan



More information about the Digitalmars-d-bugs mailing list