February 11, 2013
> Compiler now inline even when inline isn't present, and don't inline when inline is present [...]
That's what I said.

> In other terms, inline is the perfect example of why defining stuff like that explicitly make no sense.

That was no criticism.
I like to explicitly mark such things, but whatever, I like the idea anyway.
I still hope for a response from Walter or Andrei.
February 11, 2013
On Monday, 11 February 2013 at 06:52:33 UTC, deadalnix wrote:
> Ok, We have 2 usages of ref : when you actually need to modify informations, and for performance reasons. Let's talk about the second one.
>
> Passing by ref to improve performance is not ideal. First this is quite hard to know when it is actually faster to pass by ref and to pass by value, especially in generic code. Secondly it is easy to forget to use ref at some location, and a lot of small performance improvement are lost in the process. Finally, this may be error prone.
>
> I'm thinking about it for a while now and I'm now convinced that we should allow the compiler to do that job for us. Let me explain.
>
> When a function accept a struct, the compiler is free to use that function, or an altered one taking a reference as parameter. Here are some rules the compiler can use to know which one to call from callee side :

I expect this to be a nightmare for both users, who would experience new pile of struct bugs and for developers. How much code would this proposal break?

What do you mean by 'altered'? Are you taking about two function versions or a single one? If first, how does it work with linking, and if second, how does it work for different situations? What happens when you use function pointer or a delegate? How __traits works with respect to function type in case of such optimization? What happens if compiler cannot deduce from context information required to make such decision? How does it play with variardic functions? And how such optimization can be disabled?
February 11, 2013
On Monday, 11 February 2013 at 17:15:40 UTC, Maxim Fomin wrote:
> On Monday, 11 February 2013 at 06:52:33 UTC, deadalnix wrote:
>> Ok, We have 2 usages of ref : when you actually need to modify informations, and for performance reasons. Let's talk about the second one.
>>
>> Passing by ref to improve performance is not ideal. First this is quite hard to know when it is actually faster to pass by ref and to pass by value, especially in generic code. Secondly it is easy to forget to use ref at some location, and a lot of small performance improvement are lost in the process. Finally, this may be error prone.
>>
>> I'm thinking about it for a while now and I'm now convinced that we should allow the compiler to do that job for us. Let me explain.
>>
>> When a function accept a struct, the compiler is free to use that function, or an altered one taking a reference as parameter. Here are some rules the compiler can use to know which one to call from callee side :
>
> I expect this to be a nightmare for both users, who would experience new pile of struct bugs and for developers. How much code would this proposal break?
>

None.

> What do you mean by 'altered'? Are you taking about two function versions or a single one? If first, how does it work with linking, and if second, how does it work for different situations? What happens when you use function pointer or a delegate? How __traits works with respect to function type in case of such optimization? What happens if compiler cannot deduce from context information required to make such decision? How does it play with variardic functions? And how such optimization can be disabled?

The optimization cannot be used on opaques calls. This include function pointer and alike. The only function that is guaranteed to exist is the one that take the struct by value. The other one is an option that the compiler is allowed to choose to make things faster.

It is applicable for variadic function for non variadic argument, not for variadic arguments.

Finally, why would you disable something that make your code faster ?
February 11, 2013
On Monday, 11 February 2013 at 17:51:30 UTC, deadalnix wrote:
> Finally, why would you disable something that make your code faster ?

in order to do easier debugging / to avoid implementation bugs
February 11, 2013
I'm a bit confused now. It's your intention to create (worst case) 2^n permutations of the same function for each potential ref parameter (which would be the same behaviour as 'auto ref') or that the compiler could pass big structs by ref without code bloat?
February 11, 2013
On Monday, 11 February 2013 at 19:14:15 UTC, Namespace wrote:
> I'm a bit confused now. It's your intention to create (worst case) 2^n permutations of the same function for each potential ref parameter (which would be the same behavior as 'auto ref') or that the compiler could pass big structs by ref without code bloat?

 For some reason I doubt that's what he means. Seems more often than not only one or two parameter(s) need to be ref-able, so in most cases with 1 variable two (and only two) functions be made and it choose between the two based on the result. Larger than that and another method would have to be selected.
February 11, 2013
On Mon, 11 Feb 2013 07:52:28 +0100
"deadalnix" <deadalnix@gmail.com> wrote:

> Ok, We have 2 usages of ref : when you actually need to modify informations, and for performance reasons. Let's talk about the second one.
> 
> Passing by ref to improve performance is not ideal. First this is quite hard to know when it is actually faster to pass by ref and to pass by value, especially in generic code. Secondly it is easy to forget to use ref at some location, and a lot of small performance improvement are lost in the process. Finally, this may be error prone.
> 
> I'm thinking about it for a while now and I'm now convinced that we should allow the compiler to do that job for us. Let me explain.
> 

To be honest, up until recently, I mistakenly thought the compiler DID
do this. (Yea, my mistake.)

Is it possible I had confused structs with static arrays? Do static arrays do that?

February 11, 2013
On Monday, 11 February 2013 at 21:45:11 UTC, Nick Sabalausky wrote:
> On Mon, 11 Feb 2013 07:52:28 +0100 "deadalnix" <deadalnix@gmail.com> wrote:
>> 
>> I'm thinking about it for a while now and I'm now convinced that we should allow the compiler to do that job for us. Let me explain.
>> 
>
> To be honest, up until recently, I mistakenly thought the compiler DID do this. (Yea, my mistake.)
>
> Is it possible I had confused structs with static arrays? Do static arrays do that?

 I'm pretty sure static/fixed arrays are more like structs, and thereby whole copies are made rather than sending a slice. Let's find out.

  void main() {
    char[4] test = "test";
    writeln(&test, "- main");
    fun(test);
    if (test == "test")
      writeln("is passed by value/copy");
    else {
      assert(test == "best", "Something's wrong...");
      writeln("is passed by slice/ref");
    }
  }

  void fun(char[4] test){
    assert(test == "test");
    writeln(&test, "- fun");
    test[0] = 'b';
    assert(test == "best");
  }

Output:

18FDD0- main
18FDAC- fun
is passed by value/copy
February 11, 2013
On Monday, 11 February 2013 at 22:03:52 UTC, Era Scarecrow wrote:
> Output:
>
> 18FDD0- main
> 18FDAC- fun
> is passed by value/copy

 Now had the function been 'void fun(char[] test)', then passing a static/fixed array would have errored and you'd be required to send a slice of it's contents, which then is by ref. Seems using the address doesn't seem to be very helpful, so for slices you'd refer to the ptr of the array. I'm sure there's other tests that can be done... to help with the expected behavior

  //appended to main
    fun2(test);
    if (test == "test")
      writeln("is passed by value/copy");
    else {
      assert(test == "best", "Something's wrong...");
      writeln("is passed by slice/ref");
    }
  }

  void fun2(char[] test){
    assert(test == "test");
    //&test points to local test not it's contents
    writeln(test.ptr, "- fun2");
    test[0] = 'b';
    assert(test == "best");
  }

new Output:
18FDD0- main
18FDA4- fun
is passed by value/copy
18FDD0- fun2
is passed by slice/ref
February 11, 2013
On Monday, 11 February 2013 at 16:56:38 UTC, deadalnix wrote:
> On Monday, 11 February 2013 at 16:51:22 UTC, Steven Schveighoffer wrote:
>> On Mon, 11 Feb 2013 10:08:52 -0500, deadalnix <deadalnix@gmail.com> wrote:
>>
>>> A good rule of thumb to know when to pass by ref for perf is :
>>> - The struct is big, or contains mixed entities (floats and ints). 2*size_t seems like a good heuristic from my experience.
>>
>> Array slices are 2*sizeof(size_t).  I would expect them to be always copied and not ref'd.
>>
>
> First, they alway appears to be copied from the dev perspective. That why I put bunch of restrictions in the proposal.
>
> Second, slice are 2*size_t and are not mixed entities (from CPU perspective, pointer are integers). So I don't have numbers, but I expect slice to be faster when passed by copy than when passed by ref.

The idea of compiler choosing the optimal between: 'T t' and 'ref const(T) t' has been brought up a few times. Here is one attempt at getting numbers to see where a cutoff might be.

http://forum.dlang.org/thread/opufykfxwkkjchqcwgrg@forum.dlang.org

Based on this, and to avoid the boilerplate of read accessors, I use the following heuristic. If others have more friendly ways I'd be interested.

Thanks
Dan


/** Discriminates a pass type by its size
 */
template PrefersPassByRef(T) {
  static if(isAssociativeArray!T || isDynamicArray!T) {
    enum PrefersPassByRef = false;
  } else static if(T.sizeof > 16 || hasAliasing!T)  {
    enum PrefersPassByRef = true;
  } else {
    enum PrefersPassByRef = false;
  }
}

/** Discriminates a pass type by its size
 */
template PreferredPassType(T) {
  static if(PrefersPassByRef!T) {
    enum PreferredPassType = `const ref `~T.stringof;
  } else {
    enum PreferredPassType = T.stringof;
  }
}

/** Provides mixin for making a field read only.
 *  For example mixin(ReadOnly!_fieldName) provides a getter named fieldName.
 */
template ReadOnly(alias name) {
  enum v = name.stringof;
  enum p = name.stringof[1..$];
  enum prefersReference = PrefersPassByRef!(typeof(name));
  static if(prefersReference) {
    mixin(`
public @property auto ref `~p~`() const {
  return `~v~`;
}
`);
  } else {
    mixin(`
public @property auto `~p~`() const {
  return `~v~`;
}
`);
  }
}