Tutorial

Introduction to Mixins in Dart

Published on October 9, 2019
    author

    Joshua Hall

    Introduction to Mixins in Dart

    Some of the best reasons for using object-oriented programming (OOP) are its techniques for helping to keep our code clean and DRY. We’re going to explore some of Dart’s strategies for making your code reusable over separate classes.

    The Problem

    Imagine we have two creature classes, each of them with their own set of behaviors. The obvious solution would be to just directly outline the methods for each class as we need them, but many classes aren’t going to be entirely unique and will share a lot of commonality with each other. We obviously want to find the most efficient structure for writing these classes in the most reusable way.

    Our animals will have a few specific actions they can perform and a larger behavior composed out of them. As you can see, their diet may be different, but the methods are mostly the same and should ideally be broken out into something more reusable.

    main.dart
    class Alligator {
      void swim() => print('Swimming');
      void bite() => print('Chomp');
      void crawl() => print('Crawling');
      void hunt() {
        print('Alligator -------');
        swim();
        crawl();
        bite();
        print('Eat Fish');
      }
    }
    
    class Crocodile {
      void swim() => print('Swimming');
      void bite() => print('Chomp');
      void crawl() => print('Crawling');
      void hunt() {
        print('Crocodile -------');
        swim();
        crawl();
        bite();
        print('Eat Zebra');
      }
    }
    
    main() {
      Crocodile().hunt();
      Alligator().hunt();
    }
    
    // Output should be 
    // Crocodile -------
    // Swimming
    // Crawling
    // Chomp
    // Eat Zebra
    // Alligator -------
    // Swimming
    // Crawling
    // Chomp
    // Eat Fish
    

    Extensions

    The most common option we have is extensions, where we can take the properties and methods on one class and make them available in another. Since we wouldn’t use Reptile in its own instance, we can set it as an abstract class so it can’t be initialized, just extended.

    main.dart
    abstract class Reptile {
      void bite() => print('Chomp');
      void swim() => print('Swimming');
      void crawl() => print('Crawling');
      void hunt() {
        print('${this.runtimeType} -------');
        swim();
        crawl();
        bite();
      }
    }
    
    class Alligator extends Reptile {
        // Alligator Specific stuff...
    }
    
    class Crocodile extends Reptile {
        // Crocodile Specific stuff...
    }
    
    main() {
      Crocodile().hunt('Zebra');
      Alligator().hunt('Fish');
    }
    

    Mixins

    That’s nice for our current example, but as we added more animals it would quickly become evident that many of theses methods aren’t just for Reptiles. If we wanted to create a Fish class with a swim method, instead of just extending Reptile, which is very limiting when we need more functionality from other classes, since we can only use extends one per class. We can use mixins to break our more universal behaviors into smaller, more reusable components that we can add to whatever class we need them in.

    We just need to use the mixin type to store our methods and use the with keyword on every class we want it included in. Unlike extends, we can add as many mixins as we want to a class.

    main.dart
    mixin Swim {
      void swim() => print('Swimming');
    }
    
    mixin Bite {
      void bite() => print('Chomp');
    }
    
    mixin Crawl {
      void crawl() => print('Crawling');
    }
    
    abstract class Reptile with Swim, Crawl, Bite {
      void hunt(food) {
        print('${this.runtimeType} -------');
        swim();
        crawl();
        bite();
        print('Eat $food');
      }
    }
    
    class Alligator extends Reptile {
      // Alligator Specific stuff...
    }
    
    class Crocodile extends Reptile {
      // Crocodile Specific stuff...
    }
    
    class Fish with Swim, Bite {
      void feed() {
        print('Fish --------');
        swim();
        bite();
      }
    }
    
    main() {
      Crocodile().hunt('Zebra');
      Alligator().hunt('Fish');
      Fish().feed();
    }
    

    On

    The last trick we have is the ability to do something that I like to think about as a reverse-extension. We can create a mixin that utilizes the methods from a class, which we can then use with each subclass.

    If we wanted to break Hunt into its own mixin, we can use the on keyword to tell it that it will only be used on the Reptile class, which will give it access to all of its functionality, like our Swim, Crawl, and Bite mixins.

    This configuration should have the exact same output as our first one.

    main.dart
    mixin Hunt on Reptile {
      void hunt(food) {
        print('${this.runtimeType} -------');
        swim();
        crawl();
        bite();
        print('Eat $food');
      }
    }
    
    abstract class Reptile with Swim, Crawl, Bite {}
    
    class Alligator extends Reptile with Hunt {
      // Alligator Specific stuff...
    }
    
    class Crocodile extends Reptile with Hunt {
      // Crocodile Specific stuff...
    }
    

    Conclusion

    With the growing popularity of Flutter, it’s a good idea to get a good foundational understanding of the basics of the Dart programming language. Hopefully this was a helpful introduction into clarifying some of the mysteries around reusing Dart classes.

    Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

    Learn more about our products

    About the authors
    Default avatar
    Joshua Hall

    author

    While we believe that this content benefits our community, we have not yet thoroughly reviewed it. If you have any suggestions for improvements, please let us know by clicking the “report an issue“ button at the bottom of the tutorial.

    Still looking for an answer?

    Ask a questionSearch for more help

    Was this helpful?
     
    1 Comments
    

    This textbox defaults to using Markdown to format your answer.

    You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

    Thank you so much, It was very helpful and easy to understand.

    Try DigitalOcean for free

    Click below to sign up and get $200 of credit to try our products over 60 days!

    Sign up

    Join the Tech Talk
    Success! Thank you! Please check your email for further details.

    Please complete your information!

    Become a contributor for community

    Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

    DigitalOcean Documentation

    Full documentation for every DigitalOcean product.

    Resources for startups and SMBs

    The Wave has everything you need to know about building a business, from raising funding to marketing your product.

    Get our newsletter

    Stay up to date by signing up for DigitalOcean’s Infrastructure as a Newsletter.

    New accounts only. By submitting your email you agree to our Privacy Policy

    The developer cloud

    Scale up as you grow — whether you're running one virtual machine or ten thousand.

    Get started for free

    Sign up and get $200 in credit for your first 60 days with DigitalOcean.*

    *This promotional offer applies to new accounts only.