Skip to content

Commit b5b6580

Browse files
committed
Updates as per acrolynx
1 parent 71f8362 commit b5b6580

File tree

3 files changed

+61
-61
lines changed

3 files changed

+61
-61
lines changed

docs/fsharp/style-guide/component-design-guidelines.md

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# F# component design guidelines
22

3-
This document is a set of component design guidelines for F# programming, based on [the F# Component Design Guidelines, v14, Microsoft Research](fsharp-design-guidelines-v14.pdf) and [another version](http://fsharp.org/specs/component-design-guidelines/) originally curated and maintained by the F# Software Foundation.
3+
This document is a set of component design guidelines for F# programming, based on [the F# Component Design Guidelines, v14, Microsoft Research, and [another version](http://fsharp.org/specs/component-design-guidelines/) originally curated and maintained by the F# Software Foundation.
44

55
This document assumes you are familiar with F# programming. Many thanks to the F# community for their contributions and helpful feedback on various versions of this guide.
66

@@ -25,7 +25,7 @@ There are a few universal guidelines that apply to F# libraries, regardless of t
2525

2626
Regardless of the kind of F# coding you are doing, it is valuable to have a working knowledge of the [.NET Library Design Guidelines](../../standard/design-guidelines/index.md). Most other F# and .NET programmers will be familiar with these guidelines, and expect .NET code to conform to them.
2727

28-
The .NET Library Design Guidelines provide a lot of general guidance regarding naming, designing classes and interfaces, member design (properties, methods, events, etc.) and more, and are a useful first point of reference for a variety of design guidance.
28+
The .NET Library Design Guidelines provide general guidance regarding naming, designing classes and interfaces, member design (properties, methods, events, etc.) and more, and are a useful first point of reference for a variety of design guidance.
2929

3030
### Add XML documentation comments to your code
3131

@@ -77,25 +77,25 @@ In addition to the previous table, be aware of the following:
7777

7878
#### Avoid abbreviations
7979

80-
The .NET guidelines discourage the use of abbreviations (for example, “use `OnButtonClick` rather than `OnBtnClick`”). Very common abbreviations, such as `Async` for “Asynchronous”, are tolerated. This guideline is sometimes ignored for functional programming; for example, `List.iter` uses an abbreviation for “iterate”. For this reason, using abbreviations tends to be tolerated to a greater degree in F#-to-F# programming, but should still generally be avoided in public component design.
80+
The .NET guidelines discourage the use of abbreviations (for example, “use `OnButtonClick` rather than `OnBtnClick`”). Common abbreviations, such as `Async` for “Asynchronous”, are tolerated. This guideline is sometimes ignored for functional programming; for example, `List.iter` uses an abbreviation for “iterate”. For this reason, using abbreviations tends to be tolerated to a greater degree in F#-to-F# programming, but should still generally be avoided in public component design.
8181

8282
#### Avoid casing name collisions
8383

84-
The .NET guidelines say that casing alone cannot be used to disambiguate name collisions, since some client languages (e.g. Visual Basic) are case-insensitive.
84+
The .NET guidelines say that casing alone cannot be used to disambiguate name collisions, since some client languages (for example, Visual Basic) are case-insensitive.
8585

8686
#### Use acronyms where appropriate
8787

8888
Acronyms such as XML are not abbreviations and are widely used in .NET libraries in uncapitalized form (Xml). Only well-known, widely recognized acronyms should be used.
8989

9090
#### Use PascalCase for generic parameter names
9191

92-
Do use PascalCase for generic parameter names in public APIs, including for F#-facing libraries. In particular, use names like `T`, `U`, `T1`, `T2` for arbitrary generic parameters, and when specific names make sense, then for F#-facing libraries use names like `Key`, `Value`, `Arg` (but not e.g. `TKey`).
92+
Do use PascalCase for generic parameter names in public APIs, including for F#-facing libraries. In particular, use names like `T`, `U`, `T1`, `T2` for arbitrary generic parameters, and when specific names make sense, then for F#-facing libraries use names like `Key`, `Value`, `Arg` (but not for example, `TKey`).
9393

9494
#### Use either PascalCase or camelCase for public functions and values in F# modules
9595

96-
camelCase is generally used for public functions that are designed to be used unqualified (e.g. invalidArg), and for the “standard collection functions” (e.g. List.map). In both these cases, the function names act much like keywords in the language.
96+
camelCase is used for public functions that are designed to be used unqualified (for example, `invalidArg`), and for the “standard collection functions” (for example, List.map). In both these cases, the function names act much like keywords in the language.
9797

98-
### Object, Type and Module Design
98+
### Object, Type, and Module Design
9999

100100
#### Use namespaces or modules to contain your types and modules
101101

@@ -134,9 +134,9 @@ The differences between using modules and namespaces to organize code at the top
134134
* Namespaces can span multiple files
135135
* Namespaces cannot contain F# functions unless they are within an inner module
136136
* The code for any given module must be contained within a single file
137-
* Top-level modules can contain F# functions without the neeed for an inner module
137+
* Top-level modules can contain F# functions without the need for an inner module
138138

139-
The choice between a top level namespace or module affects the compiled form of the code, and thus will affect the view from other .NET languages should your API eventually be consumed outside of F# code.
139+
The choice between a top-level namespace or module affects the compiled form of the code, and thus will affect the view from other .NET languages should your API eventually be consumed outside of F# code.
140140

141141
#### Use methods and properties for operations intrinsic to object types
142142

@@ -227,7 +227,7 @@ Overuse of `[<AutoOpen>]` leads to polluted namespaces, and the attribute should
227227

228228
#### Consider defining operator members on classes where using well-known operators is appropriate
229229

230-
Sometimes classes are used to model mathematical constructus such as Vectors. When the domain being modeled has well-known operators, defining them as members intrinsic to the class is helpful.
230+
Sometimes classes are used to model mathematical constructs such as Vectors. When the domain being modeled has well-known operators, defining them as members intrinsic to the class is helpful.
231231

232232
```fsharp
233233
type Vector(x:float) =
@@ -247,7 +247,7 @@ This guidance corresponds to general .NET guidance for these types. However, it
247247

248248
#### Use method overloading for member functions, if doing so provides a simpler API
249249

250-
Method overloading is a powerful tool for simplifying an API which may need to do multiple related things.
250+
Method overloading is a powerful tool for simplifying an API that may need to do multiple related things.
251251

252252
```fsharp
253253
type Logger() =
@@ -264,7 +264,7 @@ Avoid revealing concrete representations of objects. For example, the concrete r
264264

265265
#### Avoid the use of implementation inheritance for extensibility
266266

267-
In F#, implementation inheritance is rarely used. Furthermore, inheritance heirarchies are often complex and difficult to change when new requirements arrive. Inheritance implementation still exists in F# for compatility and rare cases where it is the best solution to a problem, but alternative techniques should be sought in your F# programs when designing for polymorphism.
267+
In F#, implementation inheritance is rarely used. Furthermore, inheritance hierarchies are often complex and difficult to change when new requirements arrive. Inheritance implementation still exists in F# for compatibility and rare cases where it is the best solution to a problem, but alternative techniques should be sought in your F# programs when designing for polymorphism.
268268

269269
### Function and Member Signatures
270270

@@ -280,7 +280,7 @@ For return types containing many components, or where the components are related
280280

281281
#### Use `Async<T>` for async programming at F# API boundaries
282282

283-
If there is a corresponding synchronous operation named `Operation` that returns a `T`, then the async operation should be named `AsyncOperation` if it returns `Async<T>` or `OperationAsync` if it returns `Task<T>`. For commonly-used .NET types that expose Begin/End methods, consider using `Async.FromBeginEnd` to write extension methods as a façade to provide the F# async programming model to those .NET APIs.
283+
If there is a corresponding synchronous operation named `Operation` that returns a `T`, then the async operation should be named `AsyncOperation` if it returns `Async<T>` or `OperationAsync` if it returns `Task<T>`. For commonly used .NET types that expose Begin/End methods, consider using `Async.FromBeginEnd` to write extension methods as a façade to provide the F# async programming model to those .NET APIs.
284284

285285
```fsharp
286286
type SomeType =
@@ -312,11 +312,11 @@ The .NET Library Design Guidelines give excellent advice on the use of exception
312312

313313
* Do not throw `System.Exception` when it will escape to user code. This includes avoiding the use of `failwith`, `failwithf`, which are handy functions for use in scripting and for code under development, but should be removed from F# library code in favor of throwing a more specific exception type.
314314

315-
* Use `nullArg`, `invalidArg` and `invalidOp` as the mechanism to throw `ArgumentNullException`, `ArgumentException` and `InvalidOperationException` when appropriate.
315+
* Use `nullArg`, , and `invalidOp` as the mechanism to throw `ArgumentNullException`, , and `InvalidOperationException` when appropriate.
316316

317317
#### Consider using option values for return types when failure is not an exceptional scenario
318318

319-
The .NET approach to exceptions is that they should be “exceptional”; that is, they should occur relatively infrequently. However, some operations (for example, searching a table) may fail frequently. F# option values are an excellent way to represent the return types of these operations. These operations conventionally start with the name prefix “try”.
319+
The .NET approach to exceptions is that they should be “exceptional”; that is, they should occur relatively infrequently. However, some operations (for example, searching a table) may fail frequently. F# option values are an excellent way to represent the return types of these operations. These operations conventionally start with the name prefix “try”:
320320

321321
```fsharp
322322
// bad: throws exception if no element meets criteria
@@ -353,7 +353,7 @@ type System.Collections.Generic.IDictionary<'Key,'Value> with
353353

354354
#### Use discriminated unions instead of class hierarchies for tree-structured data
355355

356-
Tree-like structures are recursively-defined. This is awkward with inheritance, but quite elegant with Discriminated Unions.
356+
Tree-like structures are recursively defined. This is awkward with inheritance, but elegant with Discriminated Unions.
357357

358358
```fsharp
359359
type BST<'T> =
@@ -411,23 +411,23 @@ val inline highestCommonFactor : ^T -> ^T -> ^T
411411

412412
This is a suitable function for a public API in a mathematical library.
413413

414-
#### Avoid using member constraints to simulate typeclasses and duck typing
414+
#### Avoid using member constraints to simulate type classes and duck typing
415415

416-
It is possible to simulate “duck typing” using F# member constraints. However, members that make use of this should not in general be used in F#-to-F# library designs. This is because library designs based on unfamiliar or non-standard implicit constraints tend to cause user code to become inflexible and strongly tied to one particular framework pattern.
416+
It is possible to simulate “duck typing” using F# member constraints. However, members that make use of this should not in general be used in F#-to-F# library designs. This is because library designs based on unfamiliar or non-standard implicit constraints tend to cause user code to become inflexible and tied to one particular framework pattern.
417417

418418
### Operator Definitions
419419

420420
#### Avoid defining custom symbolic operators
421421

422-
Custom operators are essential in some situations and are highly useful notational devices within a large body of implementation code. For new users of a library, named functions are often easier to use. In addition custom symbolic operators can be hard to document, and users find it more difficult to lookup help on operators, due to existing limitations in IDE and search engines.
422+
Custom operators are essential in some situations and are highly useful notational devices within a large body of implementation code. For new users of a library, named functions are often easier to use. In addition custom symbolic operators can be hard to document, and users find it more difficult to look up help on operators, due to existing limitations in IDE and search engines.
423423

424-
As a result, it is generally best to publish your functionality as named functions and members, and additionally expose operators for this functionality only if the notational benefits outweight the documentation and cognitive cost of having them.
424+
As a result, it is best to publish your functionality as named functions and members, and additionally expose operators for this functionality only if the notational benefits outweigh the documentation and cognitive cost of having them.
425425

426426
### Units of Measure
427427

428428
#### Use units of measure for added type safety in F# code
429429

430-
This type information is erased when viewed by other .NET languages, so be aware that .NET components, tools and reflection will just see types-sans-units (e.g. `float` rather than `float<kg>`) after this information has been erased.
430+
This type information is erased when viewed by other .NET languages, so be aware that .NET components, tools and reflection will just see types-sans-units (for example, `float` rather than `float<kg>`) after this information has been erased.
431431

432432
### Type Abbreviations
433433

@@ -437,9 +437,9 @@ Be aware that .NET components, tools and reflection will just see the types-bein
437437

438438
#### Avoid type abbreviations for public types whose members and properties should be intrinsically different to those available on the type being abbreviated
439439

440-
In this case, the type being abbreviated reveals too much about the representation of the actual type being defined. Instead, consider wrapping the abbreviation in a class type or a single-case discriminated union (or, when performance is absolutely essential, consider using a struct type to wrap the abbreviation).
440+
In this case, the type being abbreviated reveals too much about the representation of the actual type being defined. Instead, consider wrapping the abbreviation in a class type or a single-case discriminated union (or, when performance is essential, consider using a struct type to wrap the abbreviation).
441441

442-
For example, it is tempting to define a multi-map as a special case of an F# map, e.g.
442+
For example, it is tempting to define a multi-map as a special case of an F# map, for example:
443443

444444
```fsharp
445445
type MultiMap<'Key,'Value> = Map<'Key,'Value list>
@@ -449,7 +449,7 @@ However, the logical dot-notation operations on this type are not the same as th
449449

450450
## Guidelines for Libraries for Use from other .NET Languages
451451

452-
When designing libraries for use from other .NET languages, it is very important to adhere to the [.NET Library Design Guidelines](../../standard/design-guidelines/index.md). In this document we label these libraries vanilla .NET libraries, as opposed to F#-facing libraries which use F# constructs without restriction and are mostly intended for use by F# applications. Designing vanilla .NET libraries means providing familiar and idiomatic APIs consistent with the rest of the .NET Framework by minimizing the use of F#-specific constructs in the public API. We propose the rules in the following sections.
452+
When designing libraries for use from other .NET languages, it is important to adhere to the [.NET Library Design Guidelines](../../standard/design-guidelines/index.md). In this document, we label these libraries vanilla .NET libraries, as opposed to F#-facing libraries that use F# constructs without restriction and are mostly intended for use by F# applications. Designing vanilla .NET libraries means providing familiar and idiomatic APIs consistent with the rest of the .NET Framework by minimizing the use of F#-specific constructs in the public API. We propose the rules in the following sections.
453453

454454
### Namespace and Type Design (for libraries for use from other .NET Languages)
455455

@@ -465,13 +465,13 @@ type PolarCoordinate = ...
465465
member this.Theta = ...
466466
```
467467

468-
#### Use namespaces, types and members as the primary organizational structure for your components
468+
#### Use namespaces, types, and members as the primary organizational structure for your components
469469

470470
All files containing public functionality should begin with a `namespace` declaration, and the only public-facing entities in namespaces should be types. Do not use F# modules.
471471

472-
Use non-public modules to hold implementation code, utility types and utility functions.
472+
Use non-public modules to hold implementation code, utility types, and utility functions.
473473

474-
Static types should be preferred over modules, as they allow for future evolution of the API to use overloading and other .NET API design concepts which may not be used within F# modules.
474+
Static types should be preferred over modules, as they allow for future evolution of the API to use overloading and other .NET API design concepts that may not be used within F# modules.
475475

476476
For example, in place of the following public API:
477477

@@ -850,6 +850,6 @@ The fixes we have made to prepare this type for use as part of a vanilla .NET li
850850

851851
* We used a return type of `seq<RadialPoint>` instead of `RadialPoint list` by changing a list construction using `[ ... ]` to a sequence construction using `IEnumerable<RadialPoint>`.
852852

853-
* We used the .NET delegate type System.Func instead of an F# function type.
853+
* We used the .NET delegate type `System.Func` instead of an F# function type.
854854

855855
This makes it far nicer to consume in C# code.

0 commit comments

Comments
 (0)