digitalmars.D.learn - how to access struct member using [] operator?
- grampus (7/7) Sep 24 2016 Dear all
- Nicholas Wilson (6/16) Sep 24 2016 The way you access the memers of a struct is through the dot
- Basile B. (33/41) Sep 25 2016 You can't do that. There's a problem because the string passed is
- Namespace (23/31) Sep 25 2016 ----
- Lodovico Giaretta (4/26) Sep 25 2016 Doesn't work. s["x"] is returned as float in this example. The
- grampus (3/38) Sep 25 2016 I think this approach should work for me.
- Basile B. (4/39) Sep 25 2016 WooW I have to say that I'm mesmerized !
- Basile B. (28/71) Sep 25 2016 Ther's no trick related to compile time:
- Basile B. (6/79) Sep 25 2016 "return" in "case" can infer...TIL. That's still a bit strange
- ag0aep6g (6/8) Sep 25 2016 Lodovico has already answered this.
- pineapple (2/5) Sep 26 2016 The int fields are promoted to and returned as floats.
- pineapple (11/19) Sep 25 2016 If they all share the same type, you can use a switch like
- grampus (3/26) Sep 25 2016 Thank you all for the clear reply.
- ZombineDev (57/65) Sep 26 2016 Here's my solution. It's very similar to Namespace's solution,
Dear all For example, I have a struct struct point{int x;int y} point a; Is there an easy way to access x and y by using a["x"] and a["y"] I guess I need to overload [], but can't figure out how. Someone can help? Thank you very much
Sep 24 2016
On Sunday, 25 September 2016 at 04:54:31 UTC, grampus wrote:Dear all For example, I have a struct struct point{int x;int y} point a; Is there an easy way to access x and y by using a["x"] and a["y"] I guess I need to overload [], but can't figure out how. Someone can help? Thank you very muchThe way you access the memers of a struct is through the dot syntax. i.e. a.x = a.y;Is there an easy way to access x and y by using a["x"] and a["y"]in this case "x" and "y" are strings so no.
Sep 24 2016
On Sunday, 25 September 2016 at 04:54:31 UTC, grampus wrote:Dear all For example, I have a struct struct point{int x;int y} point a; Is there an easy way to access x and y by using a["x"] and a["y"] I guess I need to overload [], but can't figure out how. Someone can help? Thank you very muchYou can't do that. There's a problem because the string passed is not known at compile-time, so the return type of "opIndex(string member)" cannot be inferred. It works only for one type: °°°°°°°°°°°°°°°°°°° import std.stdio; struct Something { int x,y; float z; int opIndex(string member) { alias T = typeof(this); foreach(m;__traits(allMembers, T)) if (m == member) { static if (is(typeof(__traits(getMember, T, m)) == int)) return __traits(getMember, T, m); } assert(0); } } void main(string[] args) { Something s; writeln(s["x"]); } °°°°°°°°°°°°°°°°°°° If you add a template parameter to opIndex then you can't call it with the array syntax so it becomes pointless to use an operator overload.
Sep 25 2016
On Sunday, 25 September 2016 at 04:54:31 UTC, grampus wrote:Dear all For example, I have a struct struct point{int x;int y} point a; Is there an easy way to access x and y by using a["x"] and a["y"] I guess I need to overload [], but can't figure out how. Someone can help? Thank you very much---- import std.stdio; struct Something { int x, y; float z; auto opIndex()(string member) { switch (member) { case "x": return this.x; case "y": return this.y; case "z": return this.z; default: assert(0); } } } void main(string[] args) { Something s; writeln(s["x"]); writeln(s["z"]); } ----
Sep 25 2016
On Sunday, 25 September 2016 at 09:01:44 UTC, Namespace wrote:---- import std.stdio; struct Something { int x, y; float z; auto opIndex()(string member) { switch (member) { case "x": return this.x; case "y": return this.y; case "z": return this.z; default: assert(0); } } } void main(string[] args) { Something s; writeln(s["x"]); writeln(s["z"]); } ----Doesn't work. s["x"] is returned as float in this example. The reason is, opIndex cannot magically change return type based on the passed-in string.
Sep 25 2016
On Sunday, 25 September 2016 at 09:01:44 UTC, Namespace wrote:On Sunday, 25 September 2016 at 04:54:31 UTC, grampus wrote:I think this approach should work for me. Thank you Namespace:)Dear all For example, I have a struct struct point{int x;int y} point a; Is there an easy way to access x and y by using a["x"] and a["y"] I guess I need to overload [], but can't figure out how. Someone can help? Thank you very much---- import std.stdio; struct Something { int x, y; float z; auto opIndex()(string member) { switch (member) { case "x": return this.x; case "y": return this.y; case "z": return this.z; default: assert(0); } } } void main(string[] args) { Something s; writeln(s["x"]); writeln(s["z"]); } ----
Sep 25 2016
On Sunday, 25 September 2016 at 09:01:44 UTC, Namespace wrote:On Sunday, 25 September 2016 at 04:54:31 UTC, grampus wrote:WooW I have to say that I'm mesmerized ! How can this works ? "member" is run time variable so the return type shouldn't be inferable.Dear all For example, I have a struct struct point{int x;int y} point a; Is there an easy way to access x and y by using a["x"] and a["y"] I guess I need to overload [], but can't figure out how. Someone can help? Thank you very much---- import std.stdio; struct Something { int x, y; float z; auto opIndex()(string member) { switch (member) { case "x": return this.x; case "y": return this.y; case "z": return this.z; default: assert(0); } } } void main(string[] args) { Something s; writeln(s["x"]); writeln(s["z"]); } ----
Sep 25 2016
On Sunday, 25 September 2016 at 16:07:59 UTC, Basile B. wrote:On Sunday, 25 September 2016 at 09:01:44 UTC, Namespace wrote:Ther's no trick related to compile time: import std.stdio; struct Something { int y; float z; double e; float x = 1234; auto opIndex()(const(char)[] member) { switch (member) { case "x": return this.x; case "y": return this.y; case "z": return this.z; case "e": return this.e; default: assert(0); } } } void main(string[] args) { Something s; char[] member = "w".dup; member[0] += args.length; writeln(s[member]); } Can we get an explanation from a compiler guy ? It seems the the switch statement is already evaluated at compiled time...On Sunday, 25 September 2016 at 04:54:31 UTC, grampus wrote:WooW I have to say that I'm mesmerized ! How can this works ? "member" is run time variable so the return type shouldn't be inferable.Dear all For example, I have a struct struct point{int x;int y} point a; Is there an easy way to access x and y by using a["x"] and a["y"] I guess I need to overload [], but can't figure out how. Someone can help? Thank you very much---- import std.stdio; struct Something { int x, y; float z; auto opIndex()(string member) { switch (member) { case "x": return this.x; case "y": return this.y; case "z": return this.z; default: assert(0); } } } void main(string[] args) { Something s; writeln(s["x"]); writeln(s["z"]); } ----
Sep 25 2016
On Sunday, 25 September 2016 at 16:26:11 UTC, Basile B. wrote:On Sunday, 25 September 2016 at 16:07:59 UTC, Basile B. wrote:"return" in "case" can infer...TIL. That's still a bit strange from the ABI point of view...because it means that under win32 it knows that z and x have to be returned in ST0, y in EAX...but cases are known at compile time...ok I think I get it :]. Depending on a static case, another CPU register is filled...On Sunday, 25 September 2016 at 09:01:44 UTC, Namespace wrote:Ther's no trick related to compile time: import std.stdio; struct Something { int y; float z; double e; float x = 1234; auto opIndex()(const(char)[] member) { switch (member) { case "x": return this.x; case "y": return this.y; case "z": return this.z; case "e": return this.e; default: assert(0); } } } void main(string[] args) { Something s; char[] member = "w".dup; member[0] += args.length; writeln(s[member]); } Can we get an explanation from a compiler guy ? It seems the the switch statement is already evaluated at compiled time...On Sunday, 25 September 2016 at 04:54:31 UTC, grampus wrote:WooW I have to say that I'm mesmerized ! How can this works ? "member" is run time variable so the return type shouldn't be inferable.Dear all For example, I have a struct struct point{int x;int y} point a; Is there an easy way to access x and y by using a["x"] and a["y"] I guess I need to overload [], but can't figure out how. Someone can help? Thank you very much---- import std.stdio; struct Something { int x, y; float z; auto opIndex()(string member) { switch (member) { case "x": return this.x; case "y": return this.y; case "z": return this.z; default: assert(0); } } } void main(string[] args) { Something s; writeln(s["x"]); writeln(s["z"]); } ----
Sep 25 2016
On 09/25/2016 06:26 PM, Basile B. wrote:Can we get an explanation from a compiler guy ? It seems the the switch statement is already evaluated at compiled time...Lodovico has already answered this. It's just an ordinary `auto` return type function. The actual return type is the common type of the different returns. Note that it falls apart when you add member with an incompatible type, like `string` or `Object`.
Sep 25 2016
On Sunday, 25 September 2016 at 16:07:59 UTC, Basile B. wrote:WooW I have to say that I'm mesmerized ! How can this works ? "member" is run time variable so the return type shouldn't be inferable.The int fields are promoted to and returned as floats.
Sep 26 2016
On Sunday, 25 September 2016 at 04:54:31 UTC, grampus wrote:Dear all For example, I have a struct struct point{int x;int y} point a; Is there an easy way to access x and y by using a["x"] and a["y"] I guess I need to overload [], but can't figure out how. Someone can help? Thank you very muchIf they all share the same type, you can use a switch like Namespace suggested. If the "x" and "y" strings are available at compile-time, you can use a mixin. auto getattr(string attr)(point a){ mixin(`return a.` ~ attr ~ `;); } auto x = a.attr!"x"; Otherwise, no. D types aren't dynamic in the same way that Python's types are.
Sep 25 2016
On Sunday, 25 September 2016 at 10:44:38 UTC, pineapple wrote:On Sunday, 25 September 2016 at 04:54:31 UTC, grampus wrote:Thank you all for the clear reply. Now I know how far I can go on this.Dear all For example, I have a struct struct point{int x;int y} point a; Is there an easy way to access x and y by using a["x"] and a["y"] I guess I need to overload [], but can't figure out how. Someone can help? Thank you very muchIf they all share the same type, you can use a switch like Namespace suggested. If the "x" and "y" strings are available at compile-time, you can use a mixin. auto getattr(string attr)(point a){ mixin(`return a.` ~ attr ~ `;); } auto x = a.attr!"x"; Otherwise, no. D types aren't dynamic in the same way that Python's types are.
Sep 25 2016
On Sunday, 25 September 2016 at 04:54:31 UTC, grampus wrote:Dear all For example, I have a struct struct point{int x;int y} point a; Is there an easy way to access x and y by using a["x"] and a["y"] I guess I need to overload [], but can't figure out how. Someone can help? Thank you very muchHere's my solution. It's very similar to Namespace's solution, the main difference being that it doesn't coerce the result to the common type of all the fields which may not be always possible and is also looses information. It also uses this.tupleof and foreach, so you don't have to write the switch cases by hand. ``` struct Something { int x, y; float z; string w; auto opIndex(string member) { import std.variant : Algebraic; import std.traits : Fields; alias FieldTypes = Fields!(typeof(this)); alias CommonType = Algebraic!(FieldTypes, typeof(null)); switch (member) { foreach (idx, field; this.tupleof) { case this.tupleof[idx].stringof[5 .. $]: return CommonType(this.tupleof[idx]); } default: assert (0, "Type `" ~ typeof(this).stringof ~ "` doesn't contain any member named `" ~ member ~ "`!"); // or return CommonType(null); } } } void main() { import std.stdio; auto s = Something(3, 4, 4.5, "asd"); writeln(s["x"]); writeln(s["y"]); writeln(s["z"]); writeln(s["w"]); writeln(s["missing_field"]); } ``` Application output: 3 4 4.5 asd Application error: core.exception.AssertError /home/d623/f162.d(26): Type `Something` doesn't contain any member named `missing_field`! The [5 .. $] trick is needed, because for e.g. idx = 0, this.tupleof[0].stringof returns "this.x" and we want to skip the "this." part (because otherwise the user would need to type s["this.x"]).
Sep 26 2016