Question #223EasyFlutter Basics

What is the use of assert in flutter give me with some example ?

#flutter

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

dart
assert(condition);
assert(condition, 'Error message');

Simple Examples

dart
void 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

dart
class 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

dart
class 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

dart
class 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

dart
class 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

dart
class 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

dart
enum 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

dart
class 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

Featureassert()if-throwValidators
When executedDebug onlyAlwaysAlways
PerformanceNo impact in releaseImpact in releaseImpact in release
Use caseDeveloper errorsUser errorsUser input
ProductionRemovedActiveActive

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

dart
class 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

dart
class 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

dart
class 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