# Type casting in Dart

# The "is" operator

## Purpose

The `is` keyword in Dart is used for type checking. It evaluates to `true` if the object has the specified type, and `false` otherwise. This can be particularly useful when you need to ensure an object is of a certain type before performing operations or accessing properties specific to that type.

## Example

```dart
class Animal {
  void breathe() {
    print("Breathing");
  }
}

class Fish extends Animal {
  void swim() {
    print("Swimming");
  }
}

void main() {
  Animal a = Fish();
  
  if (a is Fish) {
    // This block will execute because 'a' is indeed an instance of Fish
    print("It's a fish!");
    a.swim(); // This is safe to call because we've checked that 'a' is a Fish
  } else {
    print("It's not a fish");
  }
}
```

The `is` keyword is particularly useful in scenarios involving polymorphism or when dealing with collections of objects with a common superclass. It allows your code to dynamically identify the specific subtype of an object at runtime and safely perform type-specific operations.

Here's another example with a list of mixed types:

```dart
void main() {
  List<Animal> animals = [Fish(), Animal()];

  for (var animal in animals) {
    if (animal is Fish) {
      (animal as Fish).swim(); // Casting is necessary to call swim
    } else {
      animal.breathe();
    }
  }
}
```

# The "as" operator

## Purpose

The `as` keyword in Dart is used for typecast operations, allowing you to specify that an object belongs to a particular type. This can be useful in situations where you want to treat an instance of a superclass as if it were an instance of a subclass, or more generally, when you're sure that an object of a certain base type is actually a specific subtype and you want to access its properties or methods that aren't available on the base type.

## Example

```dart
class Animal {
  void breathe() {
    print("Breathing");
  }
}

class Fish extends Animal {
  void swim() {
    print("Swimming");
  }
}

void main() {
  Animal a = Fish();
  
  // Without casting, you can't call swim on an Animal
  // a.swim(); // This would be an error
  
  // Using 'as' to cast 'a' to Fish so we can call swim()
  (a as Fish).swim(); // This works
  
  // This is also a way to assert the type at runtime.
  // If 'a' was not a Fish, this would throw a TypeError.
}
```

It's important to use `as` cautiously, as it introduces the possibility of a runtime error if the object is not of the type you're casting to. Dart will throw a `TypeError` if the cast is invalid at runtime, which helps catch mistakes but also means you should be confident in your type assumptions when using `as`

# **Important Considerations**

* **Type Safety**: While the `as` operator can override compile-time type checks, it can lead to runtime errors if the cast is incorrect. Use it judiciously and only when you are certain of the object's type.
    
* **Performance**: Frequent use of `as` and `is` might impact performance. It's best to design your code in a way that minimizes the need for type checks and casts.
