Struct Unit
- Namespace
- FunctionalDdd
- Assembly
- FunctionalDdd.RailwayOrientedProgramming.dll
Represents the absence of a meaningful value, used for operations that have no return value.
This is the functional programming equivalent of void, but as a proper type that can be used with generics.
public record struct Unit : IEquatable<Unit>
- Implements
- Inherited Members
- Extension Methods
Examples
Basic usage with Result:
// Operation that doesn't return a value
public Result<Unit> DeleteUser(UserId userId)
{
var user = _repository.Find(userId);
if (user == null)
return Error.NotFound($"User {userId} not found");
_repository.Delete(user);
return Result.Success(); // Returns Result<Unit>
}
// Usage
var result = DeleteUser(userId);
if (result.IsSuccess)
Console.WriteLine("User deleted successfully");
Chaining operations that don't return values:
public async Task<Result<Unit>> ProcessOrderAsync(Order order, CancellationToken ct)
{
return await ValidateOrder(order) // Result<Unit>
.BindAsync(() => ChargePaymentAsync(order, ct)) // Result<Unit>
.TapAsync(() => SendConfirmationEmailAsync(order.Email, ct))
.TapAsync(() => UpdateInventoryAsync(order.Items, ct));
}
Converting to HTTP response:
app.MapDelete("/users/{id}", (Guid id, IUserService userService) =>
UserId.TryCreate(id)
.Bind(userService.DeleteUser)
.ToHttpResult());
// Returns 204 No Content on success, appropriate error status on failure
Combining Unit results with value results:
public Result<User> CreateAndNotify(CreateUserRequest request)
{
return FirstName.TryCreate(request.FirstName)
.Combine(LastName.TryCreate(request.LastName))
.Bind((first, last) => User.Create(first, last))
.Combine(ValidateBusinessRules(request)) // Result<Unit> - just validates
.Map((user, _) => user); // Discard Unit, keep User
}
Remarks
In functional programming, every function returns a value. When an operation doesn't have a meaningful
return value (like void methods in imperative programming), we use Unit as a placeholder type.
This allows Result<TValue> to represent both operations that return values and operations
that only succeed or fail without returning data.
Common use cases for Unit:
- DELETE operations that either succeed or fail but don't return data
- State-changing operations (e.g., sending emails, updating records)
- Validation operations that only need to indicate success/failure
- Fire-and-forget side effects in a functional pipeline
The Result class provides convenience methods for working with Unit:
- Success() - Creates a successful
Result<Unit> - Failure(Error) - Creates a failed
Result<Unit>
When converting Result<Unit> to HTTP responses, successful results automatically
map to HTTP 204 No Content, indicating success without a response body.