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

Variable Arity Functions #1586

Closed
zmoshansky opened this issue Apr 20, 2016 · 3 comments
Closed

Variable Arity Functions #1586

zmoshansky opened this issue Apr 20, 2016 · 3 comments
Labels
T-lang Relevant to the language team, which will review and decide on the RFC.

Comments

@zmoshansky
Copy link

zmoshansky commented Apr 20, 2016

PR #1587


Feature Name: Variable Arity Functions
Start Date: 2016-04-19

Related

RFC Issue #323 Is related, but covers Keyword Arguments, Default Arguments, and allegedly covers variable arity functions, but then also conflates it with variadic functions.

Summary

Support Variable Arity Functions. Which are multiple functions that have the same name with a different, but explicitly defined and finite, number n of arguments. This not to be confused with Variadic Functions (varargs), which typically support a range of 0..n arguments, much like an array.

Elixir/Erlang is a good reference.

Motivation

Variable Arity Functions provide enhanced ergonomics around library design. They allow sensible, although potentially complex, default values for function arguments. In the case that default values are also implemented, they allow for default values that rely on a runtime variable, or a computation too complex for a function signature.

Detailed design

  • A combination of both name and arity is used to determine which version of a function is called.
  • This should be completed entirely at compile time with no runtime cost.
  • The group of functions with the same name and varying arity must form a set (Mutually exclusive name+arity). This differs from RFC Issue#153, which also allows varying types.

This design does not permit any ambiguity regarding which function is dispatched. Furthermore, it avoids the complexity of using argument types to determine which function is dispatched, an approach that can subsume variable arity functions, but has it's own merits and drawbacks. The current design is a vast improvement compared to Java where type coercion can make it difficult to determine which function is dispatched.

For the remainder of this RFC, the notation function_name/[number] is used to indicate the function and arity (ex. foo/3 is the function foo that takes 3 arguments).

Example Pseudo-Code

pub struct SceneGraph {
  tree: RoseTree<Node>,
  root: &Node,
}

impl SceneGraph {
    /// Adds a node to the scenegraph
    pub fn add_node(&mut self, node: Node) -> NodeIndex {
        self.tree.add_node(node)
    }
    pub fn add_node(&mut self) -> NodeIndex {
        self.add_node(Node::new())
    }

    /// Renders the scenegraph
    pub fn render(&mut self) {
        self.render(self.root)
    }
    pub fn render(&mut self, node: &Node) {
        self.tree.render(node)
    }
}

Drawbacks

It's usage may not be worth the implementation cost and maintenance.
This could complicate virtual (runtime) dispatch with trait objects and their fat pointers.
It could increase the complexity of some future variadic function implementation.

Alternatives

  1. Use macros
  2. Use multiple names for the different arity of functions
  3. Use Option to create optional arguments

Alternative Drawbacks

  1. Macros are more opaque to novice end users, and according to the book These drawbacks make macros something of a "feature of last resort".. Potentially complex implementations are moved from easier to test/comprehend code into macros. Finally, if macro's respect scoping rules, then the struct would need to leak "private information" to make the implementation possible, if it doesn't respect scoping rules, then one cannot rely on some of rust's powerful features to ensure code is implemented properly.
  2. While this is the easiest alternative, it means that more API calls must remembered by the library user. It can also lead to alternative names that accidentally expose fragile implementation details.
    ex.) render/1,2 -> render_entire_tree/1 & render_node_and_children/2
    But if some form of dirty checking is implemented, then render_entire_tree/1 would need to be re-factored to render_dirty_nodes/1, despite no-changes as perceived by the user.
  3. Using Option carries a runtime penalty to unwrap and test the value (conceivably LLVM could optimize this under certain circumstances, although I don't believe it does). Aside from visual clutter, they can also make it more opaque as to which version/branch of a function is expected to be taken. Granted, there are times where it is useful/preferable to variable arity, although that decision should be available to the library author.

Unresolved questions

Should all functions of the same name have the same return type? (Theoretically not necessary, but it could complicate implementation)

@jimmycuadra
Copy link

I haven't felt a desire for this feature, personally. All this achieves is the ability to share function names between multiple functions, which isn't necessarily a good thing. In some cases it is clearer to use a different name to hint at the purpose of the function and why/how it is different than other, similar functions. In the case where you're forced to make a bunch of different functions for various permutations of arguments where naming them differently would serve no useful purpose, taking an options struct seems like a better choice. If that is painful, then we're back into the territory #323 is meant to address.

Also, I'm not sure this is actually important, but other RFCs include the content in a pull request rather than in the body of the issue.

@glaebhoerl
Copy link
Contributor

See also #153

@zmoshansky
Copy link
Author

zmoshansky commented Apr 20, 2016

Thanks @glaebhoerl, I didn't find that searching for "variable arity". To recap, #153 focused on variable arity and multiple definitions of the same function (with the same arity) and different signature types. It was closed as "not a priority in July 2014".

@jimmycuadra, Thanks for the advice about the RFC process. I have filed PR #1587, and updated the opening post to reflect a copy of that.

In some cases it is clearer to use a different name to hint at the purpose of the function and why/how it is different than other, similar functions.

I absolutely agree.

If that is painful, then we're back into the territory #323 is meant to address

This is in the territory of #323, but I feel like that issue doesn't adequately define the semantics of variable arity functions (conflating them with varargs) and the discussion predominantly focused on Keyword-Args & Defaults. It's very busy to have 3 distinct, although sometimes overlapping, features in a single RFC and I felt that separating this would allow for a better discussion of it's individual merits.

@Centril Centril added the T-lang Relevant to the language team, which will review and decide on the RFC. label Feb 23, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
T-lang Relevant to the language team, which will review and decide on the RFC.
Projects
None yet
Development

No branches or pull requests

4 participants