Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature request: variable-length argument lists to user-defined functions #2665

Closed
ksvanhorn opened this issue Oct 11, 2018 · 5 comments
Closed
Labels

Comments

@ksvanhorn
Copy link
Contributor

Summary:

Allow user-defined functions to have an argument list that ends with 0 or more arguments all of the same type. Call these optional arguments.

Description:

Currently there is no way to create user-defined functions that have a variable number of arguments. Here are some examples where that can be useful:

  • vector_append(v1, ..., vn): append n vectors of possibly differing lengths.
  • block_diag(M1, ..., Mn): create a block diagonal matrix from n matrices of possibly differing shapes. This kind of thing shows up in state-space models.

Additional Information:

Specifically, I am proposing the following:

  • In the definition of a user-defined function, allow the last argument to have the form T... v for some type T, meaning 0 or more arguments of type T.
  • Within the function body, size(v) refers to the number of optional arguments, and v[i] refers to the i-th optional argument. It is illegal to use v itself in any other way within the function body.

So, for example, if we have a function definition

T f(matrix M, vector... v) {
  // function body
}

and a call f(x, y1, y2), then y1 binds to v[1] and y2 binds to v[2] and size(v) is 2 in the body of f.

There is a simple implementation of this proposal, which I'll describe by example. The above function definition for f is implemented as

T f(matrix M, vector [] v) {
  // function body
}

and the call f(x, y1, y2) is implemented as f(x, {y1, y2}). This implementation does involve the creation of heterogeneous arrays (arrays whose elements may have differing shapes), but such arrays are never passed to any Stan function other than size() and the indexing operator.

@ksvanhorn
Copy link
Contributor Author

I already know that this implementation works, because I've been using it to simulate variable-length argument lists.

@ksvanhorn
Copy link
Contributor Author

One edit to the proposal: when v is the list of optional arguments to a function, it should also be legal to pass v as the list of optional final arguments to another function.

@bgoodri
Copy link
Contributor

bgoodri commented Oct 19, 2018

Could user-defined Stan functions utilize the syntax and accessors for variadic C++ functions?
https://en.cppreference.com/w/cpp/utility/variadic

@bob-carpenter
Copy link
Contributor

Thanks for the proposal. The approach you propose is similar to what C++ does under the hood with variadic arguments (as @bgoodri alludes to). This has been generalized type safely to heterogeneous arguments with parameter packs in C++11, but I'm not sure we need that genrality in Stan.

Given that we control the code generator, we could also implement the way we implement print() or reject() or { x1, ..., xN }, which is with a builder (create().add(x1).add(x2)...add(XN).build()).

We're going slowly on language changes as we rebuild the parser, AST, and code generator in a language that'll be easier to work with than C++/Boost Spirit Qi going forward.

Also, the method you provide is the way to implement this now, although it's clunky with the extra {...} and won't necessarily work with integer/real values, e.g.,

real foo(real[] x) {
  return sum(x) + 3;
}
real y = foo({1, 2, 3});  // FAILS TO COMPILE---no foo(int[])

When we get around to making Stan fully covariant, we'll allow int[] to real[] promotion the same way we allow int to real promotion everywhere.

@WardBrian
Copy link
Member

WardBrian commented Feb 14, 2024

There is a newer stanc3 issue which is similar: stan-dev/stanc3#1348
I'm going to close this older one in favor of it

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants