Christophe Travert, dans le message (digitalmars.D:170182), a écrit : > Timon Gehr , dans le message (digitalmars.D:170178), a écrit : >> That is completely unrelated. >> It is impossible to justify transitivity of const for delegate context >> pointers using this argument. It is far too general and the >> justification for the general concept comes from a specific example >> that is different from the one at hand. >> >> The question is, what the meaning of 'const' references should be: >> >> 1. data cannot be changed transitively through the reference >> >> 2. the reference can reference both 'const' and 'immutable' data and >> 'immutable' data can transitively not be changed through the >> reference. >> >> >> 1. requires transitive const for delegate context pointers, 2. does not. > > A const reference can contain > > I don't understand the difference.
Apologies, I forgot to complete my post: A const reference can contain both mutable and immutable data, as long as it does not allow to mutate it. I don't understand point 2: if the reference contain const reference, it should not modify the const reference. Of course, immutable data should not be changed in any case. This is how I understand delegates should work: [the rest of the post is unchanged] > > struct Delegate(C, F, Args) > { > C* ptr; // points to some structure containing all referenced data > R function(C*, Args) fun; > R opCall(Args) { return ptr.fun(Args); } > } > > The signature of opCall determines the type of the delegate. In reality, > the delegate is opaque, and C is not typed. ptr is a pointer to void*, > and fun knows how to use that pointer. But that does not prevent the > pointer to be const or immutable. > > Note that calling opCall is not possible if the Delegate is const, or > part of a const structure, because opCall does not have the const > attribute. > > But the signature of opCall could have any kind of attributes: const, > immutable, pure, nothrow, inout..., which can be reflected by the > delegates type. > > A delegate of type "R delegate(Args) const" would be like this: > > struct DelegateConst(C, R, Args...) > { > const C* ptr; > R function(const C*, Args) fun; > R opCall(Args) const { return ptr.fun(Args); } > } > > Now it is possible to call opCall if the DelegateConst is const. > However, it is possible to build this delegate only if fun is const with > regard to its context argument. > > The same holds if you replace const by immutable. > > Now, the context pointer can point to all type of data. C is a like a > structure, and can contain any kind of data (mutable, const, immutable, > shared...). However transitivity rules must be preserved. If the data is > immutable, the delegate context pointer must be. If the data is a mix of > mutable, const, and immutable data, there is no problem, has long has > the function mutates only the mutable data (but then, the delegate's > frame pointer type must be mutable, and the delegate is not callable if > it is const). > > However, it must respect transitivity: if the delegate is immutable, all > data contained in the context must be immutable. If the context pointer > is const, the data can be mutable, const, or immutable. > > > And where does all this comes from ? > delegates are primarily methods applied to a struct or class instance. > > class S > { > data d; > void method(arg); > } > > S s = new S; > void delegate(arg) dg = &s.method; > > The delegate is constructed directly from the object's method. (1) > > That is why it must have the same signature has objects method. If you > want to fully represent methods, delegates must have all methods > attributes: pure, nothrow, (which is a problem to introduce in > toString methods, for example), etc... but also const, immutable, and > maybe one day inout. > > Currently, delegates does not support all this. It makes life easier, > because we do not have a zillion types of delegates, and it gives a > little bit of air on const virality until we have proper systems to > simplify all this. But this is a gap in the langage. It is up to the > programmer to respect const transitivity, and not exploit this gap and > break the langage. > > (1) In my first example, a langage delegate can be obtained from my > artificial Delegate template by taking the adresse of opApply: > > Delegate!(C, R, Args) s; > R delegate(Args) dg = &s.opApply > > (2) Note that it is however possible to obtain a 'C delegate(Args) > const' but taking the adress of a const method. > > class S > { > data d; > void method(Arg) const; > } > > S s = new S; > auto dg = &s.method; > > dg is infered as 'void delegate(Arg) const' by the compiler > > -- > Christophe