Skip to content

FfiGenerator needs more docs #2769

@stuartmorgan-g

Description

@stuartmorgan-g

I'm trying to convert my YAML config to the now-recommended code format, and I'm struggling to find any information to help me do so:

  • The README has a giant table with examples of everything for YAML, which is great, but there's no similar exhaustive set of examples for the code config.
  • The README says "Refer to the code comments below and the API docs to learn more about available configuration options", and https://dart.dev/interop/objective-c-interop says "For a full list of configuration options, check out the FFIgen API documentation" but:
    • Many of the comments in config.dart are very terse, and read more like notes to maintainers than user docs. (E.g., Declarations.rename's comment is Applies renaming and returns the result. Applies how? What is the result I'm supposed to return exactly? What would this look like to use?)
    • Many of the types in config_types.dart have no comments at all.
  • The objective_c example shows only a very limited subset of options (which is fine for a starter example, but not useful for covering any other use cases).

As a concrete user journey to capture the problem, I am trying to convert this section:

objc-interfaces:
  include:
    - 'NSFileManager'
    - 'NSURL'
  member-filter:
    NSFileManager:
      include:
        - "containerURLForSecurityApplicationGroupIdentifier:"
        - "defaultManager"
    NSURL:
      include:
        - "fileURLWithPath:"
        - "URLByAppendingPathComponent:"
  • I look at the README; no examples of what member filtering look, so let's use the API docs.
  • Okay, I expect this is going to be in interfaces:, but I clearly can't use the Interfaces.includeSet since that just takes individual strings, so I'll need to use the full constructor.
  • includeMember sounds promising, so let's check the docs on that. Here it's just super.includeMember, so let's check there:
    /// Whether a member of a declaration should be included.
    ///
    /// Only used for [Categories], [Interfaces], and [Protocols] methods and
    /// properties.
    
  • Okay, so member will presumably be the method signature in this context, and I guess Declaration will be the interface? Seems likely, but it would be nice to have some kind of guidance on this. So I just need to know how to write a Declaration filter.
    • Let's check https://dart.dev/interop/objective-c-interop. Nope, no examples.
    • Can I look at the includeAll/excludeAll helpers for a clue? No, they are unconditional, so never actually use Declaration.
    • No problem, let's just check the docs for Declaration:
      class Declaration {
        final String usr;
        final String originalName;
        Declaration({required this.usr, required this.originalName});
      }
  • Hm. Okay, well, I have absolutely no idea what usr is. originalName sounds like hopefully it's the name of the thing. Why is it originalName though? Maybe because renaming is a thing (which I only know because I read docs for things that aren't what I'm trying to do; nothing about my use case involves renaming anything), but it would really be nice if there were docs on this to orient me. And on includeMember to situate Declaration in the context.
  • So I'm guessing that probably in the context of this filter function I need to write declaration.originalName is how I spell "interface name" and member is how I spell "method signature", but that feels very speculative.

At this point I just write a filter function to log everything and hurray, I was right! And usr is... I have no idea. Feels like I'm probably not supposed to be using it, so it feels weird that it's as prominent as the thing I wanted. And it makes me wonder why I'm getting a Declaration instead of just getting declaration.originalName directly as a String parameter. Especially since the member is a String rather than a Declaration; I'm not sure, as a client, why these things are different.

  • Hm, I wonder how include and includeMember interact; do I need to both include the interface and then includeMember the members, or does includeMember imply include? Hopefully the latter, but I see that the default for include is excludeAll which doesn't sound good. Although my printing filter did get called.
    • Do the docs give any hints here? Nope, neither include nor includeMemeber say anything about the interaction between them.
    • Guess and check time again.
    • Let's try the simpler version and see if it works; after all, I know from my print trials that includeMember is being called on tons of stuff, even with include not including anything.
  • No warnings about includeMember returning true for interfaces that are excluded, so that's good (1)! Let's just double check the output... and it's basically empty.
  • Okay, so let's add the (seemingly duplicate) include.
  • Hurray, now the classes are there.

At most of these steps, with the current level of documentation, it felt like I wasn't actually supposed to be using this system even though the README told me to.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    Status

    No status

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions