-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Allow empty structs with braces. #147
Conversation
What is the advantage of saying |
@bstrie: You currently have to write struct X;
struct Y {
y: int
} And you cannot write struct X {
} I think this is very annoying. I agree that you might want to keep the version with the |
+1 Whenever i see
I definitely like the second better. But am fine with both in the end I guess. |
+1 The current behavior is pretty weird. When I'm working on something, I'll frequently start out with an empty struct and add fields as I need them. |
👎 we explicitly removed the ability to say I also see no benefit to |
@kballard: Can you link to the discussion where you decided to disallow |
+1 to this proposal, I found this weird when I was learning Rust. @kballard to clarify, you mean the values are indistinguishable at runtime? Two different, empty, struct values of different types (say |
@mahkoh Where I decided it? I didn't decide it. And I don't have the link offhand, but I encourage you to Obviously without a citation I don't have proof, but my recollection is that |
@nick29581 Two values of type |
By "you" I meant to group of people you referred to here:
Isn't it this issue? rust-lang/rust#5167 |
That is only struct literals in expression position. There was never an ambiguity with items. |
I'm a bit confused by this proposal. Let's talk about struct literals first. I would find it very strange to see anyone prefer this: let x = Foo{}; ...over this: let x = Foo; As though Rust code isn't noisy enough! In the interest of having Only One Way To Do It, we forbade the useless brackets on struct literals a long time ago. This used to be a syntax ambiguity, true, but that was just galvanizing the existing urge to "bless" the form that everyone was using anyway. Finally, in an effort to further simplify, we then forced the declaration of field-less structs to adopt the same form, by forbidding empty brackets. This was not motivated by ambiguity at all, just consistency. However, this latter restriction is definitely capable of raising eyebrows when paired with the empty trait definitions, empty impl blocks, and empty functions, all of which just use empty brackets. I would ask the author to please clarify what is being proposed here. Do you want to allow the brackets in declarations, and also forbid the bracket-less form? As a separate concern, do you want to allow the brackets in literals, and also forbid the bracket-less form? |
+1 for
|
+1. @bstrie I definitely prefer the first. As soon as I see it, I know we're initializing a struct with no members. I've associated the |
@gsingh93, your perception appears to be mistaken. It is impossible to initialize a struct with no members, because a struct with no members has zero size at runtime. It is an illusion, it does not exist! |
@bstrie It's an illusion that makes things easier to read. Not having |
@gsingh93 What do you mean, more familiar? With a nullary struct definition In fact, I can't think of any way in which struct Foo; is different than enum Foo {
Foo
} and yet nobody is clamoring for enum values to require |
@kballard You have a point, but if I define something as a struct, I would like to use it with the same syntax as I use for other structs. That includes structs that have no members and structs that have some members. I don't care about the size of the struct or what the compiler considers the struct to be. To me, the programmer, I declared a struct. Thus, I would like to use struct syntax. |
Does it actually matter whether the programmer thinks there is some sort of initialization or construction going on here? If not, then I'm fine with sending the message that there is (even if that is false) and having the consistent |
@gsingh93 But Similarly, if you turn on the Your insistence on thinking of FWIW, |
@kballard The RFC is proposing One could also argue for In the end, the choice here comes down to trading off consistency - either you want a struct with 0 fields to be consistent with a struct with n fields where n > 0 (and also consistent with C/C++) or you want consistency with enum variants. You've expressed your opinion on which kind of consistency you prefer and @gsingh93 and others have expressed a different opinion, I don't think either opinion is more correct than the other. @bstrie (and @mahkoh) my understanding of the RFC (which should be clarified in the RFC itself) is that both the declaration and the literal forms should use |
And a clarification, if regular structs were the only data structure in Rust, then I think this RFC would be a clear win for consistency. However, they aren't, and we want consistency with tuple-structs and enum variants. We also strive to only have one way to express a concept in Rust code, which seems to preclude having both ways, so we have to make a choice of which kind of consistency is most important. My personal thought is that the common case here is structs with n fields and we should try to be consistent between n=0 and n>0. But I can see the point of view, that reducing the number of ways to do something or reducing noise or having consistency with enum variants (which are semantically equivalent) is more important. |
The consistency argument is a wash. Either way you're going to be inconsistent with something. In light of that, I prefer the form that will result in less noise. -1 to this. |
I was going to say the same thing @bstrie said. |
I'm mostly interested in the point mentioned by @sfackler above: Being able to write Consider a math library which contains operators and points with up to 3 coordinates. trait BinaryOperator {
fn apply(&self, a: int, b: int) -> int;
}
struct Plus;
impl BinaryOperator for Plus {
fn apply(&self, a: int, b: int) -> int {
a + b
}
}
trait Point { }
struct Point0D();
struct Point1D(f64);
struct Point2D(f64, f64);
struct Point3D(f64, f64, f64);
impl Point3D {
fn project(self, n: uint) -> Box<Point> {
let Point3D(x, y, _) = self;
match n {
0 => box Point0D() as Box<Point>,
1 => box Point1D(x) as Box<Point>,
2 => box Point2D(x, y) as Box<Point>,
_ => box self as Box<Point>,
}
}
}
I do agree that "instantiation-should-follow-declaration", that is, structs declared |
If the idea is not to force empty structs to be declared and used with |
I am opposed to TIMTOWTDI. Adding in new syntaxes for the same operation can be done backward-compatibly later. |
That sounds very confusing. 3 different types of unit structs? And you have to remember which variant of unit struct it was in order to initialize it? |
Not more confusing than having to remember the names of the fields of non-empty structs. |
@cmr: You are denying that "instantiation-should-follow-declaration" played a role in the decision to disallow |
Consistency was the only consideration. On Tue, Jul 1, 2014 at 1:10 PM, mahkoh [email protected] wrote:
|
@cmr: That issue doesn't even talk about forbidding
On the same day @sfackler comments:
When was this forbidden? For what reasons was ; chosen over { }? The issue sheds no light on these questions. The comment is followed up by:
So unless this was done on the very same day, this issue, if not completely unrelated to the removal of Indeed, on September 19th @alexcrichton writes
It appears to me that @alexcrichton realized that the choice ; over { } was driven by wanting one consistent way to declare and instantiate structs and the ambiguity. |
One advantage of making the zero-field struct syntax consistent with the non-zero one (for both the struct item as well as the construction expression forms) is that A concrete example: #![feature(macro_rules)]
macro_rules! twos { ( $S:ident $($x: ident),* ) => { $S { $( $x: 2i ),* } } }
#[deriving(Show)] struct A { x: int, y: int }
#[deriving(Show)] struct B;
pub fn main() {
let a = twos!(A x, y);
// The below does not work, since it expands into illegal syntax `B { }`.
// let b = twos!(B);
println!("Hello World: {}", a);
} (caveat: the above example is an easy strawman to tear apart; i.e. "why would you ever write So, if we care about that (I know I do; not sure about other people), then we should consider making the change proposed here. |
@pnkfelix That's a reasonable justification, but I wouldn't want to force the noisier syntax on all "normal" code just to make macros work better. I'd be fine with having it optional, kind of like trailing commas. Also, couldn't you construct a similar example for tuple structs? |
@pnkfelix Macros can handle the case anyway, by using #![feature(macro_rules)]
macro_rules! twos {
( $S:ident $($x: ident),+ ) => { $S { $( $x: 2i ),* } };
( $S:ident ) => { $S };
}
#[deriving(Show)] struct A { x: int, y: int }
#[deriving(Show)] struct B;
pub fn main() {
let a = twos!(A x, y);
// The below works just fine
let b = twos!(B);
println!("Hello World: {}", a);
println!("It works: {}", b);
} |
@kballard that sort of workaround is what I meant when I said "without special case code" in my summary. But yes, that is a way to get around the problem, and maybe it is acceptable to macro developers. |
@glaebhoerl I suppose one could construct a similar argument for tuple structs ... for some reason I differentiate between unit and tuples, so that in my head zero-tuples just do not exist, and thus I find it easier to accept that likewise zero-tuple structs do not exist, and thus a macro that expands into a tuple struct is simply going to need to take >= 1 argument. But that is really just roundabout post-hoc justification for my position above. |
(and in fact, I just remembered a case where I do mentally equate unit and zero-tuples, so just ignore what I said above.) |
I would like to only use |
Note that an opaque struct is one where the only way you can use it is via a pointer. This is why any type with values is not an opaque struct, as you can use those values directly. The only way we have to express a type with no inhabiting values is to use an enum with no variants, e.g. |
By the way, with regards to @sfackler 's point that:
my current approach to dealing with this is to write such prototype structs this way: struct Foo {
_dummy_placeholder: ()
} This way it is super-clear that I intend to put more fields in later, that this code is just still under-development. So I am not super-convinced that the "let me write braces so I have a place to put things later" holds all that much water. |
@mahkoh can you collect what you view as the best arguments from this thread and update the rfc? |
+1 for allowing braces on both declarations and literals. |
updated |
Well that's certainly not true. You're providing an extremely biased view here. |
What's that if any? None Well that's certainly not true. You're providing an extremely biased view here. —Reply to this email directly or view it on GitHub. |
@liigo There has been a lot of discussion in this PR on this topic. |
This RFC is not all that well fleshed out to begin with.
The above observations lead me to believe that this particular RFC is not going to yield a usable document for people to refer back to in the future. If we accepted such a document, it would represent a failure in the RFC process, regardless of how the core team may feel about the spirit of this suggested change. The core team was already going to close this RFC (see meeting minutes). I just wanted to write down explicitly that I would argue in favor of closing this particular RFC pull request based on the observations above. |
|
||
# Unresolved questions | ||
|
||
TIOOWTDI (with a majority in favor) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am guessing that this is meant to denote "There Is Only One Way To Do It." (But in that case, why is it in the "Unresolved Questions" section rather than "Drawbacks" section? And really, the point needs to be explicitly elaborated.)
Acronyms like this are appropriate for SMS messages and twitter; not for a documents like this, especially since some of the core team members did not know what this meant (and I didn't figure out a guess for it until well after seeing their conversation).
@kballard: I read @nikomatsakis request so that I should provide the best arguments for the change, not against. If it's not going to be accepted then that it doesn't matter anyway. It's nothing more than bikeshedding and @pnkfelix: People used such acronyms in this thread and nobody complained about them.
Because the RFC say "Allow {}", not "Allow only {}". |
The actual RFC text needs to be more formal and more detailed than just general discussion. |
I do not attempt to go through and edit everyone's comments in the dialogue on an RFC; where the expectation is that one has read the preceding dialogue before a given comment (and thus an ad-hoc acronym can at least be understandable). But I cannot afford to take that attitude on an RFC, where the document is meant to live on independently from the comment thread here.
The expansion of "TIOOWTDI" into "There is only one way to do it" is not a question. (It is also not a drawback, unless you apply a healthy amount of context to one's interpretation, which is what I was trying to do when I wrote my comment above.) I do not know your background, in terms of whether english is your native language, etc, so please do not take offense at the following bullet points. I just want to set the record straight in terms of what sorts of phrases are actually sensible for each part of an RFC:
|
Please don't waste more time on this bikeshedding. |
You are right. But why we have two ways now? On function call, we allow empty-parenthesis: |
@liigo this whole RFC is about changing the empty struct declaration syntax, and is now closed (without being merged), i.e. please read the RFC and rest of the discussion. (Also, note that @pnkfelix was just rephrasing text as an example of how an RFC should be written, not adding any new content about the proposed changes.)
@pnkfelix was trying to constructively offer assistance on what an RFC should include and how it should be written (since it is designed to be a reference document for posterity); not wasting time on bikeshedding. |
Tweak weakmap template.
No description provided.