realm / realm/SwiftLint

Rule request: [discarded_async_let_error] async let discards thrown errors

Open
#4,867 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

rule-request
Dominant language
Swift
Stars
19.7k
Forks
2.3k
Avg merge
1d 1h
Merged PRs (30d)
11

Description

New Issue Checklist
New rule request

When using async let on a throwing function, with or without try, or, inside or outside of a do/catch, the thrown error is discarded and this might be unexpected.
Wrapping in a do { } catch { } adds a false sense of effectiveness. Maybe there should be a unneeded_do_catch rule, too.
Either the do/catch should be removed or the async let _ = try ... should be replaced with try await ... while avoiding try?.

try? converts a thrown error to an optional and still discards the error.
try! avoids the described problem with other risks.

  1. Why should this rule be added? Share links to existing discussion about what
    the community thinks about this.
    This helps simplify and correct code because either the do/catch was written and is not needed or the programmer has made a logical mistake by discarding the error by forgetting to try await the result. Or, the programmer should use try await instead of async let. I'm not sure what the community thinks.

  2. Examples:

do {
   async let resultOne = MyThrowingFunction() // Trigger
   async let resultTwo = try MyThrowingFunction() // Trigger
   // async let resultThree = try? MyThrowingFunction() // Potential trigger
} catch {
   print("This never gets printed for any of the above")
}
Task {
   async let resultOne = MyThrowingFunction() // Trigger
   async let resultTwo = try MyThrowingFunction() // Trigger
   // async let resultThree = try? MyThrowingFunction() // Potential trigger
}
do {
   async let resultOne = MyThrowingFunction() // Won't trigger because do/catch + await
   try await resultOne
} catch {
   print("This gets printed")
}
do {
   async let resultTwo = try MyThrowingFunction() // Won't trigger because do/catch + await
   try await resultTwo
} catch {
   print("This gets printed")
}
do {
   async let resultTwo = try MyThrowingFunction() // Probably should trigger since try? await still discards the error
   try? await resultTwo
} catch {
   print("This gets printed")
}
Task {
   async let resultOne = MyThrowingFunction() // Trigger
   async let resultTwo = try MyThrowingFunction() // Trigger because no do/catch even though it is awaited.
   async let resultThree = try? MyThrowingFunction() // Trigger

   try await resultTwo  
}
  1. Should the rule be configurable, if so what parameters should be configurable?
    Configurations could include checking try? and/or try!.

  2. Should the rule be opt-in or enabled by default? Why?
    Enabled by default because it catches potential logical errors by the programmer and should not have many occurrences.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

The issue names no implementation files, entry points, or tests. Start by reviewing the async let examples and deciding the intended handling of discarded errors, try?, try!, and do/catch cases. Done means the rule's scope and default or configuration behavior are agreed and the listed trigger and non-trigger cases are covered.

Written by the indexing model from the issue text.

Assessment

Tech stack
swift
Domain
tooling
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.