July 07, 2017
On Friday, 7 July 2017 at 14:17:34 UTC, Jonathan M Davis wrote:
> What does it even do?

asserts that the this pointer is not null, apparently which is annoying because you'd crash anyway. I suppose you might get a nicer error message but it doesn't add much.

> I don't see how it makes any sense for _anything_ to have an invariant if it's not explicitly declared.

Worse I can't even @disable it because thats a syntax error.

> And honestly, I'm of the opinion that invariants with structs are borderline useless, because they're run even before opAssign, meaning that if you ever need to use = void; or use emplace, then you're screwed if you have an invariant, because it's bound to fail due to the object not having been initialized previously.

Huh, I didn't know that. That does seems to be purpose defeating zealotry.

>Unfortunately, I couldn't get Walter to
> agree that it made sense to not call the invariant prior to opAssign being called - which is why SysTime no longer has an invariant (it was blowing up in people's code due to emplace IIRC). As such, it seems that much more stupid for structs to get any kind fo invariant automatically.
>
> - Jonathan M Davis
July 07, 2017
On Friday, 7 July 2017 at 14:26:57 UTC, Steven Schveighoffer wrote:
> Hm... it doesn't look like an invariant, it just looks like an inserted assert inside every function.
>

Ahh, thats why I get duplicate asserts when I add an assert.

> And since when did we care about null pointers causing segfaults?
>
> Can anyone vouch for this feature?
>
> -Steve

Not me.


July 07, 2017
Steven Schveighoffer wrote:

> Hm... it doesn't look like an invariant, it just looks like an inserted assert inside every function.
>
> An incorrect assert, IMO:
>
> struct Foo
> {
>      int x;
>      void foo() {}
> }
>
> void main()
> {
>     Foo *foo;
>     foo.foo(); // shouldn't assert, wouldn't crash anyway.
> }

yeah, this is annoying. while checking for "null this" in *class* method may look hacky, i see nothing wrong in "null this" for struct method. tbh, i patched that assert (the whole invariant thingy, actually) away long time ago, and only remembered about it recently, when my code spit that error in vanilla. real PITA, 'cause adding useless checks for "if this struct pointer isn't null, then assign what struct method will assign on null, and don't forget to sync it when i'll change method, and no, you cannot assert in ternaly without deprecated comma, and... no, that code won't be converted to 'normal D'."
July 07, 2017
ketmar wrote:

> yeah, this is annoying. while checking for "null this" in *class* method may look hacky

tbh, i see nothing wrong in checking for "null this" even in class methods, but this is a completely different story.
July 07, 2017
On 7/7/17 2:27 PM, ketmar wrote:
> ketmar wrote:
> 
>> yeah, this is annoying. while checking for "null this" in *class* method may look hacky
> 
> tbh, i see nothing wrong in checking for "null this" even in class methods, but this is a completely different story.

In *final* methods maybe. Virtual methods are going to crash anyway before they get to that point.

e.g.:

class C
{
    void foo() {}
    final void bar() {}
}
void main()
{
    C c;
    version(segfault) c.foo();
    version(asserts) c.bar();
}

using -vcg-ast (BTW, I really like this feature!) shows that the assert is still put inside foo, even though it will never trigger!

In older versions of dmd, both segfault, I think maybe because the virtual invariant is attempted before calling either.

-Steve
July 07, 2017
Steven Schveighoffer wrote:

> On 7/7/17 2:27 PM, ketmar wrote:
>> ketmar wrote:
>> 
>>> yeah, this is annoying. while checking for "null this" in *class* method may look hacky
>> tbh, i see nothing wrong in checking for "null this" even in class methods, but this is a completely different story.
>
> In *final* methods maybe. Virtual methods are going to crash anyway before they get to that point.

i meant "in manual checking", i.e. "i think that compiler-inserted `assert` is not necessary at all". sorry for writing indecipherable engrish. ;-)
July 07, 2017
On 7/7/17 4:26 PM, ketmar wrote:
> Steven Schveighoffer wrote:
> 
>> On 7/7/17 2:27 PM, ketmar wrote:
>>> ketmar wrote:
>>>
>>>> yeah, this is annoying. while checking for "null this" in *class* method may look hacky
>>> tbh, i see nothing wrong in checking for "null this" even in class methods, but this is a completely different story.
>>
>> In *final* methods maybe. Virtual methods are going to crash anyway before they get to that point.
> 
> i meant "in manual checking", i.e. "i think that compiler-inserted `assert` is not necessary at all". sorry for writing indecipherable engrish. ;-)

My statement still applies ;)

-Steve
July 08, 2017
Steven Schveighoffer wrote:

> On 7/7/17 4:26 PM, ketmar wrote:
>> Steven Schveighoffer wrote:
>> 
>>> On 7/7/17 2:27 PM, ketmar wrote:
>>>> ketmar wrote:
>>>>
>>>>> yeah, this is annoying. while checking for "null this" in *class* method may look hacky
>>>> tbh, i see nothing wrong in checking for "null this" even in class methods, but this is a completely different story.
>>>
>>> In *final* methods maybe. Virtual methods are going to crash anyway before they get to that point.
>> i meant "in manual checking", i.e. "i think that compiler-inserted `assert` is not necessary at all". sorry for writing indecipherable engrish. ;-)
>
> My statement still applies ;)

yeah ;-)
July 07, 2017
On Friday, July 7, 2017 2:31:42 PM MDT Nicholas Wilson via Digitalmars-d wrote:
> On Friday, 7 July 2017 at 14:17:34 UTC, Jonathan M Davis wrote:
> > What does it even do?
>
> asserts that the this pointer is not null, apparently which is annoying because you'd crash anyway. I suppose you might get a nicer error message but it doesn't add much.
>
> > I don't see how it makes any sense for _anything_ to have an invariant if it's not explicitly declared.
>
> Worse I can't even @disable it because thats a syntax error.
>
> > And honestly, I'm of the opinion that invariants with structs are borderline useless, because they're run even before opAssign, meaning that if you ever need to use = void; or use emplace, then you're screwed if you have an invariant, because it's bound to fail due to the object not having been initialized previously.
>
> Huh, I didn't know that.

I was not pleased to find out about it either, and the result is that I tend to think that invariants have no business being in structs, much as it would be desriable for them to be there.

> That does seems to be purpose defeating zealotry.

It's desirable when the object is supposed to be in a good state, because then you know that when you do the assignment, you'll catch if something broke the invariant before the assignment. But it's completely undesirable when the object was purposely uninitialized, and since you can't choose whether the invariant is run or not, IMHO, _not_ running it would be better, but I was not persuasive enough:

https://issues.dlang.org/show_bug.cgi?id=5058

I was discussing this issue with someone at dconf, and as a result of that conversation, I've considered writing a DIP that would allow you to explicitly skip calling an invariant on a specific assignment (since in theory, you should know when you're assigning to an unitialized object), but I haven't had the time to think it through completely, let alone put together a DIP that might actually be persuasive.

- Jonathan M Davis

July 08, 2017
On 07.07.2017 16:17, Jonathan M Davis via Digitalmars-d wrote:
> On Friday, July 7, 2017 1:38:13 PM MDT Stefan Koch via Digitalmars-d wrote:
>> On Friday, 7 July 2017 at 13:34:20 UTC, Steven Schveighoffer
>>
>> wrote:
>>> On 7/7/17 4:21 AM, Nicholas Wilson wrote:
>>>> The compiler seems to inset an `assert(this !is null, "null
>>>> this");` into my struct.
>>>> which is for all intents and purposes.
>>>> struct Foo {
>>>>
>>>>       Bar b;
>>>>
>>>> }
>>>>
>>>> struct Bar {
>>>>
>>>>       void* ptr;
>>>>
>>>> }
>>>
>>> What? When is this invariant called? I've never heard of a
>>> hidden invariant being added to structs, structs are supposed
>>> to be free of such things.
>>>
>>> I would call such a thing a bug.
>>>
>>> -Steve
>>
>> It was added because someone VIP demanded it I guess.
>> you can see the assert being added using -vcg-ast ;)
> 
> What does it even do? I don't see how it makes any sense for _anything_ to
> have an invariant if it's not explicitly declared.

It is not an implicit invariant, it is an implicit precondition of a member function. (The 'this' reference is not part of the state, it is a function argument.)


> And honestly, I'm of the
> opinion that invariants with structs are borderline useless, because they're
> run even before opAssign, meaning that if you ever need to use = void;

A struct that has public methods that can accept an uninitialized instance does not have an invariant.
That does not mean invariants are useless for structs in general.

> or use emplace,

Why would the invariant be called if you use emplace? There are no public member functions involved.

> then you're screwed if you have an invariant, because it's
> bound to fail due to the object not having been initialized previously. > Unfortunately, I couldn't get Walter to agree that it made sense to 
not call
> the invariant prior to opAssign being called

It does not always make sense, and when it does make sense, it is not limited to opAssign, so maybe we can have an explicit way to disable invariant calls for member functions that do not rely on the object invariant. (For non-operator overloads there is an obvious workaround: just forward to a private member function using UFCS.)

> - which is why SysTime no
> longer has an invariant (it was blowing up in people's code due to emplace
> IIRC).

The only way this can be a problem is if they emplace a state that does not satisfy the invariant and then call opAssign. Was your invariant satisfied in the init state?

> As such, it seems that much more stupid for structs to get any kind
> fo invariant automatically.
> 
> - Jonathan M Davis
> 

That's not what is happening though.