Re: Can anyone explain this?

2018-06-05 Thread Nicholas Wilson via Digitalmars-d

On Tuesday, 5 June 2018 at 09:58:43 UTC, Nicholas Wilson wrote:

prints

Exception


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


Re: Can anyone explain this?

2018-06-05 Thread Nicholas Wilson via Digitalmars-d

On Tuesday, 5 June 2018 at 09:03:03 UTC, Simen Kjærås wrote:

On Tuesday, 5 June 2018 at 08:26:22 UTC, Nicholas Wilson wrote:
writeln("Assert"); // this is not caught because the thrown 
throwable is not an exception


Now that's plain false - If you replace the call to 
throwingFunc() with a string literal, you'll see it's properly 
caught. Also, the catch clause explicitly specifies 
AssertError, which as the name implies, is an Error, not an 
Exception.




Whoops I meant _is_.

However, if we add catch (Throwable ex) to the list of catch 
statements, that *does* catch a regular object.Exception. 
Moving the catch (Exception) statement down the list does 
nothing. Adding another layer of try-catch also catches it 
(even with just catch (Exception ex)):


That does seem odd but is consistent with the implicit "try" 
surrounding Dmain inserted by the runtime.



import std.stdio;
import core.exception;

unittest {
scope(failure) {
writeln("Not gonna happen");
}

try {
try {
static string throwingFunc() {
throw new Exception("An exception");
}
assert(0==1, throwingFunc());
} catch(AssertError ex) {
writeln("Assert");
} catch(Exception ex) {
writeln("Exception A");
}
} catch(Exception ex) {
writeln("Exception B");
}
}

So I'm stumped. It seems the exception handling is simply not 
setup correctly. This could be because of UB I guess, but I'd 
hope the AssertError would be thrown first in such a case.


The assert error will never be thrown because one of the 
parameters to the __assert_fail throws. Its like as if you had 
written.


if (0==1)
{
string tmp = throwingFunc(); // throws
__assert_fail(tmp,__LINE__,...); // dead code.
}

Actually it may be the compiler doing something funky with 
assert(0, msg); being special (assert(0,...) since the spec says 
for assert any compile time expression == 0  has the effect of 
assert(0). i.e. assert(0==1); is the same as assert(0);).


Proof


import std.stdio;
import core.exception;
bool foo() { return false;} // mess with the compiler's reasoning 
about the truthiness of the assert

void main() {
scope(failure) {
writeln("Not gonna happen");
}

try {
static string throwingFunc() {
throw new Exception("An exception");
}
assert(foo(), throwingFunc());
} catch(Exception ex) {
writeln("Exception");
} catch(AssertError ex) {
writeln("Assert");
}
}

prints

Exception



Re: Can anyone explain this?

2018-06-05 Thread Simen Kjærås via Digitalmars-d

On Tuesday, 5 June 2018 at 08:26:22 UTC, Nicholas Wilson wrote:
writeln("Assert"); // this is not caught because the thrown 
throwable is not an exception


Now that's plain false - If you replace the call to 
throwingFunc() with a string literal, you'll see it's properly 
caught. Also, the catch clause explicitly specifies AssertError, 
which as the name implies, is an Error, not an Exception.



This might just be a case of undefined behavior. According to 
https://dlang.org/spec/contracts.html:


"As a contract, an assert represents a guarantee that the code 
must uphold. Any failure of this expression represents a logic 
error in the code that must be fixed in the source code. A 
program for which the assert contract is false is, by definition, 
invalid, and therefore has undefined behaviour."


In short, what you're doing is UB, and the nasal demons are 
printing 'not gonna happen' to your console.


That also makes some sense with Andrea Fontana's comments:
- Do not have side effects in either AssignExpression that 
subsequent code depends on.
- Do not attempt to resume normal execution after an Assert 
Failure.



However, if we add catch (Throwable ex) to the list of catch 
statements, that *does* catch a regular object.Exception. Moving 
the catch (Exception) statement down the list does nothing. 
Adding another layer of try-catch also catches it (even with just 
catch (Exception ex)):


import std.stdio;
import core.exception;

unittest {
scope(failure) {
writeln("Not gonna happen");
}

try {
try {
static string throwingFunc() {
throw new Exception("An exception");
}
assert(0==1, throwingFunc());
} catch(AssertError ex) {
writeln("Assert");
} catch(Exception ex) {
writeln("Exception A");
}
} catch(Exception ex) {
writeln("Exception B");
}
}

So I'm stumped. It seems the exception handling is simply not 
setup correctly. This could be because of UB I guess, but I'd 
hope the AssertError would be thrown first in such a case.


--
  Simen


Re: Can anyone explain this?

2018-06-05 Thread Shachar Shemesh via Digitalmars-d

On 05/06/18 11:26, Nicholas Wilson wrote:
    writeln("Exception"); // Why is this not caught? I've no 
idea


That's the part I was referring to.


Re: Can anyone explain this?

2018-06-05 Thread Andrea Fontana via Digitalmars-d

On Tuesday, 5 June 2018 at 08:12:54 UTC, Shachar Shemesh wrote:

I set up to find out what happens if the assert string throws.


From here: 
https://dlang.org/spec/expression.html#assert_expressions


[...]
8. Undefined Behavior: Once in an Invalid State the behavior of 
the continuing execution of the program is undefined.

[...]

[...]
Best Practices:
- Do not have side effects in either AssignExpression that 
subsequent code depends on.
- AssertExpressions are intended to detect bugs in the program, 
do not use for detecting input or environmental errors.
- Do not attempt to resume normal execution after an Assert 
Failure.

[...]

Anyway you can try to catch "Throwable" to understand what is 
going to happen (but it's not a good idea at all to keep it in a 
program)


Andrea


Re: Can anyone explain this?

2018-06-05 Thread Nicholas Wilson via Digitalmars-d

On Tuesday, 5 June 2018 at 08:12:54 UTC, Shachar Shemesh wrote:
I set up to find out what happens if the assert string throws. 
I have to admit I did not expect the result:


$ cat test.d
import std.stdio;
import core.exception;

void main() {
scope(failure) {
writeln("Not gonna happen");
}

try {
static string throwingFunc() {
throw new Exception("An exception");
}
assert(0==1, throwingFunc());
} catch(Exception ex) {
writeln("Exception");
} catch(AssertError ex) {
writeln("Assert");
}
}

$ ldc2 --version
LDC - the LLVM D compiler (1.8.0):
  based on DMD v2.078.3 and LLVM 5.0.1
...

$ ./test
Not gonna happen
object.Exception@test.d(11): An exception


applying a bit of lowering

int Dmain (int arc, const char** argv)
{
try return main();
catch (...) dumpThrowable(); // 3 dumps exception
}
void main() {
try {
try {
 static string throwingFunc() {
throw new Exception("An exception");
}
 __assert_fail(throwingFunc(),...); // 1 throws 
before assert throws

} catch(Exception ex) {
   writeln("Exception"); // Why is this not caught? 
I've no idea

   } catch(AssertError ex) {
  writeln("Assert"); // this is not caught because 
the thrown throwable is not an exception

  }
 }
 catch(...)
 {
writeln("Not gonna happen"); // 2 scope failure is run
  throw;
 }

}


Can anyone explain this?

2018-06-05 Thread Shachar Shemesh via Digitalmars-d
I set up to find out what happens if the assert string throws. I have to 
admit I did not expect the result:


$ cat test.d
import std.stdio;
import core.exception;

void main() {
scope(failure) {
writeln("Not gonna happen");
}

try {
static string throwingFunc() {
throw new Exception("An exception");
}
assert(0==1, throwingFunc());
} catch(Exception ex) {
writeln("Exception");
} catch(AssertError ex) {
writeln("Assert");
}
}

$ ldc2 --version
LDC - the LLVM D compiler (1.8.0):
  based on DMD v2.078.3 and LLVM 5.0.1
...

$ ./test
Not gonna happen
object.Exception@test.d(11): An exception

??:? [0x3728941e]
??:? [0x372903aa]
??:? [0x3727b15c]
??:? [0x3724991d]
??:? [0x372496c9]
??:? [0x3727aecf]
??:? [0x3727addb]
??:? [0x3724a124]
??:? __libc_start_main [0xed8b01c0]
??:? [0x372495c9]

$ dmd --version
DMD64 D Compiler v2.080.0
Copyright (C) 1999-2018 by The D Language Foundation, All Rights 
Reserved written by Walter Bright


$ ./test
Not gonna happen
object.Exception@test.d(11): An exception

??:? pure @safe immutable(char)[] test.main().throwingFunc() [0xe9b1c2b3]
??:? _Dmain [0xe9b1c1ad]