But could the same thing be done with a UDF?
I'd say no. Not the same way as stored procedures. An inline UDF (heck, even a multi-statement UDF) are treated as tables (similar to views, hence the nickname, parameterized views) within T-SQL code. So not only is what is possible within a procedure vs. a UDF (or view) different, but the methods of calling them, maintaining them, and all the rest, is different.
One is not objectively superior than the other. They are all tools in the toolbox that do different things in different ways for different reasons. Defining exactly what you need and why helps you define which of the combination of tools is best in a given scenario.
TLDR: It depends.