You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
ArgParser: add [<ArgumentDefaultValue foo>] for constant defaults
Shorthand for the common case where an [<ArgumentDefaultFunction>]'s
function would just return a constant. The attribute argument is a
SynExpr spliced verbatim into the generated code, exactly as
[<ArgumentFlag>]'s value already is; the generated file inherits the
source file's `open`s, so an identifier resolves there as it does at the
use site.
Because `foo` is an ordinary .NET custom-attribute argument, F# itself
restricts it to compile-time constants (literals, [<Literal>] bindings,
enum cases) on the user's own source line, so the generator's untyped
pass need not validate it. A discriminated union case, including a flag
DU's, is not such a constant and still needs [<ArgumentDefaultFunction>].
The new attribute joins the existing "at most one default source" check,
which until now had no test coverage at all; it is now exercised over
every pair drawn from the three default-supplying attributes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: CHANGELOG.md
+5Lines changed: 5 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,5 +1,10 @@
1
1
Notable changes are recorded here.
2
2
3
+
# WoofWare.Myriad.Plugins 10.4.1
4
+
5
+
The `ArgParserGenerator` gains `[<ArgumentDefaultValue foo>]`: shorthand for an `[<ArgumentDefaultFunction>]` whose function just returns a constant.
6
+
`foo` is an ordinary .NET attribute argument, so F# restricts it to compile-time constants (literals, `[<Literal>]` bindings, and enum cases); anything else, including a discriminated union case, still needs `[<ArgumentDefaultFunction>]`.
7
+
3
8
# WoofWare.Myriad.Plugins 10.3.1
4
9
5
10
The `ArgParserGenerator` now supports positional args together with arbitrary discriminated-union args.
@@ -225,6 +227,7 @@ and you get back respectively these objects:
225
227
A = None
226
228
B = Choice2Of2 4
227
229
BWithEnv = Choice2Of2 100 // whatever the value of $MY_ENV_VAR was, or a failed parse
230
+
BWithConstant = Choice2Of2 4
228
231
DryRun = Choice2Of2 DryRunMode.Wet
229
232
AnimalPart = AnimalArgs.Fowl { Species = "pheasant" }
230
233
}
@@ -234,6 +237,7 @@ and you get back respectively these objects:
234
237
A = None
235
238
B = Choice2Of2 4
236
239
BWithEnv = Choice1Of2 8
240
+
BWithConstant = Choice2Of2 4
237
241
DryRun = Choice1Of2 DryRunMode.Dry
238
242
AnimalPart = AnimalArgs.Fish { Fins = 39 }
239
243
}
@@ -242,6 +246,11 @@ and you get back respectively these objects:
242
246
Default arguments are handled as `Choice<'a, 'a>`:
243
247
you get a `Choice1Of2` if the user provided the input, or a `Choice2Of2` if the parser filled in your specified default value.
244
248
249
+
`[<ArgumentDefaultValue foo>]` is shorthand for an `[<ArgumentDefaultFunction>]` whose function just returns a constant.
250
+
Since `foo` is an ordinary .NET attribute argument, F# restricts it to compile-time constants: literals, `[<Literal>]` bindings, and enum cases.
251
+
(A discriminated union case, such as a flag DU's, is not one of those, so those still need `[<ArgumentDefaultFunction>]`.)
252
+
Note that F# requires parentheses around an attribute argument which is not a bare literal: `[<ArgumentDefaultValue(Consts.Foo)>]`, but `[<ArgumentDefaultValue 4>]`.
253
+
245
254
You can control `TimeSpan` and friends with the `[<InvariantCulture>]` and `[<ParseExact @"hh\:mm\:ss">]` attributes.
246
255
247
256
You can generate extension methods for the type, instead of a module with the type's name, using `[<ArgParser (* isExtensionMethod = *) true>]`.
0 commit comments