Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

To-non-nullable indicator for type parameters like T! #4160

Open
HosseinYousefi opened this issue Nov 12, 2024 · 3 comments
Open

To-non-nullable indicator for type parameters like T! #4160

HosseinYousefi opened this issue Nov 12, 2024 · 3 comments
Labels
feature Proposed language feature that solves one or more problems

Comments

@HosseinYousefi
Copy link
Member

HosseinYousefi commented Nov 12, 2024

We can currently have a type parameter like class Foo<T extends Object> {} and specify a method to return T?:

class Foo<T extends Object> {
  T? foo() => null;
}

However we can't do this in the other way, meaning we have a T extends Object? and we want to specify a method to return a non-nullable version of T, I propose we add a T! variation so we can have:

class Foo<T extends Object?> {
  T! foo() => ...;
}

This is useful in the context of Java interop where the type parameter itself can be nullable but a single method be annotated with @NonNull.

@HosseinYousefi HosseinYousefi added the feature Proposed language feature that solves one or more problems label Nov 12, 2024
@lrhn
Copy link
Member

lrhn commented Nov 12, 2024

I recommend doing:

class Foo<T extends Object> {
 T foo() => ...

  // use T? everywhere being nullable is allowed.
}

Even if we had a ! operator that could be applied to type variables, it would not be able to make every type non-nullable.
For example Foo<FutureOr<int?>> would have a foo() that returns NonNull(FutureOr<int?>) which is FutureOr<int?> again.
That may not be a problem for the cases where it does work.

The ! would be a general operator on types. You probably can't write int?!, but only because it's redundant, so the only real use will be on type variables. (Again FutureOr<T>! will be FutureOr<T>, not FutureOr<T!>.)

@HosseinYousefi
Copy link
Member Author

HosseinYousefi commented Nov 12, 2024

I recommend doing:

class Foo<T extends Object> {
 T foo() => ...

  // use T? everywhere being nullable is allowed.
}

That's not an accurate representation. Foo<String> and Foo<String?> might indeed be different types. To truly differentiate them I need to add a FooOfNullable<T extends Object> and Foo<T extends Object> extends FooOfNullable<T> and override the methods previously defined as T? to now return T. But this is ugly and for K type parameters, you'd need 2^K different classes!

@lrhn
Copy link
Member

lrhn commented Nov 13, 2024

It's not the same, and nothing is because the functionality your asking for doesn't exist. I often find that the rewrite gives a better design, because the type T! isn't what is really needed. (If T is generic in a way that allows a user to include null in it's values, why does the API remove null. That's not being generic over the type T!)

Looking at it again, if the construct is going to work, the ! probably has to be reified. The static and runtime type systems both contain types of the shape T!, just like they contain types of the shape T?.

Normalization would convert T!! and T?! to Norm(T!), Null! to Never, and T! to Object if T is a supertype of Object and to T if T is a subtype of Object.
(And T!? to Norm(T?).)

Subtyping would treat T! like the intersection type T & Object (which it is, it's the dual of T? being the union type T | Null, making a type non-nullable where ? makes it nullable).

The interface signature of T! is the interface signature of NonNull(T).

It introduces yet another special-cased type, like the union types ? and Future Or. It does fit with the ? type, it's not completely arbitrary.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature Proposed language feature that solves one or more problems
Projects
None yet
Development

No branches or pull requests

2 participants