Thank you for your enjoy.
I have to emphasize that, my propose is not a parody, it contains a solution of trait Cascadable
.
suppose that you have
trait AnimalBehavior{
fn eat(&mut self:T,food:Food)->Result<(),Error>;
}
trait DogBehavior:AnimalBehavior{
fn eat(&mut self,food:Food)->Result<(),Error>;
}
struct Dog{...}
impl DogBehavior for Dog{...}
impl AnimalBehavior for Dog{...}
fn main()->Result<(),Error>{
let dog=Dog::new() eat (Food::new());
}
which eat is choosen now?
what we should written to call different eat
function?
dog as AnimalBehavior eat (food)?
My view is, define extra functions rather than grammars.
Then, the problem may be solved by existing methods:
AnimalBehavior::eat.(dog,food)
This could be done easily since dot
is an unary operator of function/methods.
Besides, structs.call (functions, with_space_before_brackets)
is legal from the oldest version to the latest version of Rust, your propose is just delete a dot, not adding a space.
consider the following statement:
impl Config{
fn add_field<T>(&mut self,x:T) /*-> &mut Self*/{
// do something with x...
// place a `self` here could be ugly and efficientless.
}
}
let config=Config::new();
// we couldn't wrote `config.add_field(x).add_field(y).add_field(z).build()` here
// since we do not add a useless self at the end of the method.
config.add_field(x);
config.add_field(y);
config.add_field(z);
let real_thing=config.build();
before Cascadable method call
, people cannot both writting simple methods without return Self
and using cascadable calls at the same time.
with the small modification, we could do both.
If you really think the signature is a problem, introduce more unary operators could solve it:
//for function(var:S,...)->U where U is either a single type or a Result<R,Error> and S=T,&T or &mut T
function.(mut var:T,...) -> return var as T
function&(var:&(mut) T,...) -> return &(mut) var as &(mut) T// compiler should pick &mut if possible, no matter what signature the function is used., since we could not upgrade &T to &mut T, and further calls may use `&mut T`
function?(var:T,...) -> return Result<var as T,Error>
what's more, we could easily infer that,
function&?(var:&(mut) T,...) -> return Result<&(mut) var as &(mut) T,Error>
since function&
is a well-defined function.
what's more, if cascadable method call
is acceptable with generating many functions with fn(self,...)->Self, we MAY add a new keyword, keep/pass_through/transparent/...
, to our program:
may not, since the keyword is hard to understand.
fn method(keep mut self,args:Args)->Self{...}
the keep
keyword have the following meanings:
- for
fn f(keep x:T)
, f(x)
never consume x
- for
fn f(keep mut x:T)
, f(x)
do not consume x
if x
is mutable, otherwise it consume x.
.
generate function with signature f.(keep mut x:T,...)
when f
is fn f(&mut x:&mut T,...)
, otherwise generate f.(keep x:T,...)
Note: for 1., f should not drop x.
for 2., it is caller, not the function, who decided to drop x.
for 3., it keeps most of the features of the original function. a cascadable method call is illegal only if the original chain is illegal.
cascadable
with f(_)->Self
generates a warning:
a.clone() // generate a clone of `a`
a.clone.() // generate a clone of `a`, discard it, the result now is `a`, not `a.clone()`, also generate an warning, since the second dot is not needed.
a.r#clone.() // tell Rust, I'm pretty sure I should using `.clone.` rather than `.clone`. Same to a.clone.(), but no warning is generated.