Skip to content
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

F# 4.1 Updates #1916

Merged
merged 22 commits into from
May 24, 2017
Merged

F# 4.1 Updates #1916

merged 22 commits into from
May 24, 2017

Conversation

cartermp
Copy link
Contributor

@cartermp cartermp commented Apr 14, 2017

Adds F# 4.1 feature to the docs. #1677 tracks what is added.

@cartermp cartermp changed the title F# 4.1 Updates for Tuples [WIP] F# 4.1 Updates Apr 21, 2017
@cartermp cartermp changed the title [WIP] F# 4.1 Updates F# 4.1 Updates Apr 24, 2017
@@ -73,6 +73,52 @@ You can also use global to reference the top-level .NET namespace, for example,

[!code-fsharp[Main](../../../samples/snippets/fsharp/lang-ref-2/snippet6408.fs)]

##

F# 4.1 introduces the notion of namespaces which allow for all underlying code to be mutually recursive. This is done via `namespace rec`. Use of `module rec` can alleviate some pains in not being able to write mutually referential code between types and modules. The following is an example of this:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo:
This is done via namespace rec. Use of module rec ...
should be:
This is done via namespace rec. Use of namespace rec ...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

@cartermp cartermp requested a review from BillWagner May 3, 2017 05:15
@cartermp
Copy link
Contributor Author

cartermp commented May 3, 2017

@dsyme I would love a look at these.

Copy link
Contributor

@dsyme dsyme left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Absolutely fantastic to have this added, this is wonderful!


[Attributes](attributes.md)

[Named Arguments](parameters-and-arguments.md#named-arguments)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just wondering - do we have some kind of link checker for #named-arguments and other hash-labels?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do, but it's only in our CI. No way to test it locally.

Discriminated unions provide support for values that can be one of a number of named cases, possibly each with different values and types. Discriminated unions are useful for heterogeneous data; data that can have special cases, including valid and error cases; data that varies in type from one instance to another; and as an alternative for small object hierarchies. In addition, recursive discriminated unions are used to represent tree data structures.

## Syntax

```fsharp
[ struct-attribute ]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should really add requirequalifiedaccess-attribute here too since it is an attribute that has linguistic effect

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also no-equality-attribute, no-comparison-attribute and friends

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added as a new section below, "Common attributes"

| Case3 of double
```

>[!WARN] With the current release of F# 4.1, multicase struct unions have multiple bugs. We do not recommend using them at this time.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this warning is a little too strong - in F# 4.1 they work well enough as long as each case has a separate type. However it is important to say that the overall size of the struct in F# 4.1 is the sum(field-sizes) not max(field-sizes) which may be very different to what people expect.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Made it less severe.


>[!WARN] With the current release of F# 4.1, multicase struct unions have multiple bugs. We do not recommend using them at this time.

Because these are value types and not reference types, there are extra considerations compared with reference Discriminated Unions:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't capitalize Discriminated Unions here?

## Syntax

```fsharp
use ptr = fixed expression
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's worth being clearer that this extends the syntax of expressions (not the syntax of other let declarations such as declarations in class types)

Copy link
Contributor Author

@cartermp cartermp May 3, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I addressed this now:

This extends the syntax of expressions to allow extracting a pointer and binding it to a name which is prevented from being collected or moved during garbage-collection.

A pointer from an expression is fixed via the [...]
[...]
Use of fixed must occur within an expression in a function or a method. It cannot be used at a script-level or module-level scope.

X : float
Y: float
Z: float;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No semicolon needed here

(a + 1, b + 1)

// Struct Tuple of floats
struct(1.025f, 1.5f)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Space after struct

let (a, b) = (1, 2)

// Construct a struct tuple from it
let struct(c, d) = struct(a, b)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Space after struct

let struct(c, d) = struct(a, b)

//
// Fst and Snd functions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// Fst and Snd functions (reference tuples only)

let (a, b) = struct(1, 2)

// Will not compile!
let struct(c, d) = (1, 2)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Space after struct, likewise below

Copy link
Contributor

@dsyme dsyme left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving since I think all the feedback has been actioned

@cartermp
Copy link
Contributor Author

@BillWagner, would really love a once-over from you as well, particularly to see if my choice of presentation makes sense.

Copy link
Contributor

@mairaw mairaw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few quick edit comments

@@ -0,0 +1,84 @@
---
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this needs to be added to the TOC

@@ -0,0 +1,84 @@
---
title: Caller Information (F#)
description: Caller Information (F#)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

description needs to be different than title

ms.assetid: a3dcc335-433b-4672-ac2d-ae6b11b816f3
---

# Caller Information
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: sentence case for headings


## Member Names

You can use the `CallerMemberName` attribute to avoid specifying the member name as a `String` argument to the called method. By using this technique, you avoid the problem that Rename Refactoring doesn't change the `String` values. This benefit is especially useful for the following tasks:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

link to the APIs? if you want to use a different name than the default class name, you can link like this:
CallerMemberName

```

>[!WARN]
With the initial release of F# 4.1, multicase struct unions have isues if the cases are of the same type. This has since been fixed and is pending an update.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo: isues
wrong note formatting. it should be WARNING not WARN and next line also starts with >

@@ -116,5 +137,14 @@ Discriminated unions work well if the nodes in the tree are heterogeneous. In th

When this code is executed, the value of `result` is 5.

## Common Attributes

The following attributes are commonly seen in Discriminated Unions:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lowercase discriminated unions?

## See Also
[F# Language Reference](index.md)

[Namespaces](namespaces.md)

[F# RFC FS-1009 - Allow mutually referential types and modules over larger scopes within files](https://github.com/fsharp/fslang-design/blob/master/FSharp-4.1/FS-1009-mutually-referential-types-and-modules-single-scope.md)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we're now standardizing in no lines in between the links in the see also section
see here for an example: https://github.com/dotnet/docs/blob/master/docs/framework/interop/compiling-an-interop-project.md (you add a space in front and 2/3 in the end)


### Converting between Reference Tuples and Struct Tuples

Because Reference Tuples and Struct Tuples have a completely different underlying representation, they are not implicitly convertable. That is, code such as the following will not compile:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

convertable -> convertible

will not -> won't


Tuples are compiled into objects of one of several generic types, all named `System.Tuple`, that are overloaded on the arity, or number of type parameters. Tuple types appear in this form when you view them from another language, such as C# or Visual Basic, or when you are using a tool that is not aware of F# constructs. The `Tuple` types were introduced in .NET Framework 4. If you are targeting an earlier version of the .NET Framework, the compiler uses versions of [System.Tuple](https://msdn.microsoft.com/library/5ac7953d-acdc-4a58-bfb7-c1f6406c0fa3) from the 2.0 version of the F# Core Library. The types in this library are used only for applications that target the 2.0, 3.0, and 3.5 versions of the .NET Framework. Type forwarding is used to ensure binary compatibility between .NET Framework 2.0 and .NET Framework 4 F# components.

### Compiled Form of Struct Tuples

Struct tuples (e.g., `struct (x, y)`), are fundamentally different from reference tuples. They are compiled into the `System.ValueTuple` type, overloaded by arity, or the number of type parameters. They are equivalent to [C# 7 Tuples](../../csharp/tuples.md) and VB.NET 15 Tuples, and interoperate bidirectionally.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

e.g. -> for example

@@ -0,0 +1,22 @@
//
// Will not compile!
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will not -> It won't

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GitHub didn't track this for some reason, but I addressed this

If you are only using tuples from F# and not exposing them to other languages, and if you are not targeting a version of the .NET Framework that preceded version 4, you can ignore this section.
## Interoperation with C# Tuples

C# 7 and VB.NET 15 introduced tuples to their respective languages. Tuples in C# and are structs, and are equivalent to struct tuples in F#. If you need to interoperate with C# uses tuples, you must use struct tuples.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VB.NET 15 -> Visual Basic 2017?

Copy link
Member

@BillWagner BillWagner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall, this looks great.

I left a couple suggestions on wording that make one explanation more clear.


You must specify an explicit default value for each optional parameter. You can't apply Caller Info attributes to parameters that aren't specified as optional.

The Caller Info attributes don't make a parameter optional. Instead, they affect the default value that's passed in when the argument is omitted.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These two paragraphs are somewhat hard to parse. How about this change:

Caller Info attributes can only be applied to optional parameters. You must supply an explicit value for each optional parameter. The Caller Info attributes cause the compiler to write the proper value for each optional parameter decorated with a Caller Info attribute.

Update if I have any of the technical details wrong for the F# implementation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

|Method, property, or event|The name of the method, property, or event from which the call originated.|
|Constructor|The string ".ctor"|
|Static constructor|The string ".cctor"|
|Destructor|The string "Finalize"|
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it Finalize, or Finalizer?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Finalize. At least, this is what's in the equivalent C# doc.

```fsharp
let deadBeef = 0xDEAD_BEEF

let deadBeefAsBits = 0b1101_1110_1010_1101_1011_1110_1010_1111
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The 2nd to last nibble should be 1110, not 1010.


let deadBeefAsBits = 0b1101_1110_1010_1101_1011_1110_1010_1111

let ssn = 012_345_6789
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does F# assign a special meaning when the first digit of a numeric literal is 0? If not, you may want to change the value used in this example.

@@ -96,6 +100,18 @@ The following example illustrates a derived class that overrides a base class me
## 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.

## Optional Arguments

Starting with F# 4.1, you can also have C#-style optional arguments with a default parameter value in methods. This is to help facilitate interoperation with C# code. The following example demonstrates the syntax:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd leave off the comparison to C#. Other languages (notably C++, and Scala) also support optional arguments.

### Compiled Form of Struct Tuples

Struct tuples (for example, `struct (x, y)`), are fundamentally different from reference tuples. They are compiled into the `System.ValueTuple` type, overloaded by arity, or the number of type parameters. They are equivalent to [C# 7 Tuples](../../csharp/tuples.md) and VB.NET 15 Tuples, and interoperate bidirectionally.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should System.ValueTuple be a reference to the type in the API docs?

@cartermp cartermp merged commit 70bac70 into dotnet:master May 24, 2017
@cartermp cartermp deleted the fs41 branch May 24, 2017 19:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants