Your First Result
Let's start with a simple example that shows the power of NOPE-PRO:
1using UnityEngine;
2using NOPE.Runtime.Core;
3using NOPE.Runtime.Core.Result;
4using NOPE.PRO.VisualDebugger;
5
6public class QuickStartExample : MonoBehaviour
7{
8 void Start()
9 {
10 // Traditional approach - exceptions and nulls everywhere!
11 // DON'T DO THIS:
12 /*
13 try {
14 var data = LoadData();
15 if (data != null) {
16 var parsed = int.Parse(data);
17 if (parsed > 0) {
18 Debug.Log($"Success: {parsed}");
19 }
20 }
21 } catch (Exception e) {
22 Debug.LogError($"Failed: {e.Message}");
23 }
24 */
25
26 // NOPE-PRO approach - beautiful and safe!
27 LoadDataSafe()
28 .EnableDebug("QuickStart") // Enable visual debugging!
29 .Bind(ParseNumber) // Chain operations
30 .Ensure(n => n > 0, "Number must be positive")
31 .Match<Unit>(
32 onSuccess: value => { Debug.Log($"✅ Success: {value}"); return Unit.Value; },
33 onFailure: error => { Debug.LogError($"❌ Failed: {error}"); return Unit.Value; }
34 );
35 }
36
37 // Return Result instead of throwing exceptions
38 Result<string, string> LoadDataSafe()
39 {
40 string data = PlayerPrefs.GetString("testData", "");
41
42 return string.IsNullOrEmpty(data)
43 ? "No data found" // Implicit conversion to Failure
44 : data; // Implicit conversion to Success
45 }
46
47 // Parse safely without exceptions
48 Result<int, string> ParseNumber(string input)
49 {
50 return Result.Of(
51 () => int.Parse(input),
52 ex => $"Invalid number format: {input}"
53 );
54 }
55}
Key Concepts in 2 Minutes
1. Result<T, E>
- No More Exceptions
1// Creating Results
2Result<int, string> success = 42; // Success
3Result<int, string> failure = "Something went wrong"; // Failure
4
5// Checking state
6if (success.IsSuccess)
7 Debug.Log($"Value: {success.Value}");
8
9// Pattern matching
10string message = failure.Match(
11 onSuccess: val => $"Got {val}",
12 onFailure: err => $"Error: {err}"
13);
2. Maybe<T>
- No More Nulls
1// Creating Maybe values
2Maybe<string> hasValue = "Hello"; // Has value
3Maybe<string> noValue = Maybe<string>.None; // No value
4
5// Safe operations
6Maybe<int> length = hasValue.Map(s => s.Length); // Maybe(5)
7
8// Pattern matching
9string result = noValue.Match(
10 onValue: val => $"Found: {val}",
11 onNone: () => "Not found"
12);
3. Chaining Operations
1// Chain multiple operations elegantly
2GetPlayerId()
3 .EnableDebug("PlayerFlow") // Track in visual debugger
4 .Bind(LoadPlayerData) // Async operation
5 .Map(player => player.Score) // Transform
6 .Ensure(score => score >= 0, "Invalid score")
7 .Tap(score => Debug.Log($"Score: {score}")) // Side effect
8 .Match<Unit>(
9 onSuccess: score => { ApplyScore(score); return Unit.Value; },
10 onFailure: error => { HandleError(error); return Unit.Value; }
11 );
Visual Debugging in Action
With NOPE_PRO_DEBUG
enabled, use the Flow Debugger window (Window → NOPE → Flow Debugger) for detailed inspection:
Common Patterns
Safe Division
1Result<float, string> Divide(float a, float b)
2{
3 return b == 0
4 ? "Cannot divide by zero"
5 : a / b;
6}
7
8public void DivideSafely()
9{
10 // Usage
11 var result = Divide(10, 2)
12 .Match(
13 success => $"Result: {success}",
14 error => $"Error: {error}"
15 );
16
17 // Output the result
18 // On success: "Result: 5"
19 // On error: "Error: Cannot divide by zero"
20 Debug.Log(result);
21}
Loading Game Data
1public Result<GameConfig, string> LoadConfig()
2{
3 return LoadFromDisk("config.json")
4 .Bind(ParseJson<GameConfig>)
5 .Ensure(config => config.Version > 0, "Invalid config version")
6 .Map(config =>
7 {
8 config.LoadTime = Time.time;
9 return config;
10 });
11}
Next Steps
Congratulations! You've learned the basics of NOPE-PRO. Here's what to explore next:
- Core Concepts - Deep dive into Railway-Oriented Programming
- Basic Usage Tutorial - Comprehensive walkthrough
- Visual Debugger Guide - Master the debugging tools
- API Reference - Complete method documentation
Quick Reference Card
1// Result<T,E> Creation
2Result<int, string> r1 = 42; // Success
3Result<int, string> r2 = "error"; // Failure
4var r3 = Result.SuccessIf(
5 condition: (1 > 0), // If condition is true, returns success result
6 successValue: "Success", // Success value
7 error: "Failure"); // Failure value
8
9var r4 = Result.Of(
10 func: () => SomeRiskyMethod(),
11 errorConverter: ex => ex.Message);
12
13
14Result<int, string> result = 0;
15// Transformations
16result.Map(x => x * 2); // Transform value
17result.Bind(x => LoadMore(x)); // Chain Results
18result.MapError(e => $"Context: {e}"); // Transform error
19result.Ensure(x => x > 0, "Must be positive"); // Add validation
20
21// Side Effects
22result.Tap(x => Debug.Log(x)); // On success, log value
23result.Match( // Handle both
24 onSuccess: x =>
25 {
26 Debug.Log($"Success: {x}");
27 return "Success handled";
28 },
29 onFailure: e =>
30 {
31 Debug.LogError($"Error: {e}");
32 return "Error handled";
33 }
34);
35
36// Maybe<T> Creation
37Maybe<int> m1 = 42; // Has value
38Maybe<int> m2 = Maybe<int>.None; // No value
39
40Maybe<int> maybe = 123;
41// Maybe Operations
42maybe.Map(x => x * 2); // Transform
43maybe.Where(x => x > 0); // Filter
44maybe.Or(0); // Provide fallback default value