Common Lisp actually does cool things (if a bit niche) things with MRVs, they're side-channels through which you can obtain additional information if you need it e.g. every common lisp rounding functions returns rounded value... and the remainder as an extra value.
So if you call
(let ((v (round 5 2)))
(format t "~D" v))
you get 2, but if you (multiple-value-bind (q r) (round 5 2)
(format t "~D ~D" q r))
you get 2 and 1.r, err := f()
r := f()
_, err := f()
The other two are completely routine and will work just fine with lists in JS or tuples in Python or Rust (barring a few syntactic alterations).
You can pass multiple return values of a function as parameters to another function if they fit the signature.
for example:
func process[T any](value T, err error) {
if err != nil {
// handle error
}
// handle value
}
this can be used in cases such as control loops, to centralize error handling for multiple separate functions, instead of writing out the error handling separately for each function. for {
process(fetchFoo(ctx))
process(fetchBar(ctx))
}That said, there are libraries out there that implement Result as generic type and it's fine working with them, as well.
I don't see what the hubbub is all about.
Perhaps what you are really trying to say is that multiple function arguments is insane full stop. You can pass in an array/tuple to the single input just the same. But pretty much every language has settled on them these days – so it would be utterly bizarre to not support them both in and out. We may not have known any better in the C days, but multiple input arguments with only one output argument is plain crazy in a modern language. You can't even write an identity function.
(this is what zig does)
Where multiple input arguments are present, not having multiple output arguments is just strange.