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
andlist<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 theSystem.Collections.Generic
namespace). As a general rule, don't use this type name; if you want this type in F#, useResizeArray<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 toGenericType<TypeParameter>
.The F# immutable list type declared in FSharp.Core is in scope with two names by default:
List
andlist
. It has one type parameter, soint list
,list<int>
,int List
, andList<int>
are equivalent.System.Collections.Generic
has a differentList<'T>
type, which has the more suitable aliasResizeArray
in F#. If you openSystem.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.