Raven in 60 seconds
Raven is a typed, expression-oriented language for .NET. Small programs can use top-level statements, while larger programs can combine functions, records, unions, classes, and interfaces.
import System.Console.*
record Shipment(Id: int, Weight: decimal)
union QuoteResult {
case Quoted(amount: decimal)
case Rejected(reason: string)
}
func Quote(shipment: Shipment) -> QuoteResult {
if shipment.Weight <= 0 {
return .Rejected("Weight must be positive")
}
let amount = 12.50m + shipment.Weight * 1.75m
return .Quoted(amount)
}
let shipment = Shipment(42, 3.5m)
let message = match Quote(shipment) {
.Quoted(let amount) => "Quote: $amount"
.Rejected(let reason) => "Cannot quote: $reason"
}
WriteLine(message)
This program shows the main shape of Raven:
importexposes .NET namespaces, types, or static members.recorddefines a value-oriented data type with a primary constructor.uniondefines a closed set of cases, each of which can carry data.funcdeclares a function without requiring a containing utility class.letintroduces an immutable local binding; usevarwhen reassignment is intentional.ifandmatchare expressions, although they can also be used for effects.- Pattern arms bind values explicitly, such as
let amount. - String interpolation uses
$nameinside a string. - .NET APIs such as
System.Console.WriteLineare available directly.
Expected failure is data
Raven uses Option<T> for a value that may be absent and Result<T, E> for an
operation that may succeed or fail in an expected way.
func ParsePort(text: string) -> Result<int, string> {
return int.Parse(text) match {
Ok(let port) when port > 0 => Ok(port)
Ok(_) => Error("Port must be positive")
Error(_) => Error("Port must be a number")
}
}
Raven projects the known framework method int.Parse(string) to a Result
whose error channel preserves its framework exception types, so match handles
its expected failures directly.
The try expression remains available for genuinely throwing APIs, and the
propagation operator ? can return an error from the current function when no
local handling is needed.
Objects remain available
Use a class when identity, mutable state, lifecycle, or open polymorphism is part of the model. Use records and unions for value-shaped and closed-domain data. Raven does not require choosing between functional and object-oriented programming for an entire application.