| Thread overview | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
November 11, 2014 The relationship of invariants and alias this | ||||
|---|---|---|---|---|
| ||||
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?
| ||||
November 11, 2014 Re: The relationship of invariants and alias this | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Mark Isaacson | 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. | |||
November 11, 2014 Re: The relationship of invariants and alias this | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Mark Isaacson | 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: | |||
November 11, 2014 Re: The relationship of invariants and alias this | ||||
|---|---|---|---|---|
| ||||
Posted in reply to H. S. Teoh | 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: >> 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 Exciting/encouraging! Done. https://issues.dlang.org/show_bug.cgi?id=13710 | |||
November 11, 2014 Re: The relationship of invariants and alias this | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Mark Isaacson | 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 ... | |||
November 11, 2014 Re: The relationship of invariants and alias this | ||||
|---|---|---|---|---|
| ||||
Posted in reply to angel | 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.
| |||
November 11, 2014 Re: The relationship of invariants and alias this | ||||
|---|---|---|---|---|
| ||||
Posted in reply to angel | 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.
| |||
November 11, 2014 Re: The relationship of invariants and alias this | ||||
|---|---|---|---|---|
| ||||
Posted in reply to ZombineDev | 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
| |||
Copyright © 1999-2021 by the D Language Foundation
Permalink
Reply