View mode: basic / threaded / horizontal-split · Log in · Help
June 24, 2008
Proposal: real struct literals
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.

- 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.  The struct literal syntax is far 
more limited: you must initialize the members in order (which quickly gets 
out of hand for more than 2 or 3 members), you can't name them, and you can 
only skip members at the end of the struct.

So I propose that struct "literals" be replaced with actual struct literals, 
which look like static struct initializers.  There is a very obvious, 
simple, unambiguous syntax for this: an identifier, followed by a static 
struct initializer.  Crazy, I know!

static s = S{ 5, y: 10, s: "hi!" };
auto s2 =  S{ 5, y: 10, s: "hi!" };

Now struct literals have all the nice capabilities of static struct 
initializers.  Static struct initializers actually no longer have to be 
special-cased.  The declaration of s above expects the initializer to be 
evaluatable at compile-time, just like any other static declaration, and so 
the struct literal on the RHS now just has to contain all 
compile-time-evaluatable values.  No problem.

------

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

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.  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.
June 24, 2008
Re: Proposal: real struct literals
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.
> 
> - 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.  The struct literal syntax is far 
> more limited: you must initialize the members in order (which quickly gets 
> out of hand for more than 2 or 3 members), you can't name them, and you can 
> only skip members at the end of the struct.
> 
> So I propose that struct "literals" be replaced with actual struct literals, 
> which look like static struct initializers.  There is a very obvious, 
> simple, unambiguous syntax for this: an identifier, followed by a static 
> struct initializer.  Crazy, I know!
> 
> static s = S{ 5, y: 10, s: "hi!" };
> auto s2 =  S{ 5, y: 10, s: "hi!" };
> 
> Now struct literals have all the nice capabilities of static struct 
> initializers.  Static struct initializers actually no longer have to be 
> special-cased.  The declaration of s above expects the initializer to be 
> evaluatable at compile-time, just like any other static declaration, and so 
> the struct literal on the RHS now just has to contain all 
> compile-time-evaluatable values.  No problem.
> 
> ------
> 
> Dreaming, this also opens up the possibility for named function parameters. 
> Consider a function:
> 
> 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.  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. 

Usually I like to find one thing to argue with in these proposals, but that
sounds about perfect. Mad props for typing this all up, though I'm not sure
it'll get anywhere. Try Bugzilla, too.
June 24, 2008
Re: Proposal: real struct literals
On Tue, 24 Jun 2008 22:30:28 +0200, Jarrett Billingsley  
<kb3ctd2@yahoo.com> wrote:

> Dreaming, this also opens up the possibility for named function  
> parameters.

Class literals?

-- 
Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
June 24, 2008
Re: Proposal: real struct literals
"Jarrett Billingsley" wrote
> So I propose that struct "literals" be replaced with actual struct 
> literals, which look like static struct initializers.  There is a very 
> obvious, simple, unambiguous syntax for this: an identifier, followed by a 
> static struct initializer.  Crazy, I know!
>
> static s = S{ 5, y: 10, s: "hi!" };
> auto s2 =  S{ 5, y: 10, s: "hi!" };

Agree 100%

-Steve
June 24, 2008
Re: Proposal: real struct literals
"Mike" <vertex@gmx.at> wrote in message news:op.uc9uhjp1kgfkbn@lucia...
> On Tue, 24 Jun 2008 22:30:28 +0200, Jarrett Billingsley 
> <kb3ctd2@yahoo.com> wrote:
>
>> Dreaming, this also opens up the possibility for named function 
>> parameters.
>
> Class literals?

That, I'm not so sure about.  How often do you have public class fields?  I 
mean, I'm sure someone could come up with a use for them, but structs seem 
much more suited to having literals.
June 24, 2008
Re: Proposal: real struct literals
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
June 24, 2008
Re: Proposal: real struct literals
"Bill Baxter" <dnewsgroup@billbaxter.com> wrote in message 
news:g3rs3g$11ub$1@digitalmars.com...

> 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.

Oo.  Nasty.

>> 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.

I'm proposing them precisely because I _don't_ like that currently struct 
literals and struct constructions overlap syntactically ;)  I was thinking 
that struct literals would not be interceptible, they would be like integer 
or string literals.  And if you want struct construction, use.. the 
constructor (and whatever syntax that implies).

But you do bring up a good point with not being able to distinguish static 
opCall vs. construction.  Still, then you have the reverse problem of what 
we have now -- S{1, 2, 3}, while not looking like a function call, actually 
might be!  :\

> 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});

I seem to remember you being interested in this idea before ;)

> 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);

Tricky, but I'm sure that some (reasonable) constraints could be put on this 
type of function to make it easier to disambiguate.

Failing using structs as named parameters, there's certainly nothing 
stopping the compiler from allowing named parameters with functions as they 
are now.  They have the names right there :P
June 25, 2008
Re: Proposal: real struct literals
Jarrett Billingsley wrote:
> "Bill Baxter" <dnewsgroup@billbaxter.com> wrote in message 
> news:g3rs3g$11ub$1@digitalmars.com...
> 

>>> 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.
> 
> I'm proposing them precisely because I _don't_ like that currently struct 
> literals and struct constructions overlap syntactically ;)  I was thinking 
> that struct literals would not be interceptible, they would be like integer 
> or string literals.  And if you want struct construction, use.. the 
> constructor (and whatever syntax that implies).

Ok.  Yeh, I can see some benefit in that too.  A POL, Plain Old Literal, 
to go with your POD, Plain Old Data.

> But you do bring up a good point with not being able to distinguish static 
> opCall vs. construction.  Still, then you have the reverse problem of what 
> we have now -- S{1, 2, 3}, while not looking like a function call, actually 
> might be!  :\

I suppose D structs could just do without a static opCall.  Actually I 
think the only real problem is that right now "aninstance()" could be a 
call to either "void static opCall()" or "void opCall()" when both are 
defined, and so the compiler gives a conflict message.  But if instead 
of static opCall you had a "constructor" then it wouldn't be considered 
a candidate for a call like "aninstance()".

So hopefully that is basically what Walter has planned for the struct 
constructors.

>> 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});
> 
> I seem to remember you being interested in this idea before ;)

Oh, yeh.  No wonder it seemed to resonate. :-)

>> 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);
> 
> Tricky, but I'm sure that some (reasonable) constraints could be put on this 
> type of function to make it easier to disambiguate.

One thing that's lacking is that you wouldn't be able to tell which 
named parameters were set vs which not set.

> Failing using structs as named parameters, there's certainly nothing 
> stopping the compiler from allowing named parameters with functions as they 
> are now.  They have the names right there :P 

Except 36 years of experience with C and C++ that makes people expect 
that the names of formal parameters don't matter.  I think the only way 
to make such a big change palatable at this point is to require some 
special syntax to use it.

--bb
June 25, 2008
Re: Proposal: real struct literals
"Bill Baxter" <dnewsgroup@billbaxter.com> wrote in message 
news:g3s45g$1ork$1@digitalmars.com...

>> Tricky, but I'm sure that some (reasonable) constraints could be put on 
>> this type of function to make it easier to disambiguate.
>
> One thing that's lacking is that you wouldn't be able to tell which named 
> parameters were set vs which not set.

Ooh, yeah.

>> Failing using structs as named parameters, there's certainly nothing 
>> stopping the compiler from allowing named parameters with functions as 
>> they are now.  They have the names right there :P
>
> Except 36 years of experience with C and C++ that makes people expect that 
> the names of formal parameters don't matter.  I think the only way to make 
> such a big change palatable at this point is to require some special 
> syntax to use it.

Funny, I don't feel the same way, probably because I've used D more than I 
have C or C++ ;)
June 25, 2008
Re: Proposal: real struct literals
Jarrett Billingsley wrote:
> "Bill Baxter" <dnewsgroup@billbaxter.com> wrote in message 
> news:g3s45g$1ork$1@digitalmars.com...
> 
>>> Tricky, but I'm sure that some (reasonable) constraints could be put on 
>>> this type of function to make it easier to disambiguate.
>> One thing that's lacking is that you wouldn't be able to tell which named 
>> parameters were set vs which not set.
> 
> Ooh, yeah.
> 
>>> Failing using structs as named parameters, there's certainly nothing 
>>> stopping the compiler from allowing named parameters with functions as 
>>> they are now.  They have the names right there :P
>> Except 36 years of experience with C and C++ that makes people expect that 
>> the names of formal parameters don't matter.  I think the only way to make 
>> such a big change palatable at this point is to require some special 
>> syntax to use it.
> 
> Funny, I don't feel the same way, probably because I've used D more than I 
> have C or C++ ;) 

Ok, but it would have impact on a backlog of 10 years' worth of D code 
too.  I agree it would be cool to have, but I also agree with Walter 
that switching D's default scheme to named parameters at this point 
would incur too much cost for too little benefit.

But when whoever sits down to start writing D++ or E, I hope he gives 
named parameters some serious thought.  That and putting the type after 
the variable instead of before.

--bb
« First   ‹ Prev
1 2
Top | Discussion index | About this forum | D home