Feature suggestion -- typed null behavior

14 views
Skip to first unread message

Jeff V

unread,
Oct 4, 2025, 5:05:33 PM (4 days ago) Oct 4
to Project Lombok
I don't know what the exact syntax would be, but the idea is to be able to specify method behavior for a null reference. Basically like creating a "null instance" that's only accessible to the JVM.

public class Foo {
  private String name;

  @OnNullReference ("No name without an object!")
  public String getName() {
    return name;
  }

  public String bar() {
    return "bar";
  }
}

...

Foo foo = null;
foo.getName(); // returns the above "No name" string
foo.bar(); // still throws NPE, no annotation

Ideally there'd be auto-generated javadoc to indicate whether a method throws NPE or executes default behavior on dereferencing null.

I have no idea of the inner workings of Lombok, so I don't know how feasible this is, but I feel like it could save a lot of boilerplate.

Reinier Zwitserloot

unread,
Oct 4, 2025, 6:28:34 PM (4 days ago) Oct 4
to Project Lombok
The devil is in the details. We've gone over umptheen proposals and they all seem cool, easy, and without downside. And then you try to hammer down _exactly_ how it is supposed to work and you either get stuck chasing your own tail, or, you come up with a nice, neat system... which I will then obliterate by coming up with a few choice examples where the nice neat system would have utterly surprising behaviour.

Separate from that, there are many, many ways to go and most of those ways fail on the first hurdle: They require the entire java ecosystem to all join the same bandwagon. Some things are like which side of the road cars drive on: We all do the same thing, or it's complete chaos.

For what its worth, the 'best' behaviour in my book would almost be a new language: Each type is free to define an immutable value which is the default for unassigned stuff. Because it's an immutable constant there is no performance penalty for introducing them 'pointlessly' (i.e. if you initialize a list field with `new ArrayList<>()` and every possible code path will necessarily completely overwrite that field before anybody ever touches it, you 'wasted' a new arraylist alloc. If you initialize a list field to `List.of()` which is then always overwritten, you merely wasted an easily inlined method call. If you initialize a string field to `"Hello, World"`, you wasted __nothing__ - a blank field still explicitly runs a direct assignment (it assigns `null`), and that assigns a link to the constant pool.

The system I'd love to see would have the same 'cost', i.e. - if you don't wanna pay it, java itself is the problem. In practice hotspot is great at eliminating even this tiny cost.

One would imagine that `List` (the interface) decrees that an expression that is an empty immutable list is the default value, and anywhere you simply declare a field `List<?> foo;`, that's what it starts out as. If you write `new List[10]`, that'll be 10 references to that same immutable list.

As a type you don't _have to_ provide a default value, but if you don't, then it is not legal java to write an uninitialized field declaration of that type (then 'users' MUST pick a value for fields; locals can simply piggyback on the existing system, where the compiler ensures all possible code flow results in an assignment before any reading or passing of that variable). You can't create arrays of that type either without using a utility where you make an array out of a series of expressions, or make an array out of a count and a single expression (I want an array of 10 lists, and each array slot is the same reference, namely, this parameter).

But trying to somehow magic that into being with lombok would be even harder.

What your proposal appears to want to do is to essentially tell lombok: Find every single last `return` statement in this method and replace it. From:

```
@NullBecomes("Hello, World")
public String foo() {
  if (x) return a();
  else return b();
}
```

to

```
public String foo() {
  final String ON_NULL$$ = "Hello, World";
  if (x) return helper$$hiddenName(a(), ON_NULL$$);
  else return helper$$hiddenName(b(), ON_NULL$$);
}

private void helper$$hiddenName(String a, String b) {
   return a == null ? b : a;
}
```

And this explains why this is never going to even work and next time I'm going to have to insist on a fully fleshed out proposal. The problem is _not_ basic "I'm not quite sure how but something like this" style ideas on null. We have a thousand of em. It's the details:

* We can't hide that helper. You're going to see it in your outline view and your autocompletes. Or we do hide it and then this one will be a large maintenance burden and goes into territory we don't like going into (class modification. Currently we mostly modify the source). We could try to inline but there be dragons, java is a little too complex for that to be easy, we'd have to program in most of how java-the-lang works. Manmonths of work. Many of them. And very errorprone.
* You cannot put arbitrary expressions in annotations. We'd need a `@NullBecomesStr` for strings and that's where it ends, because any other type of object.. you're basically screwed. Primitives can go in annotations but they can't be null, so, not relevant. Hence we'd have to go with stringly typed - `@NullToObj("new ArrayList<?>()")` which is atrocious. java code _inside a string_? No. We'd never allow it. I'm trying to be clear to save you time: Don't waste any trying to think in directions where that ends up being part of the solution.

Chris Becker

unread,
Oct 4, 2025, 7:05:27 PM (4 days ago) Oct 4
to project...@googlegroups.com
This sounds like a perfect occasion to use Lombok's awesome Extension Methods.

With focus of the methods being on higher supertypes (like Object) you could even accommodate any reference type, if you wanted to. 

The .or() method being one of the most stellar examples. 

You could also combine this pattern with fast reflection, to reduce boilerplate even more, if that's your primary concern.


Christian Becker
+49.176.2238 9755
chris.b...@gmail.com


--
You received this message because you are subscribed to the Google Groups "Project Lombok" group.
To unsubscribe from this group and stop receiving emails from it, send an email to project-lombo...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/project-lombok/3a71d26b-4e0d-4e25-870e-f805d8a19a6bn%40googlegroups.com.

Jeff V

unread,
Oct 6, 2025, 8:31:40 AM (3 days ago) Oct 6
to project...@googlegroups.com
Reiner, it sounds like you took personal offense at my suggestion, and like you're saying nobody should voice ideas unless they fully understand what it'd take to implement them. 

It seems like my suggestion was taken as, "Hey, this looks easy, so why don't you just do it!" That was not my intent.

Thank you, for explaining why it's not practical to add this feature.


I don't understand what you're talking about with "find every single return statement." What I suggested would be implemented at method invocation, so that

foo.bar()

turns into, effectively,

if (foo != null) {
  foo.bar;
}
else if (Foo#bar() has a default null method
  foo.defaultNullForBar();
}
else {
  throw new NPE();
}

I totally get that it may not actually be feasible for reasons I'm utterly ignorant of. Hence my qualifier to that effect.

Cheers,
Jeff

 

--
You received this message because you are subscribed to a topic in the Google Groups "Project Lombok" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/project-lombok/9YLUr7ANu6Y/unsubscribe.
To unsubscribe from this group and all its topics, send an email to project-lombo...@googlegroups.com.

Reinier Zwitserloot

unread,
Oct 6, 2025, 8:58:05 AM (3 days ago) Oct 6
to project...@googlegroups.com
  • Reiner, it sounds like you took personal offense at my suggestion

You've misunderstood the gist of the message then.

  • like you're saying nobody should voice ideas unless they fully understand what it'd take to implement them.

Not "fully", but, having a basic idea of what it might look like: Yes. What you're suggesting boils down to reiterating the same ground over and over and over and over again.

  • It seems like my suggestion was taken as, "Hey, this looks easy, so why don't you just do it!" That was not my intent.

Ah, I did misunderstand that bit.

  • What I suggested would be implemented at method invocation

If I understand this suggestion correctly, that would mean one of these two options is true:

  • An annotation on a method results in lombok generating code at the site of callers of that method. That is complicated and more to the point: Too much voodoo. We do not want to go there. It means a library author must put in their docs: You must use lombok or this library doesn't make sense and the docs lie to you. We don't think that's a good idea.
  • You annotate a method and it means all method invocations in the entire method get this 'convert all null values into 0/false/etc. This is not actually possible. if I invoke a method that returns a Floobargle​ (i.e. a type we do not know), what should that become?

I think you want the first option but, as mentioned, not something we're considering.
You received this message because you are subscribed to the Google Groups "Project Lombok" group.
To unsubscribe from this group and stop receiving emails from it, send an email to project-lombo...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/project-lombok/CAK578eRAYWMSk6D8H748UziBLz9jxG_YOKCt8ySztQZj_Y1X-Q%40mail.gmail.com.

Reply all
Reply to author
Forward
0 new messages