www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - New reference type designed to handle templates better

reply "Jonathan Marler" <johnnymarler gmail.com> writes:
I've been thinking about how to handle templates that have 
typically been using the 'ref' parameter attribute because they 
modify the parameter.  For example, the put/doPut functions in 
std.range use the 'ref' attribute for the output range, but in 
many cases the parameter doesn't need to be a reference type and 
the overhead that comes with it.

One idea I had is to have a different type of function argument 
attribute as opposed to "ref".

A "ref" parameter is passed by reference.  Under the hood, a 
reference parameter is equivalent to a pointer to the variable.  
Then the function is free to modify the caller's "version" of the 
variable.  This new type of function parameter, let's call it 
"pref", would instead care about what the variable is "pointing 
to" instead of the variable itself.  In some cases this means 
modifying the caller's version of the variable and in some cases 
it does not.  For example, if a basic value type like int was 
passed in, the variable isn't pointing to anything so a pointer 
to the variable itself would be passed in, but if an int* was 
passed in, then the int* would be passed by value.  I've included 
a table of common types and how "pref" would differ from "ref".

pref: modifying the data the variable is pointing to.  This means 
that if the variable is itself a pointer, then the function won't 
modify the pointer but instead modify what it's pointing to.

BasicDataType (BDT) is bool, all integer types, all float types, 
and all char types

Type     |  ref    |  pref            |  why
--------------------------------------------
BDT      | BDT*      | BDT*      | A BDT is not a pointer, so 
pref must
                                  | modify the variable itself 
which you can
                                  | say is pointing to a location 
in memory
BDT*     | BDT**     | BDT*      | A BDT* is already a pointer, 
pref will
                                  | modify the memory BDT is 
pointing to
BDT[]    | BDT[]*    | BDT[]* or BDT[] | An argument can be made 
for both,
                                  | if the function is modifying 
the contents
                                  | of the array (maybe writing 
data to it),
                                  | then the function might need 
some way of
                                  | returning how much data was 
written so
                                  | it might want to modify the 
given array
                                  | to indicate it has changed.
struct   | struct*   | struct*   | A struct variable is not a 
pointer, so
                                  | pref is a reference type for 
the struct
struct*  | struct**  | struct*   | A struct pointer is already a 
pointer
class    | class*    | class     | A class is already a pointer
function | function* | function  | A function is a pointer to 
code, a
                                  | function is usually used to 
modify data so pref treats the function as what is modifying the 
data.
delegate | delegate* | delegate  | Same as reason for function

Note: A pref modifer to a type that is a pointer to any of these 
types will not do anything to the type
Nov 05 2014
next sibling parent "Freddy" <Hexagonalstar64 gmail.com> writes:
On Wednesday, 5 November 2014 at 19:27:59 UTC, Jonathan Marler
wrote:
 I've been thinking about how to handle templates that have 
 typically been using the 'ref' parameter attribute because they 
 modify the parameter.  For example, the put/doPut functions in 
 std.range use the 'ref' attribute for the output range, but in 
 many cases the parameter doesn't need to be a reference type 
 and the overhead that comes with it.

 One idea I had is to have a different type of function argument 
 attribute as opposed to "ref".

 A "ref" parameter is passed by reference.  Under the hood, a 
 reference parameter is equivalent to a pointer to the variable.
  Then the function is free to modify the caller's "version" of 
 the variable.  This new type of function parameter, let's call 
 it "pref", would instead care about what the variable is 
 "pointing to" instead of the variable itself.  In some cases 
 this means modifying the caller's version of the variable and 
 in some cases it does not.  For example, if a basic value type 
 like int was passed in, the variable isn't pointing to anything 
 so a pointer to the variable itself would be passed in, but if 
 an int* was passed in, then the int* would be passed by value.  
 I've included a table of common types and how "pref" would 
 differ from "ref".

 pref: modifying the data the variable is pointing to.  This 
 means that if the variable is itself a pointer, then the 
 function won't modify the pointer but instead modify what it's 
 pointing to.

 BasicDataType (BDT) is bool, all integer types, all float 
 types, and all char types

 Type     |  ref    |  pref            |  why
 --------------------------------------------
 BDT      | BDT*      | BDT*      | A BDT is not a pointer, so 
 pref must
                                  | modify the variable itself 
 which you can
                                  | say is pointing to a 
 location in memory
 BDT*     | BDT**     | BDT*      | A BDT* is already a pointer, 
 pref will
                                  | modify the memory BDT is 
 pointing to
 BDT[]    | BDT[]*    | BDT[]* or BDT[] | An argument can be 
 made for both,
                                  | if the function is modifying 
 the contents
                                  | of the array (maybe writing 
 data to it),
                                  | then the function might need 
 some way of
                                  | returning how much data was 
 written so
                                  | it might want to modify the 
 given array
                                  | to indicate it has changed.
 struct   | struct*   | struct*   | A struct variable is not a 
 pointer, so
                                  | pref is a reference type for 
 the struct
 struct*  | struct**  | struct*   | A struct pointer is already 
 a pointer
 class    | class*    | class     | A class is already a pointer
 function | function* | function  | A function is a pointer to 
 code, a
                                  | function is usually used to 
 modify data so pref treats the function as what is modifying 
 the data.
 delegate | delegate* | delegate  | Same as reason for function

 Note: A pref modifer to a type that is a pointer to any of 
 these types will not do anything to the type
Not sure what you mean, but can't you just def a pointer when passing to ref function ---- void mycalle(ref int i){ } int mycaller(){ int* var=new int; mycalle(*var); } ----
Nov 05 2014
prev sibling parent reply "Jonathan Marler" <johnnymarler gmail.com> writes:
On Wednesday, 5 November 2014 at 19:27:59 UTC, Jonathan Marler 
wrote:

I haven't gotten any responses on this so I'll try one more time. 
The proposal is to add a new function parameter attribute, called 
"pref" for now.  Here's the difference:

ref : modifies the caller's variable
pref: modifies the CONTENTS of the caller's variable

Here's some examples.

These are all exactly the same:

void modify(int* x)      { *x = 3; }
void modify(ref int x)   { x  = 3; }
void modify(pref int x)  { x  = 3; }
void modify(pref int* x) { x  = 3; }

These are not the same

void modify(class c)      { c.myfield = 3; }

void modify(ref class c)  { c.myfield = 3; }
// NOT EQUIVALENT
// the ref parameter means the function can modify which
// instance the callers variable is actually pointing to.
// This adds an unnecessary level on indirection.

void modify(pref class c) { c.myfield = 3; }

Keep in mind, the pref attribute isn't very useful for 
Non-Template functions because you can just use 'ref' or not. 
However, in a template, the 'pref' attribute will select whether 
the parameter is pass by reference or pass by value based on the 
type.
Nov 07 2014
parent "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> writes:
On Friday, 7 November 2014 at 19:42:58 UTC, Jonathan Marler wrote:
 On Wednesday, 5 November 2014 at 19:27:59 UTC, Jonathan Marler 
 wrote:

 I haven't gotten any responses on this so I'll try one more 
 time. The proposal is to add a new function parameter 
 attribute, called "pref" for now.  Here's the difference:

 ref : modifies the caller's variable
 pref: modifies the CONTENTS of the caller's variable

 Here's some examples.

 These are all exactly the same:

 void modify(int* x)      { *x = 3; }
 void modify(ref int x)   { x  = 3; }
 void modify(pref int x)  { x  = 3; }
 void modify(pref int* x) { x  = 3; }

 These are not the same

 void modify(class c)      { c.myfield = 3; }

 void modify(ref class c)  { c.myfield = 3; }
 // NOT EQUIVALENT
 // the ref parameter means the function can modify which
 // instance the callers variable is actually pointing to.
 // This adds an unnecessary level on indirection.

 void modify(pref class c) { c.myfield = 3; }

 Keep in mind, the pref attribute isn't very useful for 
 Non-Template functions because you can just use 'ref' or not. 
 However, in a template, the 'pref' attribute will select 
 whether the parameter is pass by reference or pass by value 
 based on the type.
I think Manu and deadlnix should comment on this - they complained about `ref` here: http://forum.dlang.org/thread/etjuormplgfbomwdrurp forum.dlang.org?page=5 I agree that this is a real problem - but the solution you propose feels a little ad hoc. It would "solve" this particular problem, but what is the deeper cause for the problems with current ref?
Nov 07 2014