Let me give you yet another point of view which is a bit closer to discrete mathematics, that is, from introduction to functional programming. As this course is very function-heavy, it was worth to spend the very first class solely on the basics of functions. Please note that what I describe below builds quite different intuition than that of continuous functions (I don't know, perhaps it hampers progress during calculus and analysis courses).
Shortly, I completely detest the function-as-a-formula approach. It is a source of many misunderstandings, poor intuition and generally all the evil of the world ;-)
The ordered-pairs is only slightly better, the untyped aspect of set theory wrecks havoc on gullible minds of the innocent students. As @Benoît Kloeckner already pointed out, at best, this should be deferred until some foundations of mathematics have been laid out. This is not always possible, so if somebody presses for definition, I do give that one, as it is the one later introduced during other courses. However, it is crucial to stress that, until later, functions should be though of as different objects than just sets.
My preferred way of introducing functions is via mappings/correspondences (not necessarily one-to-one). Start with some simple examples like 4 objects assigned to some other objects. Then practice evaluation, and then more examples and more evaluation.
Only when students are comfortable mapping sets like $\{1, \spadesuit, \text{elephant}, \ddot\alpha\}$ to other similar silly sets, then introduce function that maps $0 \to 1$, $1 \to 2$, $2 \to 3$ and so on. Name it (whatever letter or other symbol is free), and practice evaluation. Introduce $0 \to 0$, $1 \to 2$, $2 \to 4$, and so on, assign it to another letter, and practice evaluation (usually the response is immediate).
Now one can comment that if we were to describe $\mathbb{R} \to \mathbb{R}$ function, then that would be a lot of writing. Even if it was possible, it would be extremely tedious, so normally we use shortcuts like $x \mapsto x+1$ or write $f(x) = x+1$. Similarly $\alpha \mapsto 2\cdot \alpha$ or $g(\bigstar) = 2\cdot\bigstar$. Nevertheless, such rules are not functions themselves, they only indicate which function we are talking about. In particular $x \mapsto 2x+2$ and $y \mapsto 2(y+1)$ describe the same mapping, the same function despite the fact "the rule" looks different.
And then, because the course is functional programming, we go on to high-order functions, that is, functions taking functions as an argument or returning functions as a result. We take a step back to the mapping approach and practice things like $$\Big\{0 \to \bigstar, \spadesuit \to \{\square \to 1, 2 \to \mathtt{x}\}\Big\}$$ (the actual notation is quite different, e.g. a big oval rather than braces) and their evaluation and after enough practice we go again into "rules", but then again some examples need writing down explicit mapping, so students go back and forth a number of times.
Then talk about whether function can point to itself or take itself as an argument, and then about standard conventions, notations, usual letters, and similar things.
It takes a whole class, but it seems worth it, the students were later much more comfortable with the functional aspect of the rest of the course (although the evidence is anecdotal, I had some comparison with the groups of other TAs). Finally, please recall this was a functional programming class, it probably wouldn't work for analysis course.
I hope this helps $\ddot\smile$