I think we should drop default values for struct members, since they are confusing and less flexible than non-static expressions.
With struct sugar, it will take little effort to write a constructor with the default values per member.
I think we should drop default values for struct members, since they are confusing and less flexible than non-static expressions.
With struct sugar, it will take little effort to write a constructor with the default values per member.
An idea to improve refactoring is to use a colon after ‘pub’ to make all members public.
pub: struct Foo {
bar: uint,
baz: uint
}
We could match against argument name when one argument uses named syntax:
// These calls do the same
foo(x, y, z: 0);
foo(y, x, z: 0);
foo(z:0, y, x);
If a name does not match, there will be a compiler error.
One idea from discussion on reddit:
To avoid special casing on Option, we could have a rule that the first enum variant with no type signature is matched against. There must be 2 variants, one empty and one with a single type. The reason it can only be a single type is because it needs to be unwrappable and the internal type must be the unwrapped type.
For example:
pub enum MoviesLimit {
AllMovies,
Number(uint)
}
fn get_best_movies(&self, limit: MoviesLimit = self.len()) { ... }
This will require typing the full type.
fn foo(&self, limit: Option<uint> = 2);
One idea is to use the returned value of the Default trait to match against.
We can add a new trait ‘Optional’ that generalizes types that can be used for optional arguments.
pub trait Optional<T> {
fn none() -> Self;
fn some(val: T) -> Self;
fn to_option(self) -> Option<T>;
}
impl<T> Optional<T> for Option<T> {
fn none() -> Option<T> { None }
fn some(val: T) -> Option<T> { Some(val) }
fn to_option(self) -> Option<T> { self }
}
‘Optional’ is used in the desugar and solves generic issues. The desugar is attempted whenever the types do not match. This can be used in generics.
fn foo<T: Optional<U>, U: Default>(bar: T = Default::default()) { ... }
foo(x);
foo(..);
This desugars into
fn foo<T: Optional<U>, U: Default>(bar: T) {
let bar = match bar.to_option() {
None => { Default::default() }
Some(val) => val
};
...
}
foo(Optional::some(x));
foo(Optional::none());
With a concrete type and early return:
fn foo(bar: Option<uint> = return) { ... }
foo(2);
foo(..);
This desugars into
fn foo(bar: Option<uint>) {
let bar = match bar.to_option() {
None => { return }
Some(val) => val
};
...
}
foo(Optional::some(2));
foo(Optional::none());
With struct argument:
fn foo(Foo { bar = return }) { ... }
foo(bar);
foo(..);
This desugars into
fn foo(Foo { bar }: Foo) {
let bar = match bar.to_option() {
None => { return }
Some(val) => val
};
...
}
foo(Foo { bar: Optional::some(bar) });
foo(Foo { bar: Optional::none() });
I think we should break it down into 2 RFCs, 1) for struct sugar with pub: and default arguments, 2) for overloading. Overloading should wait.
The current summary solves the concerns about struct sugar so far:
I think at least one named argument should be required to use struct sugar, because if you refactor a function where swapping is intended, it can lead to error.
fn foo(x: uint, y: uint) { ... }
foo(y, x);
When refactored to a struct this will give a compiler error.
pub: struct Foo { x: uint, y: uint }
foo(Foo { x, y }) { ... }
foo(y, x); // error: expected Foo
foo(x: y, y: x); // fix
There is a problem with statements like Vec::new().as_slice().
When desugared into the match block, it does not outlive the match arm.
This can be solved by desugaring to this:
let _x;
let children = match children.to_option() {
None => { _x = Vec::new(); _x.as_slice() },
Some(val) => val
};
Or, one can use ["", ..0].as_slice()
Here is a draft of the first RFC, focusing only on struct sugar:
This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.