digitalmars.D - The relationship of invariants and alias this
- Mark Isaacson (29/29) Nov 10 2014 I've encountered something which is probably intentional
- Mark Isaacson (3/3) Nov 10 2014 Should be noted that this behavior is the same regardless of
- H. S. Teoh via Digitalmars-d (5/8) Nov 10 2014 Sounds like a bug. Please file an issue at http://issues.dlang.org/
- Mark Isaacson (4/14) Nov 10 2014 Exciting/encouraging! Done.
- angel (7/7) Nov 11 2014 Wait !
- Mark Isaacson (10/17) Nov 11 2014 Intriguing - thanks :). Looks like you found the reason for the
- ZombineDev (28/28) Nov 11 2014 AFAIU, even if you had a getter in the alias this:
- Steven Schveighoffer (4/32) Nov 11 2014 Correct, the only real solution is to wrap with the actual operators and...
I've encountered something which is probably intentional behavior, but that I think is interesting and may merit discussion. When you do "alias this" and have an invariant, any methods that are forwarded to the aliased member do not invoke your invariant methods. This prevents me from writing a really sleek 10-liner to the tune of: struct ValueRestrictedInteger(int lowerBound, int upperBound) { int value; alias value this; this (int rhs) { value = rhs; } invariant() { assert (value >= lowerBound && value <= upperBound); } void forDemonstrationOnly() {} } unittest { ValueRestrictedInteger!(0, 100) x = 0; x += 10; x -= 100; //This works, but I don't think it should x.forDemonstrationOnly(); //This causes the assertion to fire ValueRestrictedInteger!(0, 100) y = -100; //This also would hit the assertion } I realize that this is not the most efficient way to implement this concept and that the invariant gets compiled out in a -release build... I still think this is a pretty nifty piece of code whose semantics are not unreasonable. Why shouldn't an aliased method be subject to our invariants?
Nov 10 2014
Should be noted that this behavior is the same regardless of whether or not I do an "alias this" on a primitive type as shown above or on a user defined type.
Nov 10 2014
On Tue, Nov 11, 2014 at 05:03:00AM +0000, Mark Isaacson via Digitalmars-d wrote:Should be noted that this behavior is the same regardless of whether or not I do an "alias this" on a primitive type as shown above or on a user defined type.Sounds like a bug. Please file an issue at http://issues.dlang.org/ T -- It's amazing how careful choice of punctuation can leave you hanging:
Nov 10 2014
On Tuesday, 11 November 2014 at 06:21:18 UTC, H. S. Teoh via Digitalmars-d wrote:On Tue, Nov 11, 2014 at 05:03:00AM +0000, Mark Isaacson via Digitalmars-d wrote:Exciting/encouraging! Done. https://issues.dlang.org/show_bug.cgi?id=13710Should be noted that this behavior is the same regardless of whether or not I do an "alias this" on a primitive type as shown above or on a user defined type.Sounds like a bug. Please file an issue at http://issues.dlang.org/ T
Nov 10 2014
Wait ! "x.value -= 100;" would call the invariant ? Alias this only rewrites your expression: "x -= 100;" becomes "x.value -= 100;" No method is called. Then there is no reason (is there ?) to call the invariant. If you would create getter/setter properties ...
Nov 11 2014
On Tuesday, 11 November 2014 at 08:18:36 UTC, angel wrote:Wait ! "x.value -= 100;" would call the invariant ? Alias this only rewrites your expression: "x -= 100;" becomes "x.value -= 100;" No method is called. Then there is no reason (is there ?) to call the invariant. If you would create getter/setter properties ...Intriguing - thanks :). Looks like you found the reason for the current implementation; what you've written is the "lowering" of alias this. From a semantic perspective though, we are claiming that "value *is* this"; there is an IsA relationship and I'd argue that the invariant should still apply because we are modifying "this", in a way. I totally see where you're coming from though; that's why I wanted to open the floor for discussion as to what the more desirable behavior is.
Nov 11 2014
AFAIU, even if you had a getter in the alias this: --- import std.stdio; struct ValueRestrictedInteger(int lowerBound, int upperBound) { int value; auto ref get() { return value; } alias get this; this (int rhs) { value = rhs; } invariant() { assert (value >= lowerBound && value <= upperBound); } void forDemonstrationOnly() {} } --- It would still not work: --- unittest { ValueRestrictedInteger!(0, 100) x = 0; x -= 100; //is probably lowered to something like this: // 1) invariant(); // 2) int* __temp = &x.value; // this is what get() does // 3) invariant(); // 4) *__temp = *temp - 100; //... } --- Obviously, 4) will not trigger the invariant because it doesn't call any public functions.
Nov 11 2014
On 11/11/14 6:48 AM, ZombineDev wrote:AFAIU, even if you had a getter in the alias this: --- import std.stdio; struct ValueRestrictedInteger(int lowerBound, int upperBound) { int value; auto ref get() { return value; } alias get this; this (int rhs) { value = rhs; } invariant() { assert (value >= lowerBound && value <= upperBound); } void forDemonstrationOnly() {} } --- It would still not work: --- unittest { ValueRestrictedInteger!(0, 100) x = 0; x -= 100; //is probably lowered to something like this: // 1) invariant(); // 2) int* __temp = &x.value; // this is what get() does // 3) invariant(); // 4) *__temp = *temp - 100; //... } --- Obviously, 4) will not trigger the invariant because it doesn't call any public functions.Correct, the only real solution is to wrap with the actual operators and opDispatch. -Steve
Nov 11 2014