dart-lang / core

This repository is home to core Dart packages.
https://pub.dev/publishers/dart.dev
BSD 3-Clause "New" or "Revised" License
15 stars 4 forks source link

ArgResults: Make easier for Dart2 users #39

Open matanlurey opened 6 years ago

matanlurey commented 6 years ago

This is a runtime failure in Dart2:

void readListOfNames(ArgResults results) {
  // "List<dynamic> is not a List<String>"
  List<String> names = results['names'];
}

... but patterns like this are really common.

I'd like to see a series of helper methods to make it easier to get common types and collections out of ArgResults, even if all they do behind the scenes is a combination of as and collection casts. Ideas:

Primitives

Collections

Thoughts?

/cc @nex3 @natebosch

nex3 commented 6 years ago

I think there's a general need for a good API to access heterogeneous untyped information. We have something like this for JSON-RPC 2 parameters, but it would be nice to generalize it enough that it could be used for parsed arguments, JSON/YAML objects, and so on. As the pressures to avoid dynamic values get stronger, this will be more and more relevant.

srawlins commented 6 years ago

The args package already has a delineation between bool "flags" and other-type "options." What about even just an is or has method for accessing bools?

var argParser = new ArgParser()
    ..addFlag('help');
var argResults = argParser.parse(args);
if (argResults['help']) { ... } // Error: Conditions must have a static type of 'bool'.
if (argResults['help'] == true) { ... } // What I have to do today. :(
if (argResults.has('help')) { ... } // Would be nice.
if (argResults.isNot('help')) { ... } // Lends itself nicely to negatable.
jonahwilliams commented 5 years ago

I'm looking at disabling implicit downcasts in the flutter tool, and a large portion come from ArgResults.[] returning dynamic. I'm working around this with a typed wrapper which exposes getOption, getFlag and getMultiOption in https://github.com/flutter/flutter/pull/31679.

It would be great to have something similar in the args package.

lrhn commented 4 years ago

You can do a lot with extensions these days.

extension ArgResultGetters on ArgResults {
   bool? optionalFlag(String name) => this[name] as bool?;
   bool flag(String name, {bool defaultValue: false}) => (this[name] as bool?) ?? defaultValue;
   bool has(String name) => this[name] != null;

   String stringOption(String name, {String defaultValue = ""}) => (this[name] as String?) ?? defaultValue;
   int intOption(String name, {int defaultValue = -1}) {
     var value = this[name];
     if (value is! String) return defaultValue;
     return int.tryParse(value) ?? defaultValue;
   }
   T option<T>(String name) => this[name] as T;

   List<String> multiOption(String name) => this[name] as List<String>;
}