Writing `assert(false);` means "the program's execution should never reach here. since `"x".to!int().ifThrown(false)` returns `false`, your first alternative version - which negates it - will enter the then clause of the `if` statement and crash the unit test.
As for your second alternative version - it does something completely different from the original example.
Consider this code:
```D
if("x".to!int()){
   ...
}
```
This codes parses a string to an integer. If the resulting integer is non-zero it'll enter the then clause, and if it is zero it won't enter the then clause. But what if the string can't be parsed to int(which is the case in this unit test)? In that case - it'll throw an exception.
Now, let's say that in case of exception, we want to not enter the then clause. We could write:
```D
try{
   if("x".to!int()){
      ...
   }
}catch(ConvException){}
```
But what if something inside the then clause throws a `ConvException`? We wanted to define a behavior for non-integer strings, and ended up discarding unrelated `ConvException`s!
This is where `ifThrown` comes in - it allows you to discard `ConvException`s from the condition without touching `ConvException`s from the then clause. If the string is parsed to a non-zero integer - do the then clause. If it is parsed to zero - don't do the then clause. If it can't be parsed to an integer - don't do the then clause. All cases are well defined, and exceptions from the then clause are not mysteriously disposed.

Now, let's look at your second alternate version. If the string can be parsed to an integer - `a` gets it's value. You never check if this integer is zero or non-zero, which was the entire point of the original code. If the string can't be parsed to an integer, you catch the `ConvException` with `ifThrown`, fail the assertion, and throw an `AssertError` instead.
The original idea behind `ifThrown` was to recover from the exception, but what your code replaces it with a less meaningful error.