| Thread overview | ||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
December 29, 2014 const Propagation | ||||
|---|---|---|---|---|
| ||||
Hi all,
I've got a little problem regarding const. In fact, my problem originates from C++ where I've tried to implement a visitor that deals with both const and non-const objects. As this did not work out, I checked whether it would work in D. Unfortunately, I could not figure out how. Maybe someone can help.
Basically, I would like to propagate constness to a lambda function. Here's the example code:
import std.stdio;
class Hugo {
public int x = 42;
void blah(void function(Hugo h) f) {
f(this);
}
}
void main() {
Hugo hugo = new Hugo();
void function(Hugo h) f = function(Hugo h) {
h.x = 99;
};
hugo.blah(f);
const Hugo inge = hugo;
void function(Hugo h) g = function(Hugo h) {
writeln("foobar");
};
inge.blah(g);
}
This does not compile. The D compiler complains that I must not call a mutable method on a const object (inge). However, if I make the method const, I have to also make the parameter of the lambda const which results in the compiler rejecting the call "hugo.blah(f)" since this lambda actually modifies the object.
I hope you get what I want. I want to be able to call blah() on a const instance of Hugo with a lambda that does not modify its argument and otherwise call blah() with any function, even one that modifies the object. Is that possible?
Thank you very much!
| ||||
December 29, 2014 Re: const Propagation | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Julian Kranz | You need to overload on const, and also pass in a correctly typed function as the argument (you can't call a function with a mutable parameter with a const object.
import std.stdio;
class Hugo {
public int x = 42;
void blah(void function(Hugo h) f) {
f(this);
}
// OVERLOAD
void blah(void function(const Hugo h) f) const {
f(this);
}
}
void main() {
Hugo hugo = new Hugo();
void function(Hugo h) f = function(Hugo h) {
h.x = 99;
};
hugo.blah(f);
const Hugo inge = hugo;
// CHANGE TYPE HERE
void function(const Hugo h) g = function(const Hugo h) {
writeln("foobar");
};
inge.blah(g);
}
| |||
December 29, 2014 Re: const Propagation | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Peter Alexander | Thank you for your answer. This kind of thing also works for C++, but that would mean that I would implement the whole visitor twice - one const and one non-const version. Is that really the only way? Can't I tell the D compiler that "the argument of that lambda shares the const-ness of the current object"? D offers "inout"; this actually aims into the right directing, but I guess it does not help here. Is there any "static if"-something construct to check the const-ness of an object? | |||
December 29, 2014 Re: const Propagation | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Peter Alexander | So I hope you understand; I've got no problem with changing the type of the function g as you supposed. The bad thing is the additional overload that results in duplicated code. | |||
December 29, 2014 Re: const Propagation | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Julian Kranz | On Monday, 29 December 2014 at 13:22:41 UTC, Julian Kranz wrote:
> So I hope you understand; I've got no problem with changing the type of the function g as you supposed. The bad thing is the additional overload that results in duplicated code.
So you can write something like this:
import std.stdio;
class Hugo {
public int x = 42;
void blah(this T)(void function(T h) f)
{
f(this);
}
}
void main() {
Hugo hugo = new Hugo();
void function(Hugo h) f = function(Hugo h) {
h.x = 99;
};
hugo.blah(f);
const Hugo inge = hugo;
void function(const Hugo h) g = function(const Hugo h) {
writeln("foobar");
};
inge.blah(g);
}
| |||
December 29, 2014 Re: const Propagation | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Julian Kranz | On 12/29/14 8:20 AM, Julian Kranz wrote: > Thank you for your answer. This kind of thing also works for C++, but > that would mean that I would implement the whole visitor twice - one > const and one non-const version. Is that really the only way? Can't I > tell the D compiler that "the argument of that lambda shares the > const-ness of the current object"? > > D offers "inout"; this actually aims into the right directing, but I > guess it does not help here. inout is not smart enough to know what the inout on a lambda means. It also can be confusing to understand that during the entire execution of an inout function, the inout parameters are treated as const. This would preclude using inout to do what you want. > Is there any "static if"-something construct to check the const-ness of > an object? Static-if applies to generic coding, i.e. templates. A template function may work, but I don't think you even need static if: class Hugo { ... } void blah(T)(T obj, void function(T t) f) if(T : Hugo) { f(obj);} This should work with all iterations of Hugo, and is callable via UFCS: hugo.blah(f); // should work I don't know if a template member function would be possible, as I'm pretty sure templates do not infer const. (admittedly, I have not tested any of this) -Steve | |||
December 29, 2014 Re: const Propagation | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | On 12/29/14 9:18 AM, Steven Schveighoffer wrote:
> Static-if applies to generic coding, i.e. templates. A template function
> may work, but I don't think you even need static if:
>
> class Hugo { ... }
>
> void blah(T)(T obj, void function(T t) f) if(T : Hugo) { f(obj);}
um...
blah(T : Hugo)(T obj, void function(T t) f) { f(obj); }
Maybe this will work better, but still untested :) You may need T : const(Hugo).
-Steve
| |||
December 29, 2014 Re: const Propagation | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | Thank you for your answers. All of your suggestions go into the right direction, however there's still one thing left that breakes it: the method itself (blah()) needs to be marked as const to be callable on a const object. Therefore, I need something like
void blah(...)(...) if(this ia const object) const : nothing {
}
I would also like to discuss the underlying problem. Even if we end up finding some syntactic monster to deal with this, there obviously is no sneaky syntax for it. Am I wrong thinking that is some very basic type checking problem? I mean, D already implements const transitively. Thus, if I cast some object to its const version, all its members magically turn to be const as well. Wouldn't it be natural to apply this here as well? This way, I would not even need to declare the lambda's parameter as const or anything; the compiler would only fail if I actually pass in something of which the compiler is unsure whether it changes the passed-in object or not...
| |||
December 29, 2014 Re: const Propagation | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Julian Kranz | On Monday, 29 December 2014 at 15:17:30 UTC, Julian Kranz wrote:
> Thank you for your answers. All of your suggestions go into the right direction, however there's still one thing left that breakes it: the method itself (blah()) needs to be marked as const to be callable on a const object. Therefore, I need something like
>
> void blah(...)(...) if(this ia const object) const : nothing {
> }
>
Did you try my solutions? It doesn`t need blah to be const
| |||
December 29, 2014 Re: const Propagation | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Daniel Kozak | On Monday, 29 December 2014 at 15:25:13 UTC, Daniel Kozak wrote:
> On Monday, 29 December 2014 at 15:17:30 UTC, Julian Kranz wrote:
>> Thank you for your answers. All of your suggestions go into the right direction, however there's still one thing left that breakes it: the method itself (blah()) needs to be marked as const to be callable on a const object. Therefore, I need something like
>>
>> void blah(...)(...) if(this ia const object) const : nothing {
>> }
>>
>
> Did you try my solutions? It doesn`t need blah to be const
Uuuhm, you're right, it works :-D I don't completely understand why the compiler does not require the function to be sonst any longer...
| |||
Copyright © 1999-2021 by the D Language Foundation
Permalink
Reply