digitalmars.D - people[name=="Andrew"].friends ~= peter
- antonio (87/87) May 04 2006 As I introduced in http://www.dsource.org/forums/viewtopic.php?t=967
- Daniel Keep (43/168) May 04 2006 I like the idea very much; it's similar to Python generator expressions.
- Carlos Santander (5/8) May 04 2006 I don't recall Antonio ever saying where he's originally from, but the ¿...
- Daniel Keep (6/14) May 05 2006 Yeah, I know. I've just got a thing for non-ASCII characters ^_^
- antonio (106/179) May 05 2006 ...
- Daniel Keep (66/281) May 06 2006 Out of interest, how do you resolve the following:
- antonio (92/291) May 07 2006 Of course... D specification is very clean in this point: structures,
- Antonio (7/7) May 08 2006 Reading my posted message, I felt bad about misspelling. Here you are
- Thomas Kuehne (23/29) May 08 2006 -----BEGIN PGP SIGNED MESSAGE-----
- Oskar Linde (119/228) May 05 2006 Interesting idea. This looks like a general short hand way of expressing...
- Jarrett Billingsley (5/7) May 05 2006 I think it's a very cool idea, but I think it would be better if somethi...
As I introduced in http://www.dsource.org/forums/viewtopic.php?t=967 object relations could be seen as hierarchycal structures. ¿Why not to introduce native syntax to "navigate into"/"Selec from" this kind of hierarchies? ex 1: Add Peter to the friends of people named Andrew and older than 18. Person peter = ...; Person[] people = ...; people[name=="Andrew" && age>18].friends ~= peter; ex 2: Obtain the array of not married people childs. ex 2.a: with duplicates: Person[] modernChilds = people[!married].childs; ex 2.b: without duplicates: Person[] modernChilds = Distinct(people[!married].childs); ex 3: Do something with the married childs of people with friends named Andrew ex 3.a: using foreach (1 by 1 evaluation) foreach( Person someone; people[friends[name=="Andrew"].length!=0].childs[married] ){ someone.doSomething(); } ex 3.b: Only 1 stament: people[friends[name=="Andrew"].length!=0].childs[married].doSomething(); ex 3.c: without duplicates Distinct(people[friends[name=="Andrew"].length!=0].childs[married].doSomething(); (¿could Distinct be solved with a Template?) --- These examples could be solved using "D" standard syntax. ex: (thanks to csauls) Person[] p = cities[name=="Madrid"].population[age>18 && name=="Peter"]; is equivalent to Person[] p; foreach (City x; cities) { with (x) { if (name == "Madrid") { foreach (Person y; population) { with (y) { if (age > 18 && name == "Peter") p ~= y; } } } } } Basically: ARRAY[CONDITION].SOMETHING; could be traslated to: foreach(T x; ARRAY) with(x) if( CONDITION ) { SOMETHING; } When CONDITION contains sub-ARRAY evaluations, it could be expanded as foreach(T x; ARRAY) with(x) { bool b; """Expand CONDITION and put result into b"""; if( b ) { DOSOMETHING; } } Of course, this "expanding" method doesn't solve all the posibilities... people[age>10] = new Person("Foo"); --- The main discussion about this idea was focused in 2 points: 1. "dot" or "not dot": people[.married && .age>18] vs people[married && age>18] "not dot" is more "D" syntax compliat (thanks to csaul). 2.Array syntax vs "Template" syntax: people[married && age>18] vs people![married && age>18] Personally, I prefer "Array syntax": Person p = people[5]; Person[] p = people[3..5]; // 3..5 is a "condition" Person[] p = people[5]; // ¿why not? Person[] p = people[married]; Person[] p = people[age>18 && married]; --- than this "D" proposal is more powerful. I have a very poor english... sorry: be comprensive :-) Antonio
May 04 2006
antonio wrote:As I introduced in http://www.dsource.org/forums/viewtopic.php?t=967 object relations could be seen as hierarchycal structures. ¿Why not to introduce native syntax to "navigate into"/"Selec from" this kind of hierarchies? ex 1: Add Peter to the friends of people named Andrew and older than 18. Person peter = ...; Person[] people = ...; people[name=="Andrew" && age>18].friends ~= peter; ex 2: Obtain the array of not married people childs. ex 2.a: with duplicates: Person[] modernChilds = people[!married].childs; ex 2.b: without duplicates: Person[] modernChilds = Distinct(people[!married].childs); ex 3: Do something with the married childs of people with friends named Andrew ex 3.a: using foreach (1 by 1 evaluation) foreach( Person someone; people[friends[name=="Andrew"].length!=0].childs[married] ){ someone.doSomething(); } ex 3.b: Only 1 stament: people[friends[name=="Andrew"].length!=0].childs[married].doSomething(); ex 3.c: without duplicates Distinct(people[friends[name=="Andrew"].length!=0].childs[married].doSomething(); (¿could Distinct be solved with a Template?) --- These examples could be solved using "D" standard syntax. ex: (thanks to csauls) Person[] p = cities[name=="Madrid"].population[age>18 && name=="Peter"]; is equivalent to Person[] p; foreach (City x; cities) { with (x) { if (name == "Madrid") { foreach (Person y; population) { with (y) { if (age > 18 && name == "Peter") p ~= y; } } } } } Basically: ARRAY[CONDITION].SOMETHING; could be traslated to: foreach(T x; ARRAY) with(x) if( CONDITION ) { SOMETHING; } When CONDITION contains sub-ARRAY evaluations, it could be expanded as foreach(T x; ARRAY) with(x) { bool b; """Expand CONDITION and put result into b"""; if( b ) { DOSOMETHING; } } Of course, this "expanding" method doesn't solve all the posibilities... people[age>10] = new Person("Foo"); --- The main discussion about this idea was focused in 2 points: 1. "dot" or "not dot": people[.married && .age>18] vs people[married && age>18] "not dot" is more "D" syntax compliat (thanks to csaul). 2.Array syntax vs "Template" syntax: people[married && age>18] vs people![married && age>18] Personally, I prefer "Array syntax": Person p = people[5]; Person[] p = people[3..5]; // 3..5 is a "condition" Person[] p = people[5]; // ¿why not? Person[] p = people[married]; Person[] p = people[age>18 && married]; --- than this "D" proposal is more powerful. I have a very poor english... sorry: be comprensive :-) AntonioI like the idea very much; it's similar to Python generator expressions. The example: people[married && age>18] Would be written in Python as: (p for p in people if p.married and p.age>18) With the advantage that you can also do operations on the "p"s: (p.firstName for p in people if ...) Which would return the person's first name instead of the person object itself. But I digress. As I said, I agree with the idea: it's a very nice piece of syntactic sugar. The problem is with the syntax you've chosen. One of D's strengths is that the grammar is context-free, making it easy to implement. But, without knowing anything about context, what does this mean: people[i] Well, if "i" is an integer, then it's indexing the array. If "i" is a member of the elements of the people array, then it would be a conditional expression. But what if it's a member, and "i" is an integer? Is it a conditional or an index then? And what if both are defined? Even if the compiler can work out a way to distinguish this, the syntax in its current form looks very hard for humans to parse in certain fringe cases. As you said, an alternative is "templateish" syntax: people![i] I like this more, since it's *explicit* about what's going on. That "!" means "Hey, don't actually index the array; select elements of it only". The other alternative is to come up with something like Python's notation, where the condition is written "outside" of the array. The advantage with this is that you can also perform transformations on the data (which is also a very common thing to do). At any rate, nice proposal, and I look forward to seeing something come of it :) Oh, one other thing that suddenly occured to me: what if "people" isn't an array? You use 'foreach' in your expansions, but what if "people" CAN be iterated over, but isn't an array in of itself? Then the syntax becomes downright misleading! -- Daniel "Just so long as it doesn't look like SQL" Keep P.S. Your English is better than many people I've seen who don't know any other languages. Also, that upside-down "?" is nifty :) -- v1sw5+8Yhw5ln4+5pr6OFma8u6+7Lw4Tm6+7l6+7D a2Xs3MSr2e4/6+7t4TNSMb6HTOp5en5g6RAHCP http://hackerkey.com/
May 04 2006
Daniel Keep escribió:P.S. Your English is better than many people I've seen who don't know any other languages. Also, that upside-down "?" is nifty :)I don't recall Antonio ever saying where he's originally from, but the ¿ symbol is used in Spanish to open a question. There's also the ¡ symbol. -- Carlos Santander Bernal
May 04 2006
Carlos Santander wrote:Daniel Keep escribió:Yeah, I know. I've just got a thing for non-ASCII characters ^_^ -- Daniel -- v1sw5+8Yhw5ln4+5pr6OFma8u6+7Lw4Tm6+7l6+7D a2Xs3MSr2e4/6+7t4TNSMb6HTOp5en5g6RAHCP http://hackerkey.com/P.S. Your English is better than many people I've seen who don't know any other languages. Also, that upside-down "?" is nifty :)I don't recall Antonio ever saying where he's originally from, but the ¿ symbol is used in Spanish to open a question. There's also the ¡ symbol.
May 05 2006
Daniel Keep escribió:antonio wrote:...As I introduced in http://www.dsource.org/forums/viewtopic.php?t=967 object relations could be seen as hierarchycal structures. ¿Why not to introduce native syntax to "navigate into"/"Selec from" this kind of hierarchies? ex 1: Add Peter to the friends of people named Andrew and older than 18. Person peter = ...; Person[] people = ...; people[name=="Andrew" && age>18].friends ~= peter;...--- The main discussion about this idea was focused in 2 points: 1. "dot" or "not dot": people[.married && .age>18] vs people[married && age>18] "not dot" is more "D" syntax compliat (thanks to csaul). 2.Array syntax vs "Template" syntax: people[married && age>18] vs people![married && age>18] Personally, I prefer "Array syntax": Person p = people[5]; Person[] p = people[3..5]; // 3..5 is a "condition" Person[] p = people[5]; // ¿why not? Person[] p = people[married]; Person[] p = people[age>18 && married];As I said, I agree with the idea: it's a very nice piece of syntactic sugar. The problem is with the syntax you've chosen. One of D's strengths is that the grammar is context-free, making it easy to implement. But, without knowing anything about context, what does this mean: people[i] Well, if "i" is an integer, then it's indexing the array. If "i" is a member of the elements of the people array, then it would be a conditional expression. But what if it's a member, and "i" is an integer? Is it a conditional or an index then?integer expresion refers always to the index. a char[] expresion refers to a key (associative array), etc...And what if both are defined?class Person { public in i; } void main( ) { int i; Person p = new Person(); with( p ) { i = 5; // property of p .i = 3; // dot signifies: one level out of this scope... the int i declared one. } } then people[i] for member people[.i] for out of scope declared integerEven if the compiler can work out a way to distinguish this, the syntax in its current form looks very hard for humans to parse in certain fringe cases. As you said, an alternative is "templateish" syntax: people![i] I like this more, since it's *explicit* about what's going on. That "!" means "Hey, don't actually index the array; select elements of it only".Yes... I think explicit yntax is really more clean:: *you convinced to me :-)* Let's go with the new proposed syntax: _*STEP 0*: drinking from oter sources... XPATH syntax..._ xmlNode.SelectNodes("tagNameA[conditionA]/tagNameB[conditionB]")... * "[condition]" signifies: evaluate this condition on left side tagNode contents. * When no condition is imposed XPath assumes "[true]"; then xmlNode.SelectNodes("*tagNameA/tagNameB[conditionB]*") is equivalent to xmlNode.SelectNodes("*tagNameA[true]/tagNameB[conditionB]*")... _*STEP 1*: lets propose something:_ The syntax used by the XPath D expression must be "autodefined", becuse whe dont want to use the "xmlNode.SelectNodes( ... )" method :-p. One solution is using specific *![Condition]* that defines "this is an XPath condition"... . *AggregateExpression*![*condition*] signifies: evaluate the condition on left side aggregated elements and build an aggregated result with elements that passed condition (the result could be a dynamic array) _*STEP 2* : what to do with not aggregate expressions :-(_ * ex: *Person[] youngGrandmothers = people![childs.length!=0].*mother![age<36]* *NotAggregateExpression*![*condition*] signifies: evaluate the condition on left side Element and build a dynamic result array with 0 or 1 elements (depending on the condition evaluation result). _*STEP 3:* whe have to use ![] in all hierarchy node:_ ex: // whe can asume than *![] is equivalent to ![true]* countries![population>10000000].people![age<3].mother![].mainHome! ].rooms![windows>2] ** some exceptions: the last hierarchy node doesn't need to be followed by the ![] in some cases: * When the node is a Method: ex: people![married].*doSomething();* ** * When the node is a property and it's on the left side of an assignment ex: people![married]*.name = "Peter";* people![married]*.childs ~= new Person();* people![birdtha=today]*.age++; *// This introduce an implicit right side assignment property evaluation... I suppouse this is an "exception" because compiler can solve this easily. _*STEP 4: *right side must be a member. _ Expression![condition].*member* ** _*STEP 5:* How compiler expands this expression._ I suppouse Walter must decide between a preorder or inorder evaluation * preorder: first all parents, then their childs : A![].B![].C![] could be evaluated like this: foreach(a in A) tmpA~=a; foreach(a in tmpA) foreach(b in a.B) tmpB~=b; foreach(b in tmpB) foreach(c in b.C) tmpC~=c * inorder: first parent, then their chids... when childs evaluated next parent... and so on A![].B![].C![] could be evaluated like this foreach(a in A) foreach(b in a.B) foreach (c in b.C) Well... I'm not an expert, but how hierarchy is evaluated is a compiler work and programmer must be isolated about the compiler solution. We can assume than *result elements order can't be predicted* (like realtional model). Results needs to be postprocessed (distinct, sort, ...) if needed.At any rate, nice proposal, and I look forward to seeing something come of it :)I agree... this is, basically, my dream: People writes constantly FOR + IF structures that can be easily expressed with this propossal.Oh, one other thing that suddenly occured to me: what if "people" isn't an array? You use 'foreach' in your expansions, but what if "people" CAN be iterated over, but isn't an array in of itself? Then the syntax becomes downright misleading!D propose an standard implementation for "aggregate" classes... the main goal now is to propose something D compatible: * Is there a standard I_Iterable interface? * foreach( ) recognizes this I_Iterable interface? * Array acomplish with the I_Iterable interface? I_Iterable is not part of D programming Language.... and this is another discussion :-): * It could be perfect some standard Interfaces recognized by the IDisposable interfaces).P.S. Your English is better than many people I've seen who don't know any other languages. Also, that upside-down "?" is nifty :)Spanish sintax :-). thanks a lot Antonio
May 05 2006
antonio wrote:Daniel Keep escribió:Out of interest, how do you resolve the following: char[bool] stuff; In that case, how do you tell between a key and a filter expression?antonio wrote:....As I introduced in http://www.dsource.org/forums/viewtopic.php?t=967 object relations could be seen as hierarchycal structures. ¿Why not to introduce native syntax to "navigate into"/"Selec from" this kind of hierarchies? ex 1: Add Peter to the friends of people named Andrew and older than 18. Person peter = ...; Person[] people = ...; people[name=="Andrew" && age>18].friends ~= peter;....--- The main discussion about this idea was focused in 2 points: 1. "dot" or "not dot": people[.married && .age>18] vs people[married && age>18] "not dot" is more "D" syntax compliat (thanks to csaul). 2.Array syntax vs "Template" syntax: people[married && age>18] vs people![married && age>18] Personally, I prefer "Array syntax": Person p = people[5]; Person[] p = people[3..5]; // 3..5 is a "condition" Person[] p = people[5]; // ¿why not? Person[] p = people[married]; Person[] p = people[age>18 && married];As I said, I agree with the idea: it's a very nice piece of syntactic sugar. The problem is with the syntax you've chosen. One of D's strengths is that the grammar is context-free, making it easy to implement. But, without knowing anything about context, what does this mean: people[i] Well, if "i" is an integer, then it's indexing the array. If "i" is a member of the elements of the people array, then it would be a conditional expression. But what if it's a member, and "i" is an integer? Is it a conditional or an index then?integer expresion refers always to the index. a char[] expresion refers to a key (associative array), etc...I suppose that works... but what if the person writing the code doesn't realize his local variable is being shadowed by the object's member?And what if both are defined?class Person { public in i; } void main( ) { int i; Person p = new Person(); with( p ) { i = 5; // property of p .i = 3; // dot signifies: one level out of this scope... the int i declared one. } } then people[i] for member people[.i] for out of scope declared integerHuzzah :)Even if the compiler can work out a way to distinguish this, the syntax in its current form looks very hard for humans to parse in certain fringe cases. As you said, an alternative is "templateish" syntax: people![i] I like this more, since it's *explicit* about what's going on. That "!" means "Hey, don't actually index the array; select elements of it only".Yes... I think explicit yntax is really more clean:: *you convinced to me :-)*Let's go with the new proposed syntax: *STEP 0*: drinking from oter sources... XPATH syntax... xmlNode.SelectNodes("tagNameA[conditionA]/tagNameB[conditionB]")... * "[condition]" signifies: evaluate this condition on left side tagNode contents. * When no condition is imposed XPath assumes "[true]"; then xmlNode.SelectNodes("*tagNameA/tagNameB[conditionB]*") is equivalent to xmlNode.SelectNodes("*tagNameA[true]/tagNameB[conditionB]*")... *STEP 1*: lets propose something: The syntax used by the XPath D expression must be "autodefined", becuse whe dont want to use the "xmlNode.SelectNodes( ... )" method :-p. One solution is using specific *![Condition]* that defines "this is an XPath condition"... .. *AggregateExpression*![*condition*] signifies: evaluate the condition on left side aggregated elements and build an aggregated result with elements that passed condition (the result could be a dynamic array)Just one point I'd like to make: AggregateExpression may not neccecarily be an array. It's possible that it is, say, a very *very* large iterable object. The syntax so far is fine, but I think user defined classes should be given the option of changing what the result of this is, or even specifying that the result should be an iterable object.*STEP 2* : what to do with not aggregate expressions :-( * ex: *Person[] youngGrandmothers = people![childs.length!=0].*mother![age<36]* *NotAggregateExpression*![*condition*] signifies: evaluate the condition on left side Element and build a dynamic result array with 0 or 1 elements (depending on the condition evaluation result).What if you did this instead: people![childs.length!=0].mother![age<36] ==> ((people![childs.length!=0]).mother)![age<36] In this case, let it be that: * "people![childs.length!=0]" is an aggregate result, * "(...).mother" is an aggregate containing all the values of "mother" from each of the elements in the previous result (ie: a new aggregate result). Obviously, you can't do this with a regular array... * "(...)![age<36]" is yet another aggregate result which selects the appropriate elements from the previous result. Basically, these "aggregate results" would behave kinda sorta like arrays and kinda sorta like iterables without strictly being either. Kinda wishy washy, I know :)*STEP 3:* whe have to use ![] in all hierarchy node: ex: // whe can asume than *![] is equivalent to ![true]* countries![population>10000000].people![age<3].mother![].mainHome! ].rooms![windows>2] **If you take the above suggestion of not using "real" arrays for the intermediates, then you don't need to specify ![] at each level.some exceptions: the last hierarchy node doesn't need to be followed by the ![] in some cases: * When the node is a Method: ex: people![married].*doSomething();*Hmm... not sure if I'm comfortable with that. Selecting data is fine, but then performing an operation on that... The problem is that everywhere else in D, this would be a *single* function call. In this one particular case, it's multiple function calls. If you wanted to do this, I think it might be better to spell it out explicitly: foreach(person ; people![married]) person.doSomething()From the Zen of Python: "Explicit is better than implicit."** * When the node is a property and it's on the left side of an assignment ex: people![married]*.name = "Peter";* people![married]*.childs ~= new Person();* people![birdtha=today]*.age++; *// This introduce an implicit right side assignment property evaluation... I suppouse this is an "exception" because compiler can solve this easily.Looks handy :)*STEP 4: *right side must be a member. Expression![condition].*member*I think the "must be a member" is a bit strict. Currently, you can do things like this: char[] firstFive(char[] a) { return a[0..5]; } auto firstFiveLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".firstFive; I'd like to be able to still do that. Perhaps just saying "use whatever lookup policy D currently uses on arrays" would be sufficient.** *STEP 5:* How compiler expands this expression. I suppouse Walter must decide between a preorder or inorder evaluation * preorder: first all parents, then their childs : A![].B![].C![] could be evaluated like this: foreach(a in A) tmpA~=a; foreach(a in tmpA) foreach(b in a.B) tmpB~=b; foreach(b in tmpB) foreach(c in b.C) tmpC~=c * inorder: first parent, then their chids... when childs evaluated next parent... and so on A![].B![].C![] could be evaluated like this foreach(a in A) foreach(b in a.B) foreach (c in b.C)I would say that in order would be best... provided it's implemented as chained iterators. In other words, each of the intermediate "aggregate results" should only generate elements as neccecary. The reason for this is that then you can perform very complex filters on large data sets. If you did it "preorder", then this would be ludicrously expensive: SomeHugeDataSet![size > 50*Megabytes] .largeInternalObject![size > 75*Megabytes]Well... I'm not an expert, but how hierarchy is evaluated is a compiler work and programmer must be isolated about the compiler solution. We can assume than *result elements order can't be predicted* (like realtional model). Results needs to be postprocessed (distinct, sort, ...) if needed.I've always thought it would be nice to have a few "standard" interfaces attached to things like arrays. Only thing is that I imagine converting between, say, char[] and IIterable!(char) would be very expensive. Again, I like where this proposal is trying to go. One question, 3.0, but it looks quite similar to what you're proposing, and allows you to do selects and transforms. I'd give you an example, but I can't remember any :P -- Daniel -- v1sw5+8Yhw5ln4+5pr6OFma8u6+7Lw4Tm6+7l6+7D a2Xs3MSr2e4/6+7t4TNSMb6HTOp5en5g6RAHCP http://hackerkey.com/At any rate, nice proposal, and I look forward to seeing something come of it :)I agree... this is, basically, my dream: People writes constantly FOR + IF structures that can be easily expressed with this propossal.Oh, one other thing that suddenly occured to me: what if "people" isn't an array? You use 'foreach' in your expansions, but what if "people" CAN be iterated over, but isn't an array in of itself? Then the syntax becomes downright misleading!D propose an standard implementation for "aggregate" classes... the main goal now is to propose something D compatible: * Is there a standard I_Iterable interface? * foreach( ) recognizes this I_Iterable interface? * Array acomplish with the I_Iterable interface? I_Iterable is not part of D programming Language.... and this is another discussion :-): * It could be perfect some standard Interfaces recognized by the IDisposable interfaces).
May 06 2006
Daniel Keep escribió:antonio wrote:Of course... D specification is very clean in this point: structures, clases or static/dynamic arrays: if the aggregate is a struct or a class object, that struct or class must have an /opApply/ function with the type: int *opApply*(int delegate(inout /Type/ [, ...]) /dg/); where /Type/ matches the /Type/ used in the foreach declaration of /Identifier /Yes... I think explicit yntax is really more clean:: *you convinced to me :-)*Huzzah :)Let's go with the new proposed syntax: *STEP 0*: drinking from oter sources... XPATH syntax... xmlNode.SelectNodes("tagNameA[conditionA]/tagNameB[conditionB]")... * "[condition]" signifies: evaluate this condition on left side tagNode contents. * When no condition is imposed XPath assumes "[true]"; then xmlNode.SelectNodes("*tagNameA/tagNameB[conditionB]*") is equivalent to xmlNode.SelectNodes("*tagNameA[true]/tagNameB[conditionB]*")... *STEP 1*: lets propose something: The syntax used by the XPath D expression must be "autodefined", becuse whe dont want to use the "xmlNode.SelectNodes( ... )" method :-p. One solution is using specific *![Condition]* that defines "this is an XPath condition"... .. *AggregateExpression*![*condition*] signifies: evaluate the condition on left side aggregated elements and build an aggregated result with elements that passed condition (the result could be a dynamic array)Just one point I'd like to make: AggregateExpression may not neccecarily be an array. It's possible that it is, say, a very *very* large iterable object.The syntax so far is fine, but I think user defined classes should be given the option of changing what the result of this is, or even specifying that the result should be an iterable object.You makes me thing about: my conclusion is that I commited an error supposing than ![ ] must "return" an aggregate object... I't more clean to chante the point of view to a "compiler" stament: the result is, bassycally, a set of iterations over an stament... I explay this clearly in this new fools proposal :-) : *compiler way*: * AgregateExpression![condition] is "equivalent to" foreach( ) with( ) if ( ) structure. This structure must act as a single stament. The problem is how "sub ![] expressions must be expanded". o Example: people![ children![isAGirl].length!=0 ].doSomething children![isAGirl] must act as a single stament that returns something with the length property :-(. In fact, I'm thinking in a most "closed" D programming languaje syntax like: *foreach stament enrichment*: 1: include the condition on foreach stament: foreach(Type obj; Aggregate; obj_scoped_condition) { } Equivalent to: foreach(Type obj; Aggretate) with(obj) if(obj_scoped_condition) { obj_scoped_staments; } On "D XPath way" it could be expressed as: aggregate![obj_scoped_condition]{ obj_scoped_staments; } 2: (risky): foreach must include some agregate "properties" (closed to "array" properties): foreach(....) { }.length (Number of iterations executed ) I think other properties are not necessary. With this new syntax, the example could be expressed in this alternaive way: foreach(Person p; people; foreach(Person child; childs; isAGirl).length!=0 ) { doSomething(); ) Of course, I prefer to write people![ childs![isAGril].length!=0 ]{ doSomething( ); } observe the new derived syntax implications: the right side of the aggregate![ condition] is an Stament, not a property: people![ childs![isAGril].length!=0 ] doSomething( ); // without the dot "." and, of course, the "Subject" of this discussion must be changed to: people![ name=="Andrew" ] friends ~= peter; // really nice :-) of course... this introduce some "problems"... foreach does not returns data: Person[] youngGrandmothers = new Person[]; // We have to separate the declaration people![ childs.length != 0 ] mother![age<36] youngGrandMothers~= this; // and the "~=" assignation.¿Standard D offers some way to build a dynamic array on the fly? (like Person someone = new Person(); Person anotherone = new Person(); int count = new Person[]{ someone, anotherone }; // Hoy do you do this on D? Anyway, with my last proposal, (pure native stament) you can express it using a with( ) if ( ): people![ childs.length!=0 ] with(mother)if(age<36) .... //*STEP 2* : what to do with not aggregate expressions :-( * ex: *Person[] youngGrandmothers = people![childs.length!=0].*mother![age<36]* *NotAggregateExpression*![*condition*] signifies: evaluate the condition on left side Element and build a dynamic result array with 0 or 1 elements (depending on the condition evaluation result).What if you did this instead: people![childs.length!=0].mother![age<36] ==> ((people![childs.length!=0]).mother)![age<36]In my last proposal, ![ ] is an standard D stament... it's necessary to include it.*STEP 3:* whe have to use ![] in all hierarchy node: ex: // whe can asume than *![] is equivalent to ![true]* countries![population>10000000].people![age<3].mother![].mainHome! ].rooms![windows>2] **If you take the above suggestion of not using "real" arrays for the intermediates, then you don't need to specify ![] at each level.In my last proposal... you have to write people![ married] doSomething(); because doSomething() is an stament, like people![married]{ doSometing(); doSomethingElse(); }some exceptions: the last hierarchy node doesn't need to be followed by the ![] in some cases: * When the node is a Method: ex: people![married].*doSomething();*Hmm... not sure if I'm comfortable with that. Selecting data is fine, but then performing an operation on that... The problem is that everywhere else in D, this would be a *single* function call. In this one particular case, it's multiple function calls. If you wanted to do this, I think it might be better to spell it out explicitly: foreach(person ; people![married]) person.doSomething()From the Zen of Python: "Explicit is better than implicit."With the last propossal: people![married] name="Peter"; people![married] childs~= new Person(); people![birthday == today] age++;** * When the node is a property and it's on the left side of an assignment ex: people![married]*.name = "Peter";* people![married]*.childs ~= new Person();* people![birdtha=today]*.age++; *// This introduce an implicit right side assignment property evaluation... I suppouse this is an "exception" because compiler can solve this easily.Looks handy :)this limitation is deprecated with my new proposal.*STEP 4: *right side must be a member. Expression![condition].*member*I think the "must be a member" is a bit strict. Currently, you can do things like this: char[] firstFive(char[] a) { return a[0..5]; } auto firstFiveLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".firstFive; I'd like to be able to still do that. Perhaps just saying "use whatever lookup policy D currently uses on arrays" would be sufficient.Yes. inorder is implicit in my last propossal... because each ![] is a separate stament (without dot) A![] B![] C![]** *STEP 5:* How compiler expands this expression. I suppouse Walter must decide between a preorder or inorder evaluation * preorder: first all parents, then their childs : A![].B![].C![] could be evaluated like this: foreach(a in A) tmpA~=a; foreach(a in tmpA) foreach(b in a.B) tmpB~=b; foreach(b in tmpB) foreach(c in b.C) tmpC~=c * inorder: first parent, then their chids... when childs evaluated next parent... and so on A![].B![].C![] could be evaluated like this foreach(a in A) foreach(b in a.B) foreach (c in b.C)I would say that in order would be best... provided it's implemented as chained iterators. In other words, each of the intermediate "aggregate results" should only generate elements as neccecary. The reason for this is that then you can perform very complex filters on large data sets. If you did it "preorder", then this would be ludicrously expensive: SomeHugeDataSet![size > 50*Megabytes] .largeInternalObject![size > 75*Megabytes]I will look for... not now... my bed is waiting for me. Good nightWell... I'm not an expert, but how hierarchy is evaluated is a compiler work and programmer must be isolated about the compiler solution. We can assume than *result elements order can't be predicted* (like realtional model). Results needs to be postprocessed (distinct, sort, ...) if needed.I've always thought it would be nice to have a few "standard" interfaces attached to things like arrays. Only thing is that I imagine converting between, say, char[] and IIterable!(char) would be very expensive. Again, I like where this proposal is trying to go. One question, 3.0, but it looks quite similar to what you're proposing, and allows you to do selects and transforms. I'd give you an example, but I can't remember any :P -- DanielAt any rate, nice proposal, and I look forward to seeing something come of it :)I agree... this is, basically, my dream: People writes constantly FOR + IF structures that can be easily expressed with this propossal.Oh, one other thing that suddenly occured to me: what if "people" isn't an array? You use 'foreach' in your expansions, but what if "people" CAN be iterated over, but isn't an array in of itself? Then the syntax becomes downright misleading!D propose an standard implementation for "aggregate" classes... the main goal now is to propose something D compatible: * Is there a standard I_Iterable interface? * foreach( ) recognizes this I_Iterable interface? * Array acomplish with the I_Iterable interface? I_Iterable is not part of D programming Language.... and this is another discussion :-): * It could be perfect some standard Interfaces recognized by the IDisposable interfaces).
May 07 2006
Reading my posted message, I felt bad about misspelling. Here you are a rewritten paragraph: You makes me think about: my conclusion is that I commited an error supposing than ![ ] must "return" an aggregate object... It's more clean to change the point of view to a "compiler" stament: the result is, basically, a set of iterations over an stament... I explain this clearly in this new fools proposal :-)
May 08 2006
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 antonio schrieb am 2006-05-07: <snip>¿Standard D offers some way to build a dynamic array on the fly? (like Person someone = new Person(); Person anotherone = new Person(); int count = new Person[]{ someone, anotherone }; // Hoy do you do this on D?shouldn't this be: D kludge: Thomas -----BEGIN PGP SIGNATURE----- iD0DBQFEX0KM3w+/yD4P9tIRAmpKAJiMFtf5O+Rwk40lwN1BRZtK6mo9AJYwC5e9 vvb3XmuoYeQbRXm2340Y =Knpn -----END PGP SIGNATURE-----
May 08 2006
Thanks a lot. Really nice... I think, I have to participate more actively in the d.D.learn forum :-p. Thomas Kuehne escribió:-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 antonio schrieb am 2006-05-07: <snip>�Standard D offers some way to build a dynamic array on the fly? (like Person someone = new Person(); Person anotherone = new Person(); int count = new Person[]{ someone, anotherone }; // Hoy do you do this on D?shouldn't this be: D kludge: Thomas -----BEGIN PGP SIGNATURE----- iD0DBQFEX0KM3w+/yD4P9tIRAmpKAJiMFtf5O+Rwk40lwN1BRZtK6mo9AJYwC5e9 vvb3XmuoYeQbRXm2340Y =Knpn -----END PGP SIGNATURE-----
May 09 2006
Thomas Kuehne escribió:-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 antonio schrieb am 2006-05-07: <snip>int count = new Person[]{ someone, anotherone }.length�Standard D offers some way to build a dynamic array on the fly? (like Person someone = new Person(); Person anotherone = new Person(); int count = new Person[]{ someone, anotherone }; // Hoy do you do this on D?shouldn't this be:D kludge: Thomas -----BEGIN PGP SIGNATURE----- iD0DBQFEX0KM3w+/yD4P9tIRAmpKAJiMFtf5O+Rwk40lwN1BRZtK6mo9AJYwC5e9 vvb3XmuoYeQbRXm2340Y =Knpn -----END PGP SIGNATURE-----
May 09 2006
Hi Antonio, antonio wrote:As I introduced in http://www.dsource.org/forums/viewtopic.php?t=967 object relations could be seen as hierarchycal structures. ¿Why not to introduce native syntax to "navigate into"/"Selec from" this kind of hierarchies?Interesting idea. This looks like a general short hand way of expressing select and map operations. The syntax has some problems though. See the comments below. In my std.array proposal http://www.digitalmars.com/d/archives/digitalmars/D/35455.html I have implemented .filter() and .map() function templates that allow a way of expressing the below examples in a way that work with current D. (Maybe .filter() should be renamed .select()?). I am attaching examples of how your examples would look with my std.array syntax. Those examples are rather wordy, mostly because there is no short hand notation for declaring single expression delegates. I'm not saying my examples show a better way to do things than your suggestion (quite the opposite), but they show how those kinds of expressions can be written today. My method also has the downside of creating and then iterating over temporary arrays. It would be great if one could find a way to define iterable array views. I will probably look into that soon. [After rereading, I'm not sure it was a good idea to include this:] As another perspective, I've played with the thought that D had a way of expressing single expression delegates and show how the code would look then. This hypothetical syntax is: {|T x| x+5} which is equivalent to: delegate auto(T x) { return x+5; } where auto is typeof(x+5). ...ex 1: Add Peter to the friends of people named Andrew and older than 18. Person peter = ...; Person[] people = ...; people[name=="Andrew" && age>18].friends ~= peter;With the suggested std.array, the following examples work: foreach (p; people.filter(delegate bool(Person p) { return p.name == "Andrew" && p.age > 18; })) p.friends ~= peter; people.filter(delegate bool(Person p) { return p.name == "Andrew" && p.age > 18; }) .map(delegate void(Person p) { p.friends ~= peter; }); (I'm not sure about the best way to use whitespace in such code...) And a hypothetical example with a short hand delegate notation: people.filter( {|Person p| p.name == "Andrew" && p.age > 18} ) .map( {|Person p| p.friends ~= peter} );ex 2: Obtain the array of not married people childs. ex 2.a: with duplicates: Person[] modernChilds = people[!married].childs;I don't fully understand the semantics of this one. I assume Person.childs is of type Person[]. In that case, the return type of the above would logically be Person[][], not Person[]. In that case: Person[][] modernChilds = people .filter(delegate bool(Person p) { return !p.married; }) .map(delegate Person[](Person p) { return p.childs; }); With the (IMHO, strange) assumption that the return value should be a concatenated array, just add a .join(). Hypothetical: Person[][] modernChilds = people .filter( {|Person p| !p.married } ) .map( {|Person p| p.childs } );ex 2.b: without duplicates: Person[] modernChilds = Distinct(people[!married].childs);Thanks for the idea. .distinct() (or maybe .unique()) is something I definitely should add to the std.array proposal. :)ex 3: Do something with the married childs of people with friends named Andrew ex 3.a: using foreach (1 by 1 evaluation) foreach( Person someone; people[friends[name=="Andrew"].length!=0].childs[married] ){ someone.doSomething(); }foreach(someone; people .filter(delegate bool(Person p) { return p.friends.find(delegate bool(Person p) { return p.name == "Andrew"; }) != -1; }) .map(delegate Person[](Person p) { return p.childs; }) .join() .filter(delegate Person[](Person p){ return p.married; })) { someone.doSomething(); } (Phew) Or, assuming Person has get-methods, the last map, join, filter, could be something like: .map(&Person.getChilds).join().filter(&Person.isMarried))ex 3.b: Only 1 stament: people[friends[name=="Andrew"].length!=0].childs[married].doSomething();Same as above, but with a .map instead of foreach. (Maybe a void version of .map() should be named .each() instead...?) Hypothetical: people .filter({|Person p| p.friends.contains({|Person p| p.name=="Andrew"})}) .map( {|Person p| p.childs } ) .join() .filter( {|Person p| p.married } ) .map( {|Person p| p.doSomething() } );ex 3.c: without duplicates Distinct(people[friends[name=="Andrew"].length!=0].childs[mar ied].doSomething(); (¿could Distinct be solved with a Template?)Yes. Something like this (could of course be made more efficient): import /*std.*/array; // Double dereference link above for implementation. // Used for .find() and the MakeDynamic template. /** Returns an array containing only one occurrence of each element. The resulting elements are sorted in order of first occurrence. */ template unique(ArrTy) { MakeDynamic!(ArrTy) unique(ArrTy arr) { MakeDynamic!(ArrTy) ret; foreach(uint ix, e; arr) { if (arr[0..ix].find(e) == -1) ret ~= e; } return ret; } } import std.stdio; void main() { writefln("%s","ababcdbdcbdbaba".unique()); } // Prints "abcd" (MakeDynamic is just there to support static arrays, such as char[15]).--- These examples could be solved using "D" standard syntax. ex: (thanks to csauls) Person[] p = cities[name=="Madrid"].population[age>18 && name=="Peter"]; is equivalent to Person[] p; foreach (City x; cities) { with (x) { if (name == "Madrid") { foreach (Person y; population) { with (y) { if (age > 18 && name == "Peter") p ~= y; } } } } } Basically: ARRAY[CONDITION].SOMETHING; could be traslated to: foreach(T x; ARRAY) with(x) if( CONDITION ) { SOMETHING; } When CONDITION contains sub-ARRAY evaluations, it could be expanded as foreach(T x; ARRAY) with(x) { bool b; """Expand CONDITION and put result into b"""; if( b ) { DOSOMETHING; } } Of course, this "expanding" method doesn't solve all the posibilities... people[age>10] = new Person("Foo"); --- The main discussion about this idea was focused in 2 points: 1. "dot" or "not dot": people[.married && .age>18] vs people[married && age>18] "not dot" is more "D" syntax compliat (thanks to csaul).This has the same problem as arr[length]. Assume you have the following piece of code: void petersBirthday() { Person people[] = everyone(); int index = people.indexOf(peter); people[index].age++; } What happens if Person contains a member called index?2.Array syntax vs "Template" syntax: people[married && age>18] vs people![married && age>18] Personally, I prefer "Array syntax": Person p = people[5]; Person[] p = people[3..5]; // 3..5 is a "condition" Person[] p = people[5]; // ¿why not? Person[] p = people[married]; Person[] p = people[age>18 && married];The array syntax seems ambiguous. I think normal (single element) indexing needs to have a different syntax from selection/filtered indexing. (Unless D had a more stringent separation of bool vs numeric variables.) You also suggest that T should be implicitly convertible to T[] of length 1. Is that a good idea? How would this work with user defined containers? Best regards, Oskar
May 05 2006
"antonio" <antonio abrevia.net> wrote in message news:e3e5pr$1asj$1 digitaldaemon.com...¿Why not to introduce native syntax to "navigate into"/"Selec from" this kind of hierarchies?I think it's a very cool idea, but I think it would be better if something this complex were implemented as a library. It wouldn't be nearly as elegant-looking, but I don't think D needs this as part of the language.
May 05 2006