1 / 32
⭐ 0 pts
Start
Lists
Strings
Maps
Fn
Classes
Inherit
Mixins
Enums
Q1
Q2
Q3
Q4
TxnProc
Analyzer
Utils
BankApp
Week 2 · Day 3

Lists, Functions &
Classes Mastery

Master the tools you learned. Then build something real with classes.

📋 Lists & Maps 🔤 String Methods 🔧 Functions 🔒 Closures 🏗️ Classes 📈 Inheritance 🎭 Mixins 🎯 Enums 🎮 4 Quizzes + Project

Press J anytime to jump to any section. Arrow keys to navigate.

Quick recap

What we covered in Day 2

Click any card to revisit the concept before we go deeper.

📦

Variables & Types

var, final, const, int, String, List, Map

🔗

Strings & Null

interpolation, ?, ??

⚙️

Operators

arithmetic, comparison, logical

🔀

Control Flow

if/else, for, while

🔧

Functions

void, return, named params, arrow

🏗️

Classes

blueprint, constructor, methods

Today we go deeper on all of these — using one project: building a bank 🏦

Topic 1 · Lists

List — Power Methods

var balances = [5000, 1200, 800, 15000, 3000, 500];

// Find & Filter
balances.where((b) => b > 2000); // (5000, 15000, 3000)
balances.any((b) => b > 10000); // true
balances.every((b) => b > 0); // true
balances.firstWhere((b) => b > 10000); // 15000

// Transform
balances.map((b) => b * 1.05); // add 5% interest
balances.fold(0, (sum, b) => sum + b); // 25500 (total)
balances.reduce((a, b) => a > b ? a : b); // 15000 (max)

// Sort
balances.sort(); // ascending
balances.sort((a, b) => b - a); // descending
.where()

Filter — keep items that match a condition

.map()

Transform — change each item into something new

.fold()

Accumulate — combine all items into one value

.any() / .every()

Check conditions — does any/every item pass?

.firstWhere()

Find first match — returns the first item that passes

Topic 1 · Lists

Method Chaining — step by step

Chain multiple methods together. Each step transforms the data.

var balances = [5000, 1200, 800, 15000, 3000, 500];

var result = balances
  .where((b) => b >= 1000) // Step 1
  .map((b) => b * 1.05) // Step 2
  .map((b) => 'Rs.${b.toStringAsFixed(0)}')
  .toList(); // Step 4

// ['Rs.5250', 'Rs.1260', 'Rs.15750', 'Rs.3150']
1
.where(b >= 1000)
Filter out low balances → [5000, 1200, 15000, 3000]
2
.map(b * 1.05)
Add 5% interest → [5250, 1260, 15750, 3150]
3
.map('Rs.$b')
Format as text → ['Rs.5250', 'Rs.1260', ...]
4
.toList()
Convert Iterable back to a List

📌 .where() and .map() return Iterable — call .toList() at the end to get a List back

Topic 2 · Strings

String Methods — Daily Tools

PARSING & SEARCHING
var txn = ' DEPOSIT: Rs.5000 from ATM ';

txn.trim(); // 'DEPOSIT: Rs.5000 from ATM'
txn.split(':'); // [' DEPOSIT', ' Rs.5000...']
txn.contains('DEPOSIT'); // true
txn.startsWith(' DEP'); // true
txn.indexOf('Rs.'); // 12
txn.substring(2, 9); // 'DEPOSIT'
FORMATTING
var name = 'aayush bhattarai';

name.toUpperCase(); // 'AAYUSH BHATTARAI'
name.toLowerCase(); // 'aayush bhattarai'
name[0].toUpperCase() + name.substring(1);
// 'Aayush bhattarai'

var acctNo = '42';
acctNo.padLeft(8, '0'); // '00000042'

var desc = 'ATM-DEPOSIT-KTM';
desc.replaceAll('-', ' '); // 'ATM DEPOSIT KTM'

📌 Strings are immutable — methods return NEW strings, they don't change the original

Topic 3 · Maps

Map — Key-Value Power

var accounts = {
  'Aayush': 15000,
  'Sita': 8000,
  'Ram': 3000,
  'Aarav': 25000,
};

// Access & Modify
accounts['Aayush']; // 15000
accounts['Priya'] = 5000; // add new
accounts.remove('Ram'); // remove
accounts.update('Sita', (b) => b + 1000);

// Check
accounts.containsKey('Aayush'); // true
accounts.containsValue(25000); // true
accounts.length; // 4
// Iterate
accounts.forEach((name, balance) {
  print('$name: Rs.$balance');
});

// Transform
accounts.entries
  .where((e) => e.value > 10000)
  .map((e) => '${e.key} is rich!')
  .toList();

// Keys & Values
accounts.keys; // (Aayush, Sita, Aarav, Priya)
accounts.values; // (15000, 9000, 25000, 5000)

// Remove conditionally
accounts.removeWhere((k, v) => v < 5000);
🎮 Interactive · Transaction Processor

Process transactions — click each step

Each button shows a different List operation on real bank transaction data.

📥 Deposits
📤 Withdrawals
💰 Total
📊 Largest
💵 Format
// Given transactions:
var txns = [500, -200, 300, -50, 1000];
CONCEPTS USED
RESULT
🎮 Quiz 1 · Lists & Maps

Test your understanding

3 quick questions on Lists and Maps. Think carefully before clicking.

Q1: What does .fold(0, (sum, x) => sum + x) do?
A
Filters items
B
Combines all into one value
C
Sorts the list
Correct! .fold() starts with 0 and combines each item into one accumulated value. Here it sums everything.
Q2: What's the difference between .map() and .where()?
A
map filters, where transforms
B
map transforms, where filters
C
They're the same
Correct! .map() transforms each item (change it). .where() filters (keep items that match).
Q3: accounts.entries.where((e) => e.value > 1000) — what does .entries give you?
A
Just keys
B
Just values
C
Key-value pairs
Correct! .entries gives you MapEntry objects with both .key and .value, so you can filter/transform the whole pair.
🎮 Game · Bank Balance Analyzer

Analyze the bank data

Given 5 customers with balances. Click each task to see the Dart solution.

CUSTOMER DATA
AayushRs.15000
SitaRs.8000
RamRs.500
PriyaRs.22000
AaravRs.3000
💰 Total deposits
👑 Richest
⚠️ Below Rs.1000
📊 Average
CONCEPTS
Topic 4 · Functions

Function — Anatomy Refresher

ANATOMY OF A FUNCTION
double calculateInterest(double balance, double rate) {
  return balance * rate / 100;
}
double → return type
calculateInterest → function name
(balance, rate) → parameters (inputs)
return ... → what it gives back
void

Does something, returns nothing

int / String / double

Returns a value of that type

=> arrow

One-line shortcut for return

{} named params

Readable calls with labels

Topic 4 · Functions

Writing Better Functions

BAD PRACTICES
// Too many things in one function
void doStuff(var data) {
  // validates, processes, saves, prints...
  // 50 lines of code
}

// Unclear name
void fn(int x) { ... }

// Side effects everywhere
var total = 0;
void add(int n) { total += n; }
// modifies external state
GOOD PRACTICES
// One job each
bool isValidAmount(double amount) =>
  amount > 0;

double applyInterest(double bal, double rate) {
  return bal * (1 + rate / 100);
}

String formatCurrency(double amount) {
  return 'Rs.${amount.toStringAsFixed(2)}';
}

// Pure — same input = same output
// Clear names — you know what they do
// Small — easy to test and reuse

📌 One function = one job. If you can't name it clearly, it's doing too much.

Topic 4 · Functions

Anonymous Functions & Closures

🧑‍🍳

An anonymous function is like a recipe card with no title — you use it once, right where you need it.

// Named function
bool isRich(int balance) => balance > 10000;
balances.where(isRich);

// Same thing, anonymous
balances.where((balance) => balance > 10000);

// Multi-line anonymous
balances.forEach((balance) {
  var interest = balance * 0.05;
  print('Rs.$balance → +Rs.$interest');
});
CLOSURE — CAPTURES OUTER VARIABLE
// A closure "remembers" variables from outside
double taxRate = 0.13; // 13% Nepal tax

var addTax = (double amount) {
  return amount + (amount * taxRate);
};

print(addTax(1000)); // 1130.0
print(addTax(500)); // 565.0

// taxRate changed? Closure sees it!
taxRate = 0.15;
print(addTax(1000)); // 1150.0

📌 Closures remember variables from their surroundings. That's their superpower.

Topic 4 · Functions

Higher-Order Functions — Functions as Data

Functions that take other functions as parameters, or return functions.

TAKING A FUNCTION
// Apply any operation to all accounts
void processAccounts(
  List<double> balances,
  double Function(double) operation,
) {
  for (var b in balances) {
    print(operation(b));
  }
}

// Use it 3 ways:
processAccounts(bal, (b) => b * 1.05);
processAccounts(bal, (b) => b - 100);
processAccounts(bal, (b) => b > 5000 ? b : 0);
RETURNING A FUNCTION
// Function factory!
Function(double) makeMultiplier(double rate) {
  return (double amount) => amount * rate;
}

var addInterest = makeMultiplier(1.05); // 5%
var addTax = makeMultiplier(1.13); // 13%

print(addInterest(1000)); // 1050.0
print(addTax(1000)); // 1130.0

📌 Higher-order functions make your code flexible — write once, customize with different functions.

🎮 Quiz 2 · Functions

Test your function skills

3 questions on closures, anonymous functions, and higher-order functions.

Q1: What is a closure?
A
A function that closes the app
B
A function that remembers its surrounding variables
C
A function inside a class
Correct! A closure captures and remembers variables from the scope where it was created, even after that scope is gone.
Q2: What does balances.map((b) => b * 1.05) do?
A
Filters balances
B
Transforms each balance
C
Adds to the list
Correct! .map() transforms each item. Here it multiplies every balance by 1.05 (adding 5% interest).
Q3: What's a higher-order function?
A
A function with many lines
B
A function that takes/returns other functions
C
A function in a class
Correct! A higher-order function either takes a function as a parameter or returns a function. .map(), .where(), .fold() are all examples.
🎮 Challenge · Bank Utilities

Build 5 utility functions

Each button shows a banking utility function. Click to see the code + test output.

💵 formatCurrency
✅ isValidAmount
📈 applyInterest
🧾 calculateTax
🔑 generateAccountId
CONCEPTS USED
TEST OUTPUT
Topic 5 · Classes

The Problem Without Classes

// Account 1
var name1 = 'Aayush';
var balance1 = 15000.0;
var type1 = 'savings';

// Account 2
var name2 = 'Sita';
var balance2 = 8000.0;
var type2 = 'current';

// Account 3... Account 100... 😱
// How do you manage this?
// How do you pass "one account" to a fn?
// How do you ensure balance >= 0?
📦 📦 📦
Scattered variables

name1, balance1, type1... name2, balance2, type2... Nothing connects them. Easy to mix up.

😱
No protection

Anyone can set balance1 = -5000. Nothing stops invalid data.

There has to be a better way...

Topic 5 · Classes

The Solution — Classes

BEFORE — MESSY
var name1 = 'Aayush';
var balance1 = 15000.0;
var type1 = 'savings';
var name2 = 'Sita';
var balance2 = 8000.0;
var type2 = 'current';
// ... more scattered vars
AFTER — CLEAN
class BankAccount {
  String owner;
  double balance;
  String type;

  BankAccount(this.owner, this.balance, this.type);
}

// Clean, organized, reusable!
var acc1 = BankAccount('Aayush', 15000, 'savings');
var acc2 = BankAccount('Sita', 8000, 'current');

// Pass to functions easily
void printInfo(BankAccount acc) {
  print('${acc.owner}: Rs.${acc.balance}');
}

📌 A class bundles data + behavior together. One account = one object.

Topic 5 · Classes

Constructors — Building Objects

class BankAccount {
  String owner;
  double balance;
  String type;

  // Default constructor
  BankAccount(this.owner, this.balance, this.type);

  // Named constructor — savings account
  BankAccount.savings(String owner)
    : owner = owner,
      balance = 0,
      type = 'savings';

  // Named constructor — welcome bonus!
  BankAccount.withBonus(String owner)
    : owner = owner,
      balance = 500,
      type = 'savings';
}
CREATING OBJECTS
var a1 = BankAccount('Aayush', 15000, 'savings');
var a2 = BankAccount.savings('Sita');
// balance = 0
var a3 = BankAccount.withBonus('Ram');
// balance = 500 (welcome bonus!)
Default constructor

You provide all values manually

Named: .savings()

Starts with Rs.0, type auto-set

Named: .withBonus()

New accounts get Rs.500 welcome bonus

📌 Named constructors let you create objects in different ways from the same class.

Topic 5 · Classes

Methods — What Objects Can Do

class BankAccount {
  String owner;
  double balance;

  BankAccount(this.owner, this.balance);

  void deposit(double amount) {
    balance += amount;
    print('Deposited Rs.$amount. Balance: Rs.$balance');
  }

  void withdraw(double amount) {
    if (amount > balance) {
      print('Not enough funds!');
      return;
    }
    balance -= amount;
    print('Withdrew Rs.$amount. Balance: Rs.$balance');
  }

  String getInfo() {
    return '$owner — Rs.${balance.toStringAsFixed(2)}';
  }
}
USAGE
var acc = BankAccount('Aayush', 5000);

acc.deposit(2000);
// Deposited Rs.2000. Balance: Rs.7000

acc.withdraw(1000);
// Withdrew Rs.1000. Balance: Rs.6000

acc.withdraw(10000);
// Not enough funds!

print(acc.getInfo());
// Aayush — Rs.6000.00
Topic 5 · Classes

More Methods — Computed Properties

class BankAccount {
  // ... previous code ...

  // Getter — computed property
  bool get isOverdrawn => balance < 0;
  String get formattedBalance =>
    'Rs.${balance.toStringAsFixed(2)}';

  // Method with logic
  String getStatus() {
    if (balance >= 10000) return '🟢 Healthy';
    if (balance >= 1000) return '🟡 Low';
    return '🔴 Critical';
  }

  @override
  String toString() =>
    'BankAccount($owner, $formattedBalance)';
}
USAGE
var acc = BankAccount('Aayush', 15000);

print(acc.formattedBalance);
// Rs.15000.00

print(acc.getStatus());
// 🟢 Healthy

print(acc.isOverdrawn);
// false

print(acc);
// BankAccount(Aayush, Rs.15000.00)

📌 Getters look like properties but run code. Use get when computing a value from existing data.

🎮 Quiz 3 · Basic Classes

Test your class skills

3 questions on constructors, methods, and getters.

Q1: What's a constructor?
A
A method that runs every time
B
A special method that creates objects
C
A way to delete objects
Correct! A constructor is called when you create a new object. It initializes the object's properties.
Q2: What does this.owner mean in a constructor?
A
Creates a new variable
B
Assigns the parameter to the property
C
Makes it private
Correct! this.owner is Dart shorthand — the constructor parameter is directly assigned to the class property.
Q3: What's wrong? var acc = BankAccount; acc.deposit(100);
A
Nothing wrong
B
Missing () — need BankAccount()
C
deposit needs 2 args
Correct! BankAccount without () is the class itself, not an object. You need BankAccount('name', 0) to create an instance.
Topic 6 · Inheritance

Extending — Building On Top

🏠

A SavingsAccount IS a BankAccount... with extra features. Like a house with an extra floor.

class SavingsAccount extends BankAccount {
  double interestRate;

  SavingsAccount(String owner, double balance,
    this.interestRate)
    : super(owner, balance);

  void addInterest() {
    var interest = balance * interestRate / 100;
    deposit(interest); // reuse parent!
    print('Interest: Rs.${interest.toStringAsFixed(2)}');
  }
}
USAGE
var savings = SavingsAccount('Aayush', 10000, 5.0);

savings.deposit(2000);
// Deposited Rs.2000 (inherited!)

savings.addInterest();
// Interest: Rs.600.00

print(savings.balance);
// 12600.0

📌 extends means 'is a'. SavingsAccount IS a BankAccount with extra powers.

Topic 6 · Inheritance

@override — Change Inherited Behavior

class CurrentAccount extends BankAccount {
  double overdraftLimit;

  CurrentAccount(String owner, double balance,
    this.overdraftLimit)
    : super(owner, balance);

  @override
  void withdraw(double amount) {
    if (amount > balance + overdraftLimit) {
      print('Exceeds overdraft limit!');
      return;
    }
    balance -= amount;
    print('Withdrew Rs.$amount. Balance: Rs.$balance');
  }
}
USAGE
var current = CurrentAccount('Sita', 5000, 2000);

current.withdraw(6000);
// Withdrew Rs.6000 (uses overdraft)

current.withdraw(5000);
// Exceeds overdraft limit!
SAME NAME, DIFFERENT BEHAVIOR
BankAccount
Blocks if amt > bal
CurrentAccount
Allows overdraft

📌 @override lets child classes change how inherited methods work.

Topic 7 · Mixins

Mixins — Share Abilities

🎭

A mixin is like a skill you can plug into any class. Not every account needs it — but those that do, just add with.

mixin Transferable {
  void transferTo(BankAccount other, double amt) {
    if (amt > (this as BankAccount).balance) {
      print('Not enough to transfer');
      return;
    }
    (this as BankAccount).withdraw(amt);
    other.deposit(amt);
    print('Transferred Rs.$amt to ${other.owner}');
  }
}

// Mix it in!
class SavingsAccount extends BankAccount
  with Transferable {
  // has all BankAccount + transferTo
}
USAGE
var aayush = SavingsAccount('Aayush', 10000, 5.0);
var sita = BankAccount('Sita', 5000);

aayush.transferTo(sita, 3000);
// Withdrew Rs.3000...
// Deposited Rs.3000...
// Transferred Rs.3000 to Sita

📌 Inheritance = 'is a'. Mixin = 'can do'. Use mixins when multiple unrelated classes need the same ability.

Topic 8 · Enums

Enums — Fixed Choices

🎯

An enum is like a dropdown menu — only these specific options exist, nothing else.

enum AccountType { savings, current, fixed }

class BankAccount {
  String owner;
  double balance;
  AccountType type; // not a String!

  BankAccount(this.owner, this.balance, this.type);
}

var acc = BankAccount(
  'Aayush', 10000, AccountType.savings
);
USING WITH SWITCH
String getPerks(AccountType type) {
  switch (type) {
    case AccountType.savings:
      return '5% interest yearly';
    case AccountType.current:
      return 'Unlimited transactions';
    case AccountType.fixed:
      return '8% interest, no withdrawal';
  }
}

print(getPerks(acc.type));
// '5% interest yearly'

// Dart warns if you miss a case! 🛡

📌 Enums prevent bugs. Instead of type = 'savngs' (typo!), use AccountType.savings — the compiler catches mistakes.

Topic 9 · Callable Objects

Callable Objects — Objects as Functions

In Dart, you can make an object callable — just add a call() method.

class Transaction {
  final String type;

  Transaction(this.type);

  // The magic: call() method
  String call(double amount, String account) {
    return '[$type] Rs.$amount → $account';
  }
}
USAGE
// Create transaction "functions"
var deposit = Transaction('DEPOSIT');
var withdraw = Transaction('WITHDRAW');

// Use them like functions!
print(deposit(5000, 'Aayush'));
// [DEPOSIT] Rs.5000 → Aayush

print(withdraw(2000, 'Sita'));
// [WITHDRAW] Rs.2000 → Sita

📌 Callable objects are useful when you need functions with state — like a transaction that remembers its type.

🎮 Quiz 4 · Advanced Classes

Test your OOP skills

3 questions on inheritance, mixins, and enums.

Q1: What does extends do?
A
Copies a class
B
Creates a child class that inherits from parent
C
Deletes the parent
Correct! extends creates an 'is a' relationship. The child gets all properties and methods from the parent.
Q2: When do you use a mixin instead of inheritance?
A
When you want 'is a' relationship
B
When multiple unrelated classes need the same ability
C
When you need a constructor
Correct! Mixins let you share abilities across classes that aren't related. Inheritance = 'is a'. Mixin = 'can do'.
Q3: Why use enum instead of String for account type?
A
Enums are faster
B
Compiler catches typos and missing cases
C
Enums use less memory
Correct! With enums, the compiler warns you about typos and missing switch cases. Strings have no such safety net.
🎮 Project · Banking App

Build a Banking App

Everything from today in one program. Click each feature to see the code.

🏦 Account class
💰 Deposit & Withdraw
🔄 Transfer
📋 History
🖨 Statement
CONCEPTS USED
Day 3 · Wrap up

What you learned today

Every concept here powers real Flutter apps. You now have the Dart foundation.

📋

List Power Methods

where, map, fold, any, every, chaining

🔤

String Methods

split, trim, padLeft, substring, replaceAll

🗺

Map Methods

entries, forEach, update, removeWhere, keys/values

🔧

Function Best Practices

single responsibility, pure functions, clear naming

🔒

Closures & HOF

anonymous functions, captured variables, functions as data

🏗️

Classes

constructor, methods, getters, toString

📈

Inheritance

extends, super, @override

🎭

Mixins & Enums

with keyword, fixed choices, switch safety

📞

Callable Objects

call() method, objects as functions

Take-home assignment

Take-Home: Student Management System

Build a complete system using everything you learned today.

REQUIREMENTS
1. Create a Student class with name, age, marks (List<int>), enrollmentDate
2. Add methods: addMark(), getAverage(), getGrade(), toString()
3. Create a Classroom class that holds List<Student>
4. Add: addStudent(), getTopStudent(), getFailingStudents(), getClassAverage()
5. Use enums for Grade (A, B, C, D, F)
6. Use a mixin Printable that adds printReport()
7. Create at least 5 students and demonstrate all methods
CONCEPTS YOU'LL USE
✅ Classes & constructors
✅ Methods & getters
✅ Lists & .where(), .map()
✅ Enums & switch
✅ Mixins (Printable)
✅ String interpolation

Push to your flutter-tr06 repo. This is portfolio commit #3.

Coming next

Day 4 Preview

Async Programming

Futures, await/async

💥

Error Handling

try/catch/finally

🌐

API Concepts

HTTP, JSON, REST basics

BEFORE NEXT CLASS
Read about Futures on dart.dev
🙋

Any Questions?

No question is too basic. If you're confused, someone else is too — ask now.

Practice on dartpad.dev — try the Student Management System yourself!