Jump to page: 1 2
Thread overview
Throwing specific Error Obejct for asserts
Jan 10, 2013
monarch_dodra
Jan 10, 2013
bearophile
Jan 10, 2013
monarch_dodra
Jan 10, 2013
monarch_dodra
Jan 10, 2013
monarch_dodra
Jan 10, 2013
monarch_dodra
Jan 10, 2013
Dmitry Olshansky
Jan 10, 2013
monarch_dodra
Jan 10, 2013
monarch_dodra
Jan 10, 2013
Simen Kjaeraas
Jan 10, 2013
monarch_dodra
Jan 10, 2013
monarch_dodra
January 10, 2013
Now that we have version assert, we can customize the assert flow to throw a more specific error:

Before:
//----
auto opSlice(size_t i, size_t j)
{
    assert(i <= j);
}
//----

After:
//----
auto opSlice(size_t i, size_t j)
{
    version(assert)
        if (i > j)
            throw new RangeError();
}
//----

Now, instead of having a generic AssertError (with or without a message), we have a statically typed RangeError. Yay!

I have 2 problems with this though:
1) It is verbose as shit.
2) Using a if shifts the logic from checking the valid condition, to checking if things are *in*valid condition. eg: (i <= j) vs (i > j). If find this change of flow VERY disruptive. And error prone if migrating a condition that contains "&&" or "||".

So question: Why don't we have, just like for enforce, the possibility of simply writing:
//----
    assert(i <= j, new RangeError());
//----

Seems like a win-win to me...

...Or would this be disruptive with things like "onAssertError" or "setAssertHandler" ... ?
January 10, 2013
monarch_dodra:

> After:
> //----
> auto opSlice(size_t i, size_t j)
> {
>     version(assert)
>         if (i > j)
>             throw new RangeError();
> }

But now opSlice can't be nothrow, nor transitively all the code that calls that :-(

Bye,
bearophile
January 10, 2013
On Thursday, 10 January 2013 at 14:28:44 UTC, bearophile wrote:
> monarch_dodra:
>
>> After:
>> //----
>> auto opSlice(size_t i, size_t j)
>> {
>>    version(assert)
>>        if (i > j)
>>            throw new RangeError();
>> }
>
> But now opSlice can't be nothrow, nor transitively all the code that calls that :-(
>
> Bye,
> bearophile

It can because RangeError is an *Error*.

I actually filed that one, and walter fixed it shortly after. ;)
January 10, 2013
On Thursday, 10 January 2013 at 14:31:04 UTC, monarch_dodra wrote:
> On Thursday, 10 January 2013 at 14:28:44 UTC, bearophile wrote:
>> monarch_dodra:
>>
>>> After:
>>> //----
>>> auto opSlice(size_t i, size_t j)
>>> {
>>>   version(assert)
>>>       if (i > j)
>>>           throw new RangeError();
>>> }
>>
>> But now opSlice can't be nothrow, nor transitively all the code that calls that :-(
>>
>> Bye,
>> bearophile
>
> It can because RangeError is an *Error*.
>
> I actually filed that one, and walter fixed it shortly after. ;)

Fixed by Martin Nowak actually. Apologies.

https://github.com/D-Programming-Language/dmd/commit/d77b7c2bf456e99495d8a6644a6304995d1a3b20
January 10, 2013
On Thursday, 10 January 2013 at 14:31:04 UTC, monarch_dodra wrote:
> On Thursday, 10 January 2013 at 14:28:44 UTC, bearophile wrote:
>> monarch_dodra:
>>
>>> After:
>>> //----
>>> auto opSlice(size_t i, size_t j)
>>> {
>>>   version(assert)
>>>       if (i > j)
>>>           throw new RangeError();
>>> }
>>
>> But now opSlice can't be nothrow, nor transitively all the code that calls that :-(
>>
>> Bye,
>> bearophile
>
> It can because RangeError is an *Error*.

Apologies again, if my answer was not clear: Nothrow means the function can't throw *exceptions*, but errors are fair game.

For example, this compiles:

//----
import core.exception;

void foo() nothrow
{
    throw new RangeError();
}

void main()
{
    foo();
}
//----
January 10, 2013
On 1/10/13 6:23 AM, monarch_dodra wrote:
> So question: Why don't we have, just like for enforce, the possibility
> of simply writing:
> //----
> assert(i <= j, new RangeError());
> //----

Define another function...?

Andrei
January 10, 2013
On Thursday, 10 January 2013 at 15:54:21 UTC, Andrei Alexandrescu wrote:
> On 1/10/13 6:23 AM, monarch_dodra wrote:
>> So question: Why don't we have, just like for enforce, the possibility
>> of simply writing:
>> //----
>> assert(i <= j, new RangeError());
>> //----
>
> Define another function...?
>
> Andrei

Well, I would. I'd write an overload, but I can't, because assert is built-in.

I'd have to provide a new name (such as assertError). This would not be as convenient as having an overload. That, and a library function can't match assert's built-in functionality. For example:

//----
struct S()
{
  version(assert)
    bool isValid = false; //debug only variable

  void foo()
  {
    assertError(isValid, new RangeError()); //HERE
  }
}
//----

The problem is that at best, assertError can be a noop-implementation in release, but the call is still there. The first argument will still get evaluated. Further more, it may not even compile...
January 10, 2013
10-Jan-2013 20:11, monarch_dodra пишет:
> On Thursday, 10 January 2013 at 15:54:21 UTC, Andrei Alexandrescu wrote:
>> On 1/10/13 6:23 AM, monarch_dodra wrote:
>>> So question: Why don't we have, just like for enforce, the possibility
>>> of simply writing:
>>> //----
>>> assert(i <= j, new RangeError());
>>> //----
>>
>> Define another function...?
>>
>> Andrei
>
> Well, I would. I'd write an overload, but I can't, because assert is
> built-in.
>
> I'd have to provide a new name (such as assertError). This would not be
> as convenient as having an overload. That, and a library function can't
> match assert's built-in functionality. For example:
>
> //----
> struct S()
> {
>    version(assert)
>      bool isValid = false; //debug only variable
>
>    void foo()
>    {
>      assertError(isValid, new RangeError()); //HERE
>    }
> }
> //----
>
> The problem is that at best, assertError can be a noop-implementation in
> release, but the call is still there. The first argument will still get
> evaluated. Further more, it may not even compile...

lazy keyword to the rescue.

-- 
Dmitry Olshansky
January 10, 2013
On Thursday, 10 January 2013 at 17:46:54 UTC, Dmitry Olshansky wrote:
> 10-Jan-2013 20:11, monarch_dodra пишет:
>> On Thursday, 10 January 2013 at 15:54:21 UTC, Andrei Alexandrescu wrote:
>>> On 1/10/13 6:23 AM, monarch_dodra wrote:
>>>> So question: Why don't we have, just like for enforce, the possibility
>>>> of simply writing:
>>>> //----
>>>> assert(i <= j, new RangeError());
>>>> //----
>>>
>>> Define another function...?
>>>
>>> Andrei
>>
>> Well, I would. I'd write an overload, but I can't, because assert is
>> built-in.
>>
>> I'd have to provide a new name (such as assertError). This would not be
>> as convenient as having an overload. That, and a library function can't
>> match assert's built-in functionality. For example:
>>
>> //----
>> struct S()
>> {
>>   version(assert)
>>     bool isValid = false; //debug only variable
>>
>>   void foo()
>>   {
>>     assertError(isValid, new RangeError()); //HERE
>>   }
>> }
>> //----
>>
>> The problem is that at best, assertError can be a noop-implementation in
>> release, but the call is still there. The first argument will still get
>> evaluated. Further more, it may not even compile...
>
> lazy keyword to the rescue.

Still doesn't compile though...

And using "assertError" also still isn't as convenient as "assert"
January 10, 2013
On 1/10/13 10:03 AM, monarch_dodra wrote:
> Still doesn't compile though...

See enforce's implementation.

> And using "assertError" also still isn't as convenient as "assert"

Please. You have the entire vocabulary minus assert.


Andrei
« First   ‹ Prev
1 2