Skip to content

CoreChecks.has() usage could perhaps be improved #2616

Open

Description

@time4tea

because

Subject<R> has<R>(R Function(T) extract, String name) {}

has two arguments, you cannot easily maintain a library of functions to access things across a codebase:

how about (sorry for naming, i didn't have enough time to think of a better one):

class Extractor<T, R> {
  final R Function(T) extract;
  final String name;

  Extractor(this.extract, this.name);
}

 Subject<R> get<R>(Extractor<T, R> ex) {
    return context.nest(() => ['has $ex.name'], (value) {
      try {
        return Extracted.value(ex.extract(value));
      } catch (e, st) {
        return Extracted.rejection(which: [
          ...prefixFirst('threw while trying to read ${ex.name}: ', literal(e)),
          ...const LineSplitter().convert(st.toString())
        ]);
      }
    });
  }

then you can say:

Extractor<Uri, String> scheme() => Extractor((it) => it.scheme, "scheme");
    test("scheme", () {
      check(Uri.parse("ftp://example.com"))
          ..get(scheme()).equals("ftp");
    });

the functions to extract the things you need can be shared across a codebase.
i'm sure this could be improved further, just an idea.

Activity

  1. time4tea commented on Mar 25, 2026

    @time4tea
    Author

    or another example:

    Extractor<Request, Header?> header(String name) => Extractor((it) => it.header(name), "header ${name}");
  2. time4tea commented on Apr 6, 2026

    @time4tea
    Author

    Actually, scratch this - however i didn't realise immediately from the docs that the idiomatic way to write reusable checks was to make extensions e.g.

    extension UriChecks on Subject<Uri> {
      Subject<String?> param(String name) => has((u) => u.queryParameters[name], 'param ${name}');
      Subject<String> get host => has((u) => u.host, 'host');
      Subject<String> get path => has((u) => u.path, 'path');
      Subject<String> get scheme => has((u) => u.scheme, 'scheme');
      Subject<String> get value => has((u) => u.toString(), 'toString value');
    }

    the docs only mention extensions as ways to create composite or custom checks, maybe this would be a useful addition? thx!

  3. jonasfj commented on Apr 17, 2026

    @jonasfj
    Member

    I really think that package:checks is awesome, but I'll grant that perhaps a few more illustrative examples could be useful.

    Especially, in the API references where sometimes you forget how to use something.

    Proposed: #2631

  4. natebosch commented on Apr 17, 2026

    @natebosch
    Member

    In addition to improving the docs it would help if I release the codegen I had started looking at around this API.

    #2632

  5. lrhn commented on Jul 22, 2026

    @lrhn
    Member

    Side-though: Could we swap the parameter order of has so the closure is last?

    Generally when a function takes a closure as positional argument, it's the last parameter.
    That allows big closures, like:

      .has('name', () {
        large complicated way
        to get to value, like `object.elements.fold(....)`.
      });

    without the name getting lost.

  6. natebosch commented on Jul 22, 2026

    @natebosch
    Member

    Side-though: Could we swap the parameter order of has so the closure is last?

    Generally when a function takes a closure as positional argument, it's the last parameter. That allows big closures, like:

    Yes, I am definitely open to changing this. The deciding factor when I first wrote it is that the current order makes autocomplete a bit more useful. I found it handy that I could start typing without even considering what members the object has and once I typed the . it would populate autocomplete with a list of members. This use case is narrow and I hope most uses of has are generated at some point.

  7. added a commit that references this issue on Nov 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    package:checksIssues related to pkg:checks

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions