3

Consider:

class B
{
public:
    int i = 4;
}

class A
{
public:
    B b;

    this()
    {
        b = new B;
    }

    ref B f()
    {
        return b;
    }
}

The ref storage class in front of member function f is redundant right? Class objects are always passed by reference, so returning B and ref B is equivalent?

Second: pure member functions? A pure function is to return only something that depends on the arguments. It should thus not depends on any data members of the class, since they might change the output of the function even for the same arguments passed in. So a pure member function is consequently also a static member function? (the reverse might not be true)

Third: what is the difference between a const and an immutable member class? To differentiate between member function calls of immutable and const class objects? Semantically it is equal in that we can't change data members with both attributes, right?

Fourth: should I add as many function attributes as possible? Like pure, const or immutable, nothrow and final?


Awesome, just discovered this works:

inout(B) f() inout
{
    return b;
}
Taco de Wolff
  • 1,682
  • 3
  • 17
  • 34

3 Answers3

5

ref B f() is a function that returns B by reference. B is a class reference. Ergo, it returns a class reference by reference. This is not nonsense in D, because class references can be rebound:

auto a = new A;
a.f() = new B; // rebinds a.b, possible due to return by ref

Similarly, you can also have pointers to class references in D:

class A
{
    B b;

    /* ... */

    B* f()
    {
        return &b;
    }
}

auto a = new A;
B* b = a.f(); // pointer to reference to instance of class B
*b = new B; // updates a.b

For pure member functions, the implicit this reference parameter is just that - another parameter. It is considered part of the input. With the same this object and the same regular parameters, the output is still always the same.


With a const member function, you don't know if the this object is mutable or immutable. It could be either - the const member function promises not to mutate it anyway. With an immutable member function, the this object is always immutable. The this reference can thus be passed as an immutable argument to another function, or assigned to immutable variables.


When deciding when to care about const, immutable, pure and nothrow, you must consider whether or not you actually need these various guarantees in the client code. If you're writing a library for general use, you probably don't know this, so in these cases it's best to provide as many guarantees as possible.

The situation is arguably different for final. Use it when you don't want client code to accidentally override a function that doesn't make sense to override or isn't otherwise meant to be overridden, or when you want to give the compiler more opportunities to optimize calls to that function. Final functions that don't override any functions (with override) and don't implement any interface functions don't have to be virtual functions, reducing the call overhead.

jA_cOp
  • 3,275
  • 19
  • 15
  • In case of a perfectly modularized piece of code, all functions will be pure? – Taco de Wolff Dec 26 '11 at 18:17
  • 1
    @Daevius, you cannot call impure functions from pure functions. This rules out system calls and everything depending on them. I guess by this measure, your code will never be "perfectly" modularized, it will always depend on some sort of monostate down the line. – jA_cOp Dec 26 '11 at 19:05
  • For more on `pure`, there's this recent question: http://stackoverflow.com/questions/8572399/how-is-this-pure-function-able-to-modify-non-private-state – Jonathan M Davis Dec 27 '11 at 00:32
3

The ref storage class in front of member function f is redundant right? Class objects are always passed by reference, so returning B and ref B is equivalent?

Adding ref allows you to change the b field (the actual reference, not just its contents) by writing: a.f() = new B();

Second: pure member functions?

I believe that pure methods treat this as just another argument.

Third: what is the difference between a const and an immutable member class? To differentiate between member function calls of immutable and const class objects? Semantically it is equal in that we can't change data members with both attributes, right?

Yes, but the immutable version has stronger guarantees.

Fourth: should I add as many function attributes as possible? Like pure, const or immutable, nothrow and final?

Add as many attributes as you expect will be useful when using the code you're writing. (Note that the current implementation isn't very good at detecting redundant attributes.)

Vladimir Panteleev
  • 24,651
  • 6
  • 70
  • 114
2

so returning B and ref B is equivalent?

No. ref makes the function returns an lvalue, thus allowing:

auto a = new A;
auto b = new B;
b.i = 55;
a.f() = b;
writeln(a.b.i); // 55

pure member functions?

A member function can be considered a free function taking the instance as one of the parameters.

   class A { pure void f(int others) immutable; }
<=>
   class A { ... }
   pure void f(immutable(A) this, int others);

Thus, a pure member function can still read and modify (for weakly pure ones) this, as it is just one of the parameters.


what is the difference between a const and an immutable member class?

Not sure what do you mean ☺


should I add as many function attributes as possible?

You should add function attributes that best describes your function. If the function will never be overridden, then add final. If it will never throw any exceptions, then add nothrow, etc.

(BTW, pure, nothrow and @safe can be inferred if the function is a template function.)

kennytm
  • 510,854
  • 105
  • 1,084
  • 1,005