What is the use of assert in flutter give me with some example ?
Answer
assert() in Flutter
assert() is a debugging tool in Dart/Flutter that validates assumptions during development. It helps catch bugs early by verifying conditions that should always be true.
What is assert()?
An assert statement checks a boolean condition and throws an error if the condition is false, but only in debug mode. In release/production builds, assert statements are completely ignored.
Basic Syntax
dartassert(condition); assert(condition, 'Error message');
Simple Examples
dartvoid setAge(int age) { assert(age >= 0, 'Age cannot be negative'); assert(age <= 150, 'Age seems unrealistic'); this.age = age; } void divide(double a, double b) { assert(b != 0, 'Cannot divide by zero'); return a / b; } class User { final String name; final String email; User({required this.name, required this.email}) { assert(name.isNotEmpty, 'Name cannot be empty'); assert(email.contains('@'), 'Invalid email format'); } }
Assert in Flutter Widgets
1. Constructor Validation
dartclass CustomButton extends StatelessWidget { final String text; final VoidCallback? onPressed; final Color? color; const CustomButton({ Key? key, required this.text, this.onPressed, this.color, }) : assert(text.length > 0, 'Button text cannot be empty'), super(key: key); Widget build(BuildContext context) { return ElevatedButton( onPressed: onPressed, style: ElevatedButton.styleFrom(backgroundColor: color), child: Text(text), ); } }
2. State Validation
dartclass CounterWidget extends StatefulWidget { final int initialValue; final int maxValue; const CounterWidget({ Key? key, this.initialValue = 0, this.maxValue = 100, }) : assert(initialValue >= 0, 'Initial value must be non-negative'), assert(maxValue > initialValue, 'Max must be greater than initial'), super(key: key); _CounterWidgetState createState() => _CounterWidgetState(); } class _CounterWidgetState extends State<CounterWidget> { late int _counter; void initState() { super.initState(); _counter = widget.initialValue; assert(_counter >= 0, 'Counter initialized with negative value'); } void increment() { assert(_counter < widget.maxValue, 'Counter exceeded max value'); setState(() => _counter++); } Widget build(BuildContext context) { return Column( children: [ Text('Counter: $_counter'), ElevatedButton( onPressed: increment, child: Text('Increment'), ), ], ); } }
Real-World Examples
1. List Operations
dartclass TodoList { final List<String> _todos = []; void addTodo(String todo) { assert(todo.isNotEmpty, 'Cannot add empty todo'); assert(!_todos.contains(todo), 'Todo already exists'); _todos.add(todo); } void removeTodoAt(int index) { assert(index >= 0, 'Index cannot be negative'); assert(index < _todos.length, 'Index out of bounds'); _todos.removeAt(index); } String getTodo(int index) { assert(index >= 0 && index < _todos.length, 'Index out of bounds: $index (length: ${_todos.length})'); return _todos[index]; } }
2. API Response Validation
dartclass ApiService { Future<User> fetchUser(int userId) async { assert(userId > 0, 'User ID must be positive'); final response = await http.get( Uri.parse('https://api.example.com/users/$userId'), ); assert(response.statusCode == 200, 'API call failed with status: ${response.statusCode}'); final data = json.decode(response.body); assert(data != null, 'Response body is null'); assert(data is Map, 'Response is not a Map'); return User.fromJson(data); } }
3. Widget Constraints
dartclass ResponsiveContainer extends StatelessWidget { final double width; final double height; final Widget child; const ResponsiveContainer({ Key? key, required this.width, required this.height, required this.child, }) : assert(width > 0, 'Width must be positive'), assert(height > 0, 'Height must be positive'), assert(width <= 1000, 'Width too large: $width'), assert(height <= 1000, 'Height too large: $height'), super(key: key); Widget build(BuildContext context) { return Container( width: width, height: height, child: child, ); } }
4. State Machine Validation
dartenum LoadingState { idle, loading, success, error } class DataManager { LoadingState _state = LoadingState.idle; dynamic _data; void startLoading() { assert(_state == LoadingState.idle, 'Cannot start loading from state: $_state'); _state = LoadingState.loading; } void setData(dynamic data) { assert(_state == LoadingState.loading, 'Can only set data when loading. Current state: $_state'); assert(data != null, 'Cannot set null data'); _data = data; _state = LoadingState.success; } void setError(String error) { assert(_state == LoadingState.loading, 'Can only set error when loading. Current state: $_state'); assert(error.isNotEmpty, 'Error message cannot be empty'); _state = LoadingState.error; } dynamic getData() { assert(_state == LoadingState.success, 'Cannot get data in state: $_state'); assert(_data != null, 'Data is null'); return _data; } }
5. Form Validation
dartclass RegistrationForm extends StatefulWidget { _RegistrationFormState createState() => _RegistrationFormState(); } class _RegistrationFormState extends State<RegistrationForm> { final _formKey = GlobalKey<FormState>(); String? _username; String? _email; String? _password; void submit() { assert(_formKey.currentState != null, 'Form key is null'); if (_formKey.currentState!.validate()) { _formKey.currentState!.save(); assert(_username != null && _username!.isNotEmpty, 'Username should be validated'); assert(_email != null && _email!.contains('@'), 'Email should be validated'); assert(_password != null && _password!.length >= 8, 'Password should be validated'); print('Form submitted: $_username, $_email'); } } Widget build(BuildContext context) { return Form( key: _formKey, child: Column( children: [ TextFormField( validator: (value) { assert(value != null, 'Validator received null value'); return value?.isEmpty ?? true ? 'Required' : null; }, onSaved: (value) { assert(value != null && value.isNotEmpty, 'Saved value should be valid'); _username = value; }, ), ElevatedButton( onPressed: submit, child: Text('Submit'), ), ], ), ); } }
Assert vs Other Validation
| Feature | assert() | if-throw | Validators |
|---|---|---|---|
| When executed | Debug only | Always | Always |
| Performance | No impact in release | Impact in release | Impact in release |
| Use case | Developer errors | User errors | User input |
| Production | Removed | Active | Active |
Comparison Examples:
dart// ❌ Wrong: Using assert for user input validation void processUserAge(int age) { assert(age >= 18, 'Must be 18+'); // Removed in production! // User can bypass in production } // ✅ Correct: Use runtime check for user input void processUserAge(int age) { if (age < 18) { throw ArgumentError('Must be 18 or older'); } // Always validated } // ✅ Correct: Use assert for developer assumptions void calculateDiscount(int age, double price) { assert(age >= 0, 'Age validated before calling this'); assert(price >= 0, 'Price validated before calling this'); // Developer assumption: inputs already validated return price * (age >= 65 ? 0.8 : 1.0); }
Common Use Cases
1. Null Safety Assumptions
dartclass UserProfile { String? _cachedName; void cacheName(String name) { assert(name.isNotEmpty, 'Cannot cache empty name'); _cachedName = name; } String getCachedName() { assert(_cachedName != null, 'Name not cached yet'); return _cachedName!; // Safe because of assert } }
2. Callback Validation
dartclass CustomWidget extends StatelessWidget { final VoidCallback? onTap; final bool requiresTap; const CustomWidget({ Key? key, this.onTap, this.requiresTap = false, }) : assert(!requiresTap || onTap != null, 'onTap is required when requiresTap is true'), super(key: key); Widget build(BuildContext context) { return GestureDetector( onTap: onTap, child: Container(), ); } }
3. Debug-Only Checks
dartclass DebugHelper { static void logWidgetBuild(String widgetName) { assert(() { print('Building widget: $widgetName at ${DateTime.now()}'); return true; }()); } } class MyWidget extends StatelessWidget { Widget build(BuildContext context) { DebugHelper.logWidgetBuild('MyWidget'); return Container(); } }
Best Practices
- Use assert for developer errors, not user errors
- Add descriptive error messages
- Assert preconditions at function start
- Assert postconditions before returning
- Don't rely on assert in production
- Use assert to document assumptions
Common Patterns
dart// Validate constructor parameters class Product { final String name; final double price; Product(this.name, this.price) : assert(name.isNotEmpty), assert(price >= 0); } // Validate state transitions enum State { idle, running, stopped } class Machine { State _state = State.idle; void start() { assert(_state == State.idle); _state = State.running; } void stop() { assert(_state == State.running); _state = State.stopped; } } // Validate collections void processList(List<int> numbers) { assert(numbers.isNotEmpty, 'List cannot be empty'); assert(numbers.every((n) => n >= 0), 'All numbers must be non-negative'); }
Important: assert() is a powerful debugging tool but should never be used for user input validation or business logic. It's completely removed in production builds for performance reasons.
Learn more at Dart Assert Documentation