Skip to content

Commit c5ea1a5

Browse files
roboz0redgarfgp
andauthored
Add FS-1027 (#75)
Co-authored-by: Edgar Gonzalez <[email protected]>
1 parent f768537 commit c5ea1a5

File tree

3 files changed

+90
-28
lines changed

3 files changed

+90
-28
lines changed

spec/rfc-status.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
| F# 4.1 | FS-1019 | [Implicitly Add the Module Suffix](https://github.com/fsharp/fslang-design/tree/main/FSharp-4.1/FS-1019-implicitly-add-the-module-suffix.md) | [completed](https://github.com/fsharp/fslang-spec/pull/77) |
3232
| F# 4.1 | FS-1020 | [ByRef Returns](https://github.com/fsharp/fslang-design/tree/main/FSharp-4.1/FS-1020-byref-returns.md) | |
3333
| F# 4.1 | FS-1025 | [Improve Record Type Inference](https://github.com/fsharp/fslang-design/tree/main/FSharp-4.1/FS-1025-improve-record-type-inference.md) | |
34-
| F# 4.1 | FS-1027 | [Complete Optional DefaultParameterValue](https://github.com/fsharp/fslang-design/tree/main/FSharp-4.1/FS-1027-complete-optional-defaultparametervalue.md) | |
34+
| F# 4.1 | FS-1027 | [Complete Optional DefaultParameterValue](https://github.com/fsharp/fslang-design/tree/main/FSharp-4.1/FS-1027-complete-optional-defaultparametervalue.md) | [completed](https://github.com/fsharp/fslang-spec/pull/75) |
3535
| F# 4.1 | FS-1029 | [Implement IReadOnlyCollection in list](https://github.com/fsharp/fslang-design/tree/main/FSharp-4.1/FS-1029-Implement%20IReadOnlyCollection%20in%20list.md) | |
3636
| F# 4.1 | FS-1040 | [Enum Match](https://github.com/fsharp/fslang-design/tree/main/FSharp-4.1/FS-1040-enum-match.md) | |
3737
| F# 4.5 | FS-1047 | [Match Bang](https://github.com/fsharp/fslang-design/tree/main/FSharp-4.5/FS-1047-match-bang.md) | [completed](https://github.com/fsharp/fslang-spec/pull/67) |

spec/special-attributes-and-types.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,12 @@ assemblies that are authored in other CLI languages.
3232
| System.Runtime.CompilerServices.InternalsVisibleToAttribute `[<InternalsVisibleTo(...)>]` | Directs the F# compiler to permit access to the internals of the assembly. <br>This attribute may be used in both F# and imported assemblies. |
3333
| System.Runtime.CompilerServices.TypeForwardedToAttribute `[<TypeForwardedTo(...)>]` | Indicates a type redirection. <br>This attribute may be used only in imported non-F# assemblies. It is not permitted in F# code. |
3434
| System.Runtime.CompilerServices.ExtensionAttribute <br> `[<Extension(...)>]` | Indicates the compiled form of a C# extension member. <br>This attribute may be used only in imported non-F# assemblies. It is not permitted in F# code. |
35+
| System.Runtime.InteropServices.DefaultParameterValueAttribute <br> `[<DefaultParameterValue(...)>]` | When applied to a parameter in conjunction with the `[<Optional>]` attribute, specifies the default value to be inserted at the callsite. <br>This attribute may be used in both F# and imported assemblies. |
3536
| System.Runtime.InteropServices.DllImportAttribute <br> `[<DllImport(...)>]` | When applied to a function definition in a module, causes the F# compiler to ignore the implementation of the definition, and instead compile it as a CLI P/Invoke stub declaration. <br>This attribute may be used in both F# and imported assemblies. |
3637
| System.Runtime.InteropServices.MarshalAsAttribute <br> `[<MarshalAs(...)>]` | When applied to a parameter or return type, specifies the marshalling attribute for a CLI P/Invoke stub declaration. <br>This attribute may be used in both F# and imported assemblies. However, F# does not support the specification of "custom" marshallers. |
3738
| System.Runtime.InteropServices.InAttribute <br> `[<In>]` | When applied to a parameter, specifies the CLI In attribute. <br>This attribute may be used in both F# and imported assemblies. However, in F# its only effect is to change the corresponding attribute in the CLI compiled form. |
3839
| System.Runtime.InteropServices.OutAttribute <br> `[<Out>]` | When applied to a parameter, specifies the CLI Out attribute. <br>This attribute may be used in both F# and imported assemblies. However, in F# its only effect is to change the corresponding attribute in the CLI compiled form. |
39-
| System.Runtime.InteropServices.OptionalAttribute <br> `[<Optional(...)>]` | When applied to a parameter, specifies the CLI Optional attribute. <br>This attribute may be used in both F# and imported assemblies. However, in F# its only effect is to change the corresponding attribute in the CLI compiled form. |
40+
| System.Runtime.InteropServices.OptionalAttribute <br> `[<Optional(...)>]` | When applied to a parameter, specifies the CLI Optional attribute. Should be used in conjunction with `[<DefaultParameterValue(...)>]`. <br>This attribute may be used in both F# and imported assemblies. |
4041
| System.Runtime.InteropServices.FieldOffsetAttribute <br> `[<FieldOffset(...)>]` | When applied to a field, specifies the field offset of the underlying CLI field. <br>This attribute may be used in both F# and imported assemblies. |
4142
| System.NonSerializedAttribute <br> `[<NonSerialized>]` | When applied to a field, sets the "not serialized" bit for the underlying CLI field. <br>This attribute may be used in both F# and imported assemblies. |
4243
| System.Runtime.InteropServices.StructLayoutAttribute <br> `[<StructLayout(...)>]` | Specifies the layout of a CLI type. <br>This attribute may be used in both F# and imported assemblies. |

spec/type-definitions.md

Lines changed: 87 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1939,10 +1939,28 @@ type C =
19391939

19401940
### Optional Arguments to Method Members
19411941

1942-
Method members—but not functions definitions—may have optional arguments. Optional
1943-
arguments must appear at the end of the argument list. An optional argument is marked with a?
1944-
before its name in the method declaration. Inside the member, the argument has type
1945-
`option<argType>`.
1942+
Method members—but not functions definitions—may have optional arguments. F# supports
1943+
two forms of optional arguments: F#-style optional arguments and CLI-compatible optional arguments.
1944+
1945+
CLI-compatible optional arguments are handled on the **caller side**. When a method call omits
1946+
an optional argument, the compiler reads the default value from the method's metadata and
1947+
explicitly passes that value. This contrasts with F#-style optional arguments, which are
1948+
handled by the **callee**. With F#-style optional arguments, if an argument is omitted, the
1949+
compiler passes `None`, and the callee determines the default value to use.
1950+
1951+
From the caller's perspective both styles appear as optional arguments. However, their
1952+
underlying mechanism and primary use cases differ.
1953+
1954+
The compiled representation of members varies as additional optional arguments are added. The
1955+
addition of optional arguments to a member signature results in a compiled form that is not binary-
1956+
compatible with the previous compiled form.
1957+
1958+
#### F\#-Style Optional Arguments
1959+
1960+
F#-style optional arguments must appear at the end of the argument list. An optional argument
1961+
is marked with a `?` before its name in the method declaration. Inside the member, the argument
1962+
has the type `option<argType>`. The `option` type is used to represent a value that may or may
1963+
not exist.
19461964

19471965
The following example declares a method member that has two optional arguments:
19481966

@@ -1993,10 +2011,72 @@ The resolution of calls that use optional arguments is specified in _Method Appl
19932011

19942012
Optional arguments may not be used in member constraints.
19952013

2014+
Marking an argument as optional is equivalent to adding the `FSharp.Core.OptionalArgument`
2015+
attribute ([§](special-attributes-and-types.md#custom-attributes-recognized-by-f)) to a required argument. This attribute is added implicitly for optional arguments.
2016+
Adding the `[<OptionalArgument>]` attribute to a parameter of type `'a option` in a virtual method
2017+
signature is equivalent to using the `(?x:'a)` syntax in a method definition. If the attribute is applied
2018+
to an argument of a method, it should also be applied to all subsequent arguments of the method.
2019+
Otherwise, it has no effect and callers must provide all of the arguments.
2020+
2021+
#### CLI-Compatible Optional Arguments
2022+
2023+
For interoperability with C# and other CLI languages, F# supports optional arguments with default values using
2024+
the `Optional` and `DefaultParameterValue` attributes. This mechanism is equivalent to defining an optional
2025+
argument in C# with a default value, such as `MyMethod(int i = 3)`. In F#, this would be written as:
2026+
2027+
```fsharp
2028+
open System.Runtime.InteropServices
2029+
2030+
type C() =
2031+
static member MyMethod([<Optional; DefaultParameterValue(3)>] i: int) =
2032+
i + 1
2033+
```
2034+
2035+
These attributes are typically used for C# and VB interop so that callers in those languages see an argument as optional.
2036+
They can also be from F# code in the same assembly and from separate assemblies.
2037+
2038+
CLI-compatible optional arguments are not passed as values of type `Option<_>`. If the optional
2039+
argument is present, its value is passed. If the optional argument is omitted, the default
2040+
value from the CLI metadata is supplied instead. The value `System.Reflection.Missing.Value`
2041+
is supplied for any CLI optional arguments of type `System.Object` that do not have a
2042+
corresponding CLI default value, and the default (zero-bit pattern) value is supplied for
2043+
other CLI optional arguments of other types that have no default value.
2044+
2045+
##### Allowable Default Values
2046+
2047+
The `DefaultParameterValue` attribute accepts the following types of values:
2048+
2049+
- **Primitive Types**: Constant values for `sbyte`, `byte`, `int16`, `uint16`, `int32`, `uint32`, `int64`, `uint64`, `float32`, `float`, and `string`.
2050+
- **Reference Types**: The only allowed default value is `null`.
2051+
- **Value Types**: The only allowed default value is the default value of the struct.
2052+
2053+
##### Usage and Considerations
2054+
2055+
The value provided to `DefaultParameterValue` must match the parameter's type. A mismatch will generate a compiler warning, and both the `Optional` and `DefaultParameterValue` attributes will be ignored.
2056+
2057+
For example, the following is not allowed:
2058+
2059+
```fsharp
2060+
type Class() =
2061+
static member Wrong([<Optional; DefaultParameterValue("string")>] i:int) = ()```
2062+
2063+
This will be compiled as if it were written:
2064+
```fsharp
2065+
type Class() =
2066+
static member Wrong(i:int) = ()
2067+
```
2068+
2069+
Note that the `null` value for reference types must be type-annotated, for instance: `[<Optional; DefaultParameterValue(null:obj)>] o:obj`.
2070+
2071+
It is possible to use these attributes in the following ways, though it is not standard practice:
2072+
2073+
- Specifying `Optional` without `DefaultParameterValue`: Callers can omit the argument, and a default value will be chosen by convention (the default constructor for primitive types and structs).
2074+
- Specifying `DefaultParameterValue` without `Optional`.
2075+
- Specifying `Optional; DefaultParameterValue` on any parameter, not necessarily the last one.
2076+
19962077
> Note : Imported CLI metadata may specify arguments as optional and may additionally
1997-
specify a default value for the argument. These are treated as F# optional arguments. CLI
1998-
optional arguments can propagate an existing optional value by name; for example,
1999-
`?ValueTitle = Some (...)`.
2078+
specify a default value for the argument. CLI optional arguments can propagate an existing optional
2079+
value by name; for example, `?ValueTitle = Some (...)`.
20002080
<br>For example, here is a fragment of a call to a Microsoft Excel COM automation API that
20012081
uses named and optional arguments.
20022082

@@ -2010,25 +2090,6 @@ uses named and optional arguments.
20102090
ValueTitle = "Sample Value Type")
20112091
```
20122092

2013-
> CLI optional arguments are not passed as values of type `Option<_>`. If the optional
2014-
argument is present, its value is passed. If the optional argument is omitted, the default
2015-
value from the CLI metadata is supplied instead. The value
2016-
`System.Reflection.Missing.Value` is supplied for any CLI optional arguments of type
2017-
`System.Object` that do not have a corresponding CLI default value, and the default (zero-
2018-
bit pattern) value is supplied for other CLI optional arguments of other types that have
2019-
no default value.
2020-
2021-
The compiled representation of members varies as additional optional arguments are added. The
2022-
addition of optional arguments to a member signature results in a compiled form that is not binary-
2023-
compatible with the previous compiled form.
2024-
2025-
Marking an argument as optional is equivalent to adding the `FSharp.Core.OptionalArgument`
2026-
attribute ([§](special-attributes-and-types.md#custom-attributes-recognized-by-f)) to a required argument. This attribute is added implicitly for optional arguments.
2027-
Adding the `[<OptionalArgument>]` attribute to a parameter of type `'a option` in a virtual method
2028-
signature is equivalent to using the `(?x:'a)` syntax in a method definition. If the attribute is applied
2029-
to an argument of a method, it should also be applied to all subsequent arguments of the method.
2030-
Otherwise, it has no effect and callers must provide all of the arguments.
2031-
20322093
### Type-directed Conversions at Member Invocations
20332094

20342095
As described in _Method Application Resolution_ (see [§](inference-procedures.md#method-application-resolution)), three type-directed conversions are

0 commit comments

Comments
 (0)