开发者

Equivalent of C# `readonly` keyword in D?

开发者 https://www.devze.com 2023-03-06 09:36 出处:网络
From what I understand while reading up on D, when using the immutable keyword on a variable, the value of the variable must be known at compile time, while C#\'s readonly need not be, and readonly fi

From what I understand while reading up on D, when using the immutable keyword on a variable, the value of the variable must be known at compile time, while C#'s readonly need not be, and readonly fields can be assigned in a class constructor using non开发者_JS百科-static values. Is this possible in D?


In D2, const member can only be initialized inside the constructor (or directly in the class declaration, but not both):

import io = std.stdio;

class A
{
    const int member;
    this(int nb)
    {
        this.member = nb;
    }
}

void main()
{
    A a = new A(12);
    io.writeln(a.member);
    //a.member = 14; //Error: can only initialize const member member inside constructor
}


As there appears to be some confusion (from both the original question, and he_the_great's comment) regarding immutable, I thought I'd add an aside.

When you say immutable int i = 42, you are saying that i will not be modified, not that it the value is known at compile time. immutable is actually a type modifier, and creates a new type. immutable T is a short-hand for immutable(T). immutable(T) creates a T that can never be mutated, that is, if you read the value, then call a function, the value will be the same. Compare this to const(T) which provides the weaker guarantee that this instance of the type will not be modified, but someone may have mutable access to it else where, so if you read the value and then call a function, you cannot assume the value will be the same.

In general, immutable(T) != T. However there are certain situations where they are implicitly convertible to one another. If T is a type that is said to have no "mutable indirection", for instance. That is to say, if I pass a function an immutable(int), they receive a copy -- there is no way that that function can modify the value I passed, as it is copied -- if the type system didn't allow that, it would just be annoying with no added guarantees, so the D type system allows it. However, if I pass an immutable(int*), that can be changed by the calling function. In the case of structs, if any member has mutable indirection then the struct is said to have it as well.

So to turn away from theory and back to more practical matters, it's not true at all that immutable values have to be known at compile time, and that there's no good way to create them. However, the only mutation can occur inside the constructor. For simple scalar types, this is pretty obvious:

immutable(int) i = rand();

But what about something like an object? Well, to construct a type T we use

auto t = new T();

so to construct the type immutable(T) we use

auto t = new immutable(T)();

here's a more complete little example

class Useless
{
    int i;

    this(int i)
    {
        this.i = i;
    }
}

int main(string[] args)
{
    auto o = new immutable(Useless)(cast(int) args.length);
    //o.i = 17;  error
    return o.i;  // fine
}

As you can see, mutation can occur inside the constructor. You can read member variables, but cannot write them (immutable is transitive; that is, every member (and every member of members) becomes immutable if the parent does. You can only call methods if they're marked as const.

I apologise for the off-topic rambling, but I see that a lot of people appear to be confused regarding this topic.


fwend's answer is basically dead-on, but if you're looking for something a little less verbose, you could always make a mixin to automate it. Untested code below to give the general idea:

string readOnly(string typeName, string varName) {
    // Create a private variable that prepends an _ to the name and a 
    // public accessor named name.  
    return "private " ~ typeName ~ " _" ~ varName ~ ";\n" ~
           "public " ~ typeName ~ 
           "varName() @property { return _" ~ varName ~ ";\n";
}

Usage:

class Foo {
    mixin(readOnly("int", "num"));

    void incNum() {
        _num++;
    }
}


I'd declare the field as private, then use a get accessor to read it

0

精彩评论

暂无评论...
验证码 换一张
取 消