www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Struct initializers as expressions

reply Chris Wright <dhasenan gmail.com> writes:
I can initialize a struct with named values:

---
struct Foo {
  int i, j, k, l, m, n;
}
Foo f = {k: 12};  // other fields get default initialization
---

I can initialize it with call syntax:

---
auto f = Foo(0, 0, 12, 0, 0, 0);  // works
---

I can use the latter as an expression:

---
void bar(Foo f) {}
bar(Foo(0, 0, 12, 0, 0, 0));  // just peachy
---

but not the latter:

---
void bar(Foo f) {}
bar({k: 12});
bar(Foo{k: 12});
---

Those both give:
Error: found '{' when expecting ','
Error: found ':' when expecting ','
Error: found '}' when expecting ','

This is slightly cruddy. I wanted to write

couchdb.queryView("byUsername", {key: "neia"});

But it looks like I have to use:

QueryOptions o = {key: "neia"};
couchdb.queryView("byUsername", o);

Not so good.

Ideally, I want something that lets you specify only the fields you care 
about and won't have to be modified (just recompiled) if I add more 
fields. I also want something inline.

Is there anything I can use here that's better than what I have?
Dec 02 2015
parent reply Mike Parker <aldacron gmail.com> writes:
On Thursday, 3 December 2015 at 05:26:17 UTC, Chris Wright wrote:
 I can initialize a struct with named values:

 ---
 struct Foo {
   int i, j, k, l, m, n;
 }
 Foo f = {k: 12};  // other fields get default initialization
 ---

 I can initialize it with call syntax:

 ---
 auto f = Foo(0, 0, 12, 0, 0, 0);  // works
 ---
The bottom syntax is a struct literal, the top one is not.
 Ideally, I want something that lets you specify only the fields 
 you care about and won't have to be modified (just recompiled) 
 if I add more fields. I also want something inline.

 Is there anything I can use here that's better than what I have?
AFAIK, your only option is to use a struct constructor. This is the sort of thing they're used for.
Dec 02 2015
parent reply Chris Wright <dhasenan gmail.com> writes:
On Thu, 03 Dec 2015 06:38:20 +0000, Mike Parker wrote:

 AFAIK, your only option is to use a struct constructor. This is the sort
 of thing they're  used for.
Which brings be back to positional arguments, which means that someone wishing to supply a limit on the number of query results must also give me the number of results per page, even if she doesn't care about the number of results per page. Is it worth posting a DIP for struct literals of the form `Name{fieldname: value}` ?
Dec 03 2015
next sibling parent Enamex <enamex+d outlook.com> writes:
On Thursday, 3 December 2015 at 15:31:49 UTC, Chris Wright wrote:
 On Thu, 03 Dec 2015 06:38:20 +0000, Mike Parker wrote:

 AFAIK, your only option is to use a struct constructor. This 
 is the sort of thing they're  used for.
Which brings be back to positional arguments, which means that someone wishing to supply a limit on the number of query results must also give me the number of results per page, even if she doesn't care about the number of results per page. Is it worth posting a DIP for struct literals of the form `Name{fieldname: value}` ?
I asked about that a while ago and was given noncommittal answers on why it wasn't accepted. I'd support your DIP.
Dec 03 2015
prev sibling parent reply Marc =?UTF-8?B?U2Now7x0eg==?= <schuetzm gmx.net> writes:
On Thursday, 3 December 2015 at 15:31:49 UTC, Chris Wright wrote:
 On Thu, 03 Dec 2015 06:38:20 +0000, Mike Parker wrote:

 AFAIK, your only option is to use a struct constructor. This 
 is the sort of thing they're  used for.
Which brings be back to positional arguments, which means that someone wishing to supply a limit on the number of query results must also give me the number of results per page, even if she doesn't care about the number of results per page. Is it worth posting a DIP for struct literals of the form `Name{fieldname: value}` ?
I'd support that, too. I suggest to make the struct name optional: struct S { int a, b; } struct T { string a, b; } void foo(S s); void foo(T t); foo({b: 1, a: 2}); // foo(S(2, 1)); foo({a: "bla"}); // foo(T("bla", null)); Then we can add some syntax sugar to leave out the braces, too: void bar(int a, T t) bar(42, a: "bla", b: "xyz"); This effectively gives us strongly typed named arguments, without making the names part of the function signature, which Walter objected to the last time something like this was proposed.
Dec 04 2015
next sibling parent Andrea Fontana <nospam example.com> writes:
On Friday, 4 December 2015 at 10:42:46 UTC, Marc Schütz wrote:
 I suggest to make the struct name optional:
... but not forbidden. With templates or "auto" could be useful to force the type.
Dec 04 2015
prev sibling next sibling parent reply Mike Parker <aldacron gmail.com> writes:
On Friday, 4 December 2015 at 10:42:46 UTC, Marc Schütz wrote:
;
 Then we can add some syntax sugar to leave out the braces, too:

     void bar(int a, T t)
     bar(42, a: "bla", b: "xyz");

 This effectively gives us strongly typed named arguments, 
 without making the names part of the function signature, which 
 Walter objected to the last time something like this was 
 proposed.
I like the idea of field names in a struct literal, but I would prefer to keep the parens. And no braces! The syntax for literals is already recommended over the C-style initializers, so IMO the same ought to hold for named initializers. I agree with dropping the struct name, though. bar(42, (a: "bla", b: "xyz")) I realized that if named arguments are not supported, then dropping the parens should still indicate that you're dealing with a struct, but the clear delineation is much more obvious. It also holds the door open for Walter to change his mind on named arguments.
Dec 04 2015
parent Marc =?UTF-8?B?U2Now7x0eg==?= <schuetzm gmx.net> writes:
On Friday, 4 December 2015 at 11:25:12 UTC, Mike Parker wrote:
 On Friday, 4 December 2015 at 10:42:46 UTC, Marc Schütz wrote:
 ;
 Then we can add some syntax sugar to leave out the braces, too:

     void bar(int a, T t)
     bar(42, a: "bla", b: "xyz");

 This effectively gives us strongly typed named arguments, 
 without making the names part of the function signature, which 
 Walter objected to the last time something like this was 
 proposed.
I like the idea of field names in a struct literal, but I would prefer to keep the parens. And no braces! The syntax for literals is already recommended over the C-style initializers, so IMO the same ought to hold for named initializers. I agree with dropping the struct name, though. bar(42, (a: "bla", b: "xyz")) I realized that if named arguments are not supported, then dropping the parens should still indicate that you're dealing with a struct, but the clear delineation is much more obvious. It also holds the door open for Walter to change his mind on named arguments.
Dropping the parens/braces is an optional step, but I would prefer to allow it. It looks much cleaner, and from my POV the goal is to make it look seamless. And IIRC Walter isn't really opposed to named arguments per se. He just didn't want parameter names to become part of the signature. With this proposal, they won't be, and it's opt-in from the implementer's POV.
Dec 04 2015
prev sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2015-12-04 11:42, Marc Schütz wrote:

 I'd support that, too.

 I suggest to make the struct name optional:

      struct S { int a, b; }
      struct T { string a, b; }
      void foo(S s);
      void foo(T t);

      foo({b: 1, a: 2});  // foo(S(2, 1));
      foo({a: "bla"});    // foo(T("bla", null));

 Then we can add some syntax sugar to leave out the braces, too:

      void bar(int a, T t)
      bar(42, a: "bla", b: "xyz");

 This effectively gives us strongly typed named arguments, without making
 the names part of the function signature, which Walter objected to the
 last time something like this was proposed.
I've been thinking along the same lines as well and would really like to see that feature. Wondering if it could work with opDispatch as well to swallow unrecognized fields. But I do see a problem, which I'm guessing Walter would point out as well. It might/will complicate the overloading rules. What if "a" and "b" in T would be integers instead. I think that would be ambiguous. -- /Jacob Carlborg
Dec 04 2015
next sibling parent Marc =?UTF-8?B?U2Now7x0eg==?= <schuetzm gmx.net> writes:
On Friday, 4 December 2015 at 14:07:01 UTC, Jacob Carlborg wrote:
 On 2015-12-04 11:42, Marc Schütz wrote:

 I'd support that, too.

 I suggest to make the struct name optional:

      struct S { int a, b; }
      struct T { string a, b; }
      void foo(S s);
      void foo(T t);

      foo({b: 1, a: 2});  // foo(S(2, 1));
      foo({a: "bla"});    // foo(T("bla", null));

 Then we can add some syntax sugar to leave out the braces, too:

      void bar(int a, T t)
      bar(42, a: "bla", b: "xyz");

 This effectively gives us strongly typed named arguments, 
 without making
 the names part of the function signature, which Walter 
 objected to the
 last time something like this was proposed.
I've been thinking along the same lines as well and would really like to see that feature. Wondering if it could work with opDispatch as well to swallow unrecognized fields. But I do see a problem, which I'm guessing Walter would point out as well. It might/will complicate the overloading rules. What if "a" and "b" in T would be integers instead. I think that would be ambiguous.
Right, this would need to be rejected. When the compiler sees such syntax, it would need to get a list of struct types allowed in the current position, and try to construct each of them with the given arguments. If there isn't exactly one match, it is rejected. This way, there is no change to the overloading rules themselves, it's just a rule to determine the type of the {key: value, ...} expression. After that, overloading works as usual.
Dec 04 2015
prev sibling parent Chris Wright <dhasenan gmail.com> writes:
On Fri, 04 Dec 2015 15:07:01 +0100, Jacob Carlborg wrote:

 But I do see a problem, which I'm guessing Walter would point out as
 well. It might/will complicate the overloading rules. What if "a" and
 "b" in T would be integers instead. I think that would be ambiguous.
Right. I would much rather keep any DIPs minimal in terms of scope and compiler changes. It could cause headaches with overload resolution if you didn't require the struct name in the literal, so I won't propose that at first. If named arguments come along, it would require additional care not to conflict with no-parentheses struct literal arguments. And what if a function takes two structs as parameters? Plus there would be issues with people mixing no-parens struct fields with positional parameters and getting confused.
Dec 04 2015