September 11, 2012
On Tuesday, 11 September 2012 at 17:57:17 UTC, David Piepgrass wrote:
>>>> void func (ref int[], int)
>>>>
>>>> If ref/out were required at the call site, this destroys UFCS.
>>>>
>>>> int[] array;
>>>> array.func(0); // error, ref not specified by caller
>>>
>>> For UFCS, ref should be implied.
> +1
>
>> Why? UFCS means uniform function call syntax.
> It is already understood that the thing left of '.' may be passed by reference:
>
> struct Foo { int x = 0; void f() { x++; } }
> void obvious()
> {
>    Foo foo; foo.f(); // x is passed to f() by reference
> }
>
> Perhaps your argument makes sense for classes, but not for structs. In any case the syntax (ref foo).f() would require extra work for Walter so I would not propose it. What I might propose instead is that, if the user requests (via command-line argument such as '-callSiteRef') that a warning be issued for arguments passed without 'ref' at the call site, then a situation like this should prompt a warning.
>
> class Bar { int b; }
> void changeBar(ref Bar b) { b = new Bar(); }
> void warning()
> {
>     Bar bar = new Bar();
>     bar.b = 10;
>     bar.changeBar(); // Warning: 'bar' is implicitly passed by reference. To eliminate this warning, use 'changeBar(ref bar)' instead or do not compile with '-callSiteRef'
> }
>
> Again, this problem only applies to classes, since it is understood that structs are normally passed by reference.
>
>>> Also for 'const ref' parameters, callsite ref should not be necessary.
>>>
>> The callee might escape a pointer to the argument. Which is
>> 'non-obvious' as well when there is no callsite ref.
>
> If you're referring to the fact that it's easy to have a D pointer to a stack variable outlive the variable... I don't think that this 'flaw' (I think of it as a flaw, others may think of it as a feature) is a good enough reason to say 'call site ref should be required for const ref parameters'.
>
>>> for value types, it is arguably important.
>>
>> This is not necessarily a valid conclusion. Popularity does not imply importance.
>
> I think 'ref' is a popular idea because people have used it in C# and liked it. I didn't start putting 'IN OUT' and 'OUT' in my C++ code until C# taught me the value of documenting it at the call site.


Like i have written above, when switching from C++ to C# i found it at first annoying but now i wished i would have it in C++ too. One possibility to simulate this in C++ is like the pbrt people have done it with const references and pointers (look at my post above for further details).


>
>>>> Generally speaking, if a parameter being
>>>> ref/out is surprising, there is something wrong with the design.  (There
>>>> are times it is non-obvious in otherwise good code, this seems uncommon.)
>
> I often want to 'scan' code to see what it does. Especially for debugging, I want to see where the side-effects are QUICKLY. Guessing which parameters are 'ref' requires me to analyze the code in my head. Even if I myself wrote the code, it can be time consuming. That's why I would prefer to explicitly mark possible side effects with 'ref' (of course, when passing a class to a function, the class members may be modified when the reference to the class was passed by value. But it is far easier to keep track of which classes are mutable than to keep track of which parameters of which functions are 'ref', because functions far outnumber classes.)
>

+1

It's not only that you yourself want to 'scan' through your code and QUICKLY see where parameters in function calls are modified but others might have to read your code aswell for code reviewing without browsing in the hopefully existing documentation for every single function / method. People in companies normally are not programming in isolation but are working in a team and teams often change.



>> IMHO it is better left to the future D editor.
>
> That's probably a long way off.

Yes. Looking at the current overall state of the d toolchain that might be a very long way off.

And even then, inmho, it would be a not so good solution because it would be a feature which would tie users who want this feature to a specific editor / ide.

September 12, 2012
On Tuesday, 11 September 2012 at 16:49:45 UTC, Manuel wrote:
> On Tuesday, 11 September 2012 at 08:10:21 UTC, Andrei Alexandrescu wrote:
>> On 9/11/12 1:28 AM, Manuel wrote:
>>>> Citation? I'm using C# 5.0 with Visual Studios 2012 on Windows 8 right
>>>> now and ref/out are still required at the call sight of functions.
>>>
>>> I have Visual Studio 2012 RC and can confirm, that ref and out
>>> are still required even with C# 5.0 (but maybe there is some
>>> compiler switch to disable this ??)
>>
>> Erik Meijer didn't get back to me yet about that with a link, but he did mention that the relaxation was only allowed for COM calls.
>>
>> Andrei
>
> OK, i see. For COM calls that might make sense, since binary COM modules are mostly written in C/C++ and must also not depend on any feature of any programming language so that the calling should be easily possible from any language. There these C# specific annotations are of no use since you don't get any additional safety and you just have to write more code which at the end gains you nothing.
>
>
> In general, i can understand the objections against adding these syntax annotations at the call site. When i started programming in C#, coming from a C++ background, i found writing these additional annotations rendundant and annoying and a complete waste of time.
>

Having used Turbo Pascal before I was doing C, I never understood
why so many developers cry for this at the call site.

I never had any problem with "var" parameters on Turbo Pascal (or
other languages from Wirth), nor with references in C++.

As I am not language religious, I just use them the way the
language provides them.

--
Paulo
September 12, 2012
On 11/09/2012 18:57, David Piepgrass wrote:
>>>> void func (ref int[], int)
>>>>
>>>> If ref/out were required at the call site, this destroys UFCS.
>>>>
>>>> int[] array;
>>>> array.func(0); // error, ref not specified by caller
>>>
>>> For UFCS, ref should be implied.
> +1
>
>> Why? UFCS means uniform function call syntax.
> It is already understood that the thing left of '.' may be passed by
> reference:
>
> struct Foo { int x = 0; void f() { x++; } }
> void obvious()
> {
>     Foo foo; foo.f(); // x is passed to f() by reference
> }
>
> Perhaps your argument makes sense for classes, but not for structs. In
> any case the syntax (ref foo).f() would require extra work for Walter so
> I would not propose it. What I might propose instead is that, if the
> user requests (via command-line argument such as '-callSiteRef') that a
> warning be issued for arguments passed without 'ref' at the call site,
> then a situation like this should prompt a warning.
>
> class Bar { int b; }
> void changeBar(ref Bar b) { b = new Bar(); }
> void warning()
> {
>      Bar bar = new Bar();
>      bar.b = 10;
>      bar.changeBar(); // Warning: 'bar' is implicitly passed by
> reference. To eliminate this warning, use 'changeBar(ref bar)' instead
> or do not compile with '-callSiteRef'
> }
>
> Again, this problem only applies to classes, since it is understood that
> structs are normally passed by reference.

I had only thought about UFCS and ref parameters for value types. You are right that requiring callsite ref for class ref parameters would be a useful idea, as modifying the ref itself is unusual behavior. And because of that, disallowing UFCS for functions that have a class ref parameter as the first parameter might be an elegant solution.
September 12, 2012
On 12/09/2012 13:39, Nick Treleaven wrote:
>> class Bar { int b; }
>> void changeBar(ref Bar b) { b = new Bar(); }
>> void warning()
>> {
>>      Bar bar = new Bar();
>>      bar.b = 10;
>>      bar.changeBar(); // Warning: 'bar' is implicitly passed by
>> reference. To eliminate this warning, use 'changeBar(ref bar)' instead
>> or do not compile with '-callSiteRef'
>> }
>>
>> Again, this problem only applies to classes, since it is understood that
>> structs are normally passed by reference.
>
> I had only thought about UFCS and ref parameters for value types. You
> are right that requiring callsite ref for class ref parameters would be
> a useful idea, as modifying the ref itself is unusual behavior. And
> because of that, disallowing UFCS for functions that have a class ref
> parameter as the first parameter might be an elegant solution.

Also the same applies to ref parameters with any reference types:

On 08/09/2012 14:05, Chris Nicholson-Sauls wrote:
> void func (ref int[], int)
>
> If ref/out were required at the call site, this destroys UFCS.
>
> int[] array;
> array.func(0); // error, ref not specified by caller

So the above poster was right, I completely missed this :-/

(But disallowing UFCS here still might be a good solution).
September 12, 2012
I disagree that it would be useful.
In C# it is useful because pointers that used a lot less than in D.

Consider this:

void f(ref int x)
{
...
}

...
int x = 5;
f(ref x); // good, passed by reference
...


But:
void g(int* p)
{
...
}

...
int x = 5;
g(&x); // passed by reference as well, but it is not explicit like before. You don't even know if it's a const pointer if you don't read the function's signature.
...

So someone has this cool idea which is also present in some other programming language and thinks it would be nice to add it to D. That's not how it works. Then come the problem with things not properly designed etc etc.

Anyway, who needs to see f(ref x) when you can put your mouse above the function call and see its declaration? All modern IDEs support that - and I don't think C# guys use plain text editors.
September 12, 2012
Minas:

> g(&x); // passed by reference as well, but it is not explicit like before. You don't even know if it's a const pointer if you don't read the function's signature.

The presence of "&" at call site acts exactly like the "ref" at
the call site. In both cases you don't know if it's
const/immutable.

Bye,
bearophile
September 12, 2012
Minas wrote:
> Anyway, who needs to see f(ref x) when you can put your mouse above the function call and see its declaration? All modern IDEs support that - and I don't think C# guys use plain text editors.

People debugging large bodies of code should not be required to hover the mouse over each and every function parameter for a second to properly understand structure. People using non-tooltip text editors have an even harder time.

I think you're missing the point. This code:

    int* x;
    foo(&x);

at least tells you there's a _potential_ x is being manipulated rather than just used. We don't need full insight into what's going on, just a helpful hint which narrows the potential culprits when debugging.

If fact, it would nice if even reference types where required to follow similar "is modified in function" semantics, and I have ideas about that, but I'm not going there right now...

September 12, 2012
On Wednesday, 12 September 2012 at 07:36:24 UTC, Paulo Pinto wrote:
> On Tuesday, 11 September 2012 at 16:49:45 UTC, Manuel wrote:
>> On Tuesday, 11 September 2012 at 08:10:21 UTC, Andrei Alexandrescu wrote:
>>> On 9/11/12 1:28 AM, Manuel wrote:
>>>>> Citation? I'm using C# 5.0 with Visual Studios 2012 on Windows 8 right
>>>>> now and ref/out are still required at the call sight of functions.
>>>>
>>>> I have Visual Studio 2012 RC and can confirm, that ref and out
>>>> are still required even with C# 5.0 (but maybe there is some
>>>> compiler switch to disable this ??)
>>>
>>> Erik Meijer didn't get back to me yet about that with a link, but he did mention that the relaxation was only allowed for COM calls.
>>>
>>> Andrei
>>
>> OK, i see. For COM calls that might make sense, since binary COM modules are mostly written in C/C++ and must also not depend on any feature of any programming language so that the calling should be easily possible from any language. There these C# specific annotations are of no use since you don't get any additional safety and you just have to write more code which at the end gains you nothing.
>>
>>
>> In general, i can understand the objections against adding these syntax annotations at the call site. When i started programming in C#, coming from a C++ background, i found writing these additional annotations rendundant and annoying and a complete waste of time.
>>
>
> Having used Turbo Pascal before I was doing C, I never understood
> why so many developers cry for this at the call site.
>
> I never had any problem with "var" parameters on Turbo Pascal (or
> other languages from Wirth), nor with references in C++.
>
> As I am not language religious, I just use them the way the
> language provides them.
>
> --
> Paulo


You just have cut away the last part of the history of my life and completely changed my statement to the reverse ;-)

That last part was were i was getting my enlightenment and started to embrace additional annotations at the call site. From there i never looked back and lived a happier and more glorious life with a lot of profit and lot less errors ;-)


Kevin just put this up for discussion because he realized while porting code from C# to D that he got wrong function calls on overloaded functions because of missing call site parameter annotations and just asked about the general opinion in the D community to add these to the language.

I and a lot of the other participants in this thread just asserted that it would be a nice addition to D. That does not mean, we were "crying" for these or that we are "language religious" or that without them we would have unsolvable problems and would forever quit programming in D and switch over to QuickBasic again.

It was more just a survey about the general opinion in the community. And as an intermediate result (which is not even close to be representive), the majority of the participants of this thread would like to have these added to the language, some just don't care and some don't like the idea at all.

From those who didn't like the idea the most heared counter-argument was more like: "I know my code, i have written it, so i know which method modifies which parameters. I don't need this it makes me do more work."

Which in my opinion is a bit shortsighted since in commercial development or in general when you work in a team you don't program in isolation and you have to  often use third-party-frameworks were you don't have written every method by yourself. That's why the Microsoft language designer added this to C# and you even find this in a simulated way in C++ realised with references and pointers.

The only valid counter-arguments brought up so far, were possible breakage of code (when it would be enforced) and maybe UCFS.


> As I am not language religious, I just use them the way the
> language provides them.


The good thing here in the open source world is that we are not bound to the decision of a big committee. It's not "you'll eat what's put in front of you".

If a bigger part of the D community would like to have these annotations added to the language, at least as an optional feature, then that might persuade our "benevolent dictators" (just joking - you are great!) Walther and Andrei to add them or we could just make a fork of the language and add them ourselves (more joking - no, just skip this last part - it's late) :-)

There might be other problems, maybe with the compiler internals or breakage of parts of the language. These were severe. But i think only Walther and Andrei might tell. If these wouldn't exist it would at least be possible, how David proposed it in his post, to make them optional.

At the end that won't stop me or any other poster from programming in D. It would just really be nice to see this little extra of parameter checking at least optionally in D since with all the other safeness-features like safeD, contracts, etc. it would be a good addition to the language.



September 13, 2012
On 9/13/12 1:02 AM, Manuel wrote:
> If a bigger part of the D community would like to have these annotations
> added to the language, at least as an optional feature, then that might
> persuade our "benevolent dictators" (just joking - you are great!)
> Walther and Andrei to add them or we could just make a fork of the
> language and add them ourselves (more joking - no, just skip this last
> part - it's late) :-)
>
> There might be other problems, maybe with the compiler internals or
> breakage of parts of the language. These were severe. But i think only
> Walther and Andrei might tell. If these wouldn't exist it would at least
> be possible, how David proposed it in his post, to make them optional.

I don't think there would be problems with allowing ref/out optionally at the call site. The thing is, however, that in this matter reasonable people may disagree. In C++, the equivalent argument (should we pass everything modifiable by pointer or not?) erupts every six months on internal fora at Facebook. No winning argument is made by either part. For example, it is often brought up that it's good to see "&" at the call site when debugging some urgent matter at 3am. Yet there are other people who are just as apt at debugging urgent matters at 3am, and the absence of "&" doesn't seem to be a handicap for them at all. I'd be unable to identify any pattern in engineers choosing one preference over the other. As a consequence, our code has a mix of pass-by-pointer and pass-by-reference-to-nonconst, all engineers manage either style just as well, and we've never been able to find any evidence pointing one way or another.

Now that the subject has been broken, we do have good evidence of a pattern that generates significant and difficult bugs: escaping the address of a reference. In C++:

struct A {
    A(int& host) : host_(host) {}
private:
    int& host_;
};

In D:

class A { // or struct
    A(ref int host) : _host(&host) {}
private:
    int* _host;
}

A solution we use for C++ is to require escaped addresses to be always passed as pointers or smart pointers.

Walter and I have discussed this for quite a while. We have recently decided to disallow, at least in SafeD, escaping the address of a ref parameter. In the beginning we'll be overly conservative by disallowing taking the address of a ref altogether. I'll write a DIP on that soon.


Andrei
September 13, 2012
In D:

class A { // or struct
    A(ref int host) : _host(&host) { }
private:
    int* _host;
}

Since when do we have initialization lists in D? ;)

at topic: +1