input: Write a python function to implement a MinHeap with insertion and extraction of the minimum element.
  assert len(heap) == 0
  heap.insert(5)
  heap.insert(3)
  heap.insert(8)
  assert heap.extract_min() == 3
  assert heap.extract_min() == 5
  assert heap.extract_min() == 8
  assert heap.extract_min() == False
output: class MinHeap:
      def __init__(self):
          self.heap = []
  
      def __len__(self):
          return len(self.heap)
  
      def insert(self, val):
          self.heap.append(val)
          self._heapify_up(len(self.heap) - 1)
  
      def extract_min(self):
          if not self.heap:
              return False
          if len(self.heap) == 1:
              return self.heap.pop()
          min_val = self.heap[0]
          self.heap[0] = self.heap.pop()
          self._heapify_down(0)
          return min_val
  
      def _heapify_up(self, index):
          parent_index = (index - 1) // 2
          if index > 0 and self.heap[index] < self.heap[parent_index]:
              self.heap[index], self.heap[parent_index] = self.heap[parent_index], self.heap[index]
              self._heapify_up(parent_index)
  
      def _heapify_down(self, index):
          smallest = index
          left_child_index = 2 * index + 1
          right_child_index = 2 * index + 2
  
          if left_child_index < len(self.heap) and self.heap[left_child_index] < self.heap[smallest]:
              smallest = left_child_index
          if right_child_index < len(self.heap) and self.heap[right_child_index] < self.heap[smallest]:
              smallest = right_child_index
          if smallest != index:
              self.heap[index], self.heap[smallest] = self.heap[smallest], self.heap[index]
              self._heapify_down(smallest)
  
  # Test cases
  heap = MinHeap()
  assert len(heap) == 0
  heap.insert(5)
  heap.insert(3)
  heap.insert(8)
  assert heap.extract_min() == 3
  assert heap.extract_min() == 5
  assert heap.extract_min() == 8
  assert heap.extract_min() == False