Ad hoc type restriction

Rob Ross rob.ross at gmail.com
Fri Oct 31 02:37:59 UTC 2025


I scanned this thread but haven't yet seen any references to "Programming
by Contract", so I thought I'd just mention and remind everyone about it.

But first, please don't make the "totally awesome" an enemy of the "really
really useful right now." A Null/Not-null operator would be very helpful
all by itself and I don't think that feature needs to wait for the Best
Parameter Checking System Ever.

My contribution example:

        //With apologies to Demeter.

        //API:
        FooType foo = obj.nested1().nested2().fooProvider().getFoo();

        //CURRENTLY
        FooType foo = null;
        if (obj != null
                && obj.nested1() != null
                && obj.nested1().nested2() != null
                && obj.nested1().nested2().fooProvider() != null) {
            foo = obj.nested1().nested2().fooProvider().getFoo();
        }

        //WANTED
        FooType foo = obj?.nested1()?.nested2()?.fooProvider()?.getFoo();

A not-null assertion is also nice to have.
...
// The underscore is here only to make the exclamation point more clear in
the variable name
result = obj_!.getThing();


Ok, now on to Program/Design by contract. This is a very useful technique.
Whenever I've used it, it has always been in an ad-hoc fashion. But the
"Checkers" being discussed above really seemed similar in my mind to this
concept. Being able to specify your pre-conditions, post-conditions, and
invariants in one place makes it easy to:
1. Discover the rules easily
2. Communicate clear intent to caller
3. Make it easier to reason about state in the called function
4. Makes the code easier to debug and maintain

How to implement them? Well first I feel like these Conditions could apply
both to a specific argument or return value, and/or apply to the function
as a whole. I.e.,

FooType doSomething( T1 t1, T2 t2) {...}

And perhaps t1 is an Enum and t2 can only take on certain values based on
the value of that Enum. So individual parameters could have a Contract
and/or the function could have a Contract that would be some type of
implementation of a Mediator pattern. That's the high level idea. As has
been discussed, Annotations are just post-it notes on Symbols that no one
is required to read. So if they are not available, some other mechanism
would need to be used.

Now, for my own method parameter verification, I used to check and throw
RuntimeExceptions, as I viewed these as programming errors that should all
be fixed in production code, obviating the need for the check and the
exceptions in production. For code in the critical path, I would eventually
remove these checks so runtime performance was not taking the hit. By the
time I did this, I had robust unit tests that would ensure these kinds of
errors could be caught at testing time. However, tests can't catch new bugs
that have no tests for them yet. And developers new to the code (which
includes me about 4 months after I have written it), could still introduce
bugs by passing in unexpected data, necessitating the check-and-exception
code to be reintroduced to the buggy methods.

I have since discovered the power of assertions, via the simple `assert`
keyword. Now I have the best of both worlds. I never have to delete my
argument checks, so they are always working to enforce the contract. I can
enable them in development and disable them in production so they aren't a
performance hit.

I wonder if this new Contract feature might do something similar? Maybe
even, dare I say it, allow injecting asserts into actual byte code!!! (I
know, I know, the Scandal!!) Then the developer has the final say on if
those asserts are acted upon and in what environments it's appropriate.

If not by asserts then perhaps by some new mechanism.

What I have describe so far are really simple checks on the domain and
not-nullness, etc, of method arguments. It has assumed that you can
completely enumerate the valid and not valid ranges of arguments at compile
time. That will not always be possible, especially for complex invariants
that depend on the runtime state.

So I again see another dimension for these Contracts, `runtime` and
`compile time`. Compile time Contracts could likely be fully implemented
with the existing assert mechanism. And they could be removed from the
bytecode in production environments, so there would be no performance cost.
Runtime Contracts would still require checking at runtime, and could
introduce a performance penalty, but I'm not sure this would be any greater
than what we are already doing in robust, fault-tolerant production code.

And maybe Contracts are just lambdas under the hood that are passed the
method arguments before the method is invoked and the developer is
completely on their own on implementing the code, deciding when to use an
assert or when to use check-throw.

And for my final trick, I think Contract programming would be very useful,
and so does everyone who has replied to this thread. Perhaps useful enough
to justify a new type of processor to be added to Java? One that could
affect bytecode at compile time? The Contract Processor perhaps? With
Annotations java got the @ operand. I hear that
©
Is available and will work for free!

public void dial(©PhoneNumber String Number) {...}

- Rob

P.S. the © was just for dramatic effect. In a mono-spaced code font it
looks terrible and would be hard to distinguish from @. But maybe there are
designers that could help with that, perhaps choosing an easy-to-type
special symbol in the BMP that looks like the copyright but more legible.

On Thu, Oct 16, 2025 at 1:41 AM Aaryn Tonita <atonita at proton.me> wrote:

> I somewhat feel like these side car static type analysers fail to catch on
> in Java because annotations are too flexible and thus poorly suited for
> catching type information. In comparison with python where there are many
> tools but there may only be a single type annotation, in Java there are
> many tools with multiple overlapping type annotations that can each be
> redundantly applied while there is only a single language level type
> ascribed that doesn't support restrictions without OOP ceremony. If there
> was a dedicated unique additional type annotation maybe tools would attempt
> to be more interoperable with one another but also maybe not.
>
> Today we have tools like Checker competing with JSpecify and the tools
> that came before it, and JSpecify even pointing at the sad state of affairs
> in a stackoverflow question (on the level of null restriction) where there
> are many competing and poorly interoperating tools. When the
> interoperability story is complex, the choice is hard to make and living
> with the lack of restrictions seems ok (alternately one can make between
> simply guarding like usual or going with the OOP ceremony).
>
> On Thursday, October 16th, 2025 at 2:12 AM, Archie Cobbs <
> archie.cobbs at gmail.com> wrote:
>
> On Wed, Oct 15, 2025 at 11:34 AM Manu Sridharan <manu at sridharan.net>
> wrote:
>
>> This is all mostly possible via the Checker Framework and similar
>> approaches.
>>
>
> In the spirit of due diligence, I am attempting to implement something
> like "WHAT I WANT" using the checker framework. Currently I'm battling a
> poor progress/confusion ratio.
>
> You wouldn’t need @SuppressWarnings annotations for validation either,
>> due to type refinement
>> <https://checkerframework.org/manual/#type-refinement>. And, for this
>> type of property, where you’re essentially trying to introduce new subtypes
>> of an existing type and then enforce type compatibility at assignments, the
>> implementation effort to write the checker is pretty low.
>>
>
> Let me know offline if you (or anyone else) is interested in helping me
> prototype something (I have a primordial github project).
>
> Thanks,
> -Archie
> --
> Archie L. Cobbs
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/amber-dev/attachments/20251030/9cb99b2c/attachment.htm>


More information about the amber-dev mailing list