Comments (46)
I would like to have the ability to have a parameter be either positional or named, for a common usage case in Flutter -- the children/child of a widget (note that this case also applies to any place where you are building tree-structured values).
Consider the following Flutter widget tree:
new Center(child:
new Column(children: [
new Text("Hello, World!"),
new Icon(Icons.star, color: Colors.green)
])
)
Once "new" is optional, this starts looking like a reasonable replacement for HTML, as soon as we can treat child or children arguments as positional, like this:
Center(
Column([
Text("Hello, World!"),
Icon(Icons.star, color: Colors.green)
])
)
We kinda already have this in that Text doesn't specify the 'Hello, World!' string as a child, even though it kinda is. Same thing for Icon.
It would be nice (albeit not required) if the positional argument did not have to be the first argument so you could specify the named arguments first before following them with the children specified as a positional argument.
from language.
My own takeaway (for the microscopic amount it is worth) is that I will rarely use optional positional arguments in the future--the little bit of typing this saves is just not worth it when compared to the effort that I now know will be required to add any named arguments in the future.
You are not the only one thinking so, and some teams have a "no optional positional parameters ever" policy.
That's not necessarily the best API design, but it's driven by the available features and a wish to avoid future regret.
That's why we should still add this feature. Every year we delay is another year of people doing sub-optimal API design, for APIs which might stay with us forever.
(One alternative is to change the parameter semantics completely, so that any nullable parameter is optional - aka. can be omitted, which then passes null
implicitly, and passing null
triggers the default value if there is one. E.g. #836. Since both positional and named parameters can be nullable, both can be optional at the same time).
from language.
There were a handful of comments that were all either just "+1" or "+1 for this feature", which is better expressed by adding a 👍 to the issue itself, so I deleted them.
from language.
I too ran today into this while working on a new API and I actually don't understand this restriction. If it's possible to mix named and positional parameter , why can't that positional not being optional?
from language.
We definitely love getting help from external contributors. :)
But this is a particularly tricky issue because it affects the language's calling convention. That requires work in all of our implementations: VM, native compiler, development web compiler, and optimized web compiler. Any of those could potentially have negative performance implications that might make the feature untenable.
So to make progress on this, we really have to talk to all of the implementation teams and see how they think they would support it and what the performance costs might be before we could make any decisions.
from language.
I think it's worth noting that there's some nice synergy between this issue and the new Dart 2.17 features.
Since we now have "named arguments anywhere", we could eventually change child
and children
into positional arguments:
Container(
color: Colors.green,
Column(
mainAxisSize: MainAxisSize.min,
[
Text('Elegant as heck'),
],
),
)
Combining optional positional & named arguments can also be helpful when using super initializers:
class CustomBox extends StatelessWidget {
final int? height;
const CustomBox([this.height, Key? key]) : super(key: key); // the old way to do it
const CustomBox([this.height, super.key]); // throws an error
const CustomBox([this.height], {super.key}); // it would be great if this worked!
...
}
It's unfortunate to hear that this issue affects Dart's calling convention. Guess I'll just keep my fingers crossed that it'll work out!
from language.
In maintaining the protobuf library we have functions that take positional optional arguments, making it hard to add further optional arguments.
Refactoring the existing functions to take only named arguments is probably the 'right thing to do(tm)' but that is a breaking change and thus very costly.
For example GeneratedMessage.fromBuffer
currently has the signature
void mergeFromBuffer(List<int> input,
[ExtensionRegistry extensionRegistry = ExtensionRegistry.EMPTY]);
If we want to add more options to the parsing (for example bool ignoreUnknownFields
) it would be nice to add as a named optional, but that is currently not possible.
from language.
Every year we delay is another year of people doing sub-optimal API design, for APIs which might stay with us forever.
This is really is the most important argument for prioritizing this feature, IMHO. I'm currently designing a new API, and there are simply method signatures that beg to have optional, positional arguments – but I can't use them, because I need named ones, too.
So once the API is published, I'm going to be stuck with the suboptimal signature. Which will be a small stab in my heart every time I'm going to call it. 😐
So seeing that this was first proposed nine years ago, and nobody really posted a show-stopper as for the logic or sense of the feature – I think there's a chance for you guys to make a lot of people really happy by finally making a decision. 😜
from language.
I would love to see this, together with making child en children positional in Flutter 🙏
from language.
I would prefer removing optional positional parameters as it greatly simplifies things. #2232
from language.
I agree. Why we cant have both: positional and named optional parameters at the same time?
from language.
There are lots of confusing and conflicting statements in the comments on this issue. What I was just looking for--and what I feel @lrhn was asking for when opening this issue nine years ago--was the ability to have both an optional positional argument and an optional named argument (see function4, below). While looking into this, it appears to me that Dart actually doesn't allow any arguments of any type after the closing bracket of an optional positional argument (see functions 4, 5, and 7)!
void function1 (int reqdPosn, {required int? reqdNamed}) {} // allowed
void function2 (int reqdPosn, {int optNamed=1}) {} // allowed
void function3 (int reqdPosn, [int optPosn=1]) {} // allowed
void function4 ([int optPosn=1], {int optNamed=1}) {} // error
void function5 ([int optPosn=1], {required int reqdNamed=1}) {} // error
void function6 ({int optNamed=1}, [int optPosn=1]) {} // error*
void function7 ([int optPosn1=1], [int optPosn2=1]) {} // error
void function8 ([int optPosn1=1, int optPosn2=1]) {} // allowed
// * Yes, this violates the 'All positional arguments must be before any named
// arguments" rule but I though it worth testing for the sake of completeness!
I see no inherent confusion (to parsers or humans) in allowing both types of arguments but if there is, perhaps it would be best to state it (them?) and close this issue.
IMO, I suspect that the requested feature is wanted the most when one is adding functionality to an existing function that has an optional positional argument. My own takeaway (for the microscopic amount it is worth) is that I will rarely use optional positional arguments in the future--the little bit of typing this saves is just not worth it when compared to the effort that I now know will be required to add any named arguments in the future.
from language.
Sorry, no, this won't make it into Dart 3. I would like to fix it at some point, but it's one of those issues that's annoying but not troublesome enough to reach the top of the priority list.
from language.
@JaffaKetchup, This feature is fairly often used in Python. Probably, the one who raised this request, use it too. The main reason for having both at the same time is, that the options you often use (but not always), you don't want to name. However, the rarely used options should be named for maintainability, but they often do not even have a position.
E.g. Using open
you usually read a text file, so using open("myfile")
is sufficient. However if you happen to write one, you use the positional parameter mode
: open("myfile", "w")
. But there are a bunch of further options, for which you must use names. Of course, this could be written, too: open("myfile", mode="w")
. Note, that Python have 3 types of parameters all of which can be optional: positional only, named/keyword only, and those which can be used in position or with name (this latter is the default).
This can be a really strong feature if you get used to it.
from language.
@irhn what about python like args/kwargs:
def fun(*args, **kwargs): pass
Python's approach doesn't work well in a statically-typed language like Dart where you want to be able definitely associate different static types with each optional parameter.
from language.
Is such a thing allowed now?
Future<Database> connect({String dbName, [String dbUserName, String dbPassword]}) {}connect(dbName:"sample"); connect(dbName:"sample", dbUserName:"username", dbPassword:"password");
That wasn't the problem. The problem was using them as separate, and not nested, like this:
Future<Database> connect({String dbName}, [String dbUserName, String dbPassword])
from language.
@lrhn There seems to be an infinite recursion in that issue link list :P
What's the issue with tracking this?
from language.
C# has the "optionally named parameters" feature, in that they allow you to specify arguments either by position or by name. They're named arguments, not named parameters. C# does not have named (only) parameters.
from language.
It is asking for non-overlapping [] and {}.
Examples:
new List([length = 0], {fill: null});
Stream.subscribe([onData], {onError, onDone})
new Date(year, [month, ...., milliseconds], {isUtc: false})
from language.
Since dart-lang/sdk#47451 has been released, I believe this could be revisited, maybe after all objectives at dart-lang/sdk#47451 have been completed, but maybe it's mature enough. @lrhn
from language.
I, sadly, don't think "named arguments anywhere" has any effect on the viability of this issue.
Named arguments anywhere is a simple reshuffling of arguments at the call site, it does not affect the declaration of functions. Allowing both named and optional positional arguments on the same function would affect function declarations and the low-level function call protocol.
from language.
@lrhn, did you intend to close some other issue which is subsumed by this one?
from language.
Is there any chance of this coming in Dart 3? It would seem like an ideal time for it, considering that this has been opened for 11 years!
I'm pretty sure it won't...
from language.
I'm currently overhauling the APIs of get_it and get_it_mixin. It really would make APIs much better if we at least had the first parameter an optional positional that can have a default value and get mixed with named ones that follow
from language.
Thanks for the example, @escamoteur!
With a rough idea about the possible rules of a proposal according to this issue ('allow both positional and optional named parameters'), the example declaration might be expressed as follows:
T get<T extends Object>(
[dynamic paramPositional], {
dynamic param,
String? instanceName,
Type? type,
}) {
param ??= paramPositional;
... // Remaining implementation unchanged.
}
void main() {
var v = valueTopassToTheFactory;
get<MyFactory>(v); // OK.
get<MyFactory>(param: v); // OK.
get<MyFactory>(v, param: v); // Bug: Pass both parameters, no error.
}
Pro: This is a mechanism that will work for statically checked invocations as well as invocations where the function has static type dynamic
or Function
, which is a very nice consistency property.
Con: There is no direct support for making a choice ("should we pass this argument by name or by position?"), which means that we have to declare two distinct parameters and use something like a default value of null and the ??=
construct in order to use the parameter that actually received a useful value and ignore the other parameter. There is no support (in the language) for getting a diagnostic message if both parameters receive a non-trivial value by mistake.
With the 'optionally named parameter' proposal, we'd do as follows:
T get<T extends Object>({
dynamic param?,
String? instanceName,
Type? type,
}) {
// ... // Remaining implementation unchanged.
}
void main() {
var v = valueTopassToTheFactory;
get<MyFactory>(v); // OK.
get<MyFactory>(param: v); // OK.
get<MyFactory>(v, param: v); // Compile-time error.
(get as dynamic)<MyFactory>(param: v); // OK.
(get as dynamic)<MyFactory>(v); // Throws at run time.
}
Pro, at least for this example: We can express the property that it is the same parameter which is passed by name or positionally, and there is no danger that we're going to pass both of them by accident.
Con: This mechanism is compile-time-only, which means that the ability to pass a named parameter positionally does not work for dynamic invocations. However, it does work to pass it as a named parameter.
from language.
This issue is related to issue dart-lang/sdk#6496, but asks for less.
from language.
This comment was originally written by @seaneagan
Is this asking for:
- 2 separate optional parameters within the same declaration, one named, one positional
- allowing a single optional parameter to be both named and positional
The former could be solved by non-overlapping [] and {}. If overlapping [] and {} are allowed, then would have to decide whether to allow both {[ and [{ as well as }] and ]].
from language.
Added this to the Later milestone.
Added Accepted label.
from language.
This comment was originally written by @seaneagan
Sounds perfect! The only other thing I would change (also mentioned in issue dart-lang/sdk#6496) is to use = instead of : for named positional default values:
new List([length = 0], {fill = null});
The = to default positional optionals doesn't mimic call site syntax, so why does the named positional default syntax try to? I think it's more importatnt to be consistent between how to default optional parameters regardless of whether they are named or positional.
from language.
This comment was originally written by @rbishop-bah
Related: Issue dart-lang/sdk#17101
from language.
Removed this from the Later milestone.
Added Oldschool-Milestone-Later label.
from language.
Removed Oldschool-Milestone-Later label.
from language.
Issue dart-lang/sdk#17101 has been merged into this issue.
from language.
Marked this as blocking dart-lang/sdk#21406.
from language.
Since 2.0 is thinking of some drastic changes is there any way the more extreme do like C#, Python, of dart-lang/sdk#6496 can be revisited.
@gbracha would a DEP be required for this?
from language.
@donny-dont if this issue is fixed then we will be able to do:
greet([String salutation = 'Hello'], {String who}) {
print('$salutation $who!');
}
Then if there is really a need to allow parameters to be both named and positional, we could further allow something like this syntax:
greet({[String salutation = 'Hello', String who]}) {
print('$salutation $who!');
}
But personally, I think that creates unnecessarily bloated API surface.
from language.
Any guesses when this might get implemented?
from language.
Something new? This sounds like a useful feature...
from language.
@irhn what about python like args/kwargs: def fun(*args, **kwargs): pass
abstract class Controller {
String render(String template, [List<Map<String, Object?>> *contexts /*= const []*/, ]{Map<String, Object?> **data /*= const {}*/}) {
data = contexts.reduce(...) + data;
return environment.getTemplate(template).render(data);
}
}
abstract class Template {
String render(Map<String, Object?> context);
}
abstract class Environment {
Template getTemplate(String name);
}
from language.
Any knowledge on how someone can assist on that? I just have no idea on if this could be developed from outsiders and where to look for potential solutions/problems.
from language.
Whoops, yes. I thought I was looking at an SDK-repo issue. I followed a link with dart-lang/sdk/
in it to get there.
I just hadn't noticed the issue had been moved here, and the old link was forwarding, so it's all the same issue.
from language.
Is there any chance of this coming in Dart 3? It would seem like an ideal time for it, considering that this has been opened for 11 years!
from language.
Sad to hear that, but thanks for letting us know. Just looking forward to Dart 3 now :)
from language.
@escamoteur, it would be interesting to see the concrete example, can you show it using a small snippet of code?
One of the sources of complexity in this feature is the need to support a different calling convention (in particular, such that invocations of first class functions using the type dynamic
or Function
can work, or even statically checked invocations on a supertype). This would potentially require a substantial amount of work in several different backends.
If we're satisfied with a static mechanism then we do have a lightweight proposal here: #831, 'optionally named parameters'.
The idea is that some parameters can be named, but they are marked as 'optionally named', and they can then be passed as positional parameters. At each call site, a compile-time transformation will check the actual argument list, cut off any 'extra' positional parameters (so if the function declares 1 positional parameter, but we're passing 3, we have 2 extras), and re-adding those extra parameters with a name (so foo(1, 2, 3, z: 4)
becomes foo(1, x: 2, y: 3, z: 4)
). The declaration specifies which named parameters are subject to this transformation, and in which order.
The main limitation is that (foo as dynamic)(1, 2, 3, z: 4)
will fail because it will be called exactly as written (the compile-time transformation won't change any dynamic calls), and foo
doesn't actually accept 3 positional parameters (also, x
or y
could be required).
How would that work for you?
from language.
Just a very simple example
T get<T extends Object>({
dynamic param,
String? instanceName,
Type? type,
});
in 99% of the case, people don't pass any of these parameters with the exception, of the registered Type in GetIt is a factory. Then being able to pass a parameter is quite common and it would be nice to be about to write
GetIt.I<Myfactory>(valueTopassToTheFactory);
instead of
GetIt.I<Myfactory>(param: valueTopassToTheFactory);
not sure if that would be possible with the linked proposal.
from language.
If I'm honest, I'm not sure I like #831 ('optionally named parameter') to resolve this ('allow both positional and optional named parameters'). It in itself seems like an overcomplication and a fairly niche use-case feature - are there other languages that have this feature? As a resolution to this, it kind of feels like a low quality workaround.
Just as another example for this issue, adding named arguments to a method with existing unnamed positional arguments, without causing a breaking change.
from language.
Related Issues (20)
- Destructuring records in functions HOT 5
- Lower the directory depth cost of packages HOT 2
- Can an augmentation library be an entry point? HOT 9
- How do we merge augmentation imports? HOT 6
- Grammar rule adjustments for augmentation libraries HOT 1
- False analyzer warnings when using nullable extensions HOT 2
- Augmentation libraries can't be main libraries as well? HOT 2
- Augmenting declarations cannot occur outside augmentation libraries, right? HOT 4
- Proposal: remove special analyzer behavior for await expressions with "null context". HOT 5
- Proposal: remove special front end behavior for await expressions with context `dynamic`. HOT 2
- Proposal: align front end behavior with analyzer for if-null expressions in context `dynamic`. HOT 3
- Support debugging Dart projects with compilation errors HOT 3
- Pattern matching allows you to refer to its own scope HOT 3
- Proposal: add a context for RHS of equality operations. HOT 1
- matching default values in switch statements (with record patterns) HOT 4
- Failing analysis of macro test prevents other actions HOT 1
- [augmentation-libraries] Missing grammar rule for extension and enum augmentations? HOT 6
- Assignment expressions in `if`-statements don't correctly promote nullable variables HOT 4
- Eliminate symbol literals with several identifiers? HOT 10
- Update the spec parser to take stop and continuation tokens into account for `<typeArguments>` as a selector
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from language.