Argh. I always forget that Discourse requires top-posting. All I was saying is that the original proposal involved no syntactic sugar.
How are namespace conflicts handled, then? You often do want to use static methods on types other than the original constructor; would you have to use an alias and keep the function in its own module? Is that really simpler or easier, or am I missing a way in current Rust that this would be clean to resolve?
Under this proposal, how will this code work?
struct Foo(pub uint);
impl Foo {
fn new(n: uint) -> Foo {
Foo(1 << n) // <-- ?
}
}
let foo = Foo(8); // <-- ?
This proposal doesnât alter any language semantics, just conventions. So that example will operate in exactly the same way that it does today.
There appears to be a lot of confusion along these lines, so Iâd like to clarify how I understand this proposal with an example. The current convention for the âmainâ constructor function of a type is to define a static new
method on it:
struct Foo {
x: int,
}
impl Foo {
fn new(x: int) -> Foo {
Foo {
x: x,
}
}
}
Under this proposal, the convention will be changed to defining a method in the same scope with the same name as the type:
struct Foo {
x: int,
}
fn Foo(x: int) -> Foo {
Foo {
x: x,
}
}
This is doable today, and is in fact used in some places (particularly in rustc
itself, where conventions are somewhat ignored); for example, syntax::ptr::P
uses this convention.
In that case a tuple-like struct cannot have such âconstructorsâ.
struct Foo(uint, uint);
fn Foo(n: uint) -> Foo { // â error: duplicate definition of value `Foo`
Foo(n, 1 << n)
}
True, my view is that a tuple-struct already has a default constructor, and if you want a different one, you should either use a struct with field-names.
It annoys me that constructors in C++ donât have easily searchable names (since obviously the class name gets used many times), besides which it isnât obvious in a few cases that the constructor is being called. Typing a few extra letters to make that explicit with consistent notation is definitely worth it in my opinion.
Far, Far prefer this. itâs fine to have named functions for âalternativeâ/âspecial caseâ/âcomplexâ constructors, but Iâve always found ::new() to be redundant, unnecessary ugliness that stabs me in the eye. I used tuple-structs for vector maths purely because I dislike the idiomatic Vec3::new(x,y,z) convention. This proposed convention would allow you to move back & forth more easily. This is the kind of pointless refactoring issue weâre trying to escape from C++. âif you reverse this choice later, you have to change calling conventions âŚâ
You can currently write struct Foo{} fn Foo()->Foo{} , and it is unambiguous both at call & definition site, hence still easy to search for. (grep struct Foo{
vs struct Foo(
vs fn Foo
vs Foo(
vs Foo{
)
Donât âThrow out the baby with the bathwaterâ when comparing to C++: C++âs system is difficult because of many combined factors: header files, everything is overloaded, there are hidden conversions, and its hard to distinguish a definition from a use in a single line. Rustsâ lack of headers & simpler grammar (especially introducing types with â:â ) cut through many problems.
box Foo::new() also looks very redundant.
itsâ also repurposing of the word ânewâ compared to other languages which might cause confusion for people creating cross-langauge C wrappers.would people expect extern âCâ Foo_new() to really be a function that allocates and initialises, returning Foo* ? opposite is Foo_delete(Foo*) ? Rust doesnât exist in isolation.
Are there any details in language support, for example does use foo::Bar
get all symbols âBarâ from foo (both the struct and the fn,if you make one)
I totally misunderstood the original proposal. If itâs just about conventions, then my answer would be to not default to either, but to just choose whichever makes sense for your actual struct (or something else entirely)⌠For little things like Vec3
, Iâd definitely agree this seems nicer.
This makes it clash with tuple struct constructors though. I prefer Foo::new()
for user defined constructors, and Foo()
for compiler provided tuple-like construction for variants/tuple structs.
I would strongly vote for consistency. As bstrie already wrote: Why should ::new
be special compared to ::with_capacity
?
Reminder: If this change comes, it also has to be ensured that &Foo
returns a function pointer as &Foo::new
does
My main problem is that it breaks the style. I donât really like Rustâs default style, but at least itâs consistent.
I could live with Foo::foo()
or non-method foo()
.
::new() is a huge improvement in consistency then introducing the idea of constructors. -1
Type::new()
is one of the things that I immediately liked about Rust. It shows that the constructor is not special or magical in any way; it is just a function. Of course, when the constructor is a free function this is still the case, but this is not immediately obvious, especially for people coming from C++/C#/Java, where the constructor is special. If Vec()
would be the default constructor for Vec
, then it could also be confusing that Vec::with_capacity(c)
is a constructor as well. It might be more consistent with tuple structs and enum variants, but it is less consistent with non-default constructors.
The five extra characters do not bother me at all. Rust is already quite concise (e.g. Rc
instead of C++âs shared_ptr
).
&Foo
wonât produce a function pointer, but a reference to a function pointer - assuming fn Foo(...) -> Foo {...}
, which is possible today, even if a type Foo
is declared in the same module.
That said, Foo
is no different than Foo::new
, or any other free function or static method.
I real like the fact that rust does not have special constructors but just static methods witch initialise the object on POD basis.
Also the initialisation with Enumval(...)
and Foo {...}
shows clearly that itâs a POD initialisation where Foo::new(..)
might do other stuff like data transformation, validity checks or even mutating mutable constants.
So -1 for this idea. Also the current convention is much clearer in regret to additional constructors like from_âŚ
As far as I can tell, at least in my own code, you would write
struct Foo *foo_alloc() {...}
void foo_free(struct Foo *foo) {...}
not
struct Foo *foo_new() {...}
void foo_delete(struct Foo *foo) {...}
new
and delete
just feel very "C++", not C. C uses malloc
and free
.
I much prefer Vec::new()
over Vec()
. I dislike method overloading, and I dislike using the type name for the constructor name in C++. Rust seems to get it right, to me. I also love the searchability of ::new(
. I can find many ctor calls just by searching for that string, unlike C++.
In C++, because you canât use a different name for ctor overloads, you are sometimes forced to add extra unused parameters to ctors, just so that you can abuse method overloading in order to choose the overload that you actually want. In Rust, you never have that problem.
Keep it the way it is.
In case itâs unclear, no such change is happening now that alpha has been released.
This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.