Noob question about (data) struct(ure) syntax


#1

Stupid syntax question: Why does assigning a value of a struct component happen via a colon? This confuses something, since the colon is actually typical for the data type specification?
And why is the name of the structure (generally a data structure) not written like a data type after a colon, but after the assignment operator (=)?

Sorry for that stupid question, but I’m a bit screwed up by C.

struct Point
{
    x: i32,
    y: i32,
}

// why not: 
 let origin: Point = {x = 0, y = 0};

// instead of:
 let origin = Point {x: 0, y: 0};  // origin: Point

mh ok… first looks a little bit unaesthetic with multiple „=“ :smiley:


#2

Well, part of the reason that it’s not that is because it’s ambiguous on seeing the { whether it’s going to be a block (let origin: Point = { x }; is legal syntax) or a struct literal (struct Point { x } is legal syntax).

I don’t know why it’s : instead of =, though.


#3

Once upon a time the core team discussed changing struct literals to use =, and various arguments were made in favor of the change, but in the end, inertia won out. (It would have required updating basically every Rust file in existence, at a time when the team was trying to stabilize the language and get 1.0 out the door.)

The current syntax with : is shared with languages like JavaScript, Go, and Python (and now Swift).

The Rust compiler was originally written in OCaml, which uses = in struct literals, so Graydon was clearly aware of that syntax but chose : anyways, for whatever reasons.


#4

Thank you for the explanation and the referenced discussion. Obviously, this question does not seem to be so wrong.
The explanations concerning the „=“ make sense.

kballard commented on 6 May 2014 :

I disagree with this proposal. Variable assignment is, well, assignment. But fields in struct initializers are declarations of value, not assignments of value. I also agree with @pcwalton about type-syntax-follows-initialization-syntax.

tbu- commented on 12 May 2014:

As you can see I parse the : as is. It isn’t really an assignment because you’re referencing an instantiation of the struct.

let x = SomeStruct { x: 4 };
      ^ assignment happens here
let x = SomeStruct { x: 4 };
                      ^ this is just describing one possible instance of SomeStruct

Another syntax question, which comes to mind here, concerns the brackets of data structures. Tuple structs look like a function call:

struct Color(i32, i32, i32);

let black = Color(0, 0, 0);

Is that on purpose? Because I find that somehow obvious, alternatively with square brackets to highlight the difference to a common tuple or to blocks of statement:

struct Color [i32, i32, i32];

let black: Color = [0, 0, 0];

or generally for structures:

struct zhl [a: i32, b: f64, …]
let beispiel: zhl = [b: 6597.87, a: 76, …];

#5

About your suggestion:

let black: Color = [0, 0, 0];

This syntax suggests that the struct name can be omitted! However this information is important for the compiler, so I think the struct name should stand directly in front of the values:

let black = Color [0, 0, 0];

Apart from that, in my opinion the square brackets are too similar to an array or to slice syntax (if the tuple struct contains 2 values).

About this code:

let black = Color(0, 0, 0);

Yes, someone could confuse this with a function, but I don’t consider this a problem. If it was a function, it would probably return a Color according to the function name, so it doesn’t make a difference whether it is a tuple struct or a function.


#6

An RFC even describes that they “can be thought of” in that way: https://github.com/rust-lang/rfcs/blob/8ee535b4fcc8bb22c121ad19a36414f1259397c0/text/1506-adt-kinds.md#tuple-structs

(It’s not exactly the same, though, because of patterns. But in expressions it really is just like a function.)


#7

ok
your elucidations are very plausible and helpful for a better understanding of the language

thanks for answering :slight_smile:

It’s nice how well Rust is thought out,
as well as the language is discussed down to the smallest detail


#8

You can even use the tuple struct constructor where a closure is expected. https://play.rust-lang.org/?gist=897a64465a9a21d0f69e671ac3a1169f&version=stable&mode=debug


#9

@notriddle: For such cases, the tupel-like structure was also created deliberately? Can you give me other useful / meaningful examples? =)

And I still would like to know why the Rust language creators have deliberately decided not to write the name of a self-defined structure template as a data type, but always before the value assignment. What is the meaning behind it?
What bothers me a bit, that always basically the element names must be written, although the order would actually be sufficient (and why not the explicit writing of the name only optional)?


#10

Not sure what you mean by this. If it is the fact that assignments usually look like

let x = Point { x: 1 };

instead of

let x: Point = { x: 1 };

you’re conflating two separate things. Rust is perfectly happy for you to write

let x: Point = Point { x: 1 };

but people don’t because type inference takes care of it.


#11

I mean, why not like in C?

struct RGB
{
	r: u8,
	g: u8,
	b: u8
}

let farbe = RGB { 0, 12, 43 }; // without annoying labeling elements 

Then tuple-like structures would actually be superfluous or could be further developed for even more specific purposes.


#12

Rust has JavaScript-esque name punning, which makes it impossible to do that in a backwards-compatible way, and makes it unnecessary in most non-toy examples, anyway:

struct RGB {
	r: u8,
	g: u8,
	b: u8
}

let (r, g, b) = (0, 12, 434);
let farbe = RGB { g, r, b }; // equivalent to g: g, r: r, b: b

Secondly, this only makes sense when there’s a “canonical” order to the elements. Like, x/y/z always being in alphabetical order, and r/g/b always being in that order. In every other case, you end up having to memorize the order to be able to read it.


#13

Because if you don’t want names, then you do struct RGB(u8, u8, u8);. If you want names, then you have to use the names.


#14

Ok, I already knew that. I just ask, WHY did the language designers choose to explicitly mention the name of the defined structure and elements. It’s the same with the “enum” as well, while at C it’s enough just to write the name of the element.
I guess that in Rust this somewhat verbose wording was wanted in order to avoid naming conflicts or
additional namespace constructions (eg misuse of classes in c++ for such things) and make the program more readable, better maintainable overall?


#15

This view that only “canonical” things should actually be called positional makes sense. With RGB (…) or Pt3D (…) one would already guess the correct order due to the name or more general conventions. But I think it would still be nice to be able to address the individual elements by means of identifiers (r, g, b or x, y, z) instead of numbers. On the other hand, it would somehow be confusing to allow either numbers or alternatively identifiers while using the tuple-like struct concerned. In this respect, the regulation makes sense in Rust. I’m clearly too messed up by C, and think too much about the syntax. XD
However, I find it somewhat confusing that while structures and functions are not in the naming conflict, but tuple-like structures must not share the name of an ordinary structure or function.

Tuple-like structures in Rust generally appear like “the 5th wheel on the car”, as Germans like to say, for something superfluous, or only rarely necessary.


#16

I don’t know why they did that, but I’m happy they did!

During my C-lectures I had some nasty beugs, because my team-mate re-ordered the fields in the struct for “better memory alignment”, but he didn’t do so for places where the struct was used…