Update to Tutorial D, July 2020
Quote from Hugh on July 7, 2020, 4:14 pmThe ill-advised support for WITH clauses on statements has been deleted. At the same time, WITH clause support has been added to various places where a commalist of "assigns" is used, such as EXTEND and UPDATE, inside the braces. See www.thethirdmanifesto.com.
Hugh
The ill-advised support for WITH clauses on statements has been deleted. At the same time, WITH clause support has been added to various places where a commalist of "assigns" is used, such as EXTEND and UPDATE, inside the braces. See http://www.thethirdmanifesto.com.
Hugh
Quote from Dave Voorhis on July 7, 2020, 8:31 pmAs I usually ask when updates come out, I wonder if I could trouble you for some simple examples, perhaps along with a sentence or short paragraph or two of motivation for the changes?
As I usually ask when updates come out, I wonder if I could trouble you for some simple examples, perhaps along with a sentence or short paragraph or two of motivation for the changes?
Quote from Hugh on July 9, 2020, 11:22 amHere'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.
What if, in Chris's example, the name chosen for temp is QTY?
Hugh
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.
What if, in Chris's example, the name chosen for temp is QTY?
Hugh
Quote from dandl on July 9, 2020, 1:03 pmQuote from Hugh on July 9, 2020, 11:22 amHere'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.
Normal? The compiler should issue a warning if a variable overrides another in a nested scope. This is a potent source of bugs.
What if, in Chris's example, the name chosen for temp is QTY?
That's exactly the kind of bug I had in mind. These things look easy in toy examples, but can be really hard to find in real code.
Hugh
Quote from Hugh on July 9, 2020, 11:22 amHere'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.
Normal? The compiler should issue a warning if a variable overrides another in a nested scope. This is a potent source of bugs.
What if, in Chris's example, the name chosen for temp is QTY?
That's exactly the kind of bug I had in mind. These things look easy in toy examples, but can be really hard to find in real code.
Hugh
Quote from Dave Voorhis on July 9, 2020, 2:49 pmQuote from dandl on July 9, 2020, 1:03 pmQuote from Hugh on July 9, 2020, 11:22 amHere'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.
Normal? The compiler should issue a warning if a variable overrides another in a nested scope. This is a potent source of bugs.
Yes, but I presume the warning mechanism, if any, would be implementation-dependent and should only apply to shadowing a definition in an outer scope. Attempts to redefine a variable or attribute in the current scope should almost certainly be an error.
Quote from dandl on July 9, 2020, 1:03 pmQuote from Hugh on July 9, 2020, 11:22 amHere'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.
Normal? The compiler should issue a warning if a variable overrides another in a nested scope. This is a potent source of bugs.
Yes, but I presume the warning mechanism, if any, would be implementation-dependent and should only apply to shadowing a definition in an outer scope. Attempts to redefine a variable or attribute in the current scope should almost certainly be an error.
Quote from Dave Voorhis on July 9, 2020, 3:08 pmQuote from Hugh on July 9, 2020, 11:22 amHere'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.
What if, in Chris's example, the name chosen for temp is QTY?
I kind of see the point, I guess, but how is it superior to this?
EXTEND S : { temp := ( SP MATCHING S ) WHERE THE_QTY(QTY) > 200 AND NOT ( P# = P#('P1') ), A := SUM ( temp , THE_QTY(QTY) ) , B := MAX ( temp , THE_QTY(QTY) ) , C := MIN ( temp , THE_QTY(QTY) ) , D := COUNT ( temp ) } {ALL BUT temp}I'm all for syntactic additions that provide benefits, but to be honest I'm having a hard time seeing the benefits of WITH inside EXTEND, at least.
I feel like I'm missing something (that should be?) obvious.
(Note that I made a few small tweaks to the original to fit the relvar & type definitions supplied with Rel, as I don't like to post code I haven't run. :-)
Quote from Hugh on July 9, 2020, 11:22 amHere'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.
What if, in Chris's example, the name chosen for temp is QTY?
I kind of see the point, I guess, but how is it superior to this?
EXTEND S : { temp := ( SP MATCHING S ) WHERE THE_QTY(QTY) > 200 AND NOT ( P# = P#('P1') ), A := SUM ( temp , THE_QTY(QTY) ) , B := MAX ( temp , THE_QTY(QTY) ) , C := MIN ( temp , THE_QTY(QTY) ) , D := COUNT ( temp ) } {ALL BUT temp}
I'm all for syntactic additions that provide benefits, but to be honest I'm having a hard time seeing the benefits of WITH inside EXTEND, at least.
I feel like I'm missing something (that should be?) obvious.
(Note that I made a few small tweaks to the original to fit the relvar & type definitions supplied with Rel, as I don't like to post code I haven't run. :-)
Quote from dandl on July 10, 2020, 4:46 amQuote from Dave Voorhis on July 9, 2020, 2:49 pmQuote from dandl on July 9, 2020, 1:03 pmQuote from Hugh on July 9, 2020, 11:22 amHere'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.
Normal? The compiler should issue a warning if a variable overrides another in a nested scope. This is a potent source of bugs.
Yes, but I presume the warning mechanism, if any, would be implementation-dependent and should only apply to shadowing a definition in an outer scope. Attempts to redefine a variable or attribute in the current scope should almost certainly be an error.
Everything here is implementation dependent. The language definition for TD explicitly excludes any details of scopes or how they might work; an implementation could perfectly well have only a single flat global scope and conform just fine. The word 'local' does appear, but in the sense of local=program, non-local=database. I have no idea what Rel does, because it isn't documented.
In my view, it has to be easy to tell what a name in a program refers to, and it should not be possible for an existing name to take on a new meaning because a new declaration was added. Name conflicts can arise innocently, such as when nested scopes introduce names that were defined elsewhere. My preference is to ignore the conflict, but provide a warning if the name is used in a way that might possibly be ambiguous; then the choice should be explicit, whether to treat this as a conflict, or by masking, or by an explicit mechanism such as a scope operator or alias. It's hairy stuff, but failing to address it is to invite bugs.
BTW is greatly dislike calling this 'shadowing' -- it's a misuse of the word. To shadow is to follow around, to copy, to watch closely. 'Name masking' is a better term.
Quote from Dave Voorhis on July 9, 2020, 2:49 pmQuote from dandl on July 9, 2020, 1:03 pmQuote from Hugh on July 9, 2020, 11:22 amHere'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.
Normal? The compiler should issue a warning if a variable overrides another in a nested scope. This is a potent source of bugs.
Yes, but I presume the warning mechanism, if any, would be implementation-dependent and should only apply to shadowing a definition in an outer scope. Attempts to redefine a variable or attribute in the current scope should almost certainly be an error.
Everything here is implementation dependent. The language definition for TD explicitly excludes any details of scopes or how they might work; an implementation could perfectly well have only a single flat global scope and conform just fine. The word 'local' does appear, but in the sense of local=program, non-local=database. I have no idea what Rel does, because it isn't documented.
In my view, it has to be easy to tell what a name in a program refers to, and it should not be possible for an existing name to take on a new meaning because a new declaration was added. Name conflicts can arise innocently, such as when nested scopes introduce names that were defined elsewhere. My preference is to ignore the conflict, but provide a warning if the name is used in a way that might possibly be ambiguous; then the choice should be explicit, whether to treat this as a conflict, or by masking, or by an explicit mechanism such as a scope operator or alias. It's hairy stuff, but failing to address it is to invite bugs.
BTW is greatly dislike calling this 'shadowing' -- it's a misuse of the word. To shadow is to follow around, to copy, to watch closely. 'Name masking' is a better term.
Quote from Dave Voorhis on July 10, 2020, 6:07 amQuote from dandl on July 10, 2020, 4:46 amBTW is greatly dislike calling this 'shadowing' -- it's a misuse of the word. To shadow is to follow around, to copy, to watch closely. 'Name masking' is a better term.
There are many terms in programming that could have been better chosen in the dim mists of time -- my pet peeve is using "function" for things that aren't, but good luck dislodging that one from C and friends -- and it is what it is. See, for example, https://en.wikipedia.org/wiki/Variable_shadowing
I suppose the idea is that the old outer-scope variable is now forced to stand in the shadow of the new inner-scope one, and thus shaded is too dark to see.
Or something.
I have seen "name masking" used to refer to such obscuring of identifiers in general and "variable shadowing" used only for variables, but "shadowing" is the usual term.
Quote from dandl on July 10, 2020, 4:46 amBTW is greatly dislike calling this 'shadowing' -- it's a misuse of the word. To shadow is to follow around, to copy, to watch closely. 'Name masking' is a better term.
There are many terms in programming that could have been better chosen in the dim mists of time -- my pet peeve is using "function" for things that aren't, but good luck dislodging that one from C and friends -- and it is what it is. See, for example, https://en.wikipedia.org/wiki/Variable_shadowing
I suppose the idea is that the old outer-scope variable is now forced to stand in the shadow of the new inner-scope one, and thus shaded is too dark to see.
Or something.
I have seen "name masking" used to refer to such obscuring of identifiers in general and "variable shadowing" used only for variables, but "shadowing" is the usual term.
Quote from Hugh on July 10, 2020, 2:40 pmQuote from Dave Voorhis on July 9, 2020, 3:08 pmQuote from Hugh on July 9, 2020, 11:22 amHere'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.
What if, in Chris's example, the name chosen for temp is QTY?
I kind of see the point, I guess, but how is it superior to this?
EXTEND S : {temp := ( SP MATCHING S ) WHERE THE_QTY(QTY) > 200 AND NOT ( P# = P#('P1') ),A := SUM ( temp , THE_QTY(QTY) ) ,B := MAX ( temp , THE_QTY(QTY) ) ,C := MIN ( temp , THE_QTY(QTY) ) ,D := COUNT ( temp )} {ALL BUT temp}EXTEND S : { temp := ( SP MATCHING S ) WHERE THE_QTY(QTY) > 200 AND NOT ( P# = P#('P1') ), A := SUM ( temp , THE_QTY(QTY) ) , B := MAX ( temp , THE_QTY(QTY) ) , C := MIN ( temp , THE_QTY(QTY) ) , D := COUNT ( temp ) } {ALL BUT temp}EXTEND S : { temp := ( SP MATCHING S ) WHERE THE_QTY(QTY) > 200 AND NOT ( P# = P#('P1') ), A := SUM ( temp , THE_QTY(QTY) ) , B := MAX ( temp , THE_QTY(QTY) ) , C := MIN ( temp , THE_QTY(QTY) ) , D := COUNT ( temp ) } {ALL BUT temp}I'm all for syntactic additions that provide benefits, but to be honest I'm having a hard time seeing the benefits of WITH inside EXTEND, at least.
I feel like I'm missing something (that should be?) obvious.
(Note that I made a few small tweaks to the original to fit the relvar & type definitions supplied with Rel, as I don't like to post code I haven't run. :-)
I admit that your example is equivalent and only very slightly "inferior". However, the idea doesn't work for the various UPDATE statements.
Btw, on reflection I find Chris's example rather contrived. Why extend all tuples of S with exactly the same values? One might as well extend TABLE_DEE with that lot.
Hugh
Quote from Dave Voorhis on July 9, 2020, 3:08 pmQuote from Hugh on July 9, 2020, 11:22 amHere'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.
What if, in Chris's example, the name chosen for temp is QTY?
I kind of see the point, I guess, but how is it superior to this?
EXTEND S : {temp := ( SP MATCHING S ) WHERE THE_QTY(QTY) > 200 AND NOT ( P# = P#('P1') ),A := SUM ( temp , THE_QTY(QTY) ) ,B := MAX ( temp , THE_QTY(QTY) ) ,C := MIN ( temp , THE_QTY(QTY) ) ,D := COUNT ( temp )} {ALL BUT temp}EXTEND S : { temp := ( SP MATCHING S ) WHERE THE_QTY(QTY) > 200 AND NOT ( P# = P#('P1') ), A := SUM ( temp , THE_QTY(QTY) ) , B := MAX ( temp , THE_QTY(QTY) ) , C := MIN ( temp , THE_QTY(QTY) ) , D := COUNT ( temp ) } {ALL BUT temp}EXTEND S : { temp := ( SP MATCHING S ) WHERE THE_QTY(QTY) > 200 AND NOT ( P# = P#('P1') ), A := SUM ( temp , THE_QTY(QTY) ) , B := MAX ( temp , THE_QTY(QTY) ) , C := MIN ( temp , THE_QTY(QTY) ) , D := COUNT ( temp ) } {ALL BUT temp}I'm all for syntactic additions that provide benefits, but to be honest I'm having a hard time seeing the benefits of WITH inside EXTEND, at least.
I feel like I'm missing something (that should be?) obvious.
(Note that I made a few small tweaks to the original to fit the relvar & type definitions supplied with Rel, as I don't like to post code I haven't run. :-)
I admit that your example is equivalent and only very slightly "inferior". However, the idea doesn't work for the various UPDATE statements.
Btw, on reflection I find Chris's example rather contrived. Why extend all tuples of S with exactly the same values? One might as well extend TABLE_DEE with that lot.
Hugh
Quote from dandl on July 10, 2020, 3:20 pmWhat purpose does WITH serve, exactly? It looks like it just declares and initialises a variable local to a block, so how is it different from VAR?
What purpose does WITH serve, exactly? It looks like it just declares and initialises a variable local to a block, so how is it different from VAR?