The Forum for Discussion about The Third Manifesto and Related Matters

Please or Register to create posts and topics.

Update to Tutorial D, July 2020

PreviousPage 4 of 9Next
Quote from AntC on July 16, 2020, 12:20 pm
Quote from Hugh on July 16, 2020, 11:33 am
Quote from AntC on July 16, 2020, 6:17 am
Quote from Hugh on July 9, 2020, 11:22 am

Here's a response from Chris Date:

Here's a trivial example of the kind of thing I had in mind: 

EXTEND S :

{ WITH ( temp := ( SP MATCHING S ) WHERE QTY > 500 AND NOT ( PNO = 'P1' )  ) :

A := SUM ( temp , QTY ) ,

B := MAX ( temp , QTY ) ,

C := MIN ( temp , QTY ) ,

D := COUNT ( temp ) }

Obviously the definition of temp could be arbitrarily complex in practice.

Obviously, temp is in scope for each of the assigns, overriding any existing definition under normal block-scoping rules.

 

Ah, here's a maybe better example/reworking of Chris's:

EXTEND S :
{ WITH ( temp := ( SP MATCHING REL{ TUP{ S# S# } } ) WHERE QTY > 500 AND NOT ( PNO = 'P1' ) ) :
A := SUM ( temp , QTY ) ,
B := MAX ( temp , QTY ) ,
C := MIN ( temp , QTY ) ,
D := COUNT ( temp ) }
EXTEND S : { WITH ( temp := ( SP MATCHING REL{ TUP{ S# S# } } ) WHERE QTY > 500 AND NOT ( PNO = 'P1' ) ) : A := SUM ( temp , QTY ) , B := MAX ( temp , QTY ) , C := MIN ( temp , QTY ) , D := COUNT ( temp ) }
[snip]

( SP MATCHING REL{ TUP{ S# S# } } ) isn't a valid expression.  The second appearance of S# is undefined (unless a variable of that name is in scope).  You seem to be imagining that the second operand of a dyadic relational operator invocation can reference attributes of the first (a mistake I have made myself before now).  Try putting those operands the other way around if you don't see what I mean.

 

> You seem to be imagining that the second operand of a dyadic relational operator invocation can reference attributes of the first

Thanks Hugh but no, that wouldn't have achieved the logic I was trying for. (What seems to you would have been an identity operation on SP.) I want/expect the free S# to denote the attribute name in the outer S. I expected (didn't imagine) that in an 'open expression' within the body of EXTEND S, free names (i.e. S#) would get bound to attribute names introduced by the target of the EXTEND. That is, even if there were a variable of that name in scope, it would get shadowed by the attribute names introduced via S. Similarly in SUM( temp, QTY), apparently, Tutorial D expects that free names in the exp (second argument to SUM, and note that it can be an exp, not just an <attribute ref>) bind to attribute names introduced by the relexp (first argument).

The r.h. operand of MATCHING (or other dyadic relops) isn't bound by attribute names from the l.h. operand. If that MATCHING were a JOIN, I'd expect I could happily put those operands the other way round.

OK If what I showed doesn't work, how do I achieve the intent of 'recalculating' temp for each tuple in S that's getting EXTENDed? What Dave shows is perhaps the only way? That is

EXTEND S :
{ temp := ( SP MATCHING REL{ TUP{ S# S# } } ) WHERE QTY > 500 AND NOT ( PNO = 'P1' ) ,
A := SUM ( temp , QTY ) ,
B := MAX ( temp , QTY ) ,
C := MIN ( temp , QTY ) ,
D := COUNT ( temp )
} {ALL BUT temp}
EXTEND S : { temp := ( SP MATCHING REL{ TUP{ S# S# } } ) WHERE QTY > 500 AND NOT ( PNO = 'P1' ) , A := SUM ( temp , QTY ) , B := MAX ( temp , QTY ) , C := MIN ( temp , QTY ) , D := COUNT ( temp ) } {ALL BUT temp}
EXTEND S :
{ temp := ( SP MATCHING REL{ TUP{ S# S# } } ) WHERE QTY > 500 AND NOT ( PNO = 'P1' ) ,
  A := SUM ( temp , QTY ) ,
  B := MAX ( temp , QTY ) ,
  C := MIN ( temp , QTY ) ,
  D := COUNT ( temp ) 
} {ALL BUT temp}

Or will that not work either? Why not?

Where does the Tutorial D spec tell us which syntactic constructs introduce attribute names into scope; and what is the textual extent of that scope in the 'body' of the construct?

 

 

The spec might have benefited from a phrase along the lines of, "Unless otherwise specified, semantics and scope should be assumed to essentially be those of well-known, conventional imperative programming languages such as C, PL/I, and Pascal."

I've picked languages that were well-known at the time the initial Tutorial D specs were written, of course. Java was brand new or still soon-to-be, C# didn't exist yet, Python still too obscure to mention, JavaScript should never be mentioned except disparagingly, and so forth.

The "unless otherwise specified" means "open expressions", for which some description of lambda expressions -- which they effectively are -- might be helpful now, though at the time the first Tutorial D specs were written probably wouldn't generally have been any more familiar than "open expressions."

Indeed, that might still be the case. Even in popular conventional languages that support some form of lambda expressions, I get the impression that a significant number of working programmers treat them as "nope, I don't get that stuff" or "that's that 'functional' crap, innit?"

I'm the forum administrator and lead developer of Rel. Email me at dave@armchair.mb.ca with the Subject 'TTM Forum'. Download Rel from https://reldb.org

Where does the Tutorial D spec tell us which syntactic constructs introduce attribute names into scope; and what is the textual extent of that scope in the 'body' of the construct?

The spec might have benefited from a phrase along the lines of, "Unless otherwise specified, semantics and scope should be assumed to essentially be those of well-known, conventional imperative programming languages such as C, PL/I, and Pascal."

I've picked languages that were well-known at the time the initial Tutorial D specs were written, of course. Java was brand new or still soon-to-be, C# didn't exist yet, Python still too obscure to mention, JavaScript should never be mentioned except disparagingly, and so forth.

The "unless otherwise specified" means "open expressions", for which some description of lambda expressions -- which they effectively are -- might be helpful now, though at the time the first Tutorial D specs were written probably wouldn't generally have been any more familiar than "open expressions."

There was (and is) absolutely nothing on the planet quite like 'open expressions'. You can model your general rules for operators and blocks on Algol 60 or any of its descendants, but when you implemented open expressions you were Robinson Crusoe, first man on the island. Yes, Lisp had lambda functions and various languages since have appropriated that term (I dislike it, but we're stuck with it), but they have little in common. It's not a block, it has no local scope, it's not a closure, it has no well-defined arguments, it has no well-defined surrounding scope. It's a bit of a bastard.

It is what it says, merely an expression in which identifiers corresponding to relation attributes appear to take on successive values during the execution of some surrounding algorithm. I think it does D languages a disservice. I think there are far better ways to do what it does.

Indeed, that might still be the case. Even in popular conventional languages that support some form of lambda expressions, I get the impression that a significant number of working programmers treat them as "nope, I don't get that stuff" or "that's that 'functional' crap, innit?"

Fortunately there are none of those amongst present company.

Andl - A New Database Language - andl.org
Quote from Dave Voorhis on July 17, 2020, 10:27 am
Quote from AntC on July 16, 2020, 12:20 pm
Quote from Hugh on July 16, 2020, 11:33 am
Quote from AntC on July 16, 2020, 6:17 am
Quote from Hugh on July 9, 2020, 11:22 am

Here's a response from Chris Date:

Here's a trivial example of the kind of thing I had in mind: 

EXTEND S :

{ WITH ( temp := ( SP MATCHING S ) WHERE QTY > 500 AND NOT ( PNO = 'P1' )  ) :

A := SUM ( temp , QTY ) ,

B := MAX ( temp , QTY ) ,

C := MIN ( temp , QTY ) ,

D := COUNT ( temp ) }

Obviously the definition of temp could be arbitrarily complex in practice.

Obviously, temp is in scope for each of the assigns, overriding any existing definition under normal block-scoping rules.

 

Ah, here's a maybe better example/reworking of Chris's:

EXTEND S :
{ WITH ( temp := ( SP MATCHING REL{ TUP{ S# S# } } ) WHERE QTY > 500 AND NOT ( PNO = 'P1' ) ) :
A := SUM ( temp , QTY ) ,
B := MAX ( temp , QTY ) ,
C := MIN ( temp , QTY ) ,
D := COUNT ( temp ) }
EXTEND S : { WITH ( temp := ( SP MATCHING REL{ TUP{ S# S# } } ) WHERE QTY > 500 AND NOT ( PNO = 'P1' ) ) : A := SUM ( temp , QTY ) , B := MAX ( temp , QTY ) , C := MIN ( temp , QTY ) , D := COUNT ( temp ) }
[snip]

( SP MATCHING REL{ TUP{ S# S# } } ) isn't a valid expression.  The second appearance of S# is undefined (unless a variable of that name is in scope).  You seem to be imagining that the second operand of a dyadic relational operator invocation can reference attributes of the first (a mistake I have made myself before now).  Try putting those operands the other way around if you don't see what I mean.

 

> You seem to be imagining that the second operand of a dyadic relational operator invocation can reference attributes of the first

Thanks Hugh but no, that wouldn't have achieved the logic I was trying for. (What seems to you would have been an identity operation on SP.) I want/expect the free S# to denote the attribute name in the outer S. I expected (didn't imagine) that in an 'open expression' within the body of EXTEND S, free names (i.e. S#) would get bound to attribute names introduced by the target of the EXTEND. That is, even if there were a variable of that name in scope, it would get shadowed by the attribute names introduced via S. Similarly in SUM( temp, QTY), apparently, Tutorial D expects that free names in the exp (second argument to SUM, and note that it can be an exp, not just an <attribute ref>) bind to attribute names introduced by the relexp (first argument).

The r.h. operand of MATCHING (or other dyadic relops) isn't bound by attribute names from the l.h. operand. If that MATCHING were a JOIN, I'd expect I could happily put those operands the other way round.

OK If what I showed doesn't work, how do I achieve the intent of 'recalculating' temp for each tuple in S that's getting EXTENDed? What Dave shows is perhaps the only way? That is

EXTEND S :
{ temp := ( SP MATCHING REL{ TUP{ S# S# } } ) WHERE QTY > 500 AND NOT ( PNO = 'P1' ) ,
A := SUM ( temp , QTY ) ,
B := MAX ( temp , QTY ) ,
C := MIN ( temp , QTY ) ,
D := COUNT ( temp )
} {ALL BUT temp}
EXTEND S : { temp := ( SP MATCHING REL{ TUP{ S# S# } } ) WHERE QTY > 500 AND NOT ( PNO = 'P1' ) , A := SUM ( temp , QTY ) , B := MAX ( temp , QTY ) , C := MIN ( temp , QTY ) , D := COUNT ( temp ) } {ALL BUT temp}
EXTEND S :
{ temp := ( SP MATCHING REL{ TUP{ S# S# } } ) WHERE QTY > 500 AND NOT ( PNO = 'P1' ) ,
  A := SUM ( temp , QTY ) ,
  B := MAX ( temp , QTY ) ,
  C := MIN ( temp , QTY ) ,
  D := COUNT ( temp ) 
} {ALL BUT temp}

Or will that not work either? Why not?

Where does the Tutorial D spec tell us which syntactic constructs introduce attribute names into scope; and what is the textual extent of that scope in the 'body' of the construct?

 

 

The spec might have benefited from a phrase along the lines of, "Unless otherwise specified, semantics and scope should be assumed to essentially be those of well-known, conventional imperative programming languages such as C, PL/I, and Pascal."

And that would work fine for explicitly declared variables, including the Selector and component names for the types of those variables. We could also say that database relvar names we treat as declared in a block outside the program text.

The difficulty is with the attribute names for relvars and relational expressions -- whether for database relvars or for local relvars or for expressions mentioning them or for REL{  } literals.

 

 

The "unless otherwise specified" means "open expressions", for which some description of lambda expressions -- which they effectively are -- might be helpful now, though at the time the first Tutorial D specs were written probably wouldn't generally have been any more familiar than "open expressions."

Indeed, that might still be the case. Even in popular conventional languages that support some form of lambda expressions, I get the impression that a significant number of working programmers treat them as "nope, I don't get that stuff" or "that's that 'functional' crap, innit?"

I can see a sort of 'family resemblance' between the body of lambda terms and open expressions. What drives the scoping of names, though, is the lambda's binding mechanism, which is prefixed to the body, like quantification is prefixed to the 'matrix' of Propositional Logic expressions. That 'functional' stuff shows us the way, because in more modern FP, the binding mechanism 'deconstructs' and binds to the data structure of an argument; it doesn't merely bind a varname to the whole argument:

( λ (Point x y) → sqrt (x ^ 2 + y ^ 2) )

Takes an argument that must be a data structure with Selector/Constructor Point, with therefore two components; binds the first component to x, the second to y; then gives those names scope of the 'body' of the lambda term, to the right of the .

EXTEND S : {  } in my opinion, though Hugh seems to disagree, takes the attribute names of S and gives those names scope of the 'body' of the EXTEND, within the {   }. Thus if there's any same-named attributes in the scope surrounding the EXTEND, they get shadowed.

rx WHERE boolexp takes the attribute names of rx and gives those names scope of the boolexp. Same consideration re shadowing.

rx1 MATCHING rx2 doesn't give the attribute names of rx1 scope within rx2 nor vice versa.

SUM( rx, expr) gives the attribute names of rx scope of the expr.

Applying that to the example Hugh disputes:

EXTEND S :
{ WITH ( temp := ( SP MATCHING REL{ TUP{ S# S# } } ) WHERE QTY > 500 AND NOT ( PNO = 'P1' ) ) :
A := SUM ( temp , QTY ) , ...
(working from the bottom up) The QTY in the SUM( ) is bound to the temp argument of SUM( ). The QTY, PNO are bound by the WHERE to the relational expression (SP MATCHING ...). The MATCHING doesn't bind attribute names of either operand.
The WITH binds only the names appearing on lhs of :=, i.e. temp. In particular, if the relcon is a relation, it doesn't bind the attribute names of that relation. The attribute names only get bound if temp is mentioned by an open-expression-inducing operator/function.
The EXTEND S : { ... } binds the attribute names from relvar S, including S#. So in a sub-term REL{ TUP{ S# S#}}, the second S#'s binding is to the S of the EXTEND. There's no binding appearing outside the WITH but inside the EXTEND that would shadow the scope of attribute name S# bound from S.
So -- and I've looked into this further since yesterday's traffic with Hugh -- I think my form is legit (making some reasonable assumptions about how WITH would work inside the body of a relop), and I disagree with Hugh's "isn't a valid expression".
The second form I gave (the compromise with Dave's suggestion) I think is also valid, and could be run in Rel today. (Would need adjusting for whether the actual attribute names are S#, P# or SNO, PNO; and for the the THE_QTY(QTY) business.)
Quote from Dave Voorhis on July 16, 2020, 1:31 pm
Quote from Hugh on July 16, 2020, 11:56 am

Somewhere in the plethora of recent posts in this thread Dave Voorhis said that he removed WITH support on statements in Rel when we deleted it from Tutorial D.  But that deletion took place the day I started this thread and I had previously found that Rel lacked it.  That's why I said I had been encouraged by Rel's lack of support for it.

I beg to differ. It's at the top of page 122 of my paper copy of DTATRM, and roughly the middle of page 127 in DTATRM.pdf:

  • The <with> statement has been dropped and WITH expressions have been clarified.

I remember being a tad disappointed, and there might have been discussion about it on the forum at the time, but I removed it in accordance with DTATRM.

That <with> statement was merely a statement defining one or more local constants, as opposed to a WITH clause that appears as part of a statement.

Perhaps we have been over-cautious on both counts.  If either or both of these constructs are successfully implemented (in Rel for example), I suppose we could reconsider.  I encourage you to have a go!

Hugh

Coauthor of The Third Manifesto and related books.
Quote from AntC on July 16, 2020, 12:20 pm
Quote from Hugh on July 16, 2020, 11:33 am
Quote from AntC on July 16, 2020, 6:17 am
Quote from Hugh on July 9, 2020, 11:22 am

Here's a response from Chris Date:

Here's a trivial example of the kind of thing I had in mind: 

EXTEND S :

{ WITH ( temp := ( SP MATCHING S ) WHERE QTY > 500 AND NOT ( PNO = 'P1' )  ) :

A := SUM ( temp , QTY ) ,

B := MAX ( temp , QTY ) ,

C := MIN ( temp , QTY ) ,

D := COUNT ( temp ) }

Obviously the definition of temp could be arbitrarily complex in practice.

Obviously, temp is in scope for each of the assigns, overriding any existing definition under normal block-scoping rules.

 

Ah, here's a maybe better example/reworking of Chris's:

EXTEND S :
{ WITH ( temp := ( SP MATCHING REL{ TUP{ S# S# } } ) WHERE QTY > 500 AND NOT ( PNO = 'P1' ) ) :
A := SUM ( temp , QTY ) ,
B := MAX ( temp , QTY ) ,
C := MIN ( temp , QTY ) ,
D := COUNT ( temp ) }
EXTEND S : { WITH ( temp := ( SP MATCHING REL{ TUP{ S# S# } } ) WHERE QTY > 500 AND NOT ( PNO = 'P1' ) ) : A := SUM ( temp , QTY ) , B := MAX ( temp , QTY ) , C := MIN ( temp , QTY ) , D := COUNT ( temp ) }
[snip]

( SP MATCHING REL{ TUP{ S# S# } } ) isn't a valid expression.  The second appearance of S# is undefined (unless a variable of that name is in scope).  You seem to be imagining that the second operand of a dyadic relational operator invocation can reference attributes of the first (a mistake I have made myself before now).  Try putting those operands the other way around if you don't see what I mean.

 

> You seem to be imagining that the second operand of a dyadic relational operator invocation can reference attributes of the first

Thanks Hugh but no, that wouldn't have achieved the logic I was trying for. (What seems to you would have been an identity operation on SP.) I want/expect the free S# to denote the attribute name in the outer S. I expected (didn't imagine) that in an 'open expression' within the body of EXTEND S, free names (i.e. S#) would get bound to attribute names introduced by the target of the EXTEND. That is, even if there were a variable of that name in scope, it would get shadowed by the attribute names introduced via S. Similarly in SUM( temp, QTY), apparently, Tutorial D expects that free names in the exp (second argument to SUM, and note that it can be an exp, not just an <attribute ref>) bind to attribute names introduced by the relexp (first argument).

The r.h. operand of MATCHING (or other dyadic relops) isn't bound by attribute names from the l.h. operand. If that MATCHING were a JOIN, I'd expect I could happily put those operands the other way round.

OK If what I showed doesn't work, how do I achieve the intent of 'recalculating' temp for each tuple in S that's getting EXTENDed? What Dave shows is perhaps the only way? That is

EXTEND S :
{ temp := ( SP MATCHING REL{ TUP{ S# S# } } ) WHERE QTY > 500 AND NOT ( PNO = 'P1' ) ,
A := SUM ( temp , QTY ) ,
B := MAX ( temp , QTY ) ,
C := MIN ( temp , QTY ) ,
D := COUNT ( temp )
} {ALL BUT temp}
EXTEND S : { temp := ( SP MATCHING REL{ TUP{ S# S# } } ) WHERE QTY > 500 AND NOT ( PNO = 'P1' ) , A := SUM ( temp , QTY ) , B := MAX ( temp , QTY ) , C := MIN ( temp , QTY ) , D := COUNT ( temp ) } {ALL BUT temp}
EXTEND S :
{ temp := ( SP MATCHING REL{ TUP{ S# S# } } ) WHERE QTY > 500 AND NOT ( PNO = 'P1' ) ,
  A := SUM ( temp , QTY ) ,
  B := MAX ( temp , QTY ) ,
  C := MIN ( temp , QTY ) ,
  D := COUNT ( temp ) 
} {ALL BUT temp}

Or will that not work either? Why not?

Where does the Tutorial D spec tell us which syntactic constructs introduce attribute names into scope; and what is the textual extent of that scope in the 'body' of the construct?

See the definition of <extend> on page 24 of the latest version at the TTM website.

Your revised example looks valid to me.  The second appearance of S# is an attribute reference denoting that value of that attribute in the "current tuple" of S, the relation being extended.  Such attribute references are also permitted in SUMMARIZE and WHERE.

Hugh

Coauthor of The Third Manifesto and related books.

Your revised example looks valid to me.  The second appearance of S# is an attribute reference denoting that value of that attribute in the "current tuple" of S, the relation being extended.  Such attribute references are also permitted in SUMMARIZE and WHERE.

This concept of 'current tuple' I find highly suspect. All we are supposed to know is that the attribute names actually appearing in the open expression are bound to certain values, and the result of the expression will be used for some purpose. If we have an open expression (for the S relation) such as STATUS*10, then the computation need only be done 3 times (there are only 3 unique values), so which is the 'current tuple' for these 3 occasions?

I much prefer a set-oriented view in which the entire calculation is performed simultaneously, rather than the iteration implied by 'current tuple'.

Andl - A New Database Language - andl.org
Quote from Hugh on July 17, 2020, 1:44 pm
Quote from Dave Voorhis on July 16, 2020, 1:31 pm
Quote from Hugh on July 16, 2020, 11:56 am

Somewhere in the plethora of recent posts in this thread Dave Voorhis said that he removed WITH support on statements in Rel when we deleted it from Tutorial D.  But that deletion took place the day I started this thread and I had previously found that Rel lacked it.  That's why I said I had been encouraged by Rel's lack of support for it.

I beg to differ. It's at the top of page 122 of my paper copy of DTATRM, and roughly the middle of page 127 in DTATRM.pdf:

  • The <with> statement has been dropped and WITH expressions have been clarified.

I remember being a tad disappointed, and there might have been discussion about it on the forum at the time, but I removed it in accordance with DTATRM.

That <with> statement was merely a statement defining one or more local constants, as opposed to a WITH clause that appears as part of a statement.

The <with> statement that defined one or more local constants was what I thought you meant by "WITH clauses on statements."

I didn't know there was a WITH clause that appears as part of a statement, which would account for why I didn't implement it.

That statements with WITH clauses -- as opposed to a WITH statement -- ever existed comes as a surprise to me. It explains why the wording of the first post did seem a tad odd. I thought a WITH statement was what you meant.

Where was it defined and/or demonstrated?

I can't find mention of WITH clauses on statements in DTATRM, though I admit I gave up searching through instances of 'with' because my annoying PDF viewer ignores case distinctions and punctuation. I couldn't find it in the DTATRM grammar either, though I might be staring right at it and can't see it for looking.

Unless it was added later?

Perhaps we have been over-cautious on both counts.  If either or both of these constructs are successfully implemented (in Rel for example), I suppose we could reconsider.  I encourage you to have a go!

Support for a WITH statement that defines one or more local constants is certainly implementable. Rel used to have one. I've made a note to put it back in.

I'm the forum administrator and lead developer of Rel. Email me at dave@armchair.mb.ca with the Subject 'TTM Forum'. Download Rel from https://reldb.org
Quote from dandl on July 17, 2020, 11:30 am

Where does the Tutorial D spec tell us which syntactic constructs introduce attribute names into scope; and what is the textual extent of that scope in the 'body' of the construct?

The spec might have benefited from a phrase along the lines of, "Unless otherwise specified, semantics and scope should be assumed to essentially be those of well-known, conventional imperative programming languages such as C, PL/I, and Pascal."

I've picked languages that were well-known at the time the initial Tutorial D specs were written, of course. Java was brand new or still soon-to-be, C# didn't exist yet, Python still too obscure to mention, JavaScript should never be mentioned except disparagingly, and so forth.

The "unless otherwise specified" means "open expressions", for which some description of lambda expressions -- which they effectively are -- might be helpful now, though at the time the first Tutorial D specs were written probably wouldn't generally have been any more familiar than "open expressions."

There was (and is) absolutely nothing on the planet quite like 'open expressions'. You can model your general rules for operators and blocks on Algol 60 or any of its descendants, but when you implemented open expressions you were Robinson Crusoe, first man on the island. Yes, Lisp had lambda functions and various languages since have appropriated that term (I dislike it, but we're stuck with it), but they have little in common. It's not a block, it has no local scope, it's not a closure, it has no well-defined arguments, it has no well-defined surrounding scope. It's a bit of a bastard.

This is one of the reasons university computer science departments love running a final-year "comparative paradigms" or other programming language comparison course/module: you can make one reasonably contentious statement like, "the <x> feature in language <y> is actually lambda expressions disguised" in the first ten minutes of the first class of week 1 and be guaranteed to get a full term's worth of student/teacher debate out of it. No other preparation needed.

So, yes, "open expressions" are and aren't lambda expressions. In Rel, they are lambda expressions internally, plus some magic to avoid requiring explicit parameter declarations and the like. It works a bit like this:

Imagine a typical WHERE -- like S WHERE STATUS = 20 -- implemented in a conventional modern imperative programming language like Java, C#, whatever. Assuming s is a language variable containing a relation value from the canonical 'S' relvar, it would probably be something like this:

s.where(tuple => tuple.STATUS == 20)

In other words, the variable s is an instance of a class (probably Relation) with a method where that accepts a lambda expression that returns a boolean and defines a single parameter called tuple that represents the current tuple (cue reference to, but not discussion about, another post in this thread about "current tuples".)

The where method iterates the tuples in s, passing each to the specified lambda function for evaluation. For each tuple passed in via tuple, it tests whether tuple's STATUS attribute is 20 or not, returning true if it is and false if not. The where method emits a new Relation instance containing tuples where the lambda function returned true.

Now we just do syntactic, but not semantic, tweakery. Remove the dot after s, eliminate the tuple parameter definition because it's assumed, eliminate the tuple parameter reference because it's also assumed, remove needless parens, and use a single = to represent an equality test. We get:

s where STATUS = 20

Employ Tutorial D case conventions:

S WHERE STATUS = 20

Oh, look, we're right where we started. It was a lambda expression all along. (A lambda in open expression's clothing, so to speak.)

I'm the forum administrator and lead developer of Rel. Email me at dave@armchair.mb.ca with the Subject 'TTM Forum'. Download Rel from https://reldb.org
Quote from Dave Voorhis on July 17, 2020, 6:44 pm
Quote from dandl on July 17, 2020, 11:30 am

Where does the Tutorial D spec tell us which syntactic constructs introduce attribute names into scope; and what is the textual extent of that scope in the 'body' of the construct?

The spec might have benefited from a phrase along the lines of, "Unless otherwise specified, semantics and scope should be assumed to essentially be those of well-known, conventional imperative programming languages such as C, PL/I, and Pascal."

I've picked languages that were well-known at the time the initial Tutorial D specs were written, of course. Java was brand new or still soon-to-be, C# didn't exist yet, Python still too obscure to mention, JavaScript should never be mentioned except disparagingly, and so forth.

The "unless otherwise specified" means "open expressions", for which some description of lambda expressions -- which they effectively are -- might be helpful now, though at the time the first Tutorial D specs were written probably wouldn't generally have been any more familiar than "open expressions."

There was (and is) absolutely nothing on the planet quite like 'open expressions'. You can model your general rules for operators and blocks on Algol 60 or any of its descendants, but when you implemented open expressions you were Robinson Crusoe, first man on the island. Yes, Lisp had lambda functions and various languages since have appropriated that term (I dislike it, but we're stuck with it), but they have little in common. It's not a block, it has no local scope, it's not a closure, it has no well-defined arguments, it has no well-defined surrounding scope. It's a bit of a bastard.

This is one of the reasons university computer science departments love running a final-year "comparative paradigms" or other programming language comparison course/module: you can make one reasonably contentious statement like, "the <x> feature in language <y> is actually lambda expressions disguised" in the first ten minutes of the first class of week 1 and be guaranteed to get a full term's worth of student/teacher debate out of it. No other preparation needed.

So, yes, "open expressions" are and aren't lambda expressions. In Rel, they are lambda expressions internally, plus some magic to avoid requiring explicit parameter declarations and the like. It works a bit like this:

Imagine a typical WHERE -- like S WHERE STATUS = 20 -- implemented in a conventional modern imperative programming language like Java, C#, whatever. Assuming s is a language variable containing a relation value from the canonical 'S' relvar, it would probably be something like this:

s.where(tuple => tuple.STATUS == 20)

In other words, the variable s is an instance of a class (probably Relation) with a method where that accepts a lambda expression that returns a boolean and defines a single parameter called tuple that represents the current tuple (cue reference to, but not discussion about, another post in this thread about "current tuples".)

The where method iterates the tuples in s, passing each to the specified lambda function for evaluation. For each tuple passed in via tuple, it tests whether tuple's STATUS attribute is 20 or not, returning true if it is and false if not. The where method emits a new Relation instance containing tuples where the lambda function returned true.

Now we just do syntactic, but not semantic, tweakery. Remove the dot after s, eliminate the tuple parameter definition because it's assumed, eliminate the tuple parameter reference because it's also assumed, remove needless parens, and use a single = to represent an equality test. We get:

s where STATUS = 20

Employ Tutorial D case conventions:

S WHERE STATUS = 20

Oh, look, we're right where we started. It was a lambda expression all along. (A lambda in open expression's clothing, so to speak.)

Yes, I get that you can approach it that way. Yes, anonymous functions are sufficiently powerful that, coupled with a suitable tuple iterator, and some assumptions about scope they can be used to implement open expressions in a language that uses them. Just because you can rewrite a Java lambda as an OE doesn't mean that that the reverse holds and that open expressions are lambdas. In fact the equivalent construct in LINQ and Andl targeting an SQL back end does not use anything like them.

Assume you started from a different place. Perhaps you have a language with operations as per the RA and an underlying engine that does operations on relations (possibly in parallel) but does not give you an iterator. Perhaps the scalar computation is very expensive and you need to minimise its use, or do it in batches. Perhaps your backend is SQL. As long as you are fixated on open expressions and iterators, you close off possibilities.

Andl - A New Database Language - andl.org

I can't find mention of WITH clauses on statements in DTATRM, though I admit I gave up searching through instances of 'with' because my annoying PDF viewer ignores case distinctions and punctuation. I couldn't find it in the DTATRM grammar either, though I might be staring right at it and can't see it for looking.

Adobe Acrobat does a perfectly fine job of searching. There are 59 occurrences of WITH, and a reference to <with> statement on p127, nothing else I could find. In fact, I couldn't find any overview explanation of what it does, but the low level spec is on p101.

Andl - A New Database Language - andl.org
PreviousPage 4 of 9Next