> Ah, that all makes sense. My objections are met. Thanks for the
>clarifications.
> I also realize that if you made those assumptions I was talking about
>in the caller, it would break binary class compatibility too. If we change
>the ensure/require and the app doesn't recompile with the new classlib,
>there would be an inconsistency of assumptions. Please *do* make sure you
>don't use the caller's "ensure" in any null reference optimizations, if you
>do them.
>
> Now, knowing all that, I have a request so that Classpath can be
>compiled the same with either Kiev or javac and not have any adverse
>effects:
> Problem: ensure/require checks will not show up when compiled with
>javac. If we copy/paste the assertions, then Kiev will do the checks
>*twice*, slowing down the library.
I've not catched why... Do you check null pointers in code? As far as
I know - you try to omit this checks, since JVM itself checks nulls and
indexes of arrays... And compiler do not generates checks *before*
it calls a methods. It's going to warn/error if conditions may (be proved,
or have possibility) to fail, but all runtime checks are done in one place -
within called method.
> Possible Solution(s):
> 1. Allow an alternate syntax for ensure/require within the code
>itself: KievAdditions.ensure(boolean,String) and
>KievAdditions.require(boolean,String). When Kiev's parser saw it, it would
>see the special reference and turn it into the equivalent
>ensure/require/assert statement. When javac compiled it, the compiler and
>the runtime would look for the KievAdditions class with those methods,
which
>Kiev could provide and people could distribute with their apps. (I'll
write
>that class *myself* if you want :)
Since I not understand the reason I can't be shure about solution...
Anyway, there are asserts that match this approach.
I.e.
String foo(String x) {
Debug.assert( x!=null, "Null argument");
...
String $return = ...; //
Debug.assert( $return!=null, "Null return");
return $return;
}
is (about, see notes below) equivalent to
String foo(String x)
require { x != null :: "Null argument"; }
ensure { $return != null :: "Null return"; }
{
...
}
Kiev compiler optimizes Debug.assert(...) methods (and all assert
methods you'll wrote in child classes of kiev.stdlib.Debug) to not
call assert methods if condition not fails, i.e. this will be compiled as
String foo(String x) {
if( !(x!=null) ) Debug.assert(false,"Null argument");
...
String $return = ...; //
if( !($return!=null) ) Debug.assert(false,"Null return");
return $return;
}
I've found, that (unoptimized) calls to assert methods slowdown
application a lot, but calls only if condition fails - slowdowns
only some persents. Especially, when error message is
a non-constant expression, like
Debug.assert( x < 3, "Argument x =="+x+" is >= 3");
So, 1) you may use assert(...) methods to be compatible
both with java and kiev, 2) kiev optimizes assertions like
require/ensure checks, 3) you may wrote your own
assert methods, 4) asserts are powerful enough to
be catched, analyzed and so on - see documentation and
sources of kiev.stdlib.Debug class for examples
> 2. Don't-Compile-Me-Kiev Comments. Say if /*NO_KIEV*/ ...
>/*/NO_KIEV*/ is ignored in Kiev. It will, however, be picked up by javac.
>Any comment structure you desire is fine, this is just an example.
Yes, this kind of comments will be helpful for mixed libraries...
I'l add it as far as we really see the need... Because now I'm
not shure about the best syntax...
> I know that it's kind of annoying and would increase the size of
>extensions, but if it's not too difficult to do #1, it would absolutely be
>the most useful to us and to anyone else who desires compatibility with
>javac. #2 will work fine if not, though.
>
> I really like this, because you can optimize out all those sanity
>checks in a production release of a product. I am curious, though: does
>ensure/require give you any other benefits besides the ability to turn
>sanity checks on and off?
The difference between require/ensure and asserts is mostly in
convinience, cleare syntax, and the fact, that require/ensure
constraints are *derived* by method's of child class.
For example, if you have multiple points of return, it's cleare and
more convinient to have *one* piece of code that describes
return checks, instead of putting assert(...) calls before
each return statement.
Also, if you see in code (I hope - there will be time to see it
in documentation too) that this method does not returns null,
you may be shure, that any method, that overwrites this method
will not return null too.