Using in as a parameter qualifier

Ali Çehreli acehreli at yahoo.com
Fri May 31 08:58:25 PDT 2013


On 05/31/2013 02:40 AM, Shriramana Sharma wrote:

 > On Fri, May 31, 2013 at 12:12 PM, Ali Çehreli <acehreli at yahoo.com> wrote:
 >>>     double x,y ;
 >>>     this () {}
 >>
 >> That is not allowed. In D, every type has the .init property, which 
is its
 >> default value.
 >
 > Hm can you clarify that a bit? If I actually try it I get:
 >
 > pair.d(14): Error: constructor pair.pair.this default constructor for
 > structs only allowed with @disable and no body

For structs, the default value of an object is required to be known at 
compile time, which is its default value. To enforce that rule, the 
default constructor cannot be provided for structs.

What the error message is saying is that you can declare it just to 
disable its use:

struct Pair {
     double x = 10.75;
     double y = 20.25;

     // Default constructor disabled
     @disable this();

     // Users must use another constructor:
     this(double x, double y) { this.x = x; this.y = y; }
}

As you see, you must also provide a proper constructor that is 
appropriate for that type.

 >>> Consider a function that operates on a pair:
 >>> double abs2 ( pair a ) { return a.x * a.x + a.y * a.y ; }
 >>> In C++ the function signature would be: double abs2 ( const pair & a )
 >>> So I thought const ref pair a would be appropriate in D -- is that 
right?
 >>
 >> Yes:
 >> double abs2(ref const(Pair) a) { /* ... */ }
 >
 > But is this the idiomatic D way of doing things? I mean, would one
 > normally prefer in or ref const(T) which somehow seems more awkward
 > than even const T &?

Although 'in' feels like it would make all the sense for an in-parameter 
(at least because it conveys our intent to the compiler), Jonathan 
explained why 'in' is disappointing.

I still use 'in' in the examples in many chapters, which needs to be 
corrected at some point:

   http://ddili.org/ders/d.en/function_parameters.html

I gave a talk at DConf 2013, which included D's move semantics (starting 
on slide 11):

   http://dconf.org/talks/cehreli.html

Interestingly, that talk is already old :) due to the improvements in 
dmd 2.063. Here is an adaptation of an example on the dmd 2.063 changelog:

import std.stdio;

struct S
{
     this(int i)           { writeln("1"); }
     this(int i) const     { writeln("2"); }
     this(int i) immutable { writeln("3"); }
     this(int i) shared    { writeln("4"); }
}

void main()
{
     auto a = new S;           // writes "1"
     auto b = new const S;     // writes "2"
     auto c = new immutable S; // writes "3"
     auto d = new shared S;    // writes "4"
}

D's move semantics are explained in the following blog posts by Bartosz 
Milewski:

 
http://bartoszmilewski.com/2008/10/18/who-ordered-rvalue-references-part-1/

 
http://bartoszmilewski.com/2008/10/26/who-ordered-rvalue-references-part-2/

 
http://bartoszmilewski.com/2008/11/03/who-ordered-rvalue-references-part-3/

So, I would use 'ref const' only in special cases and only after 
profiling proves that there would be no performance penalty for doing 
that. After all, ref is implemented by a pointer and the indirect access 
to the members of the object through that pointer may be slow depending 
on the application. That indirection may even cause the CPU access 
outside of its caches, which is a relatively very slow operation.

However, my short tests on this has demonstrated that by-ref is faster 
with today's dmd even on a contrived program that accesses to random 
elements of huge arrays.

However, :) if you are going to make a copy of the argument anyway, 
always take a struct by-value. That works with both lvalue and rvalue 
arguments and in the case of rvalues, you will get the automatic move 
semantics.

My choice is by-value for structs unless there is any reason not to. 
Also note that by-ref-to-const is an anti-idiom even in C++ even in 
surprising places. Everybody defines operator= by taking reference to 
const, which may be slower than taking by-value. This is the idiomatic 
way of writing operator= in C++:

     Foo & operator= (Foo that)
     {
         this->swap(that);
         return *this;
     }

 > it makes optimization sense to not copy it but just automatically 
provide a
 > reference to it right?

Unless the language makes a guarantee about that we cannot take the 
address of the parameter and save it. We wouldn't know whether it is a 
copy or a reference.

 > So I would expect in to mean const ref -- doesn't it work that way, 
and if
 > not, why not?

Another reason is less surprise because structs have copy semantics by 
default.

Ali



More information about the Digitalmars-d-learn mailing list