List<int> vs int list in F Sharp

To expand slightly on John Palmer's correct answer, here's an F# Interactive session that illustrates how int list and List<int> are synonyms, right up until the moment when they aren't. And note how there's also list<int> and ResizeArray<int> for extra confusion:

F# Interactive for F# 4.0 (Open Source Edition)
Freely distributed under the Apache 2.0 Open Source License

For help type #help;;

> typeof<list<int>>.Namespace ;;
val it : string = "Microsoft.FSharp.Collections"
> typeof<list<int>>.Name ;;     
val it : string = "FSharpList`1"
> typeof<List<int>>.Namespace ;;
val it : string = "Microsoft.FSharp.Collections"
> typeof<List<int>>.Name ;;     
val it : string = "FSharpList`1"
> typeof<int list>.Namespace ;;
val it : string = "Microsoft.FSharp.Collections"
> typeof<int list>.Name ;;     
val it : string = "FSharpList`1"
> typeof<ResizeArray<int>>.Namespace ;;
val it : string = "System.Collections.Generic"
> typeof<ResizeArray<int>>.Name ;;     
val it : string = "List`1"
- 
- printfn "Now we'll open System.Collections.Generic. Watch what happens."
- ;;
Now we'll open System.Collections.Generic. Watch what happens.
val it : unit = ()
> open System.Collections.Generic ;;
> typeof<list<int>>.Namespace ;;
val it : string = "Microsoft.FSharp.Collections"
> typeof<list<int>>.Name ;;
val it : string = "FSharpList`1"
> typeof<List<int>>.Namespace ;;
val it : string = "System.Collections.Generic"
> typeof<List<int>>.Name ;;     
val it : string = "List`1"
> typeof<int list>.Namespace ;;
val it : string = "Microsoft.FSharp.Collections"
> typeof<int list>.Name ;;
val it : string = "FSharpList`1"
> typeof<ResizeArray<int>>.Namespace ;;
val it : string = "System.Collections.Generic"
> typeof<ResizeArray<int>>.Name ;;     
val it : string = "List`1"

So List<int> with an uppercase L will be the F# list type (an immutable linked list with a head pointer, which has O(1) head access and prepending, but O(N) tail access and appending) if you haven't opened the System.Collections.Generic namespace. But if you have, then suddenly List<int> resolves to the .Net System.Collections.Generic.List<T> class, which is a mutable data structure with O(1) lookups anywhere, amortized O(1) appends, but O(N) prepends. So it really matters which one you're using.

To be on the safe side, if you intend to use the F# list structure, I'd write it as either int list (my preference since it reads like English) or list<int> (which some people prefer since it reads like C#). Neither of those will suddenly acquire a different meaning when you open a .Net namespace; they will continue to refer to the F# list structure. And avoid using List<int> to refer to F# lists; only use that when you have opened the System.Collections.Generic namespace and you intend to get a .Net System.Collections.Generic.List<T> instance. Finally, note that in F#, System.Collections.Generic.List<T> has a type alias available without opening the System.Collections.Generic namespace. By default, without needing to open any namespaces, you can access this type under the name ResizeArray<T>.

Summary:

Safe type names:

  • int list and list<int> (always refer to the F# singly-linked list type)
  • ResizeArray<int> (always refers to the C# System.Collections.Generic.List<T> type)

Unsafe type names because their meaning changes depending on what namespace you've opened:

  • List<int> (refers to the F# singly-linked list type at first, but changes meaning to the C# type if you open the System.Collections.Generic namespace). As a general rule, don't use this type name; if you want this type in F#, use ResizeArray<int> instead.

There is no difference, there is a type alias.

Except under one case, where you have run

 open System.Collections.Generic

Which has its own list type


  • Generally, for generic types with one parameter, TypeParameter GenericType is equivalent to GenericType<TypeParameter>.

  • The F# immutable list type declared in FSharp.Core is in scope with two names by default: List and list. It has one type parameter, so int list, list<int>, int List, and List<int> are equivalent.

  • System.Collections.Generic has a different List<'T> type, which has the more suitable alias ResizeArray in F#. If you open System.Collections.Generic, List refers to this mutable, array-wrapping type.

To avoid confusion, it is customary to not use List with a capital L to refer to a type in F#. Instead, list with a lowercase l is used for the FP-originating, immutable, singly-linked lists, while ResizeArray is used to refer to the OO-style mutable collection. Most people also stick to the different styles int list versus ResizeArray<int> and avoid the other combinations.

As for type information, IDEs and similar sometimes attempt to display types in the way they were declared, as there are often many ways to refer to the same type. This does not imply a difference in behavior.

Tags:

List

Generics

F#