While Dart is in its core an object-oriented programming language, that doesn’t mean that you’re stuck only with that paradigm. In fact, Dart is something called a multi-paradigm language! Functional programming (FP) makes your code easier to test and reuse, and also makes it less error prone.
With Dart, it’s easy to start introducing practical functional concepts into your code in a reasonable amount. This way, you reap the benefits of FP while not confusing others (and yourself) with how your Dart code is written.
Imperative vs Functional Programming
Before we can start looking into any of the more advanced concepts of FP, let's get the basics out of the way so that we're all on the same page. Let's look at a very simple example where we want to sum the numbers inside a List<int>
. First up, the imperative approach:
main.dart
void imperative() {
/// Imperatively sum elements of a list
const List<int> list = [1, 2, 3, 4];
int sum = 0;
for (int i = 0; i < list.length; ++i) {
sum = sum + list[i];
}
}
These are absolutely simple few lines of code where we sum the integers inside of the List
using a for
loop.
In order to accomplish this though, we need to create a mutable int sum
, then another int i
that we don't even really care about, it's just there so that the for-loop can run. Inside of the loop, we mutate the sum
variable by adding to it the integer value present in the list at the index we're currently iterating over.
This is all simple, of course, but we're really managing the workings of our program by ourselves and telling it what to do step by step. Should this bit of code do something more complex than just summing a list of integers, we could have trouble reading and maintaining it.
Let's now look at how we can do the exact same thing in FP:
main.dart
void functional() {
/// Functionally sum elements of a list
const List<int> list = [1, 2, 3, 4];
final sum = list.fold<int>(
0, // initial value
(previous, current) => previous + current,
);
}
Instead of creating a for-loop, we call fold
on the list. We can declare the sum variable to be final
. It is no longer mutable thus making the code less error prone from us accidentally mutating this variable from another place in the codebase.
We also don't need to worry about managing a for-loop using some sort of an iterative variable. The fold
method operates on a higher level of abstraction and just provides us with the previous sum and the current element value that we can add to the previous sum. No need to worry about indexes or any other implementation details.
Overall, the functional approach has less moving parts and is less error-prone.
More Complex Example
In another just a little bit more complex code, we have a List<String>
from which we want to create a new List
that holds both the original String
and also its length inside of a record (String, int)
. Imperative code looks like the following:
main.dart
void imperative() {
/// Assign character count to strings
const List<String> strings = ['dart', 'is', 'awesome'];
final List<(String, int)> charCounts = [];
for (int i = 0; i < strings.length; ++i) {
charCounts.add((strings[i], strings[i].length));
}
}
If we now decide that the charCounts
list should only contain strings that are longer than two characters, we need to write an if-statement inside of the for-loop.
main.dart
void imperative() {
/// Assign character count to strings and leave only
/// the ones longer than 2 characters
const List<String> strings = ['dart', 'is', 'awesome'];
final List<(String, int)> charCounts = [];
for (int i = 0; i < strings.length; ++i) {
if (strings[i].length > 2) {
charCounts.add((strings[i], strings[i].length));
}
}
}
We again need to get into the already existing code, find out its implementation details (e.g. that the iteration variable is int i
) and only then can we add this new functionality.
If we implement the exact same thing in a functional approach (at first without filtering the strings by length), we get:
main.dart
void functional() {
/// Assign character count to strings
const List<String> strings = ['dart', 'is', 'awesome'];
final charCounts = strings.map((string) => (string, string.length));
}
map
, please read the official docs.The code is looking much cleaner without the for-loop already. However, the functional approach really shines once we try to filter the strings by length.
main.dart
void functional() {
/// Assign character count to strings and leave only
/// the ones longer than 2 characters
const List<String> strings = ['dart', 'is', 'awesome'];
final charCounts = strings
.where((string) => string.length > 2)
.map((string) => (string, string.length));
}
We don't need to get inside a previously written code and study its implementation details before we add the new functionality. All we need to do is to chain method calls that are separate from each other, yet can work together as well to create a brand new functionality.
It's something like pieces of Lego that look good separately but you can also join them in various ways. If we were to fit the imperative approach with the for-loop and an if-statement into this Lego analogy, it's as if we were not simply joining individual pieces together, but rather cutting things out with a scalpel and then melting these odd cut-up pieces together with a blowtorch (not so nice).
OOP vs FP Class Hierarchies
Dart is a strongly object-oriented programming language where everything is a class. Even all the functions you write are in the end understood as classes with a method, more specifically, subclasses of the Function
abstract class from the dart:core library.
This, however, doesn't mean that you are stuck with only the OOP paradigm! Dart has all the features needed to support a FP approach to class hierarchies by allowing you to create algebraic data types.
First, let's take a look at a regular class hierarchy. All of the following code has been taken from an official Dart article on Medium but I've modified the pseudocode to actually be able to compile and run.
main.dart
abstract class Recipe {
final int time;
final int temp;
final List<String> ingredients;
Recipe({
required this.time,
required this.temp,
required this.ingredients,
});
void bake();
}
class Cake extends Recipe {
Cake() : super(
time: 40,
temp: 325,
ingredients: ['Flour', 'Eggs', 'Milk'];
);
@override
void bake() => time * temp;
}
class Cookies extends Recipe {
Cookies() : super(
time: 25,
temp: 350,
ingredients: ['Flour', 'Butter', 'Sugar'];
);
@override
void bake() {
(time / 2) * temp;
//TODO: Rotate cookies
(time / 2) * (temp - 15);
}
}
The abstract base class Recipe
has three fields and a single method. All of the subclassed Cake
and Cookies
then assign their own values for these fields and implement the bake
method.
This is a standard example of a class hierarchy in OOP but let's now write the exact same thing with an FP approach.
main.dart
sealed class Recipe {
final int time;
final int temp;
final List<String> ingredients;
Recipe({
required this.time,
required this.temp,
required this.ingredients,
});
}
class Cake extends Recipe {
Cake()
: super(
time: 40,
temp: 325,
ingredients: ['Flour', 'Eggs', 'Milk'],
);
}
class Cookies extends Recipe {
Cookies()
: super(
time: 25,
temp: 350,
ingredients: ['Flour', 'Butter', 'Sugar'],
);
}
void bake(Recipe recipe) {
switch (recipe) {
case Cake():
recipe.time * recipe.temp;
case Cookies():
(recipe.time / 2) * recipe.temp;
//TODO: Rotate cookies
(recipe.time / 2) * (recipe.temp - 15);
}
}
Notice that the class Recipe
is no longer marked abstract
but rather sealed
. All the fields remain the same and the Cake
and Cookies
subclasses populate those fields with their own values through the super-constructor just as in the OOP approach but notice what's missing. There is no bake
method in any of the classes. Instead, it's now a top-level function.
Algebraic data types separate data from logic. The code run by the bake
function is exactly the same now as it was when it was a member method inside of the classes but now we're using a switch
statement to execute the proper code for any Recipe
subclass that was passed in.
Because the Recipe
base class is sealed
, the switch statement will not compile unless we switch through all the existing subclasses of Recipe
, so the FP code is just as safe to write as the OOP version.
Pure Functions
Separating data from the operation performed with that data resulted in having a top-level bake
function which is only dependent on its parameters and can "communicate with the outside" only by returning a value. Here it returns void
but the point still stands. This makes bake
a pure function.
main.dart
void bake(Recipe recipe) {
switch (recipe) {
case Cake():
recipe.time * recipe.temp;
case Cookies():
(recipe.time / 2) * recipe.temp;
//TODO: Rotate cookies
(recipe.time / 2) * (recipe.temp - 15);
}
}
With the OOP approach, the bake
function was a member of a class (a method), and accessed the fields of the class. Although in our case this didn't happen, such a method can also mutate fields of the class, thus making the return value not the only point of communication with the outside.
main.dart
class Cake extends Recipe {
Cake() : super(
time: 40,
temp: 325,
ingredients: ['Flour', 'Eggs', 'Milk'];
);
@override
void bake() => time * temp;
}
The advantages of a pure function as opposed to an unpure method are that it's easier to test and maintain since EVERYTHING a function does is contained within it. There are no possible side effects somewhere else in the codebase and you, for example, can't forget to mock an object while testing because every dependency of that function is passed in as an argument.
Error Handling
Another area where FP principles shine is error handling. Enough of those exceptions and try-catch statements all over the place! While we could write all the functional error handling code from scratch, we're going to use the fpdart package which is a must-have in your project if you want to move more into the FP paradigm.
pubspec.yaml
dependencies:
fpdart: ^1.1.0
Let's say we have the following enum implementation for a US-style grade that can be A, B, C, D or F and we also have a method for parsing strings. If the string contains something else that a valid grade letter character, we throw an ArgumentError
.
main.dart
enum Grade {
A, B, C, D, F;
static Grade parse(String grade) => switch (grade.toUpperCase()) {
'A' => Grade.A,
'B' => Grade.B,
'C' => Grade.C,
'D' => Grade.D,
'F' => Grade.F,
_ => throw ArgumentError('Invalid grade: $grade'),
};
}
The problem with throwing errors like this is that the following will compile without an issue.
main.dart
void main() {
final grade = Grade.parse('definitely not valid string');
somehowUseGrade(grade);
}
You see that? We're missing a try-catch block but we're going to find about this only at runtime when our app crashes because of an uncaught ArgumentError
.
It's easy enough to remember to wrap the grade parsing with a try-catch in this small example code but in complex apps its incredibly hard, if not impossible, to remember which method throws which kind of an exception and to catch everything properly.
Sure, you can write documentation and comments all over the place but still, you're relying on yourself to remember things. It would be much better to let the Dart compiler let you know that you're not handling errors correctly. Failing at compile time is what we want, not at run time.
Using Either
The fpdart package provides us with a type called Either
. In its principle it is a generic sealed class with two subclasses - Left
and Right
. The left "side" of Either holds the error while the right side holds the right (correct) value.
The principle of using Either
is to unify the exception flow and data flow into the return type of a function. In our simple case, the left side will hold only the error message string.
main.dart
enum Grade {
A, B, C, D, F;
static Either<String, Grade> parse(String grade) =>
switch (grade.toUpperCase()) {
// Instantiating a Right subclass of Either directly
'A' => Right(Grade.A),
// The convention is to use a helper function though (lower case "r")
'C' => right(Grade.C),
'B' => right(Grade.B),
'D' => right(Grade.D),
'F' => right(Grade.F),
// Error goes into the Left subclass of Either
_ => left('Invalid grade: $grade'),
};
}
Since we've eliminated the separate flow of exceptions the following code will not compile.
main.dart
void main() {
final grade = Grade.parse('A');
// Error: Argument type 'Either' can't be assigned to parameter type 'Grade'.
somehowUseGrade(grade);
}
We're now forced to handle the error and that's a good thing! Either
is just a regular sealed class so we can technically use the regular switch statement...
main.dart
void main() {
final gradeEither = Grade.parse('A');
switch (gradeEither) {
case Left(value: final l):
handleError(l);
case Right(value: final r):
somehowUseGrade(r);
}
}
But the convention is to use the helper match
method on the Either
class to do the same thing in less lines of code.
main.dart
void main() {
final gradeEither = Grade.parse('A');
gradeEither.match(
(l) => handleError(l),
(r) => somehowUseGrade(r),
);
}
Conclusion
In this tutorial you've learned the basics of practical functional programming principles and also error handling using the Either type. Understanding these foundations allows you to venture further into functional programming with the fpdart package. I will cover some of the more advanced techniques of writing FP code in an upcoming tutorial so make sure you're subscribed not to miss it!
مرافق تصنيع إيليت بايب Elite Pipe مجهزة بأحدث الآلات ، مما يتيح عمليات الإنتاج الفعالة وجودة المنتج المتسقة.
Matt, Welcome back!!!
To be honest I thought you were lost due to Covid 19.
lol.
يعمل مصنع إيليت بايب Elite Pipe في العراق كمحفز لتطوير البنية التحتية ، حيث يزود السوق بأنابيب البولي إيثيلين عالي الكثافة وأنابيب uPVC والتجهيزات التي تساهم في نمو ونجاح مختلف القطاعات.
certainly like your website but you need to take a look at the spelling on quite a few of your posts. Many of them are rife with spelling problems and I find it very troublesome to inform the reality nevertheless I will definitely come back again.
What i do not realize is in fact how you are no longer actually much more well-favored than you might be right now. You’re very intelligent. You recognize thus considerably in relation to this topic, made me in my view believe it from numerous numerous angles. Its like men and women are not fascinated until it is one thing to do with Lady gaga! Your own stuffs excellent. All the time handle it up!
Wonderful beat ! I wish to apprentice while you amend your web site, how could i subscribe for a blog web site? The account aided me a acceptable deal. I had been a little bit acquainted of this your broadcast provided bright clear idea
What i do not understood is in truth how you are not actually a lot more smartly-liked than you may be now. You are very intelligent. You realize therefore significantly in the case of this topic, produced me individually imagine it from numerous numerous angles. Its like men and women don’t seem to be fascinated until it is one thing to do with Woman gaga! Your own stuffs nice. All the time care for it up!
Hello, Neat post. There’s an issue together with your site in internet explorer, would check this텶E still is the marketplace chief and a large element of other folks will leave out your magnificent writing due to this problem.
Thanks, I have recently been looking for info about this subject for a while and yours is the greatest I have discovered so far. However, what in regards to the bottom line? Are you certain in regards to the supply?
I was recommended this website by my cousin. I am not sure whether this post is written by him as nobody else know such detailed about my difficulty. You are wonderful! Thanks!
I am not sure where you’re getting your info, but good topic. I needs to spend some time learning much more or understanding more. Thanks for magnificent info I was looking for this information for my mission.
I do agree with all the ideas you have introduced on your post. They are very convincing and will definitely work. Still, the posts are very short for newbies. May just you please prolong them a little from subsequent time? Thank you for the post.
Monetize your website Best Affiliate Community
Learn to make money online Affiliate Discord
Join affiliate marketing community Top Affiliate Marketing
Learn to make money online Affiliate Marketing Community
Learn about affiliate marketing Best Affiliate Community
Learn about affiliate marketing Affiliate Marketing Community
Monetize your website Affiliate Discord
Fantastic beat I would like to apprentice while you amend your web site how could i subscribe for a blog site The account helped me a acceptable deal I had been a little bit acquainted of this your broadcast offered bright clear concept
Hey,
The moment we’ve all been waiting for is finally here – GoBuildr is now LIVE! 🎉
🌐 Create ultra-lightning-fast websites, sales funnels, eCommerce stores, and more in less than 60 seconds, with just a keyword!
🚀 Say goodbye to the limitations of traditional page builders. GoBuildr combines the functionality of 16 different tools into one powerful app, supercharged with AI-assisted technology.
⇒ Click Here To Checkout Demo https://ext-opp.com/GoBuildr
Escort Sakarya Bayan Birbirinden güzel kadınlarla alakadar ne ararsanız bulabileceğiniz Bayan arkadaş arama sayfası sizin için 24 saat hizmet sunar.
He Got 256,354 Free Views With AI…
Can you believe it?
People spend thousands of dollars to get that kind of result…
My friend Kundan just did it for free…
He only used his new app… AI ScreenSnap…
It’s the world’s first AI app that can generate videos with the power of Video-Exclusive AI Engine…
That can edit, record, and generate videos with just a few clicks… with zero experience…
Click here now and watch AI ScreenSnap in action https://ext-opp.com/AIScreenSnap
men thats great very good..
Fantastic site Lots of helpful information here I am sending it to some friends ans additionally sharing in delicious And of course thanks for your effort
men thats great very nice..
Narin ve tatlı, aynı zamanda escort sakarya sakarya arkadaş canlısı ve eğlenceyi seven bir insanım. Her zaman gülümseyen ve çok açık fikirli güzel bir hanımefendiyim. Doğal bir vücudum var, inanılmaz deneyim arayışında iseniz o halde ne arzuladığınızı bana iletebilirsiniz.
Usually I do not read article on blogs however I would like to say that this writeup very compelled me to take a look at and do so Your writing taste has been amazed me Thanks quite nice post
hi brother
i want ask can i use new feature in dart 3 records instead of dartz and fpdart ?
Normally I do not read article on blogs however I would like to say that this writeup very forced me to try and do so Your writing style has been amazed me Thanks quite great post
I really like reading through a post that can make men and women think. Also, thank you for allowing me to comment!
It seems like you’re repeating a set of comments that you might have come across on various websites or social media platforms. These comments typically include praise for the content, requests for improvement, and expressions of gratitude. Is there anything specific you’d like to discuss or inquire about regarding these comments? Feel free to let me know how I can assist you further!
Thank you for reaching out! If you have any specific questions or topics in mind, please feel free to share them, and I’ll do my best to assist you. Whether you’re curious about a particular technology, scientific concept, literary work, or anything else, I’m here to provide information, advice, or engage in a discussion. Don’t hesitate to let me know how I can help you further!
A.I Create & Sell Unlimited Audiobooks to 2.3 Million Users – https://ext-opp.com/ECCO
Su kaçağı tespiti, genellikle duvarların kırılmasını gerektirmez. Gelişmiş teknolojiler, hasarı en aza indirirken kaçağı doğru bir şekilde tespit etmeyi mümkün kılar. https://www.ucuzailan.com/kadikoy-su-tesisatcisi-221
Create Stunning Ebooks In 60 Seconds – https://ext-opp.com/AIEbookPal
I appreciate you sharing this blog post. Thanks Again. Cool.
Elevate Learning Adventures with The Story Shack!
A library of 200+ high-quality books tailored to the school curriculum.
StoryShack’s Build a Book bundle features word searches, quizzes, creative coloring pages, high-quality images, and top SEO keywords.
StoryShack’s StoryCraft Pro bundle includes the “Melody Minds Library” with 350+ music tracks and “AnimateMasters Pro,” offering 30+ categories of animations.
And as if that’s not enough, here are the MEGA BONUSES:
✔ 100+ Mega Mazes Pack
✔ 100+ Sudoku Elements Pack
✔ 100+ Comic Book Template Pack
✔ 100+ Handwriting Practice Template Pack
✔ 100+ Kids Story Book Templates
✔ Canva Book Templates
✔ Additional beautiful content like journal prompts
✔ INCLUDED: The Ultimate Workbook
Click https://ext-opp.com/StoryShack to explore The Story Shack e-Learning Collection and seize the opportunity for multiplied income!
kalorifer peteği yeri değiştirme Beşiktaş Su Kaçağı Tespiti hizmetimiz ile bu sorunların tespiti yapılarak, doğru bir şekilde çözüme kavuşturulması sağlanır. Bu hizmet sayesinde https://blooder.net/read-blog/25057
Su sızıntısı bulma teknikleri Şişli Şişli su tesisatçısı, işlerini titizlikle yapan ve müşteri memnuniyetini her şeyin önünde tutan bir firma. https://travelwithme.social/read-blog/25642
Ümraniye da profesyonel tesisatçılar Ümraniye da lavabo tıkanıklığı yaşadığımızda, bu firma ile iletişime geçtik ve son derece memnun kaldık. Hızlı cevapları ve etkili çözümleri sayesinde sorunumuz kısa sürede ortadan kalktı.Teşekkür ederim! https://worldknowledge.wiki/umraniye-tikali-kanal-acma/
Millions of Free Traffic with AI Tools – https://ext-opp.com/AIVault
Ümraniye televizyon montajı Ümraniye’de elektrik tamiratı hizmeti, evlerin ve iş yerlerinin elektrik sistemlerinde oluşabilecek herhangi bir arızayı düzeltmek için hayati öneme sahiptir. Elektrik tamircileri, uzman bilgi ve deneyimleriyle elektrik ağını kontrol eder, arızaları tespit eder ve güvenli bir şekilde onarım yaparlar. Ümraniye’deki bu hizmet, kesintisiz elektrik sağlamak ve güvenliği sağlamak için kritik bir rol oynar. https://web.humansnet.com/read-blog/2132
Beşiktaş Su Kaçağı Bulma Fiyatları Beşiktaş Su Sızıntı Tespiti ihtiyaçlarınızda teknolojik ekipmanlarımız ve uzman kadromuz ile hizmetinizdeyiz. https://thechirobar.com/?p=296862
Thank you for your response! I’m grateful for your willingness to engage in discussions. If there’s anything specific you’d like to explore or if you have any questions, please feel free to share them. Whether it’s about emerging trends in technology, recent breakthroughs in science, intriguing literary analyses, or any other topic, I’m here to assist you. Just let me know how I can be of help, and I’ll do my best to provide valuable insights and information!
MobiApp AI – True Android & iOS Mobile Apps Builder (Zero Coding Required) https://ext-opp.com/MobiAppAI
Kadıköy elektrikçi olarak kadıköy ilçesine yakın bir konumdayız. Hizmetlerimizi en iyi ekipmanlar ile en uygun fiyatlara yapıyoruz Kadıköy Elektrik Ustası. Kadıköy merkez ve kadıköyün bütün mahallerine profosyonel hizmet kalitesi ile hizmet veriyoruz. https://kansabook.com/ustaelektrikci
kalorifer peteği değişimi fiyatı Ümraniye’deki kanal görüntüleme hizmetlerinin, çevreye duyarlı ve güvenli ekipmanlarla yapılması önemlidir. Bu, hem işçilerin hem de çevrenin sağlığını korur. https://lifeinsuranceacademy.org/?p=10810
Word’s First NLP & ML Based Email, Voice & Video Marketing Autoresponder Thats Boost Email Delivery, Click & Open Rates Instantly https://ext-opp.com/VidMailsAI