Skip to content

block syntax redundant #1854

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

Closed
mcandre opened this issue Feb 16, 2012 · 9 comments
Closed

block syntax redundant #1854

mcandre opened this issue Feb 16, 2012 · 9 comments
Labels
A-frontend Area: Compiler frontend (errors, parsing and HIR) E-easy Call for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue.

Comments

@mcandre
Copy link

mcandre commented Feb 16, 2012

Rust's block syntax is redundant. Why not use the same syntax as function definitions, just omit the name like JavaScript and Lisp do?

This would simplify the compiler and making learning Rust that much easier.

@brson
Copy link
Contributor

brson commented Feb 16, 2012

@nikomatsakis and I were discussing this the other day, thinking that perhaps the function kind inferrence on lambda blocks is too clever. To make the function syntax more usable we can do as you suggest and make the argument types optional. Additionally we were thinking that we could omit the parens for functions without arguments, so spawn would look like

spawn fn~ {
};

@brson
Copy link
Contributor

brson commented Feb 16, 2012

We could go as far as you suggest and remove block syntax. fn { } looks just as good as (possibly better than) {|| }

@nikomatsakis
Copy link
Contributor

Yes, I'm now a fan of allowing fn expressions (with optionally omitted parentheses and variable types) wherever we allow {||...}.

I am not sure how I feel about removing {||...} altogether though. I think i'd be inclined to keep it but have it always be a stack closure (fn&). Yes, it's two ways to write the same thing, but

vec::iter(v) fn {
}

doesn't look right to me. But maybe it just takes getting used to (Even in that example, I am assuming we allow fn as a synonym for the more strictly correct fn&).

@brson
Copy link
Contributor

brson commented Feb 16, 2012

Agreed.

@ssylvan
Copy link

ssylvan commented Feb 17, 2012

How about go the other way and make the normal function definition just be a let statenent that binds a lambda of some sort?

I really like the idea of unifying syntaxes though, but it's worth considering changing the declaration to be more like the expression, instead of going the other way. Also, it would be cool if there wasn't two ways to declare a function (either by using special-case function declaration syntax, or just creating a lambda, of some sort, and assining it to a variable).

Maybe get rid of special function declarations, and do something like:

// just declare a variable that happens to be a function...
let foo1 = ( x : int ) -> int {
   x+5
};

// alternative form, do inference the other way, either would be legal
let foo2 : (int) -> int = x {
  x+5
};

// full syntax, all types explicit, no inference
let foo3 : (int)->int = (x : int) -> int {
   x+5
};

These all sort of look enough like function definitions, but are really just declaring a variable like any other.

EDIT: oh, this is kind of a strawman proposal. I haven't considered how this syntax would be parsed. I can imagine it might be ambiguous or something.

@mcandre
Copy link
Author

mcandre commented Feb 17, 2012

As a Lisper, I would love to have fn name(args...) { ... } desugar to let name = fn(args...) { ... }, assuming fn is treated as lambda. It would simplify compilation and make the language easier to learn.

@bstrie
Copy link
Contributor

bstrie commented Feb 17, 2012

I realize that I'm in a minority here, but (perhaps due to the scarcity of documentation and my own lack of expertise) I often have trouble passing functions around in Rust. In addition (and here I'm guessing I'm even more in the minority) I often don't even care about the types of the arguments and return values of my functions; all I want is for my functions to "just work". In both these cases, the {|args| body} syntax is indispensable in its ability to infer my intentions.

Perhaps this is a use case that you don't really care if Rust supports--loose "script-like" programming where the programmer isn't really paying attention to what he's doing, and if that's the case then I understand. But far from making it harder to learn the language, Rust's block syntax (occasionally) frees me from stalling out on laboriously specifying function signatures, allowing me to continue learning other aspects of the language.

@nikomatsakis
Copy link
Contributor

From rust-dev mailing list:

I am not in favor of removing named fn items for several reasons.

  1. I like that named functions do not inherit their environment. I find that for long functions I typically only want one or two variables from the environment, and inheriting more than that is inviting bugs, as those other variables are not meant to be used. This could admittedly be addressed by requiring explicit capture clauses.
  2. In addition, the order of closure construction is very significant in Rust, particularly when you do things like move data into a closure. But declarations like "fn foo()" do not look like side-effecting statements, although they would be. Also, item decl order is generally insignificant in Rust, but this would no longer be the case.
  3. Finally, the issue of mutually recursive functions would become quite annoying. As I understand it, this proposal would mean that functions inherit the names that appear before their declaration, making it hard to write a mutually recursive function declaration. If you decide to inherit all names from the parent, then it becomes quite challenging to know whether all variables that might be used have been initialized. You end up needing a let rec form or something like that.

No doubt these issues can be addressed, but just making "fn foo(x,y)" sugar for "let foo = {|x, y| ...}" will not be very usable by itself (imo).

@nikomatsakis
Copy link
Contributor

I am going to close this issue and open a new one more narrowly tailored to the proposal that @brson described. I don't think we will remove block syntax nor named fn items---and, if we were going to do it, I'd like to see a more detailed proposal addressing the concerns I described above. If anyone disagrees, please feel free to re-open.

killerswan pushed a commit to killerswan/rust that referenced this issue Mar 26, 2012
Also adds proper checking for cont/break being inside a loop.

Closes rust-lang#1854
Issue rust-lang#1619
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-frontend Area: Compiler frontend (errors, parsing and HIR) E-easy Call for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue.
Projects
None yet
Development

No branches or pull requests

5 participants