Skip to content

Consolidate and enhance F# optional parameters documentation #47580

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 8 additions & 17 deletions docs/fsharp/language-reference/members/methods.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ Methods can be marked `inline`. For information about `inline`, see [Inline Func

Non-inline methods can be used recursively within the type; there is no need to explicitly use the `rec` keyword.

## Instance Methods
## Instance methods

Instance methods are declared with the `member` keyword and a *self-identifier*, followed by a period (.) and the method name and parameters. As is the case for `let` bindings, the *parameter-list* can be a pattern. Typically, you enclose method parameters in parentheses in a tuple form, which is the way methods appear in F# when they are created in other .NET Framework languages. However, the curried form (parameters separated by spaces) is also common, and other patterns are supported also.

Expand All @@ -61,7 +61,7 @@ The following example illustrates the definition and use of a non-abstract insta

Within instance methods, do not use the self identifier to access fields defined by using `let` bindings. Use the self identifier when accessing other members and properties.

## Static Methods
## Static methods

The keyword `static` is used to specify that a method can be called without an instance and is not associated with an object instance. Otherwise, methods are instance methods.

Expand All @@ -71,7 +71,7 @@ The following example illustrates the definition and use of static methods. Assu

[!code-fsharp[Main](~/samples/snippets/fsharp/lang-ref-1/snippet3402.fs)]

## Abstract and Virtual Methods
## Abstract and virtual methods

The keyword `abstract` indicates that a method has a virtual dispatch slot and might not have a definition in the class. A *virtual dispatch slot* is an entry in an internally maintained table of functions that is used at run time to look up virtual function calls in an object-oriented type. The virtual dispatch mechanism is the mechanism that implements *polymorphism*, an important feature of object-oriented programming. A class that has at least one abstract method without a definition is an *abstract class*, which means that no instances can be created of that class. For more information about abstract classes, see [Abstract Classes](../abstract-classes.md).

Expand All @@ -89,13 +89,13 @@ The following example illustrates a derived class that overrides a base class me

[!code-fsharp[Main](~/samples/snippets/fsharp/lang-ref-1/snippet3404.fs)]

## Overloaded Methods
## Overloaded methods

Overloaded methods are methods that have identical names in a given type but that have different arguments. In F#, optional arguments are usually used instead of overloaded methods. However, overloaded methods are permitted in the language, provided that the arguments are in tuple form, not curried form. The following example demonstrates it:

```fsharp
type MyType(dataIn: int) =
let data = dataIn
let data = dataIn
member this.DoSomething(a: int) = a + data
member this.DoSomething(a: string) = sprintf "Hello world, %s!" a

Expand All @@ -104,20 +104,11 @@ printfn "With int: %d" (m.DoSomething(2)) // With int: 12
printfn "With string: %s" (m.DoSomething("Bill")) // With string: Hello world, Bill!
```

## Optional Arguments
## Optional arguments

Starting with F# 4.1, you can also have optional arguments with a default parameter value in methods. This improves interoperability with C# code. The following example demonstrates the syntax:
F# supports optional arguments for methods. For detailed information about the different forms of optional arguments available in F#, see [Optional parameters](../parameters-and-arguments.md#optional-parameters).

```fsharp
open System.Runtime.InteropServices
// A class with a method M, which takes in an optional integer argument.
type C() =
member _.M([<Optional; DefaultParameterValue(12)>] i) = i + 1
```

Note that the value passed in for `DefaultParameterValue` must match the input type. In the above example, it is an `int`. Attempting to pass a non-integer value into `DefaultParameterValue` would result in a compile error.

## Example: Properties and Methods
## Example: Properties and methods

The following example contains a type that has examples of fields, private functions, properties, and a static method.

Expand Down
31 changes: 19 additions & 12 deletions docs/fsharp/language-reference/parameters-and-arguments.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,15 @@ title: Parameters and Arguments
description: Learn about F# language support for defining parameters and passing arguments to functions, methods, and properties.
ms.date: 08/15/2020
---
# Parameters and Arguments
# Parameters and arguments

This topic describes language support for defining parameters and passing arguments to functions, methods, and properties. It includes information about how to pass by reference, and how to define and use methods that can take a variable number of arguments.

## Parameters and Arguments
This article describes language support for defining parameters and passing arguments to functions, methods, and properties. It includes information about how to pass by reference and how to define and use methods that can take a variable number of arguments.

The term *parameter* is used to describe the names for values that are expected to be supplied. The term *argument* is used for the values provided for each parameter.

Parameters can be specified in tuple or curried form, or in some combination of the two. You can pass arguments by using an explicit parameter name. Parameters of methods can be specified as optional and given a default value.

## Parameter Patterns
## Parameter patterns

Parameters supplied to functions and methods are, in general, patterns separated by spaces. This means that, in principle, any of the patterns described in [Match Expressions](match-expressions.md) can be used in a parameter list for a function or member.

Expand Down Expand Up @@ -83,7 +81,7 @@ Occasionally, patterns that involve incomplete matches are useful, for example,

The use of patterns that have incomplete matches is best reserved for quick prototyping and other temporary uses. The compiler will issue a warning for such code. Such patterns cannot cover the general case of all possible inputs and therefore are not suitable for component APIs.

## Named Arguments
## Named arguments

Arguments for methods can be specified by position in a comma-separated argument list, or they can be passed to a method explicitly by providing the name, followed by an equal sign and the value to be passed in. If specified by providing the name, they can appear in a different order from that used in the declaration.

Expand Down Expand Up @@ -122,13 +120,20 @@ w.Height // = 10

Note that those members could perform any arbitrary work, the syntax is effectively a short hand to call property setters before returning the final value.

## Optional Parameters
## Optional parameters

F# supports two distinct forms of optional parameters for methods, each serving different purposes:

- [Optional parameters (F# native)](#optional-parameters-f-native)
- [Optional parameters (C# interop)](#optional-parameters-c-interop)

### Optional parameters (F# native)

You can specify an optional parameter for a method by using a question mark in front of the parameter name. From the callee's perspective, optional parameters are interpreted as the F# option type, so you can query them in the regular way that option types are queried, by using a `match` expression with `Some` and `None`. Optional parameters are permitted only on members, not on functions created by using `let` bindings.

You can pass existing optional values to method by parameter name, such as `?arg=None` or `?arg=Some(3)` or `?arg=arg`. This can be useful when building a method that passes optional arguments to another method.

You can also use a function `defaultArg`, which sets a default value of an optional argument. The `defaultArg` function takes the optional parameter as the first argument and the default value as the second.
You can also use a function `defaultArg`, which sets a default value of an optional argument using shadowing. The `defaultArg` function takes the optional parameter as the first argument and the default value as the second. Unlike C#-style extensions, this function allows the method author to tell if the caller passed in a value or not.

The following example illustrates the use of optional parameters.

Expand All @@ -145,7 +150,9 @@ Baud Rate: 9600 Duplex: Full Parity: false
Baud Rate: 4800 Duplex: Half Parity: false
```

For the purposes of C# and Visual Basic interop you can use the attributes `[<Optional; DefaultParameterValue<(...)>]` in F#, so that callers will see an argument as optional. This is equivalent to defining the argument as optional in C# as in `MyMethod(int i = 3)`.
### Optional parameters (C# interop)

For the purposes of C# interop, you can use the attributes `[<Optional; DefaultParameterValue<(...)>]` in F#, so that callers will see an argument as optional. This is equivalent to defining the argument as optional in C# as in `MyMethod(int i = 3)`. This form was introduced in F# 4.1 to help facilitate interoperation with C# code.

```fsharp
open System
Expand All @@ -172,9 +179,9 @@ type C =
static member Wrong([<Optional; DefaultParameterValue("string")>] i:int) = ()
```

In this case, the compiler generates a warning and will ignore both attributes altogether. Note that the default value `null` needs to be type-annotated, as otherwise the compiler infers the wrong type, i.e. `[<Optional; DefaultParameterValue(null:obj)>] o:obj`.
In this case, the compiler generates a warning and will ignore both attributes altogether. Note that the default value `null` needs to be type-annotated; otherwise, the compiler infers the wrong type, that is, `[<Optional; DefaultParameterValue(null:obj)>] o:obj`.

## Passing by Reference
## Pass by reference

Passing an F# value by reference involves [byrefs](byrefs.md), which are managed pointer types. Guidance for which type to use is as follows:

Expand Down Expand Up @@ -208,7 +215,7 @@ You can use a tuple as a return value to store any `out` parameters in .NET libr

[!code-fsharp[Main](~/samples/snippets/fsharp/parameters-and-arguments-1/snippet3810.fs)]

## Parameter Arrays
## Parameter arrays

Occasionally it is necessary to define a function that takes an arbitrary number of parameters of heterogeneous type. It would not be practical to create all the possible overloaded methods to account for all the types that could be used. The .NET implementations provide support for such methods through the parameter array feature. A method that takes a parameter array in its signature can be provided with an arbitrary number of parameters. The parameters are put into an array. The type of the array elements determines the parameter types that can be passed to the function. If you define the parameter array with `System.Object` as the element type, then client code can pass values of any type.

Expand Down