www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - people[name=="Andrew"].friends ~= peter

reply antonio <antonio abrevia.net> writes:
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];
   	
	
---
In the forum, we told about C# 2.0 similar sintax based on XPath I think 
than this "D" proposal is more powerful.


I have a very poor english... sorry:  be comprensive :-)
Antonio


		
May 04 2006
next sibling parent reply Daniel Keep <daniel.keep.lists gmail.com> writes:
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];
      
     
 ---
 In the forum, we told about C# 2.0 similar sintax based on XPath I think
 than this "D" proposal is more powerful.
 
 
 I have a very poor english... sorry:  be comprensive :-)
 Antonio
 

I 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
next sibling parent reply Carlos Santander <csantander619 gmail.com> writes:
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
parent Daniel Keep <daniel.keep.lists gmail.com> writes:
Carlos Santander wrote:
 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.

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/
May 05 2006
prev sibling parent reply antonio <antonio abrevia.net> writes:
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 8bit


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?
   

to a key (associative array), etc...
 And what if both are defined?
   

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

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

   

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!
   

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 compiler, like c# foreach or using staments (IIterable and 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 :)
   

Antonio
May 05 2006
parent reply Daniel Keep <daniel.keep.lists gmail.com> writes:
antonio wrote:
 
 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?
   

to a key (associative array), etc...

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?
 And what if both are defined?
   

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 integer

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

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.
 *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.
 
 At any rate, nice proposal, and I look forward to seeing something come
 of it :)

   

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!
   

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 compiler, like c# foreach or using staments (IIterable and IDisposable interfaces).

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, though: have you looked at Linq in C#? I think it's slated for version 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/
May 06 2006
parent reply antonio <antonio abrevia.net> writes:
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 8bit

Daniel Keep escribió:
 antonio wrote:
   
 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.

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

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

c#, java) 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 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.

include it.
   
 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."


doSomething(); because doSomething() is an stament, like people![married]{ doSometing(); doSomethingElse(); }
   
 **

     * 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 :)

people![married] name="Peter"; people![married] childs~= new Person(); people![birthday == today] age++;
   
 *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]

inorder is implicit in my last propossal... because each ![] is a separate stament (without dot) A![] 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 :)

   
       

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!
   
       

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 compiler, like c# foreach or using staments (IIterable and IDisposable interfaces).

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, though: have you looked at Linq in C#? I think it's slated for version 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

Good night
May 07 2006
next sibling parent Antonio <antonio abrevia.net> writes:
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
prev sibling parent reply Thomas Kuehne <thomas-dloop kuehne.cn> writes:
-----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 
 c#, java)

     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: # Person[] count = new Person[]{ someone, anotherone }; D kludge: # # template makeDynArray(T){ # T[] makeDynArray(T[] raw ...){ # return raw.dup; # } # } # # # Person[] count = makeDynArray!(Person)(someone, anotherone); # Thomas -----BEGIN PGP SIGNATURE----- iD0DBQFEX0KM3w+/yD4P9tIRAmpKAJiMFtf5O+Rwk40lwN1BRZtK6mo9AJYwC5e9 vvb3XmuoYeQbRXm2340Y =Knpn -----END PGP SIGNATURE-----
May 08 2006
next sibling parent Antonio <antonio abrevia.net> writes:
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 
 c#, java)

     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: # Person[] count = new Person[]{ someone, anotherone }; D kludge: # # template makeDynArray(T){ # T[] makeDynArray(T[] raw ...){ # return raw.dup; # } # } # # # Person[] count = makeDynArray!(Person)(someone, anotherone); # Thomas -----BEGIN PGP SIGNATURE----- iD0DBQFEX0KM3w+/yD4P9tIRAmpKAJiMFtf5O+Rwk40lwN1BRZtK6mo9AJYwC5e9 vvb3XmuoYeQbRXm2340Y =Knpn -----END PGP SIGNATURE-----

May 09 2006
prev sibling parent Antonio <antonio abrevia.net> writes:
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 
 c#, java)

     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: # Person[] count = new Person[]{ someone, anotherone };

 
 
 D kludge:
 #
 # template makeDynArray(T){
 #     T[] makeDynArray(T[] raw ...){
 #         return raw.dup;
 #     }
 # }
 #
 
 #
 # Person[] count = makeDynArray!(Person)(someone, anotherone);
 #
 
 Thomas
 
 
 -----BEGIN PGP SIGNATURE-----
 
 iD0DBQFEX0KM3w+/yD4P9tIRAmpKAJiMFtf5O+Rwk40lwN1BRZtK6mo9AJYwC5e9
 vvb3XmuoYeQbRXm2340Y
 =Knpn
 -----END PGP SIGNATURE-----

May 09 2006
prev sibling next sibling parent Oskar Linde <oskar.lindeREM OVEgmail.com> writes:
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
prev sibling parent "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"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