December 13, 2016
On 2016-12-13 05:07, Jonathan M Davis wrote:

> It also could be problematic with unit tests - especially unit
> tests that catch AssertErrors (e.g. if someone wants to test the
> contracts).

I also expect all unit test frameworks that are slightly more advanced then the built-in we have now would like to catch AssertErrors.

-- 
/Jacob Carlborg
December 13, 2016
On Tuesday, 13 December 2016 at 06:36:47 UTC, Shachar Shemesh wrote:
> Also, please note that not all non-Exception Throwables are terminal for the process. We use a Throwable that is not an Exception in order to force termination of a fiber from outside in a clean way. If proper unwinding is not guaranteed under this condition, we have a problem.

yes, we have a big problem.
December 13, 2016
On Monday, 12 December 2016 at 21:02:11 UTC, Andrei Alexandrescu wrote:
>
> That will come too.
>
>
> Andrei

Great teaser :)

For reference, here is how I currently do this:

- make Object.~this() @nogc with a cast
- throw emplaced exceptions in malloc'd memory
- release them explicitely at catch time

This probably breaks chaining so maybe RC objects are needed first, dunno.


December 13, 2016
On Tuesday, 13 December 2016 at 07:49:59 UTC, Jacob Carlborg wrote:
> On 2016-12-13 05:07, Jonathan M Davis wrote:
>
>> It also could be problematic with unit tests - especially unit
>> tests that catch AssertErrors (e.g. if someone wants to test the
>> contracts).
>
> I also expect all unit test frameworks that are slightly more advanced then the built-in we have now would like to catch AssertErrors.

Well, they _have_ to unless they want to completely ignore existing unittest blocks. But I don't see how making them a singleton would stop that.

Atila
December 13, 2016
On 12/13/2016 01:34 AM, Shachar Shemesh wrote:
> unlinking GC from phobos is not likely to happen until that happens

You can avoid linking druntime today with -betterC. -- Andrei
December 13, 2016
On 13.12.2016 01:57, Andrei Alexandrescu wrote:
> On 12/12/16 4:35 PM, Brad Roberts via Digitalmars-d wrote:
>> Of course, then you'll find the fun of all the tests (and probably code)
>> that catch AssertError.
>
> You can catch AssertError. There's no guarantees dtors have been called
> during unwinding. -- Andrei


If 'in'-contracts are not allowed to corrupt the program state, then I don't really see how implementations will be able to not call dtors.
December 13, 2016
On 12/13/2016 11:39 AM, Timon Gehr wrote:
> On 13.12.2016 01:57, Andrei Alexandrescu wrote:
>> On 12/12/16 4:35 PM, Brad Roberts via Digitalmars-d wrote:
>>> Of course, then you'll find the fun of all the tests (and probably code)
>>> that catch AssertError.
>>
>> You can catch AssertError. There's no guarantees dtors have been called
>> during unwinding. -- Andrei
>
>
> If 'in'-contracts are not allowed to corrupt the program state, then I
> don't really see how implementations will be able to not call dtors.

One way to accomplish that is to have assert work differently when called from within contracts. (I'm not sure whether that's currently done that way.) -- Andrei
December 13, 2016
On 13.12.2016 17:47, Andrei Alexandrescu wrote:
> On 12/13/2016 11:39 AM, Timon Gehr wrote:
>> On 13.12.2016 01:57, Andrei Alexandrescu wrote:
>>> On 12/12/16 4:35 PM, Brad Roberts via Digitalmars-d wrote:
>>>> Of course, then you'll find the fun of all the tests (and probably
>>>> code)
>>>> that catch AssertError.
>>>
>>> You can catch AssertError. There's no guarantees dtors have been called
>>> during unwinding. -- Andrei
>>
>>
>> If 'in'-contracts are not allowed to corrupt the program state, then I
>> don't really see how implementations will be able to not call dtors.
>
> One way to accomplish that is to have assert work differently when
> called from within contracts. (I'm not sure whether that's currently
> done that way.) -- Andrei

I assume you don't refer to passing along a runtime flag whether execution is currently in a contract and then selectively disable calling of dtors.

So I think you are suggesting a breaking change in language semantics:

void myAssert(bool x){
    // this function could be in a different compilation unit
    assert(x);
}

class C{
    void foo(int a)in{
        myAssert(a>0);
    }body{

    }
}
class D:C{
    override void foo(int a)in{
        myAssert(a<0);
    }body{

    }
}

void main(){
    D d = new D;
    d.foo(1);
    d.foo(-1);
}


(Using 'assert' for specifying contracts is a questionable design decision anyway: it is not possible to distinguish implementation bugs in the contract code and functions it calls from contract violations.)
December 13, 2016
On 12/13/2016 12:18 PM, Timon Gehr wrote:
> I assume you don't refer to passing along a runtime flag whether
> execution is currently in a contract and then selectively disable
> calling of dtors.

No, something simpler than that - nontransitive. Consider:

T fun(R range)
in
{
    assert(range.front == 42);
}
body
{
    ...
}

Here, the assert keyword present straight in the contract has a distinct meaning from the assert present transitively in code invoked by the contract. If the assert in the contract fails, that's the contract not passing. Assume Range.front() has e.g. assert(!empty) inside, that's a different kind of failure - in this case it may arguably be a bug in the contract definition.

> So I think you are suggesting a breaking change in language semantics:
>
> void myAssert(bool x){
>     // this function could be in a different compilation unit
>     assert(x);
> }
>
> class C{
>     void foo(int a)in{
>         myAssert(a>0);
>     }body{
>
>     }
> }
> class D:C{
>     override void foo(int a)in{
>         myAssert(a<0);
>     }body{
>
>     }
> }
>
> void main(){
>     D d = new D;
>     d.foo(1);
>     d.foo(-1);
> }

Yah, this would have to do with user code not using the assert keyword inside the contract.

> (Using 'assert' for specifying contracts is a questionable design
> decision anyway: it is not possible to distinguish implementation bugs
> in the contract code and functions it calls from contract violations.)

I agree it's odd. I've always thought of asserts in contracts as "cheap" conditionals that return false if not met. Asserts (and other Throwables) thrown from code transitively invoked by the contract are a different business.

The saving grace here is that assert is a keyword as opposed to an ordinary function :o).

I don't know how contracts are currently implemented. Thanks for raising this discussion about a matter that's been buzzing in my mind for a while.


Andrei

December 13, 2016
On 12/13/2016 01:23 AM, Shachar Shemesh wrote:
> On 12/12/16 23:02, Andrei Alexandrescu wrote:
>> Why am I not surprised :o).
>
> I'm not sure what to make of that comment.

Just jesting, and not always in style. Apologies. Let me restate the factors at play here; admittedly the matter is a bit fuzzily defined at the moment:

* A number of D libraries (Ilya's Mir being a prominent one) aim to offer a C-level API that is shunning a relatively heavy runtime support library. Mir makes use of D's cool compile-time introspection and such, but avoids things like module information and the garbage collector. A good way to go about it is compile with -betterC and not link druntime.

* Druntime has a simple charter: isolate the platform-dependent things needed to get a D implementation going. However, its design predates a bunch of great things done with templates. This makes for druntime to miss many opportunities to be smaller, more modular, and faster.

* People have noticed that certain simple uses of D trigger calls into druntime that are not quite justified. For example, assigning an array of int to another array of int issues a call into a function that uses dynamic introspection (!) to copy any array into any other array. A template present in object.d would trivially do this using introspection to boil down to memcpy.

* Generally reducing the footprint of druntime support amenities for performing something with D is a good thing. Hence, assert() not requiring the GC to be linked is good because it would allow folks who don't link the GC at all to still use assert without needing to redefine it.

The community has been aware for a while that there's some good opportunity to use modern techniques such as lowering and templates to make druntime smaller, more modular, and actually more self-effacing. Ilya brought this point strongly recently with a good use case, and https://github.com/dlang/druntime/pull/1710 is a step in that direction.


Andrei