Two little proposals


#1

Hi, I have two tiny ideas that could improve language a little.

  1. Make it a warning (or even an error) to declare a variable of type (), except when it’s due to generic type resolution. This is pretty useless, but some people new to Rust might do it by mistake, for example by saving the result of assignment. Also would make finding errors like unwanted semicolon easier in some cases.

  2. Inferring the type of created object. It’s one of few places in Rust where full type declaration is needed, and it’s almost always superfluous and looks like code duplication (most notably in new() methods of structs). This would require a new keyword though, I think, to differentiate from code blocks - for example, make, used like this:

struct OverlyLongName {
    foo: i32
}

impl OverlyLongName {
    fn new() -> OverlyLongName {
        make {
            foo: 5
        }
    }
}

What do you think?


#2

re 2, you can use the Self keyword to avoid typing the long name in type signatures:

impl OverlyLongName {
    fn new() -> Self {
        OverlyLongName { foo: 5 }
    }
}

However you still have to type the long name in the struct initialization. It would be nice if you could initialize the struct as Self { foo: 5 }, I’d be in favor of that.

re 1, you could create a custom lint, out of the standard library, that catches the behavior you describe. If the lint proves to be popular you could propose it for inclusion in the standard library via an RFC. I don’t have experience with custom lints, but rust-clippy looks like a good place to start.


#3

Last time I checked, the guidelines said using Self in other contexts than trait declaration was a bad practice. Has it changed in the last few months?

Also, the concept I’ve described would be far more general than Self - you could use it in any context, e.g. to initialize a temporary used as an argument to some function.

Wow, nice link! I didn’t know such custom lints are possible - certainly will take a look. Thanks!


#4

Last time I checked, the guidelines said using Self in other contexts than trait declaration was a bad practice. Has it changed in the last few months?

I’ll admit that I haven’t checked the rust-guidelines in a long time, but I don’t recall such directive. And I’m actually under the impression that only recently we started allowing Self inside impl blocks. (In fact, I realized that it was possible because I saw this PR)

Also, the concept I’ve described would be far more general than Self - you could use it in any context, e.g. to initialize a temporary used as an argument to some function.

Oh, right, I see. That I’m not so in sure about. I feel that struct initialization is not that common to warrant a new syntax just for it. Of course, just my opinion :slight_smile:


#5

About the type name thing: I have thought about it in the past and I’d personally be in favor of reusing _ for type name deduction, if it were implemented. So you’d have _ { ... } for named structs and _::Variant for enums. I could also see _(...) for tuple structs, but I’m not sure that would be sane syntactically.

I would prefer _ for the symmetry with type inference in generics, e.g. .connect::<Vec<_>>().


#6

Right, forgot about _. It has this special meaning that’s very appropriate here - although, I fear the special-char-fest will make the code much less pleasant to read. Still, it’s “less” breaking than new keyword, so has bigger chances of being chosen as RFC.