Print a Connect 4 grid based on some rules for each cell
Is the graphic representation of a data structure an integral part of that data structure (val gString = myGrid.asText) or separate and independent from the data structure (val gString = asText(myGrid))?

I tend to favor the former, but if the Grid API is solid and supplies everything needed for one or more graphic representations, then the latter is probably the better choice. It's a little hard to judge here as you haven't provided the Grid (or Piece) code.

I question the choice of iterating through coordinates that are known to be outside the Grid just for the purpose of drawing a border. Wouldn't it be easier to get the grid contents and simply "wrap" them with border characters?

def asText(grid :Grid) :String = {
  val border = "|" + "-"*grid.x + "|"
  (1 to grid.y).map{ y =&gt;
    (1 to grid.x).map{ x =&gt;
      if      (grid.pieces.contains(Piece("X", x, y))) "X"
      else if (grid.pieces.contains(Piece("O", x, y))) "O"
      else "."
    }.mkString("|", "", "|")
  }.mkString(s"$border\n", "\n", s"\n$border")
}