Skip to content

proposal: strict_exceptions (safe/unsafe concept to make Dart more predictable) #58934

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

Closed
bernaferrari opened this issue Nov 22, 2022 · 3 comments
Labels
devexp-linter Issues with the analyzer's support for the linter package legacy-area-analyzer Use area-devexp instead. linter-lint-proposal linter-status-pending

Comments

@bernaferrari
Copy link
Contributor

bernaferrari commented Nov 22, 2022

strict_exceptions

Details

Disclaimer: I know the odds are against this issue, but I really like this idea and would love to see it at least being considered for 10 seconds.

I love Rust safeness. I dislike when someone calls firstWhere and it throws. Or when someone does http.get and it fails (by throwing an exception). Or when someone calls json.decode and something bad happens. These errors usually happen on runtime and are unpredictable. Uber had an issue where something that might never happen happened when a server call went rogue. Certain kind of runtime issues could be avoided in Dart, I believe.

Maaaaybe, Dart could have an annotation like @unsafe that the analyzer uses to check if certain code can or cannot crash. It wouldn't affect anything else, but it would surely be a helper for people that want a stricter code with greater warranties that it won't misbehave.

JavaScript has strict mode, which eliminates silent errors. I wish Dart had a similar feature (although this would be way more strict than JS).

With sealed classes, most of these weird exception situations (like http.get) could be wrapped into a Result: Success | Error scenario, like Kotlin. Therefore, unpredictable places throwing an exception could be an even stronger motivation for my strict mode proposal.

Biggest challenge is figuring out how plug-ins would work with this lint when not opted in.

Kind

Guard against runtime unpredictable exceptions. Allow the user to have a predictable execution.

Bad Examples

void searchForSomething(List<String> list) {
  list.firstWhere(...); // uh oh! This might throw an exception!
}

void getDocument() {
  Firebase.getDocument(); // This library doesn't opt into strict mode. You should add a try/except around this method or @unsafe to the function.
}

Good Examples

@unsafe
void searchForSomething(List<String> list) {
  list.firstWhere(...); // Ok, the annotation says this is ok.
}

void searchForSomething(List<String> list) {
  try {
      list.firstWhere(...); // Inside try/catch. Perfect.
  } catch () {
    // ...
  }
}
@bernaferrari bernaferrari changed the title proposal: strict_dart (safe/unsafe concept to make Dart more predictable) proposal: strict_exceptions (safe/unsafe concept to make Dart more predictable) Nov 22, 2022
@lrhn
Copy link
Member

lrhn commented Nov 23, 2022

If you really want to have checked exceptions, consider an annotation like

@Throws<FormatException>()

which also says which exception is thrown.
Then you can also ensure that all the exceptions are caught.

The "Good" example of } catch (_) { is bad code. You should never do a catch-all except in very general framework code.
If you know the exceptions being thrown, you can do

 } on FormatException catch(e) { ... }

and ensure that all annotated exceptions are caught.

It does mean that the lint needs to check every method call of an annotated method, each throw of a non-Error, and each catch (and rethrow), to check which annotated exceptions are potentially uncaught in a method, and also not annotated on the method itself.

It's not clear whether you can annotate functions, or only methods.
You can annotate a function variable, like @Throws<FormatException>() int Function(String) parse;, but you can't annotate the return type of a function returning a function:

@Throws<X>()
int Function(String) createParse(int radix) => ...;

It's unclear whether this annotates the createParse function, or the function it returns. (Or both?).
May need a @Returns<Throws<X>>() (which can be nested as deep as needed).

Same issue for

int Function(@Throws<X>() int Function(String) parse, String source) f;

Can we put annotations on function type parameters at all? It's a structural type, so it doesn't really exist as an entity.

Might also need to have some rules about overriding in subclases.
If int foo() doesn't throw exceptions in a superclass, can an override in a subclass be annotated as @Throws<X>()?
(Safety says "no". It's also not a good idea to start throwing new exceptions in subclass overrides without the annotation.)

Seems like something needing a big effort, but the optionality of it is very Dart 1-ish (an optional, pluggable type system.)

I also wouldn't use this for errors (aka, thrown objects implementing Error). Those should not occur at runtime. You are not expected to catch them, you are expected to prevent them before they happen.
(I admit firstWhere is badly designed, because you can't really check first whether there is an element satisfying the test, and yet it throws a StateError if it doesn't find one. That's a reason to use firstWhereOrNull, not to start treating the error as an exception.)
That also means that there is no chance of the platform libraries being annotated to report which methods throw errors. (Almost all methods can throw errors, even if it's only StackOverflowError.)

@srawlins
Copy link
Member

@bernaferrari can you say whether this is different from #58232? That is our lint request with the most upvotes

@bernaferrari
Copy link
Contributor Author

It seems really similar. I'll close this. Thanks!

@bernaferrari bernaferrari closed this as not planned Won't fix, can't repro, duplicate, stale Nov 23, 2022
@devoncarew devoncarew added devexp-linter Issues with the analyzer's support for the linter package legacy-area-analyzer Use area-devexp instead. labels Nov 19, 2024
@devoncarew devoncarew transferred this issue from dart-archive/linter Nov 19, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
devexp-linter Issues with the analyzer's support for the linter package legacy-area-analyzer Use area-devexp instead. linter-lint-proposal linter-status-pending
Projects
None yet
Development

No branches or pull requests

4 participants