Result Type — ایک کنٹینر کی قسم جو کسی آپریشن کے نتیجے کی نمائندگی کرتی ہے جو کامیابی (Success) یا ناکامی (Failure) کے ساتھ مکمل ہو سکتا ہے۔ استثنیات کے برعکس، Result غلطی کو اسٹیک انوائنڈنگ کے بغیر ایک عام قدر کے طور پر منتقل کرتا ہے، جس سے متوقع غلطیوں کا انتظام زیادہ محفوظ اور قابل ترکیب ہو جاتا ہے۔ Apple Swift Documentation (2026) کے مطابق، Swift میں Result<Success, Failure> پروگرام کے عمل کو روکے بغیر map اور flatMap کے ذریعے خودکار غلطی کے انتظام کے ساتھ آپریشنز کو زنجیر بنانے کی اجازت دیتا ہے۔
اہم نکات
Result Type ایک عام قسم ہے جو کسی آپریشن کے نتیجے کو سمیٹتی ہے جو کامیاب یا ناکام ہو سکتا ہے۔ استثنیات کے برعکس، جہاں ایک غلطی عام بہاؤ کو روکتی ہے اور catch بلاک تلاش کرنے کے لیے اسٹیک انوائنڈنگ کی ضرورت ہوتی ہے، Result غلطی کو ایک عام قدر کے طور پر منتقل کرتا ہے — کال کرنے والا ہمیشہ ایک آبجیکٹ حاصل کرتا ہے اور اسے سنبھالنے کا فیصلہ کرتا ہے۔ یہ خاص طور پر متوقع غلطیوں کے لیے مفید ہے: غلط ان پٹ، کاروباری اصول، سرور کا مسترد کرنا، جہاں استثنیات بہت بھاری طریقہ کار ہوں گے۔
Result کا تصور فنکشنل پروگرامنگ سے آیا ہے، جہاں اسی طرح کی اقسام کو Either (یا Left/Right) کہا جاتا ہے۔ Swift میں، Result Swift 5.0 میں ایک معیاری قسم بن گیا؛ Kotlin میں، Result<T> معیاری لائبریری میں ظاہر ہوا؛ Dart 3.0 میں، بلٹ ان Result<T> متعارف کرایا گیا۔ ہر نفاذ کنٹینر کے ساتھ کام کرنے کے لیے طریقے فراہم کرتا ہے: map (کامیابی کی قدر کو تبدیل کرنا)، flatMap (Result افعال کو زنجیر بنانا)، mapError (غلطی کو تبدیل کرنا)، fold (دونوں صورتوں کو سنبھالنا)۔ Result Type موبائل ڈویلپمنٹ میں فنکشنل غلطی کے انتظام کی بنیاد ہے، متوقع منظرناموں کے لیے try-catch کا متبادل۔
Result کا بنیادی فائدہ ترکیب پذیری ہے۔ آپ متعدد آپریشنز، جن میں سے ہر ایک ناکام ہو سکتا ہے، کو بغیر nested try-catch بلاکس کے ایک زنجیر میں یکجا کر سکتے ہیں۔ اگر زنجیر میں کوئی آپریشن Failure کے ساتھ ناکام ہوتا ہے، تو پوری زنجیر روک دی جاتی ہے اور Failure لوٹاتی ہے — ایک if شرط یا catch بلاک کے بغیر۔ یہ کوڈ کو لکیری اور پڑھنے کے قابل بناتا ہے، خاص طور پر متعدد ترتیب وار API درخواستوں یا کاروباری اصولوں کی جانچ کے منظرناموں میں۔
Swift میں، Result<Success, Failure> دو صورتوں والا ایک enum ہے: .success(Success) اور .failure(Failure)، جہاں Failure Error پروٹوکول سے محدود ہے۔ Swift Result map، flatMap، mapError اور get طریقوں کے ساتھ ایک مکمل فنکشنل قسم ہے۔ get ایک خاص طریقہ ہے: یہ نتیجہ کامیاب ہونے پر Success قدر لوٹاتا ہے اور Failure ہونے پر غلطی پھینکتا ہے۔ یہ Result کو فنکشنل اور استثنیٰ پر مبنی اسلوب کے درمیان ایک پل کے طور پر کام کرنے کی اجازت دیتا ہے: ایک زنجیر میں map/flatMap کے ذریعے سنبھالنا اور آخر میں throws کوڈ کے ساتھ انضمام کے لیے do-catch کے ساتھ get کا استعمال۔
Swift Result عام پیرامیٹرز کے ساتھ ایک enum ہے، جو کمپائلر کو switch یا do-catch کے ذریعے جامع ہینڈلنگ نافذ کرنے کی اجازت دیتا ہے۔ اگر آپ NetworkError enum میں ایک نیا کیس شامل کرتے ہیں، تو کمپائلر تمام switch اظہار میں غلطی پیدا کرے گا جہاں اس کیس کو ہینڈل نہیں کیا گیا۔ جامع جانچ استثنیات پر Result کا بنیادی فائدہ ہے: کمپائلر ضمانت دیتا ہے کہ بلڈ وقت پر تمام ممکنہ غلطیوں کا محاسبہ کیا گیا ہے۔ اس کے برعکس، Swift میں استثنیات کی کمپائلر کے ذریعے جانچ نہیں کی جاتی (صرف throws کا اعلان کیا جاتا ہے، لیکن غلطی کی قسم نہیں)۔
enum NetworkError: Error {
case badURL
case requestFailed(String)
case decodingFailed
}
func fetchUser(id: Int) -> Result<User, NetworkError> {
guard let url = URL(string: "https://api.example.com/users/\(id)") else {
return .failure(.badURL)
}
let result = performRequest(url: url)
switch result {
case let .success(data):
if let user = try? JSONDecoder().decode(User.self, from: data) {
return .success(user)
}
return .failure(.decodingFailed)
case let .failure(error):
return .failure(.requestFailed(error.localizedDescription))
}
}
// switch کے ساتھ استعمال
let result = fetchUser(id: 42)
switch result {
case .success(let user):
showUser(user)
case .failure(.badURL):
logError("Invalid URL")
case .failure(.requestFailed(let msg)):
showAlert(msg)
case .failure(.decodingFailed):
logError("Decoding error")
}
Result<Success, Failure> قسم کی سطح پر غلطی کو ٹائپ کرنے کی اجازت دیتا ہے: fetchUser فنکشن Result<User, NetworkError> لوٹاتا ہے، جہاں NetworkError تین صورتوں والا ایک ٹھوس enum ہے۔ کال کرنے والا جامع کوریج کے ساتھ switch کے ذریعے ہر کیس کو ہینڈل کرتا ہے — کمپائلر چیک کرتا ہے کہ تمام variants کو ہینڈل کیا گیا ہے۔ جامع switch استثنیات پر Result کا ایک اہم فائدہ ہے: کمپائلر ضمانت دیتا ہے کہ آپ .badURL، .requestFailed یا .decodingFailed کو ہینڈل کرنا نہیں بھولیں گے۔ استثنیات کے ساتھ، کمپائلر ہینڈلنگ کی ضرورت نہیں کرتا، اور کوڈ کے جائزے میں ایک غائب catch(.badURL) آسانی سے نظر انداز ہو سکتا ہے۔
Kotlin میں، Result<T> معیاری لائبریری سے ایک بلٹ ان قسم ہے جو کامیابی (T) یا غلطی (Throwable) کی نمائندگی کرتی ہے۔ Swift کے برعکس، Kotlin Result ایک ٹھوس غلطی کی قسم بتانے کی اجازت نہیں دیتا — صرف Throwable۔ یہ سادگی کے لیے کیا گیا ہے لیکن when اظہار کے ذریعے اضافی غلطی کی قسم کی جانچ کی ضرورت ہے۔ Kotlin Result fold (دونوں صورتوں کو سنبھالنا)، getOrNull (کامیابی یا null)، getOrDefault (کامیابی یا ڈیفالٹ)، map، recover، andThen افعال کو سپورٹ کرتا ہے۔ Kotlin کی ایک خصوصیت: Result فنکشن کی حدود میں براہ راست پھیلانے کے لیے ڈیزائن نہیں کیا گیا ہے — اضافی موافقت کے بغیر اسے Android SDK طریقوں یا Kotlin Coroutines API کے لیے واپسی کی قسم کے طور پر استعمال نہیں کیا جا سکتا۔
fun parseJson(input: String): Result<JsonObject> {
return runCatching {
JsonParser.parseString(input).asJsonObject()
}
}
fun validateEmail(email: String): Result<String> {
return if (email.contains("@")) {
Result.success(email.trim())
} else {
Result.failure(IllegalArgumentException("Invalid email"))
}
}
data class SignupData(val name: String, val email: String)
fun processSignup(name: String, email: String): SignupResult {
return validateEmail(email).fold(
onSuccess = { validateName(name) },
onFailure = { SignupResult.Error("Invalid email") }
)
}
runCatching Kotlin میں ایک آسان ریپر ہے جو کسی بھی استثنیٰ کو پکڑتا ہے اور Result.failure لوٹاتا ہے۔ validateEmail تصدیق کے لحاظ سے Result.success یا Result.failure لوٹاتا ہے۔ fold دونوں صورتوں کو کمپیکٹ طریقے سے سنبھالتا ہے: Success پر، اگلا تصدیقی فنکشن کال کیا جاتا ہے؛ Failure پر، SignupResult.Error لوٹایا جاتا ہے۔ اہم: Kotlin Result ڈیٹا کلاس فیلڈز میں ذخیرہ کرنے یا suspend فنکشن کی حدود میں براہ راست منتقل کرنے کے لیے ڈیزائن نہیں کیا گیا ہے — Jetpack Compose یا MVVM میں UI حالات کی نمائندگی کرنے کے لیے حسب ضرورت sealed class (Success/Error/Loading) استعمال کریں۔
Dart 3.0 سے، معیاری لائبریری میں ایک بلٹ ان Result<T> شامل ہے — دو کنسٹرکٹرز کے ساتھ ایک sealed class: T.ok() (کامیابی) اور Error.error() (Object اور StackTrace کے ساتھ غلطی)۔ Dart 3.0 سے پہلے، Flutter ڈویلپرز dartz پیکیج سے Either<L, R> یا حسب ضرورت sealed class استعمال کرتے تھے۔ Dart میں بلٹ ان Result کم سے کم ہے: یہ براہ راست map/flatMap فراہم نہیں کرتا — ان افعال کو when کے ذریعے یا توسیعی طریقوں کا استعمال کرکے لاگو کرنا ضروری ہے۔ سنجیدہ فنکشنل ہینڈلنگ کے لیے، fpdart سے Either map، flatMap، mapLeft، fold، andThen اور bind آپریٹرز کی حمایت کے ساتھ ایک زیادہ طاقتور حل ہے۔
Either<L, R> fpdart پیکیج سے ایک بائیں جانب دار قسم ہے، جہاں Left غلطی ہے اور Right کامیابی ہے۔ بلٹ ان Result<T> کے برعکس، Either قسم پیرامیٹر کی سطح (L) پر غلطی کو ٹائپ کرتا ہے، جو کمپائل وقت پر غلطی کی قسم کے فرق کی اجازت دیتا ہے۔ fpdart پیکیج فنکشنل کمبینیٹرز کا ایک مکمل سیٹ فراہم کرتا ہے: map (Right -> Right)، mapLeft (Left -> Left)، flatMap (bind — nested Either)، andThen (تبدیلی کے بغیر زنجیر)، fold (Either سے باہر نکلنا)، getOrElse (ڈیفالٹ قدر)۔ فنکشنل نقطہ نظر کے ساتھ Flutter ایپلیکیشنز کے لیے، Either حقیقی معیار ہے۔
import 'dart:convert';
import 'package:fpdart/fpdart.dart';
class UserService {
Either<AppError, User> fetchUser(String id) {
try {
final response = await http.get(
Uri.parse('https://api.example.com/users/$id')
);
if (response.statusCode == 200) {
final user = User.fromJson(
json.decode(response.body)
);
return Either.of(user);
}
return Either.left(
AppError.serverError(response.statusCode)
);
} on SocketException catch (e) {
return Either.left(AppError.networkError(e.message));
}
}
}
// fold کے ساتھ استعمال
final result = await service.fetchUser('42');
result.fold(
(left) => showError(left.message),
(right) => showUser(right),
);
Either<L, R> fpdart سے ایک بائیں جانب دار قسم ہے: Left — غلطی، Right — کامیابی۔ fetchUser Either<AppError, User> لوٹاتا ہے، جہاں AppError ٹھوس غلطی کی اقسام (serverError، networkError) کے ساتھ ایک sealed class ہے۔ fold دونوں صورتوں کو سنبھالتا ہے: پہلا کال بیک Left (غلطی) کے لیے، دوسرا Right (کامیابی) کے لیے۔ Dart 3.0 میں، بلٹ ان Result بھی fold کو سپورٹ کرتا ہے، لیکن map/flatMap فراہم نہیں کرتا۔ زنجیروں کے لیے، fpdart سے Either map، flatMap (bind)، mapLeft، andThen فراہم کرتا ہے — غلطی کی ترکیب کے لیے فنکشنل کمبینیٹرز کا ایک مکمل سیٹ۔
استثنیات پر Result کا بنیادی فائدہ ترکیب ہے۔ اگر آپ کے پاس متعدد آپریشنز ہیں، جن میں سے ہر ایک ناکام ہو سکتا ہے، تو آپ انہیں بغیر کسی nested if یا try-catch کے map اور flatMap کا استعمال کرکے زنجیر بنا سکتے ہیں۔ map کامیابی کی قدر کو تبدیل کرتا ہے: Result.success(x) -> Result.success(f(x))۔ flatMap (جسے bind یا andThen بھی کہا جاتا ہے) ان صورتوں کے لیے ہے جہاں تبدیلی خود ایک Result لوٹاتی ہے: Result.success(x) -> f(x) -> Result<Y>۔ اگر کوئی مرحلہ Failure کے ساتھ ناکام ہوتا ہے، تو بعد کے آپریشنز انجام نہیں دیئے جاتے — زنجیر روک دی جاتی ہے۔
data class UserRequest(val userId: String, val token: String)
sealed class AuthError {
data object InvalidToken : AuthError()
data class UserNotFound(val id: String) : AuthError()
}
typealias Outcome<T> = Either<AuthError, T>
fun validateToken(token: String): Outcome<String> =
if (token.isNotBlank()) Either.right(token)
else Either.left(AuthError.InvalidToken)
fun fetchProfile(userId: String): Outcome<Profile> =
if (userId == "42") Either.right(Profile("Alice"))
else Either.left(AuthError.UserNotFound(userId))
// flatMap کے ذریعے ترکیب (fpdart میں andThen)
val result = validateToken("abc123")
.flatMap { fetchProfile("42") }
.map { it.name }
.getOrElse { "Guest" }
println(result) // "Alice"
زنجیر: validateToken -> fetchProfile -> map name -> getOrElse «مہمان»۔ اگر validateToken Left (InvalidToken) لوٹاتا ہے، تو زنجیر روک دی جاتی ہے اور «مہمان» لوٹاتی ہے۔ اگر fetchProfile Left (UserNotFound) لوٹاتا ہے — بھی «مہمان»۔ اگر دونوں آپریشنز کامیاب ہوتے ہیں — پروفائل کا نام۔ flatMap Either افعال کو یکجا کرنے کی اجازت دیتا ہے، جن میں سے ہر ایک ناکام ہو سکتا ہے، ایک لکیری زنجیر میں۔ روایتی استثنیٰ کے اسلوب میں، اسی کوڈ کے لیے دو nested try-catch یا null جانچ کی ضرورت ہوگی۔ آخر میں getOrElse ترکیب سے باہر نکلنے کا نقطہ ہے، جو Failure کی صورت کے لیے ایک ڈیفالٹ قدر فراہم کرتا ہے۔
Result اور استثنیات باہم مخصوص نقطہ نظر نہیں ہیں۔ ہر ایک کا اپنا ڈومین ہے، اور ایک اچھی طرح سے ڈیزائن کردہ موبائل ایپلیکیشن میں، دونوں استعمال ہوتے ہیں۔ انتخاب اس بات پر منحصر ہے کہ غلطی متوقع ہے یا غیر متوقع۔ Result متوقع غلطیوں کے لیے ہے جو کاروباری منطق کا حصہ ہیں: غلط ای میل، ناکافی فنڈز، شرح کی حد سے تجاوز۔ استثنیات غیر متوقع نظام کی غلطیوں کے لیے ہیں: نیٹ ورک کا نقصان، OutOfMemoryError، NullPointerException (جو نہیں ہونی چاہئیں لیکن ہوتی ہیں)۔
| معیار | Result Type | استثنیات (Exception/Error) |
|---|---|---|
| غلطی کی قسم | متوقع (کاروباری منطق) | غیر متوقع (نظام) |
| کارکردگی | کم لاگت (اسٹیک انوائنڈنگ کے بغیر) | زیادہ لاگت (اسٹیک انوائنڈنگ، StackTrace حصول) |
| ترکیب | map/flatMap کے ذریعے — لکیری زنجیریں | nested try-catch — پڑھنا مشکل |
| کمپائلر | جامع جانچ (switch/when) | صرف Java میں چیک شدہ استثنیات |
| عمل کا بہاؤ | روکا نہیں جاتا — غلطی ایک قدر کے طور پر | قریب ترین catch تک روک دیا جاتا ہے |
| جانچ | آسان: نتیجہ چیک کریں، isSuccess/isError کی تصدیق کریں | assertThrows اور mock آبجیکٹ کی ضرورت ہے |
| کب استعمال کریں | کاروباری توثیق، درخواست کی زنجیریں، فارم | نیٹ ورک کا نقصان، I/O غلطیاں، نظام کی خرابی |
عملی اصول: اگر غلطی ایپلیکیشن کے عام کام کے بہاؤ کا حصہ ہے (صارف نے غلط ای میل درج کی، ناکافی اجازتیں) — Result استعمال کریں۔ اگر غلطی ایک غیر معمولی صورت حال ہے (سرور جواب نہیں دے رہا، میموری ختم) — استثنیات استعمال کریں۔ موبائل ڈویلپمنٹ میں، پرتوں کی حدود میں Result (UseCase -> ViewModel) اور پرتوں کے اندر استثنیات (API -> Repository) ایک عام نمونہ ہے جو دونوں نقطہ نظر کے فوائد کو یکجا کرتا ہے۔
موجودہ استثنیٰ پر مبنی کوڈ کو Result میں منتقل کرنا بتدریج ہونا چاہیے۔ پرتوں کی حدود سے شروع کریں: throws فنکشن کالز کو Result { try ... } (Swift) یا runCatching { ... } (Kotlin) میں لپیٹیں۔ پھر Repository اور UseCase طریقوں کی واپسی کی قسم کو Result/Either سے بدلیں، اندرونی نفاذ کو استثنیات پر چھوڑتے ہوئے۔ آخری مرحلے میں، ViewModel کو منتقل کریں: استثنیات کے ساتھ UiState کے بجائے، ایک sealed class UiState<T> (Loading، Success، Error) استعمال کریں، جہاں Error ایک Throwable نہیں بلکہ ایک ڈومین غلطی ذخیرہ کرتا ہے۔ بتدریج منتقلی عالمی ری فیکٹرنگ کے بغیر ہر پرت کو الگ سے جانچنے کی اجازت دیتی ہے۔
اکثر پوچھے گئے سوالات
Optional (T?) کسی قدر کی موجودگی یا عدم موجودگی کی نمائندگی کرتا ہے — nil کا مطلب ہے «کوئی ڈیٹا نہیں» لیکن وجہ نہیں بتاتا۔ Result (Success/Failure) میں نہ صرف کامیابی بلکہ ایک ٹھوس قسم کے ساتھ غلطی کی وجہ بھی شامل ہے۔ Optional استعمال کریں جب عدم موجودگی معمول ہو (مثال کے طور پر، ایک اختیاری پروفائل فیلڈ)، اور Result استعمال کریں جب آپ کو غلطی کی معلومات کی ضرورت ہو۔
Swift میں، Result { try throwingFunc() } استعمال کریں — Result کنسٹرکٹر ایک throws closure لیتا ہے۔ Kotlin میں، runCatching { throwingFunc() } استعمال کریں، جو Result<T> لوٹاتا ہے۔ Dart میں، Result<T>.tryCatch(() => throwingFunc()) استعمال کریں۔ یہ Result زنجیروں میں استثنیٰ پر مبنی کوڈ کے آسان انضمام کی اجازت دیتا ہے۔
کامیابی کی قدر کو تبدیل کیے بغیر غلطی کی قسم کو تبدیل کرنے کے لیے mapError (Swift) یا mapLeft (Dart/Kotlin میں Either) استعمال کریں۔ اگر آپ کو دونوں صورتوں کو سنبھالنے اور ایک قدر لوٹانے کی ضرورت ہے، تو fold استعمال کریں۔ زنجیر کو روکے بغیر لاگنگ کے لیے، onFailure (Kotlin) یا ایک سابقہ معائنہ نقطہ استعمال کریں۔
ہاں، لیکن احتیاط سے۔ K2 کمپائلر اور عکاسی کی خصوصیات کی وجہ سے Kotlin Result<T> کو براہ راست suspend فنکشنز کی واپسی کی قسم کے طور پر تجویز نہیں کیا جاتا۔ Coroutines میں حالات کی نمائندگی کرنے کے لیے اپنی خود کی sealed class NetworkResult<T> (Success، Error، Loading) استعمال کریں۔ کاروباری منطق میں متوقع غلطیوں کے لیے، Arrow سے Either ایک زیادہ طاقتور متبادل ہے۔
fold ایک طریقہ ہے جو دو کال بیک لیتا ہے: onSuccess (کامیابی کی صورت کے لیے) اور onFailure (غلطی کی صورت کے لیے)، اور کسی بھی قسم کی ایک قدر لوٹاتا ہے۔ یہ switch اظہار کے برابر ہے لیکن ایک اعلیٰ ترتیب کے فنکشن کے طور پر۔ fold Result زنجیروں سے اہم خارجی نقطہ ہے، جہاں آپ Success/Failure کو UiState، صارف کے لیے ایک سٹرنگ یا کسی اور Result میں تبدیل کرتے ہیں۔
خلاصہ
ہم ایک موبائل ایپلیکیشن ٹرنکی تیار کریں گے
IT Sectr 2017 سے اسٹارٹ اپس اور کاروبار کے لیے iOS اور Android ایپلیکیشنز بناتا ہے۔ ہم آپ کو مشورہ دیں گے اور بہترین حل تجویز کریں گے۔
مزید پڑھیں