100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Programming

F# vs C#

A practical comparison of F# and C# across paradigm, type safety, syntax, and when to choose each on the .NET platform.

PracticeIntermediate8 min readJul 10, 2026
Analogies

F# and C#: Two Faces of .NET

F# and C# both target the .NET runtime, compile to the same Common Intermediate Language (CIL), and share the base class library and NuGet ecosystem, yet they differ sharply in default paradigm. F# is functional-first: values are immutable by default, type inference removes most explicit annotations, and code reads as a series of expressions. C# is object-oriented and imperative-first: variables are mutable by default and classes are the primary organizing unit, though modern C# has borrowed functional features such as LINQ, records, and pattern matching.

🏏

Cricket analogy: Compare Test cricket to T20 cricket: both are cricket played under the same ICC rules on the same size pitch, but Test cricket (F#) defaults to a patient, disciplined approach while T20 (C#) defaults to aggressive stroke-play, even though a batter like Virat Kohli can adapt technique to either format.

Type Systems and Null Safety

F# has a strong, inferred type system, and values of ordinary F# types cannot be null by default; instead, the idiomatic way to represent an optional value is Option<'T>, which forces callers to pattern-match on Some x or None before using the value. C# historically allowed null on any reference type, a common source of NullReferenceException at runtime. C# 8 introduced nullable reference types as an opt-in compiler feature, but the checks are advisory warnings rather than a runtime guarantee, so a null can still slip through if warnings are ignored or suppressed.

🏏

Cricket analogy: Think of DRS (Decision Review System): F#'s Option type is like a mandatory third-umpire review before any dismissal is finalized, forcing an explicit check, whereas pre-2018 C# null handling was like an umpire's raw on-field call with no review safety net, risking a wrong decision reaching the scoreboard.

Interop, Tooling, and When to Choose Each

Because F# and C# compile to the same CIL, projects of one language can reference projects of the other directly within a single .NET solution, with no interop shims required. Many teams write core business logic, domain models, and data pipelines in F# for correctness and testability, while using C# for ASP.NET Core controllers, EF Core migrations, or UI-heavy code where imperative style and a larger hiring pool matter. F# Interactive (FSI), a REPL bundled with the F# tooling, also enables rapid prototyping and data exploration that has no direct equivalent in typical C# workflows.

🏏

Cricket analogy: Like a franchise fielding a specialist death-bowler such as Jasprit Bumrah for the tricky last overs and all-rounders for the middle overs: a team mixes F# for gnarly, correctness-critical logic and C# for the broad, high-volume overs of everyday CRUD work, all within the same XI.

fsharp
// F#: immutable discriminated union + exhaustive pattern matching, no nulls needed
type Shape =
    | Circle of radius: float
    | Rectangle of width: float * height: float

let area shape =
    match shape with
    | Circle r -> System.Math.PI * r * r
    | Rectangle (w, h) -> w * h

// Equivalent C# requires a class hierarchy or a switch expression:
// double Area(Shape s) => s switch {
//     Circle c => Math.PI * c.Radius * c.Radius,
//     Rectangle r => r.Width * r.Height,
//     _ => throw new ArgumentException()
// };

Both F# and C# compile to the same Common Intermediate Language (CIL) and run on the same .NET runtime, so a single solution can freely mix .fs and .cs projects, referencing types across languages with no interop shims required.

F# discriminated unions and C# don't map perfectly: consuming an F# DU from C# exposes it as a class hierarchy with Tag properties and static factory methods rather than a native switch pattern, which can feel clunky until C# 8+ pattern matching syntax is used.

  • F# and C# both compile to .NET IL and can be freely mixed within one solution.
  • F# defaults to immutability and expression-based syntax; C# defaults to mutable, statement-based syntax.
  • F#'s Option<'T> type forces explicit handling of missing values at compile time; C#'s nullable reference types are advisory warnings, not hard guarantees.
  • F# pattern matching on discriminated unions is exhaustive-checked by the compiler; C# switch expressions only recently gained comparable pattern matching.
  • Many teams use F# for domain logic, pipelines, and correctness-critical code, and C# for ASP.NET Core web layers and broader team collaboration.
  • F# Interactive (FSI) enables REPL-style rapid prototyping that has no direct C# equivalent in typical workflows.

Practice what you learned

Was this page helpful?

Topics covered

#Programming#FStudyNotes#FVsC#Two#Faces#NET#Type#StudyNotes#SkillVeris#ExamPrep