www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Throwing specific Error Obejct for asserts

reply "monarch_dodra" <monarchdodra gmail.com> writes:
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 

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" ... ?
Jan 10 2013
next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
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
Jan 10 2013
prev sibling next sibling parent "monarch_dodra" <monarchdodra gmail.com> writes:
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. ;)
Jan 10 2013
prev sibling next sibling parent "monarch_dodra" <monarchdodra gmail.com> writes:
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
Jan 10 2013
prev sibling next sibling parent "monarch_dodra" <monarchdodra gmail.com> writes:
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(); } //----
Jan 10 2013
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
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
Jan 10 2013
parent reply Dmitry Olshansky <dmitry.olsh gmail.com> writes:
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
Jan 10 2013
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
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
Jan 10 2013
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 1/10/13 11:56 AM, monarch_dodra wrote:
 On Thursday, 10 January 2013 at 18:31:17 UTC, Andrei Alexandrescu wrote:
 And using "assertError" also still isn't as convenient as "assert"

Please. You have the entire vocabulary minus assert. Andrei

Fine. I know how to take a hint.

OK OK now you're making me feel bad for being abrupt :o). There is a back story to this. Generally we're trying to stem a tide of big trenches built around small points in this forum (things like the "one-click" issue in the changelog, hiding member variable names, etc). In such discussions we sometimes latch on one simple thing and set great store to it, to the point of losing a sense of proportion to its actual importance. There must be a way to say: "OK, the point has been understood and well taken, but it has not been convincing enough" without getting anyone angry and without engendering a rehash of the argument. Andrei
Jan 10 2013
prev sibling next sibling parent "monarch_dodra" <monarchdodra gmail.com> writes:
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...
Jan 10 2013
prev sibling next sibling parent "monarch_dodra" <monarchdodra gmail.com> writes:
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"
Jan 10 2013
prev sibling next sibling parent "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
On 2013-01-10, 19:03, monarch_dodra wrote:

 On Thursday, 10 January 2013 at 17:46:54 UTC, Dmitry Olshansky wrote:
 10-Jan-2013 20:11, monarch_dodra =D0=BF=D0=B8=D1=88=D0=B5=D1=82:
 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 <=3D 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=



 as convenient as having an overload. That, and a library function ca=



 match assert's built-in functionality. For example:

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

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

 The problem is that at best, assertError can be a noop-implementatio=



 in
 release, but the call is still there. The first argument will still =



 evaluated. Further more, it may not even compile...

lazy keyword to the rescue.

Still doesn't compile though...

So you're saying this does compile for you, with -release? struct S( ) { version(assert) bool isValid =3D false; void foo() { assert(isValid); } } It certainly does not for me. -- = Simen
Jan 10 2013
prev sibling next sibling parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Thursday, 10 January 2013 at 19:31:18 UTC, Simen Kjaeraas 
wrote:
 So you're saying this does compile for you, with -release?

 struct S( ) {
     version(assert)
         bool isValid = false;

     void foo() {
         assert(isValid);
     }
 }

 It certainly does not for me.

As a matter of fact, yes. Yes I am. Are you using 2.061 ?
Jan 10 2013
prev sibling next sibling parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Thursday, 10 January 2013 at 19:47:46 UTC, monarch_dodra wrote:
 On Thursday, 10 January 2013 at 19:31:18 UTC, Simen Kjaeraas 
 wrote:
 So you're saying this does compile for you, with -release?

 struct S( ) {
    version(assert)
        bool isValid = false;

    void foo() {
        assert(isValid);
    }
 }

 It certainly does not for me.

As a matter of fact, yes. Yes I am. Are you using 2.061 ?

Scratch that. Template was throwing me off.
Jan 10 2013
prev sibling parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Thursday, 10 January 2013 at 18:31:17 UTC, Andrei Alexandrescu 
wrote:
 And using "assertError" also still isn't as convenient as 
 "assert"

Please. You have the entire vocabulary minus assert. Andrei

Fine. I know how to take a hint.
Jan 10 2013