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 much
You 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 much
If 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 much
Here'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









Nicholas Wilson <iamthewilsonator hotmail.com> 