Dart Package - How to hide internal methods and classes?

3,145

Solution 1

The usual approach to having package-only declarations is to put them in a library in the lib/src/ directory, and not export that library. The other libraries in the package can import the package-only library, but users outside the package are discouraged from importing libraries in lib/src/ directly. (It's not impossible, just something that's discouraged because the package is free to change those libraries without warning).

If the package-only features require access to library private parts of public classes, then they need to be in the same library. The traditional way is then to declare both in a library in lib/src/ and export only the parts of that library which needs to be public:

library myPackage;
export "src/allDeclarations.dart" hide Private, Declarations;
// or, preferably, 
export "src/allDeclarations.dart" show Public, Things;

Generally you should only put exported and non-exported declarations in the same library if absolutely necessary. Otherwise the hide/show lists become too cumbersome and it's to easy to forget a declaration in a hide list.

Solution 2

You have a few possibilities:

  • Making a method/variable private, by prefixing it with _:

    class _InternalEvent {}
    
  • Use the hide/show directives:

    // lib/src/event.dart
    class InternalEvent {}
    
    class VisibleEvent {}
    
    
    // lib/my_package.dart
    export 'src/event.dart' hide InternalEvent; 
    
    OR
    
    export 'src/event.dart' show VisibleEvent;
    

Solution 3

For package-private members exists an annotation, @internal.

Using @internal the analyzer emit a warning when:

  • you export the annotated element (from a file under lib)
  • a consumer of your package imports the annotated element

Anyway, Dart seems to me to make things really complicated. The need to have members who are neither completely public nor inaccessible from outside the file is elementary, yet no solution provides certainties. Note that:

  • the doc says to keep the package-private elements in files under lib/src, yet the consumers of your package will still be able to import them, without even the analyzer producing a warning; it's just a convection;
  • using the @internal annotation, the analyzer (ie the ide, which rely on the analyzer) produces a warning, but nothing prevents you from compiling the code anyway. The situation improves a little if you increase the severity level of the warning produced by the analyzer when the annotation is not respected. To do this, you need to create an analysis_options.dart file like the following:
    analyzer:
      errors:
        invalid_use_of_internal_member: error #possible values: ignore, info, warning, error
    

Note that the @internal annotation, like other similar ones (@visibleForTesting, @protected) is part of the meta package, which is included in the Flutter Sdk, but which must be included as a dependency in pure-dart packages.

Share:
3,145
wisetap.com
Author by

wisetap.com

Flutter and Node.js developer Graduated in Computer Science Check my website and GitHub as well :)

Updated on December 21, 2022

Comments

  • wisetap.com
    wisetap.com over 1 year

    I am developing a package for Flutter Apps

    There are methods and classes that are useful only for the package itself, and not for the programmer who will import my package, is possible to hide this methods and classes for further implementation?

    Example:

    DataService.dart

    export class DataService{
    
        //Must be visible only for my library
        static notifyDataChanged(InternalEvent internalEvent){ ... }
    
        //Must be visible for anyone
        static addCallbackOnDataChange(onDataChangeCallback) { ... }
    
    }
    

    InternalEvent.dart

    //Must be visible only for my library as well
    export class InternalEvent {
       ...
    }
    
  • Ivo
    Ivo about 2 years
    show and hide doesn't seem to have any effect for me. I could be wrong but I also believe show and hide are meant to be used on import statements, not export.