Jump to page: 1 2
Thread overview
people[name=="Andrew"].friends ~= peter
May 05, 2006
antonio
May 05, 2006
Daniel Keep
OT Re: people[name=="Andrew"].friends ~= peter
May 05, 2006
Carlos Santander
May 05, 2006
Daniel Keep
May 05, 2006
antonio
May 07, 2006
Daniel Keep
May 07, 2006
antonio
May 08, 2006
Antonio
May 09, 2006
Thomas Kuehne
May 09, 2006
Antonio
May 09, 2006
Antonio
May 05, 2006
Oskar Linde
May 05, 2006
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 05, 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];
> 
> 
> ---
> 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 05, 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 05, 2006

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
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[married].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
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 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".
> 
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
      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 :)
> 
Spanish sintax :-).  thanks a lot
Antonio



May 07, 2006

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?
>> 
> integer expresion refers always to the index.  a char[] expresion refers 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?
>> 
> 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 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".
>> 
> 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.

> *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 :)
>>
>> 
> 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
>       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 07, 2006
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.
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
    /


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

>> *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]
>
> 
¿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?


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.
> 
In my last proposal, ![ ] is an standard D stament... it's necessary to 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."
> 
In my last proposal...  you have to write people![ married] 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 :)
> 
With the last propossal:
    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.
>
> 
this limitation is deprecated with my new proposal.
>> **
>> *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]
>
> 
Yes.
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 :)
>>>
>>> 
>>> 
>> 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
>>       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
>
> 
I will look for... not now... my bed is waiting for me. Good night


May 08, 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 :-)
« First   ‹ Prev
1 2