February 26, 2006
Unknown W. Brackets wrote:
> Obviously that has nothing to do with what I meant.

Uh, sorry I'm tired.

> 
> Consider:
> 
> int foo(out C x, out C y, out C z);
> 
> It is possible I may not want to specify a y or a z.  I may however still want the return value and x.  In other parts of my code, I may want x and y, or all three.  Only in some places will I not want z or y.
> 
> You clearly misunderstood me.  Using in has absolutely nothing to do with this.

I see that now:

> 
> Currently, a workaround would be:
> 
> int foo(out C x)
> {
>    C dummy1, dummy2;
>    return foo(x, dummy1, dummy2);
> }

No: a workaround would be:

private int dummy1, dummy2;
void foo(out int x = dummy1, out int y = dummy2, out int z = dummy3){...}

int foo(out C x)
{
   return foo(x);
}

It complicates library code just a little but simplifies users code.

> 
> But this really is going to the side a bit of the topic.

I thought the topic was initialization of out parameters.
February 26, 2006
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.

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.

3. Requirements to use synchronized blocks around accesses to the variables, which would normally not be necessary with typical out parameters.  This would be needed because the function may depend on the global variables not changing mid-function, but the function might get called numerous times concurrently in multiple threads.

It's true that programming involves the above all the time, but they can all be avoided in this case by not using your described method.  As such, I consider them flaws in the proposed method.

-[Unknown]


> Unknown W. Brackets wrote:
>> Obviously that has nothing to do with what I meant.
> 
> Uh, sorry I'm tired.
> 
>>
>> Consider:
>>
>> int foo(out C x, out C y, out C z);
>>
>> It is possible I may not want to specify a y or a z.  I may however still want the return value and x.  In other parts of my code, I may want x and y, or all three.  Only in some places will I not want z or y.
>>
>> You clearly misunderstood me.  Using in has absolutely nothing to do with this.
> 
> I see that now:
> 
>>
>> Currently, a workaround would be:
>>
>> int foo(out C x)
>> {
>>    C dummy1, dummy2;
>>    return foo(x, dummy1, dummy2);
>> }
> 
> No: a workaround would be:
> 
> private int dummy1, dummy2;
> void foo(out int x = dummy1, out int y = dummy2, out int z = dummy3){...}
> 
> int foo(out C x)
> {
>    return foo(x);
> }
> 
> It complicates library code just a little but simplifies users code.
> 
>>
>> But this really is going to the side a bit of the topic.
> 
> I thought the topic was initialization of out parameters.
February 26, 2006
On Sun, 26 Feb 2006 14:44:57 -0800, Unknown W. Brackets <unknown@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
February 27, 2006
Unknown W. Brackets wrote:
> Yes, but this is a topic about a bug.  We are no longer really talking about the bug.

Do we agree then that the bug is that
void f(out int x = 5) isn't an error?

> 
> If you used your workaround, you would have:
> 
> 1. Extra global variables somewhere in memory, which may not be desirable.

But as Regan said, possibly only one for each type.

> 
> 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.

Same happens here.
void f(out int x = globalX) -> globalX is initialized to int.init.
No bugs here.

> 
> 3. Requirements to use synchronized blocks around accesses to the variables, which would normally not be necessary with typical out parameters.  This would be needed because the function may depend on the global variables not changing mid-function, but the function might get called numerous times concurrently in multiple threads.

I agree this is a problem in multithreaded enviroment.

> 
> It's true that programming involves the above all the time, but they can all be avoided in this case by not using your described method.  As such, I consider them flaws in the proposed method.

But there isn't any other way to solve what you wanted? Or is there?
I mean wanting not allways to pass out arguments to a function.
Atleast not other way without changing the language so that out default params are made strange and inconsistent.

But I agree this discussion sholud probably end soon :)
February 27, 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@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
February 27, 2006
Unknown W. Brackets wrote:
> 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.

Don't see what the problem is, you as an author of foo know what you are doing so know if there should be only one dummy variable or more.

> 
> If a variable is a pointer, it should be a pointer.  

Agree.

> Classes, as reference types, are clear because they are always pointers.  

Agree.

> 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.

Well in this case it is a moose&. D handles references a little strange meaning they aren't really real types, but they are still here. An out parameter means int is passed by reference.

You should think about it as: void test(int& x) in C++.

> 
> In every other way, out and inout parameters are treated as moose.  

Not really. Can the original moose changed when you pass it as in? No. Can it be changed when you pass it as out, or inout. Yes. So they aren't  really treated the same.

> 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.

I am sorry if anything I said seams patronizing or condescending. I can assure you I didn't mean it that way. I was just trying to explain my point of view. Maybe my imperfect English is a cause for occasional bad choise of words that can be misinterpreted.

Once again. I am sorry. Maybe it is best to stop the conversation.
February 27, 2006
On Mon, 27 Feb 2006 01:41:04 +0100, Ivan Senji <ivan.senji_REMOVE_@_THIS__gmail.com> wrote:
>> 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.
>
> I am sorry if anything I said seams patronizing or condescending. I can assure you I didn't mean it that way. I was just trying to explain my point of view.

I couldn't have put it better Ivan. "[Unknown]" you have my apologies also.

Regan
February 27, 2006
On Sun, 19 Feb 2006 17:53:45 -0800, Unknown W. Brackets wrote:

> The spec says:
> 
> out parameters are set to the default initializer for the type of it.
> 
> Which makes perfect sense, and works just fine.  The trick comes in when I try some parameter initialization.

I'm writing this without reading the entire thread, so please excuse me if I'm out of line.

I also preface these remarks by noting that the documentation is exceedingly light on the whole 'default parameter' specification.

Functions:
  "A function parameter's default value is not inherited ..."

 Change log for v0.92:
  "Added default arguments to function parameters. Semantics are like C++."

Anyhow, it seems that you are thinking in terms of "initialize" rather than "default". The difference is that "default" (which is what I believe D is implementing) is invoked by the compiler when a omit a parameter on the call, and "initialize" is when the compiler applies a value to a parameter which you have not omitted, and I don't think the D has implemented this concept.

 foo(in int a) // foo gets (a copy) the value of 'a'.
 foo(in int a = 5) // foo gets 'a' if you pass it,
                   // otherwise it gets the literal 5

 foo(out int a) // foo gets (a reference to) the value of 'a' and
                // sets the value of 'a' to the default initializer for
                // for 'int'.
 foo(out int a = 5) // foo gets a reference to 'a' if you pass it etc...,
                   // otherwise it gets a reference to the literal 5
                   // and sets the value of 5 to 0
                   // (which doesn't make sense to me)


 foo(inout int a) // foo gets (a reference to) the value of 'a'.
 foo(inout int a = 5) // foo gets a reference to 'a' if you pass it,
                   // otherwise it gets a reference to the literal 5
                   // (which doesn't make sense to me)

So I think that defining default parameters for 'out' and 'inout' arguments should be a compile-time error, because in these cases the called program will be receiving the address of a literal.

Can Walter clarify the intent of the default parameter syntax when used in conjunction with 'out' and 'inout'?

-- 
Derek
(skype: derek.j.parnell)
Melbourne, Australia
"Down with mediocracy!"
27/02/2006 1:38:08 PM
February 27, 2006
Derek Parnell wrote:
> On Sun, 19 Feb 2006 17:53:45 -0800, Unknown W. Brackets wrote:
> 
> 
>>The spec says:
>>
>>out parameters are set to the default initializer for the type of it.
>>
>>Which makes perfect sense, and works just fine.  The trick comes in when I try some parameter initialization. 
> 
> 
> I'm writing this without reading the entire thread, so please excuse me if
> I'm out of line.

Who in his right mind would read the entire thread. :)

> 
> I also preface these remarks by noting that the documentation is
> exceedingly light on the whole 'default parameter' specification.
> 
> Functions:
>   "A function parameter's default value is not inherited ..."
> 
>  Change log for v0.92:
>   "Added default arguments to function parameters. Semantics are like C++."
> 
> Anyhow, it seems that you are thinking in terms of "initialize" rather than
> "default". The difference is that "default" (which is what I believe D is
> implementing) is invoked by the compiler when a omit a parameter on the
> call, and "initialize" is when the compiler applies a value to a parameter
> which you have not omitted, and I don't think the D has implemented this
> concept.
> 

Correct.

>  foo(in int a) // foo gets (a copy) the value of 'a'.
>  foo(in int a = 5) // foo gets 'a' if you pass it,                    // otherwise it gets the literal 5
> 
>  foo(out int a) // foo gets (a reference to) the value of 'a' and
>                 // sets the value of 'a' to the default initializer for
>                 // for 'int'.
>  foo(out int a = 5) // foo gets a reference to 'a' if you pass it etc...,                    // otherwise it gets a reference to the literal 5
>                    // and sets the value of 5 to 0
>                    // (which doesn't make sense to me)

I must agree this doesn't make sense.
But this does:
foo(out int a = globalA)
//if you pass something a reference to it is passed
//if you don't a reference toa global int 'globalA' is passed

This (to me) makes sense, is usefull, and is implemented.

> 
> 
>  foo(inout int a) // foo gets (a reference to) the value of 'a'.
>  foo(inout int a = 5) // foo gets a reference to 'a' if you pass it,                    // otherwise it gets a reference to the literal 5
>                    // (which doesn't make sense to me)
> 
> So I think that defining default parameters for 'out' and 'inout' arguments
> should be a compile-time error, because in these cases the called program
> will be receiving the address of a literal.

I think constant arguments for default out/inout arguments shuld be an error, non constant don't need to be.

> 
> Can Walter clarify the intent of the default parameter syntax when used in
> conjunction with 'out' and 'inout'?
> 

This would be a good thing.
1 2 3
Next ›   Last »