>I have many technical problems with the require / ensure thing and its use
>in Java.
>
>To make the argument below simpler, I will pretend that Classpath is always
>compiled using Kiev and its require/ensure keywords.
>
>Does Kiev optimize methods *assuming* that the requirements are met before
>the method is called? Does it optimize the caller based on *assumptions*
>about the return value using "ensure"? If it does, there are a number of
>very serious problems that could arise.
No, all checks are done within the called method itself, except
private methods, where no invariants (class-level constraints) are
checked. Also, there is no big posibility to optimize program
by require/ensure constraints. The primary goal is compile-time
error check (for those conditions that can be calculated at
compile time) and debug run-time checks (for those constraints,
that can be checked only at run time).
>Consider compiling a Java app against the ordinary Sun library and then
>running it on a VM with Classpath installed. Unwarranted assumptions will
>be made in Classpath's library (since they aren't checked at the caller),
>and the program will not behave as expected.
>
>The other case is when the app is compiled against Classpath and run
against
>a normal VM. Assumptions may be made about a library method's return
value,
>and the program, again, will not behave as expected. This one we at least
>have control over and can minimize by only using "ensure" when it ensures
>exactly the same behavior as Sun, even though we may have better behavior.
If I get you right, then here's what I think. The only "optimizeable"
constraints
are those, that can be checked at compile time. Also, since we can't know
the
caller of method - we can't optimize it. All checks, if they need to be
done, are
done *within* the called method, not in the caller method.
So, if java app, compiled against Sun's classes will be runned on $classpath
library - all checks will be done.
Next, when compiled with $classpath application will be runned on Sun's
classes... I think, normal exceptions will be thrown, instead of
kiev.stdlib.AssertionFailedException. Of course, it's possible to make
program optimization based on constraints, but anyway, it's not yet
done, since there is no such library, thus, there is nothing to
optimize yet. Anyway, I think about call-by-contract as debug feature,
not the way to optimize programs.
>Don't get me wrong here, I think ensure / require is a great idea. The
only
>thing I can think of is some sort of switch in the VM to let Classpath know
>not to make assumptions about parameters to public methods and apps know
not
>to make assumptions about return values from Classpath. This would require
>Kiev putting two sets of code into the final code and then having a flag
>sitting somewhere that it checks at runtime to figure out whether or not to
>make assumptions about the class library's methods. It would, of course,
>default to not making assumptions, since that is expected behavior in a
>normal VM and that is what writers of non-Kiev apps would want. That would
>be messy, but the only way for Kiev-compiled classes to be compatible with
>Java. I don't know if you're willing to put in that much work for such a
>special case. But I don't see anything we can do on this end.
In fact, the structure of bytecode is:
method:
code attribute
bytecode
require checks // depending on compile debug flag
the method's code
ensure checks // depending on compile debug flag
standard attributes of code attribute
extended require/ensure code attributes, required for child classes
The structure and code generation is done in the way to JVM be able
insert/remove require/ensure checks at run-time easyly.
I try to generate constraint's checks in the way that the code of
method itself do not depend on this checks (since I hope
that earlier or later JVMs like japhar or kaffe will be able
to switch this checks ob/off on the fly).
>A question about Kiev that is sort of off-topic: is it possible for me to
>write an ensure that *never* generates a runtime check? Say I'm absolutely
>certain the return value will work the way I say it does, but I just want
to
>let the caller know that so that Kiev can do some optimizations (retval !=
>null would be a prime example of something like that) after the method
call,
>such as not checking for NullPointerException.
I can't say for shure, whether I made this kind of optimization,
but even if not - it's not hard to add it. I check code flow control
instantly, and always know for shure whether variable's value
is/is not/uncertain == 'null'.
The main problem, is that in child classes I need convert constraint
check bytecode back into source code (to analize flow control
and optimize generated code) - and I not yet wrote this.
In child classes I just insert require/ensure checks *as is*, without
(significant) analization and optimization. And, since it's not possible
(currently) in general, I may comment out this optimization at all.