UFCS: Unified Function Call Syntax, i.e. why you can do Type::method(&this, params)
. UMCS: Unified Method Call Syntax, i.e. allowing you to do foo.function(params)
in some fashion for free function
instead of requiring associated method lookup.
Some sort of "pipe" operator has been considered desirable for a while, e.g. item |> function(param)
translating to function(item, param)
, potentially including autoref behavior. The thing is, Rust already has a "pipe" operator: the applicative .
. The "only" issue is that item.function
locks you into method name lookup instead of function name lookup.
So I have two ideas I'd like to see general temperature for:
UMCS.. Importantly, item.function(params)
still always gives method lookup, and (item.function)(params)
still always gives field lookup. We add a third form: item.(function)(params)
, which looks up the path function
using function/item name lookup rules, and attempts to call it as function(item, params)
, including applying autoref rules to item
if it's "immediately obvious" that autoref is needed. (Autoref is complicated. The rules should mirror method autoref as closely as possible. The main caveat to uses is that if a parameter is generic, autoref doesn't apply and the by-value use of the receiver place is attempted and checked for satisfying the trait bounds, completely ignoring if autoref would satisfy.)
Extension functions. Allow function items to be written with their first parameter binding as self
, e.g. fn function(self: String)
. When doing method lookup (e.g. s.function()
), any extension functions imported into scope are included in the name resolution iff the receiver is a potential match (i.e. is a receiver for the type). For the purpose of name resolution priority, extension functions equal traits, and behaves similarly as to if it were defined with a trait. The function is of course still callable with function syntax.
Both have their weirdness and edge cases, but I think both are useful and potentially desirable. item.(path::to::func)(args)
looks significantly weirder than item.path::to::func(args)
, but some syntactic signal to switch from method to path lookup is needed, and I personally think item.(f)(args)
is better than item.self::f(args)
to get local scope lookup (is that "path self
" or "receiver self
"?). Extension functions probably need to answer whether a receiver of &Type
acts like a trait implemented for Type
(i.e. with a &self
method) or for &Type
(i.e. with a self
method); a pure desugar (or proc macro) definitely needs to, but a language feature might be able to paper over the small differences?