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

unified function call syntax #4

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 92 additions & 0 deletions 0000-ufcs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
- Start Date: 2014-03-17
- RFC PR #: 4
- Rust Issue #:

# Summary

Universal Function Call Syntax (UFCS) and syntax for associated items.

Add syntax for calling associated functions (aka static methods) where both the
definition and declaration of the function can be un-ambiguously specified.

Note, this does not block 1.0, but we need to ensure our plan is backwards
compatible.

# Motivation

```
Trait T1 { fn f() -> Self; }

Trait T2 { fn f() -> Self; }

fn g1<X: T1 + T2>() -> X { X::f() // hypothetical ideal syntax }
```

We need a way to call 'static method's (hereafter referred to as associated
funtions) which can distinguish between `f()` declared in `T1` and `f()`
declared in `T2`. We also need to specify the `Self` type for these methods,
i.e., specify the implementation of `f()`.

Our current syntax is to use `T1::f()` which allows the former but not the
latter. Furthermore, it is counter-intuitive in the common case of not having a
method declared in multiple traits (e.g., `X: T2`). The common example is that
we would like to write `X::size_of()`

# Background

Issues #6894, #8888, #12330.

pnkfelix's blog post: http://blog.pnkfx.org/blog/2013/04/22/designing-syntax-for-associated-items-in-rust/

nmatsakis's blog posts:
http://www.smallcultfollowing.com/babysteps/blog/2013/04/02/associated-items/
and http://www.smallcultfollowing.com/babysteps/blog/2013/04/03/associated-items-continued/

# Detailed design

Wherever type variables appear in the program they may be annotated with a bound
to remove ambiguity in the bound of the type variable used for typing. This is
analogous to using type ascription to remove ambiguity on the type of variables
which have polymorphic type. Where necessary, brackets can be used around types
in paths. For example the fully specified method call in the above example would
be `(X:T1)::f()` which would call `f()` defined in the implementation of `X` for
`T1`.

In the common case of no conflicting method definitions in traits, we would
allow `X::f()`.

## Extension to associated items.

The syntax extends in the obvious way to associated types and values, if and
when we add those. This would allow the following kinds of uses

```
// n1 and n2 have the same type
fn f<G: Graph>(n1: (G:Graph)::Node, n2: G::Node) {
...
let x = G::Node::magic_number; // associated value
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The full syntax for this is written as (G: Graph)::Node::magic_number, right?

I'm still mildly concerned about this from a grammar perspective, especially if we ever use : for type ascription on expressions (because then in (x: y..., x can legitimately be either a type or an expression).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think there is any particular ambiguity so long as we restrict the set of type expressions to paths. Though this is perhaps an unfortunate limitation.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even with just paths, it means that something like (Foo<T>: Graph) can't work (unless we use Foo::<T> there too).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, you would write Foo::<T> if this appears in an expression context.

}
```

(Note: associated types and values are not part of this RFC, but we should make
(sure we don't close any doors in that direction).

# Alternatives

We could use `as` rather than `:`. That reads better but requires whitespace in
paths (which pnkfelix objects to). It is analagous to casting, but I'm not sure
if that is a nice symetry or misleading.

There have been other, similar proposals. See the background section for links.

# Unresolved questions

Do we allow the shorthand `T1::f()` if the `Self` type can be inferred (as in
the example given due to the return type). This would be required for backwards
compatibility with the current syntax.

Do we generalise and allow bound ascription anywhere type variables can be used
(other than there declaration)?

Do we generalise further and allow type ascription? (I don't think there is any
motivation for doing so, other than symetry).