Proposal: real struct literals

Bill Baxter dnewsgroup at billbaxter.com
Tue Jun 24 15:22:39 PDT 2008


Jarrett Billingsley wrote:
> The status of struct literals and construction in D1 has always really 
> grated on me.  So I've come up with a possible alternative syntax which 
> would supplant the current syntax.  (I've reproduced this in an enhancement 
> request in bugzilla.)
> 
> The current struct literals use a function-call-looking style to construct 
> structs.  This has some minor issues:
> 
> - If you define a static opCall for the struct, even if it isn't supposed to 
> be used as a "constructor", you can no longer use struct literals on that 
> struct.  I'm not sure if this was an intended aspect of the design, but it 
> becomes annoying to implement that static opCall without using struct 
> literals!
> 
> - Once structs get real constructors, the opCall "blessing" becomes 
> superfluous, and I hope plans are in the works to remove it.

But there will still be the problem that using call syntax for struct 
construction gets in the way of using structs as functors.  There's no 
way to distinguish between "I'm constructing" and "I'm calling this as a 
functor".  If you're lucky construction parameters and functor 
parameters don't overlap, but if you're unlucky you must contort your 
code.  Struct construction should not use function call syntax.

> - Using a struct literal does not call a function, so it seems weird to use 
> syntax that looks like a function call to construct it.
> 
> The much more serious issue is that in terms of features and syntax, static 
> struct initialization and struct literals are *completely* different.
> 
> struct S
> {
>     int x, y;
>     char[] s;
> }
> 
> void foo()
> {
>     static S s = { 5, y: 10, s: "hi!" };
>     auto s2 = S(5, 10, "hi!");
> }
> 
> They have completely different syntax and features.  Static struct 
> initializers are far more powerful: you can name members, initialize them 
> out of order, and skip arbitrary members.  

This is the only place where I disagree with you.  Static struct 
initializers are more powerful in the ways you list, but in other ways 
they are less powerful.  With the static opCall you can make the 
parameters be whatever you want them to be -- they don't necessarily 
have to correspond to an actual member of the struct.  And you can also 
put arbitrary extra construction logic inside a static opCall.

So I like the idea generally, but I would like it much better if there 
were some way to override the default behavior of S{ 5, y:10, s: "hi!" 
}.  But that seems tricky without having named arguments to begin with.

Perhaps, though, it would be enough to allow overriding the non-named 
argument flavors?  I.e. you can have an opConstruct that implements 
S{5,10,"hi"}, but not one for S{5,y:10,s:"hi!"}.

Or named arguments get filtered out, so S{5,y:10,s:"hi!"} sets y=10 and 
s="hi!" then calls S{5}.  Too subtle maybe?

--bb

> ------
> 
> Dreaming, this also opens up the possibility for named function parameters. 
> Consider a function:

Agreed.  Struct literals seem like a good way to do named function 
parameters.

> 
> struct Args
> {
>     void* dest;
>     void* src;
>     size_t num;
> }
> 
> void memcopy(Args args)
> {
>     // Copy args.num bytes from args.src to args.dest
> }
> 
> ...
> 
> memcopy(Args{ dst, src, 8 }); // Use ordered params
> memcopy(Args{ src: a, dest: b, num: a.length }); // Use named params
> 
> The issue with this is that you have to have a different named struct for 
> every function that takes this style of parameters.  

That is a pain.

> But -- here's the cool 
> trick -- extend typesafe variadic parameters to take structures like they 
> already do for classes...
> 
> void memcopy(Args args...) // hee hee!
> 
> memcopy(dst, src, 8); // woah, looks like a normal function..
> memcopy(src: a, dest: b, num: a.length); // bam, named params for free!
> 
> Having colons in the parameter list for a function call is also unambiguous. 

Yeh, then maybe you could even extend that to the declaration of the 
function too with an anonymous struct as the parameter:

void memcopy(struct{void *src, void *dest, size_t num});

Seems possible, though not necessarily easy for Mr. Compiler Writer.
Main problem is overloading.  How do you pick the right version of 
memcopy if there are several when presented a call like:

     memcopy(src: a, dest: b, num: a.length);

--bb



More information about the Digitalmars-d mailing list