Now I know that technically in theory one could just use blocks to convey values in and out of any body of code. What I'm asking is whether or not a built-in syntax exists for input parameters and return values similar to what pretty much all other programming languages consider to be functions?
A function in Minecraft and a function in programming is completely different.
A function in Minecraft is just a list of commands, which can be executed in game with a single command, running commands in the function from top to bottom. The only other thing you can do with functions right now is leave comments in the code, which start with a #.
So to answer both of your questions; no.
While it's true that functions don't take any inputs or return any outputs, there are ways to fake it. A good way to conceptualize it is to look under the hood of how a language like C++ actually does function calls. Take this function declaration:
public list<Player> Foo(int a, int b);
When that function is called, the calling code pushes the values of
b on to the top of the stack. The function will pop those values off, and just before it's finished, it'll push the list of players on at the same place
a was for the calling code to continue to use.
Now we don't have a stack that we can use when making command contraptions, but we do have some things that are almost as good: scoreboards and tags. In C++, the function knows (relative to the stack pointer) where
b are, and where to put the
list<Player> when it's done. In Minecraft, we can use scoreboard values to pass around ints, tags to pass around players and entities, and tagged armor stands to pass around coordinates, and use the name of the function in those scoreboards and tags so the function knows where to look.
So let's see how the above C++ function might look in Minecraft commands. First, we need to pass in our two integers. We'll use a fake scoreboard player for this:
scoreboard objectives add a dummy scoreboard objectives add b dummy scoreboard players set #Foo a 1 scoreboard players set #Foo b 5
After this, we can just call the function:
To return the list of players, a command similar to this one inside Foo can be used:
scoreboard players tag @a[<some selector>] add FooResult
In the calling portion we can then use those tagged players in another command:
tell @a[tag=FooResult] Hello!
This is just one relatively simple example, but hopefully it shows that there's a lot of complexity that can be added to commands and functions.
So, especially in 1.13 when a function/command is called, you need to give it parameters, that sounds a lot like an input to me. You could key coordinates for instance, or you could use a 'soft' variable, like the nearest non-player entity @e[type=!player].
You can also have other commands manage your inputs to zero in on something extremely specific and conditional. A system to manage in 'input' or 'victim/s' of the command. And you can set it up so that either the player has instant control over triggering, or the game is constantly sensing for the trigger conditions.
Then you have a lot of foo/bar to do with the command once the victim is selected. One thing you can do that is relevant is perform math operations on two stored score values; such as adding them, setting one equal to the other, or doing something if they are equal.
As far as output goes, obviously there are lots of things that can be considered output. You could say hello world, you can build something, you can interact with the world, or the scoreboard, and you can call other functions.
What I think other people are trying to get at is that there is a very limited ability to use scores as inputs. You can - in some limited ways; but you can't directly use a stored score or tag as a single x-coordinate in tp for example. and you can't call a function passing another function (as a native function) to it as an input as you would in functional programming. You are limited to using the other function as a called output that is hard-coded. If you want input from another command you need to store the commands output first, and you are fairly limited to what DATA can be both stored and accessed by downstream commands.
As of 1.13 with the next execute, store, tag, tick and load features, I can't say that there is much distinction between what can be done with datapacks and functional-like programming capabilities, but the game is so state-dependent and the limitations on inputs to commands make it hard to say that commands provide the true functional-equivalent to computer-programming functions(pun). But, they are comparable and getting much more powerful. The new store and other features in execute are incredible and very relevant to this question.
For another example, see this video on creating a sphere using recursion. You call some commands that call other functions in a recursive loop with a tail condition to produce a sphere. That is sort of the hallmark of intro to functional programming: