digitalmars.D - Anonymous structs
- Jacob Carlborg (80/80) Feb 11 2013 I've been thinking for this feature for a while. An anonymous struct is
- Nick Sabalausky (1/1) Feb 11 2013 Isn't that all basically syntax sugar for tuples?
- Jacob Carlborg (9/10) Feb 11 2013 I didn't really thing of tuples, but it might be considered that. I
- Russel Winder (13/14) Feb 12 2013 At EuroPython 2010 Guido van Rossum reported that tuple literals were
- Martin Nowak (3/4) Feb 13 2013 The tuple problem again was my first thought too.
- Jacob Carlborg (4/6) Feb 13 2013 That looks quite similar. I'll have to read through the whole issue.
- Era Scarecrow (19/32) Feb 11 2013 What if there's another anonymous struct that has a little more?
- Jacob Carlborg (10/22) Feb 11 2013 "point2" is completely independent of the other declarations. But you
- Era Scarecrow (40/64) Feb 12 2013 Maybe if it was an interpreted language or scripting, but not
- Jacob Carlborg (27/80) Feb 12 2013 This has nothing to do with some other struct. It's lowered to something...
- Era Scarecrow (33/42) Feb 12 2013 Seems I did misread what you had, however having it creating
- Jacob Carlborg (4/9) Feb 12 2013 I don't know what you're talking about. Where did "delegate" come from?
- Era Scarecrow (53/61) Feb 13 2013 Then let's step back. You can make a scope block without having
- Jacob Carlborg (10/26) Feb 13 2013 My suggestion is for anonymous structs, nothing else. It can only
- Era Scarecrow (18/26) Feb 13 2013 I'm aware of that.
- Jacob Carlborg (7/21) Feb 13 2013 I think this all sounds like a big misunderstanding. I though you wanted...
- MattCoder (9/15) Feb 11 2013 At the first look it seems interesting, but imagine that you need
- Jacob Carlborg (15/32) Feb 11 2013 If you add a new member to the anonymous struct declared in "foo" any
- Brian Schott (4/5) Feb 11 2013 That looks like it would confuse the parser because it looks
- Jacob Carlborg (5/7) Feb 11 2013 That might be the case, I have no idea. Is there another syntax that
- Michael (6/6) Feb 13 2013 In some DSL a struct can be defined as something like:
I've been thinking for this feature for a while. An anonymous struct is basically what it sound like, a struct without a name. The inserting part is its members. If two anonymous structs have the same members (not necessarily in the same order) they are considered to be of the same type. This shows how anonymous structs looks like: { int x, int y } point = { y: 4, x: 5 }; auto point2 = { x: 1, y: 2 }; point = point2; In this example "point" and "point2" are of the same type since they have the same members. This is basically lowered to something similar to: struct __AnonymousStruct_int_x_int_y { int x; int y; } __AnonymousStruct_int_x_int_y point; point.y = 4; point.x = 5; __AnonymousStruct_int_x_int_y point2; point2.x = 1; point2.y = 2; point = point2; The compiler will implicitly generate a new struct type with a name that will always be the same if it has the same members. These structs will then behave just like any other structs, accessing members and so on. assert(point2.x == 1); assert(point.y == 2); The advantage of anonymous structs is that they can be declared in place, in function declartions for example: void foo ({ int x, int y } point) { } foo({ y: 5, x: 3 }); When calling a function and passing in an anonymous structs it's possible to drop the braces to get a more pleasing and less verbose syntax: foo(y: 5, x: 3); With this syntax sugar we can basically get named parameters. With the braces it also looks like JSON. Anonymous structs can be implicitly converted to and from regular named struts: * Named struct to anonymous struct: struct Bar { int x; int y; } foo(Bar(1, 2)); * Anonymous struct to named struct: void bar (Bar b) {} bar(x: 3, y: 4); It would also be nice to have opDispatch soak up everything that doesn't match, if it's declared in a named struct: struct Options { int x; int y; private Variant[string] members; void opDispatch (string name, T) (T t) { members[name] = Variant(t); } } void fooBar (Options options) {} fooBar(x: 5, a: "asd", y: 1.2, b: 4); "x" and "y" are matched with the regular members, "a" and "b" are matched to opDispatch which takes care of them. Perhaps this initializer syntax can be used for classes as well: class FooBar { int x; int y; } FooBar fb = { x: 3, y: 5 }; The above would be lowered to: FooBar fb = new FooBar(); fb.x = 3; fb.y = 5; Thoughts? -- /Jacob Carlborg
Feb 11 2013
Isn't that all basically syntax sugar for tuples?
Feb 11 2013
On 2013-02-11 22:54, Nick Sabalausky wrote:Isn't that all basically syntax sugar for tuples?I didn't really thing of tuples, but it might be considered that. I assume you are referring to std.typecons.Tuple? Except the syntax, there are some limitations with Tuple. It cannot be implicitly converted to other types based on its members. I don't know if that's possible to fix. It can also contain just types, or just values. BTW, isn't tuples and structs basically the same thing in the end. -- /Jacob Carlborg
Feb 11 2013
On Mon, 2013-02-11 at 16:54 -0500, Nick Sabalausky wrote:Isn't that all basically syntax sugar for tuples?At EuroPython 2010 Guido van Rossum reported that tuple literals were always intended to be thought of as struct literals. --=20 Russel. =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel.winder ekiga.n= et 41 Buckmaster Road m: +44 7770 465 077 xmpp: russel winder.org.uk London SW11 1EN, UK w: www.russel.org.uk skype: russel_winder
Feb 12 2013
On 02/11/2013 10:54 PM, Nick Sabalausky wrote:Isn't that all basically syntax sugar for tuples?The tuple problem again was my first thought too. http://d.puremagic.com/issues/show_bug.cgi?id=6365
Feb 13 2013
On 2013-02-13 18:42, Martin Nowak wrote:The tuple problem again was my first thought too. http://d.puremagic.com/issues/show_bug.cgi?id=6365That looks quite similar. I'll have to read through the whole issue. -- /Jacob Carlborg
Feb 13 2013
On Monday, 11 February 2013 at 21:30:52 UTC, Jacob Carlborg wrote:I've been thinking for this feature for a while. An anonymous struct is basically what it sound like, a struct without a name. The inserting part is its members. If two anonymous structs have the same members (not necessarily in the same order) they are considered to be of the same type. This shows how anonymous structs looks like: { int x, int y } point = { y: 4, x: 5 }; auto point2 = { x: 1, y: 2 }; point = point2; In this example "point" and "point2" are of the same type since they have the same members. This is basically lowered to something similar to:What if there's another anonymous struct that has a little more? { int x, int y } point = { y: 4, x: 5 }; { int x, int y, int color } color_point = { y: 4, x: 5, color: 0x000000 }; //which anonymous struct does it go with? //Or can auto only work with named/returned structs? auto point2 = { x: 1, y: 2 }; point = point2; //error, point2 type void _error We can instantiate structs with fewer arguments than elements they hold. It would either have to go the safe route, or try it's best to either be 'safe' or 'whatever seems to work' until you change something and break it utterly with no description of 'what' it is. Anonymous structs would be more useful as single instances like unions can be in C. (I think it's disallowed in D, or I had trouble with them) Nick Sabalausky wrote:Isn't that all basically syntax sugar for tuples?Maybe. I would think an explicit tuple would be better.
Feb 11 2013
On 2013-02-11 23:20, Era Scarecrow wrote:What if there's another anonymous struct that has a little more? { int x, int y } point = { y: 4, x: 5 }; { int x, int y, int color } color_point = { y: 4, x: 5, color: 0x000000 }; //which anonymous struct does it go with? //Or can auto only work with named/returned structs? auto point2 = { x: 1, y: 2 }; point = point2; //error, point2 type void _error"point2" is completely independent of the other declarations. But you can think of it having the same type as "point". It can also be implicitly converted to "color_point". It's not the actual type that's interesting, it's the members. The compiler checks the members to see if two values are of the same types.We can instantiate structs with fewer arguments than elements they hold. It would either have to go the safe route, or try it's best to either be 'safe' or 'whatever seems to work' until you change something and break it utterly with no description of 'what' it is.It's not the actual type that's interesting, as long as the members match they're considered to be the same type. -- /Jacob Carlborg
Feb 11 2013
On Tuesday, 12 February 2013 at 07:46:31 UTC, Jacob Carlborg wrote:On 2013-02-11 23:20, Era Scarecrow wrote:Maybe if it was an interpreted language or scripting, but not statically typed. Just because they are anonymous doesn't mean they suddenly have new 'alias this' members written to convert from one type to the other. auto point2 = {color: 0x00ff00}; //second definition probably point2 = point; //converts how? May be safe.. point = point2; //loss of data...What if there's another anonymous struct that has a little more? { int x, int y } point = { y: 4, x: 5 }; { int x, int y, int color } color_point = { y: 4, x: 5, color: 0x000000 }; //which anonymous struct does it go with? //Or can auto only work with named/returned structs? auto point2 = { x: 1, y: 2 }; point = point2; //error, point2 type void _error"point2" is completely independent of the other declarations. But you can think of it having the same type as "point". It can also be implicitly converted to "color_point". It's not the actual type that's interesting, it's the members. The compiler checks the members to see if two values are of the same types.Really? Wow... Sounds like an interface... So this means it would auto deduce it's type based on matching... /*each struct could be a lot more complex, but so long as 'x' is present and assignable, then the lower ones allow it to be potentially correct */ struct S{int x; enum y = 0;} struct T{int x; enum y = "str";} struct U{int x; enum y = 0.45;} struct V{int x; enum y = [1, 2];} {int x; enum junk = false;} something = {}; {int x; enum junk = ["some","thing"];} something2 = {}; assert(something.y == false); //probably assert(something2.y == ["some","thing"]); //probably auto x = {}; //legally could be S, T, U or V, or anonymous(s) auto x3 = {45}; //legally could be S, T, U or V, or anonymous(s) auto x2 = {x: 45}; //legally could be S, T, U or V, or anonymous(s) //may or may not work, 1 in 6 as correct. //if these must be true, then they are all S (or annonymous1) assert(x.y == 0); assert(x2.y == 0); assert(x3.y == 0); No, deducing types like this won't work for static typing, be they anonymous or not. The only way they'd work is if they only existed for the one instance, being point or point_color, but auto wouldn't allow you to auto determine it; But still that doesn't seem like a good syntax to have and I'd rather take the extra line to define the type to ensure it's uniqe, Or tuples if it's only data..We can instantiate structs with fewer arguments than elements they hold. It would either have to go the safe route, or try it's best to either be 'safe' or 'whatever seems to work' until you change something and break it utterly with no description of 'what' it is.It's not the actual type that's interesting, as long as the members match they're considered to be the same type.
Feb 12 2013
On 2013-02-12 13:08, Era Scarecrow wrote:On Tuesday, 12 February 2013 at 07:46:31 UTC, Jacob Carlborg wrote:You don't seem to get how I want it to work.On 2013-02-11 23:20, Era Scarecrow wrote:Maybe if it was an interpreted language or scripting, but not statically typed. Just because they are anonymous doesn't mean they suddenly have new 'alias this' members written to convert from one type to the other.What if there's another anonymous struct that has a little more? { int x, int y } point = { y: 4, x: 5 }; { int x, int y, int color } color_point = { y: 4, x: 5, color: 0x000000 }; //which anonymous struct does it go with? //Or can auto only work with named/returned structs? auto point2 = { x: 1, y: 2 }; point = point2; //error, point2 type void _error"point2" is completely independent of the other declarations. But you can think of it having the same type as "point". It can also be implicitly converted to "color_point". It's not the actual type that's interesting, it's the members. The compiler checks the members to see if two values are of the same types.auto point2 = {color: 0x00ff00}; //second definition probablyThis has nothing to do with some other struct. It's lowered to something like: struct __AnonymousStruct_int_color { int color; } point2.color = 0x00ff00; It has nothing to do with "color_point".point2 = point; //converts how? May be safe..Since "point" is declared as: { int x, int y } point; And "point2" is declared as: { int color } point2; It's a type error, the members doesn't match.point = point2; //loss of data...Same as above.Really? Wow... Sounds like an interface...Yes, in a way.So this means it would auto deduce it's type based on matching...When "auto" is used it doesn't try to match on anything else./*each struct could be a lot more complex, but so long as 'x' is present and assignable, then the lower ones allow it to be potentially correct */ struct S{int x; enum y = 0;} struct T{int x; enum y = "str";} struct U{int x; enum y = 0.45;} struct V{int x; enum y = [1, 2];} {int x; enum junk = false;} something = {}; {int x; enum junk = ["some","thing"];} something2 = {}; assert(something.y == false); //probablyType error. "something" doesn't have the member "y".assert(something2.y == ["some","thing"]); //probablySame as above.auto x = {}; //legally could be S, T, U or V, or anonymous(s)No, it has nothing to do with any other declared struct. Don't even now if this would be legal, since it's kind of pointless do have an anonymous struct without members.auto x3 = {45}; //legally could be S, T, U or V, or anonymous(s)No, same as above.auto x2 = {x: 45}; //legally could be S, T, U or V, or anonymous(s)Legal, is and can only be anonymous. It has nothing to do with S, T, U or V. It's anonymous, period.//may or may not work, 1 in 6 as correct. //if these must be true, then they are all S (or annonymous1) assert(x.y == 0); assert(x2.y == 0); assert(x3.y == 0);Compile error for all, since none have the member "y".No, deducing types like this won't work for static typing, be they anonymous or not. The only way they'd work is if they only existed for the one instance, being point or point_color, but auto wouldn't allow you to auto determine it; But still that doesn't seem like a good syntax to have and I'd rather take the extra line to define the type to ensure it's uniqe, Or tuples if it's only data..You obviously don't understand how I want it to work. -- /Jacob Carlborg
Feb 12 2013
On Tuesday, 12 February 2013 at 14:10:41 UTC, Jacob Carlborg wrote:On 2013-02-12 13:08, Era Scarecrow wrote:Seems I did misread what you had, however having it creating dozens of misc/anonymous types doesn't seem like a wise idea. The entire block as it was defined is more like a scope/code block rather than a struct declaration; Then is it a delegate instead? (without return type or input type possibly) int x = 100; int y = { int z; int isPrime(int n); z = x * 100; // z = isPrime(100); //alternate to avoid 'nested' }; //was code block run? (delegate or anonymous function) assert(y.z == 10000); writeln(y.z); //allowed? writeln(y.isprime(x)); //allowed? y(); //allowed? //if y is code block can be run... //last line is return line? Or not? assert(y() == x*100); // assert(y() == 0); //isprime version Now if it relies on x or not, is it now nested or not? Keep in mind the following is completely legal in C/C++/D. I've used this before to help separate and fold code. { //inner scope { int tmp = 256; //some code involving tmp } }No, deducing types like this won't work for static typing, be they anonymous or not. The only way they'd work is if they only existed for the one instance, being point or point_color, but auto wouldn't allow you to auto determine it; But still that doesn't seem like a good syntax to have and I'd rather take the extra line to define the type to ensure it's uniqe, Or tuples if it's only data..You obviously don't understand how I want it to work.
Feb 12 2013
On 2013-02-12 21:30, Era Scarecrow wrote:Seems I did misread what you had, however having it creating dozens of misc/anonymous types doesn't seem like a wise idea. The entire block as it was defined is more like a scope/code block rather than a struct declaration; Then is it a delegate instead? (without return type or input type possibly)I don't know what you're talking about. Where did "delegate" come from? -- /Jacob Carlborg
Feb 12 2013
On Wednesday, 13 February 2013 at 07:28:14 UTC, Jacob Carlborg wrote:On 2013-02-12 21:30, Era Scarecrow wrote:Then let's step back. You can make a scope block without having 'if' or any other statment that separates it. unittest { int x; { x++;//code block is valid } Now if you attach that to a variable it's effectively a delegate, function, or predicate; depending on syntax of how it's called. auto y = delegate void(){ x++; }; auto y = (){ x++; }; //shortened to auto y = { x++; }; //if no calling variables gets shortened to..?? Now if there's only type declarations and no instructions, it can be an anonymous struct (probably), but what if it has code? Is it a code block? The code gets defaulted to a function inside it? Illegal to do period? (at which point it breaks regular compatibility most likely). auto z = {int x,y,color;}; //types only, could be struct... auto z = { //which is it? int x,y,color; x++; y++; color = 0xffffff; }; This can either be 1) POD struct, instructions are illegal 2) instructions called right away, still a POD struct otherwise auto z = { int x,y,color; }; z.x++; z.y++; z.color = 0xffffff; 3) delegate/function/predicate z(); //call is legal, or passable to template function 4) structs legal and instructions are effectively postblit (or opCall or something) struct anonymous_int_x_y_color { int x,y,color; this(this) { x++; y++; color = 0xffffff; } } anonymous_int_x_y_color z; } 5) none of it is legal, leaves you having to specify what it is which is probably safer than assumption or ambiguity. It can be easy to forget a simple set of parenthesis (or semicolon, or equal sign) sometimes when you're programming, having it make assumptions of code 'this is a struct' vs 'this is a delegate' could be quite the annoyance, perhaps with very confusing error messages. IMO the way you're suggest having anonymous structs seems unneeded.Seems I did misread what you had, however having it creating dozens of misc/anonymous types doesn't seem like a wise idea. The entire block as it was defined is more like a scope/code block rather than a struct declaration; Then is it a delegate instead? (without return type or input type possibly)I don't know what you're talking about. Where did "delegate" come from?
Feb 13 2013
On 2013-02-13 09:45, Era Scarecrow wrote:Then let's step back. You can make a scope block without having 'if' or any other statment that separates it. unittest { int x; { x++;//code block is valid } Now if you attach that to a variable it's effectively a delegate, function, or predicate; depending on syntax of how it's called. auto y = delegate void(){ x++; }; auto y = (){ x++; }; //shortened to auto y = { x++; }; //if no calling variables gets shortened to..?? Now if there's only type declarations and no instructions, it can be an anonymous struct (probably), but what if it has code? Is it a code block? The code gets defaulted to a function inside it? Illegal to do period? (at which point it breaks regular compatibility most likely).My suggestion is for anonymous structs, nothing else. It can only contain declarations of fields. I would thought that was pretty clear, especially since the subject says "Anonymous structs" and not something like "Anonymous delegates". I also showed how the syntax is lowered into a regular named struct, which would make things even more clear. But apparently not. Is my English so bad or is it just the idea that is so bad? -- /Jacob Carlborg
Feb 13 2013
On Wednesday, 13 February 2013 at 10:35:08 UTC, Jacob Carlborg wrote:My suggestion is for anonymous structs, nothing else. It can only contain declarations of fields. I would thought that was pretty clear, especially since the subject says "Anonymous structs" and not something like "Anonymous delegates".I'm aware of that.I also showed how the syntax is lowered into a regular named struct, which would make things even more clear. But apparently not. Is my English so bad or is it just the idea that is so bad?More like how to make it syntactically proper/unambiguous & compatible so the compiler could identify and use it properly; Sudden new use(s) of code blocks without somehow clarifying it's intended use (before hand) could be a problem, or worse yet, prevent something better later if it's introduced & used (and you get the same C++ issues where you can't fix/change something without breaking anything relying on a defined feature). Remember, just cause it seems simple (to us) doesn't mean it's simple. Maybe I'm thinking too far ahead... How much extra complexity would be be to add the feature? If we're using say Lex & Yacc for example a simple feature would be only a couple lines; If you need to make whole new branch(es) then it may not be a good idea. If it requires complex rules, then it may not be reliable as we won't remember them all while we're programming.
Feb 13 2013
On 2013-02-13 14:02, Era Scarecrow wrote:More like how to make it syntactically proper/unambiguous & compatible so the compiler could identify and use it properly; Sudden new use(s) of code blocks without somehow clarifying it's intended use (before hand) could be a problem, or worse yet, prevent something better later if it's introduced & used (and you get the same C++ issues where you can't fix/change something without breaking anything relying on a defined feature). Remember, just cause it seems simple (to us) doesn't mean it's simple. Maybe I'm thinking too far ahead... How much extra complexity would be be to add the feature? If we're using say Lex & Yacc for example a simple feature would be only a couple lines; If you need to make whole new branch(es) then it may not be a good idea. If it requires complex rules, then it may not be reliable as we won't remember them all while we're programming.I think this all sounds like a big misunderstanding. I though you wanted to turn my proposal to some kind of delegate. Sometimes it's better to very clear and spell out exactly what one mean, something like: "This syntax will/could conflict with delegates". -- /Jacob Carlborg
Feb 13 2013
On Monday, 11 February 2013 at 21:30:52 UTC, Jacob Carlborg wrote:The advantage of anonymous structs is that they can be declared in place, in function declartions for example: void foo ({ int x, int y } point) { } foo({ y: 5, x: 3 });At the first look it seems interesting, but imagine that you need to change one type or add more members to that struct, have you imagined the mess to change all those declarations? Because that case I prefer the old way: void foo(MyPointStruct point) { } Any changing in "MyPointStruct" will be consumed by all the code.
Feb 11 2013
On 2013-02-11 23:58, MattCoder wrote:On Monday, 11 February 2013 at 21:30:52 UTC, Jacob Carlborg wrote:If you add a new member to the anonymous struct declared in "foo" any existing call will still match. That's just like the current initializer syntax works: struct Bar { int a; int b; } Bar bar = { b: }; // "a" is default initialized If you remove a member from the anonymous struct declared in "foo" you will get a compile error since there will be a member that doesn't match.The advantage of anonymous structs is that they can be declared in place, in function declartions for example: void foo ({ int x, int y } point) { } foo({ y: 5, x: 3 });At the first look it seems interesting, but imagine that you need to change one type or add more members to that struct, have you imagined the mess to change all those declarations?Because that case I prefer the old way: void foo(MyPointStruct point) { } Any changing in "MyPointStruct" will be consumed by all the code.I'm not sure I see the difference compared with the anonymous struct. -- /Jacob Carlborg
Feb 11 2013
On Monday, 11 February 2013 at 21:30:52 UTC, Jacob Carlborg wrote:{ int x, int y } point = { y: 4, x: 5 };That looks like it would confuse the parser because it looks almost exactly like a BlockStatement until you get several tokens in.
Feb 11 2013
On 2013-02-12 00:17, Brian Schott wrote:That looks like it would confuse the parser because it looks almost exactly like a BlockStatement until you get several tokens in.That might be the case, I have no idea. Is there another syntax that would work better that could fit in a function declaration as well? -- /Jacob Carlborg
Feb 11 2013
In some DSL a struct can be defined as something like: auto myStruct = new Struct("a:int; b:string; c:boolean"); So this looks like a simple dictionary or AA like Variant[string] myStruct. I don't see big difference in use. So D Way approach is Tuple -simple and good enough.
Feb 13 2013