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

In connection with WITH clauses on statements, Chris asked me:

What are the semantics of WITH (X := 1): WITH (X := 2): X := WITH (X:= X+!): X ;?

My answer, with which he agreed, was the assignment of 3 to a local variable named X.  But if those X constants are all at the same level of nesting, then perhaps such an example should be prohibited, just as two variables with the same name and at the same level of nesting would be.

In the same email he pointed out that, e.g., WITH ( X := 1 ) : COMMIT; is useless and in his opinion (not necessarily mine) should be prohibited.

Hugh

Coauthor of The Third Manifesto and related books.
Quote from Hugh on July 23, 2020, 2:18 pm

In connection with WITH clauses on statements, Chris asked me:

What are the semantics of WITH (X := 1): WITH (X := 2): X := WITH (X:= X+!): X ;?

My answer, with which he agreed, was the assignment of 3 to a local variable named X.  But if those X constants are all at the same level of nesting, then perhaps such an example should be prohibited, just as two variables with the same name and at the same level of nesting would be.

I'm inclined to make X a constant, not a variable. Thus, a given named assignee -- like X in the above -- can only be assigned once per WITH statement between the WITH parentheses, and not at all outside of it.

In the same email he pointed out that, e.g., WITH ( X := 1 ) : COMMIT; is useless and in his opinion (not necessarily mine) should be prohibited.

In this example, is its uselessness -- and thus the rationale for prohibition -- the fact that X is not referenced, or something specific to COMMIT, or something else?

(I'm quite sure I know the answer, but since the biggest mistakes often come from the most obvious assumptions...)

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 23, 2020, 5:06 pm
Quote from Hugh on July 23, 2020, 2:18 pm

In connection with WITH clauses on statements, Chris asked me:

What are the semantics of WITH (X := 1): WITH (X := 2): X := WITH (X:= X+!): X ;?

My answer, with which he agreed, was the assignment of 3 to a local variable named X.  But if those X constants are all at the same level of nesting, then perhaps such an example should be prohibited, just as two variables with the same name and at the same level of nesting would be.

I'm inclined to make X a constant, not a variable. Thus, a given named assignee -- like X in the above -- can only be assigned once per WITH statement between the WITH parentheses, and not at all outside of it.

In the same email he pointed out that, e.g., WITH ( X := 1 ) : COMMIT; is useless and in his opinion (not necessarily mine) should be prohibited.

In this example, is its uselessness -- and thus the rationale for prohibition -- the fact that X is not referenced, or something specific to COMMIT, or something else?

(I'm quite sure I know the answer, but since the biggest mistakes often come from the most obvious assumptions...)

Re your first point, we assume that the X that is the target of := in the actual statement (i.e., the one immediately following 2):) must refer to a local variable and should not be treated as an introduced name that happens also to be in scope.  You might disagree, of course, but I'd alos like to know how you fell about the multiple redefinitions of X as a constant, arguably all at the same level of nesting (or do you think they are nested, even if ineffectually?).

Re the second, I think it's the uselessness thereof, but personally I don't agree with Chris.  I've asked him his opinion on this example:

WITH ( X := 1 ) : BEGIN; COMMIT; END;

That appears to be doubly useless.  A useless constant definition and a useless COMMIT of no updates.

Hugh

Coauthor of The Third Manifesto and related books.
Quote from Hugh on July 24, 2020, 2:26 pm
Quote from Dave Voorhis on July 23, 2020, 5:06 pm
Quote from Hugh on July 23, 2020, 2:18 pm

In connection with WITH clauses on statements, Chris asked me:

What are the semantics of WITH (X := 1): WITH (X := 2): X := WITH (X:= X+!): X ;?

My answer, with which he agreed, was the assignment of 3 to a local variable named X.  But if those X constants are all at the same level of nesting, then perhaps such an example should be prohibited, just as two variables with the same name and at the same level of nesting would be.

I'm inclined to make X a constant, not a variable. Thus, a given named assignee -- like X in the above -- can only be assigned once per WITH statement between the WITH parentheses, and not at all outside of it.

In the same email he pointed out that, e.g., WITH ( X := 1 ) : COMMIT; is useless and in his opinion (not necessarily mine) should be prohibited.

In this example, is its uselessness -- and thus the rationale for prohibition -- the fact that X is not referenced, or something specific to COMMIT, or something else?

(I'm quite sure I know the answer, but since the biggest mistakes often come from the most obvious assumptions...)

Re your first point, we assume that the X that is the target of := in the actual statement (i.e., the one immediately following 2):) must refer to a local variable and should not be treated as an introduced name that happens also to be in scope.

Ah, you mean a local variable that already exists and is in scope, but its declaration is not shown?

The introduced constant (via WITH) should shadow the variable name (perhaps with a warning about shadowing) and the attempted assignment should fail.

You might disagree, of course, but I'd alos like to know how you fell about the multiple redefinitions of X as a constant, arguably all at the same level of nesting (or do you think they are nested, even if ineffectually?).

I'd consider them to be different nesting levels. This:

WITH (X := 1): WITH (X := 2): WRITELN WITH (X:= X+1): X ;

Is equivalent to:

WITH (X := 1): BEGIN
  WITH (X := 2): BEGIN
    WRITELN WITH(X := X+1): X;
  END;
END;

Re the second, I think it's the uselessness thereof, but personally I don't agree with Chris.  I've asked him his opinion on this example:

WITH ( X := 1 ) : BEGIN; COMMIT; END;

That appears to be doubly useless.  A useless constant definition and a useless COMMIT of no updates.

Hugh

There are already a potentially infinite number of possible do-nothing programs. I'm not sure preventing this particular one without preventing all the others makes sense, particularly as detecting some infinitely large subset of all do-nothing programs is almost certainly a variation on the Halting Problem.

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 24, 2020, 4:48 pm
Quote from Hugh on July 24, 2020, 2:26 pm
Quote from Dave Voorhis on July 23, 2020, 5:06 pm
Quote from Hugh on July 23, 2020, 2:18 pm

In connection with WITH clauses on statements, Chris asked me:

What are the semantics of WITH (X := 1): WITH (X := 2): X := WITH (X:= X+!): X ;?

My answer, with which he agreed, was the assignment of 3 to a local variable named X.  But if those X constants are all at the same level of nesting, then perhaps such an example should be prohibited, just as two variables with the same name and at the same level of nesting would be.

I'm inclined to make X a constant, not a variable. Thus, a given named assignee -- like X in the above -- can only be assigned once per WITH statement between the WITH parentheses, and not at all outside of it.

In the same email he pointed out that, e.g., WITH ( X := 1 ) : COMMIT; is useless and in his opinion (not necessarily mine) should be prohibited.

In this example, is its uselessness -- and thus the rationale for prohibition -- the fact that X is not referenced, or something specific to COMMIT, or something else?

(I'm quite sure I know the answer, but since the biggest mistakes often come from the most obvious assumptions...)

Re your first point, we assume that the X that is the target of := in the actual statement (i.e., the one immediately following 2):) must refer to a local variable and should not be treated as an introduced name that happens also to be in scope.

Ah, you mean a local variable that already exists and is in scope, but its declaration is not shown?

The introduced constant (via WITH) should shadow the variable name (perhaps with a warning about shadowing) and the attempted assignment should fail.

You might disagree, of course, but I'd alos like to know how you fell about the multiple redefinitions of X as a constant, arguably all at the same level of nesting (or do you think they are nested, even if ineffectually?).

I'd consider them to be different nesting levels. This:

Is equivalent to: <snip>

From a compiler writer point of view, you get to make decisions.

  1. Should there be a new scope at every WITH, or at WITH BEGIN, or not at all?
  2. Should scopes be lexically nested, or nested some other way, or not at all?
  3. Should a declaration made in a scope be tested to see if the name is already in scope, and if so, should the new name be a simple override, carry a warning, be prohibited or be dealt with some other way.

There is no one size fits all, and most decisions carry the potential for undesirable consequences.

 

Re the second, I think it's the uselessness thereof, but personally I don't agree with Chris.  I've asked him his opinion on this example:

WITH ( X := 1 ) : BEGIN; COMMIT; END;

That appears to be doubly useless.  A useless constant definition and a useless COMMIT of no updates.

Hugh

There are already a potentially infinite number of possible do-nothing programs. I'm not sure preventing this particular one without preventing all the others makes sense, particularly as detecting some infinitely large subset of all do-nothing programs is almost certainly a variation on the Halting Problem.

There is absolutely no point making this an error, but it might be reasonable to issue a warning if a declaration has not been used when the scope is closed. The aim here is to help programmers find their own mistakes.

Andl - A New Database Language - andl.org
Quote from dandl on July 25, 2020, 1:28 am
Quote from Dave Voorhis on July 24, 2020, 4:48 pm
Quote from Hugh on July 24, 2020, 2:26 pm
Quote from Dave Voorhis on July 23, 2020, 5:06 pm

 

In the same email he pointed out that, e.g., WITH ( X := 1 ) : COMMIT; is useless and in his opinion (not necessarily mine) should be prohibited.

In this example, is its uselessness -- and thus the rationale for prohibition -- the fact that X is not referenced, or something specific to COMMIT, or something else?

(I'm quite sure I know the answer, but since the biggest mistakes often come from the most obvious assumptions...)

 

The introduced constant (via WITH) should shadow the variable name (perhaps with a warning about shadowing) and the attempted assignment should fail.

You might disagree, of course, but I'd alos like to know how you fell about the multiple redefinitions of X as a constant, arguably all at the same level of nesting (or do you think they are nested, even if ineffectually?).

I'd consider them to be different nesting levels. This:

Is equivalent to: <snip>

 

 

Re the second, I think it's the uselessness thereof, but personally I don't agree with Chris.  I've asked him his opinion on this example:

WITH ( X := 1 ) : BEGIN; COMMIT; END;

That appears to be doubly useless.  A useless constant definition and a useless COMMIT of no updates.

Hugh

There are already a potentially infinite number of possible do-nothing programs. I'm not sure preventing this particular one without preventing all the others makes sense, particularly as detecting some infinitely large subset of all do-nothing programs is almost certainly a variation on the Halting Problem.

There is absolutely no point making this an error, but it might be reasonable to issue a warning if a declaration has not been used when the scope is closed. The aim here is to help programmers find their own mistakes.

Yes industrial strength compilers usually issue warnings for names declared but not referenced. (And even have sophisticated guards like: suppress those warnings in this section of the program or for particular declarations.) But with Tutorial D declarations for relation and tuple types, I see a couple of difficulties.

  • Quite possibly your WITH is introducing a shorthand for a relational expression. Then that expression effectively declares a bunch of attribute names -- although they're only visible in 'open expressions' in the body that the WITH is prefixed to. If some particular attribute name is not used within any such 'open expression', issuing a warning is probably too much nannying; OTOH if none of the attribute names are used, that does suggest shome mishtake.
  • The WITH-introduced relational expression probably references database relvars, then they (or rather, their attribute names) might also be in scope just outside the WITH; then introduced attribute names will shadow those just outside. To adapt an example from earlier in the thread:
EXTEND S :
{ WITH ( temp := ( SP MATCHING REL{ TUP{ S# S# } } ) WHERE QTY > 500 AND NOT ( PNO = 'P1' ) JOIN P) :
  A := SUM ( temp , QTY ) ,
  B := MAX ( temp , CITY ) ,     // beware!
  C := MIN ( temp , QTY ) ,
  D := COUNT ( temp ) ,
  E := TOUPPER(CITY) }                 // different CITY!
temp's heading includes attribute CITY, because of the JOIN P. Then in MAX( temp, CITY ), the CITY from temp shadows the in-scope CITY from the EXTEND S. That's a daft example; but I could probably contrive some nastier example where confusion will reign. It's all getting rather beyond tutorial level.
Quote from AntC on July 25, 2020, 5:09 am
Quote from dandl on July 25, 2020, 1:28 am
Quote from Dave Voorhis on July 24, 2020, 4:48 pm
Quote from Hugh on July 24, 2020, 2:26 pm
Quote from Dave Voorhis on July 23, 2020, 5:06 pm

 

In the same email he pointed out that, e.g., WITH ( X := 1 ) : COMMIT; is useless and in his opinion (not necessarily mine) should be prohibited.

In this example, is its uselessness -- and thus the rationale for prohibition -- the fact that X is not referenced, or something specific to COMMIT, or something else?

(I'm quite sure I know the answer, but since the biggest mistakes often come from the most obvious assumptions...)

 

The introduced constant (via WITH) should shadow the variable name (perhaps with a warning about shadowing) and the attempted assignment should fail.

You might disagree, of course, but I'd alos like to know how you fell about the multiple redefinitions of X as a constant, arguably all at the same level of nesting (or do you think they are nested, even if ineffectually?).

I'd consider them to be different nesting levels. This:

Is equivalent to: <snip>

 

 

Re the second, I think it's the uselessness thereof, but personally I don't agree with Chris.  I've asked him his opinion on this example:

WITH ( X := 1 ) : BEGIN; COMMIT; END;

That appears to be doubly useless.  A useless constant definition and a useless COMMIT of no updates.

Hugh

There are already a potentially infinite number of possible do-nothing programs. I'm not sure preventing this particular one without preventing all the others makes sense, particularly as detecting some infinitely large subset of all do-nothing programs is almost certainly a variation on the Halting Problem.

There is absolutely no point making this an error, but it might be reasonable to issue a warning if a declaration has not been used when the scope is closed. The aim here is to help programmers find their own mistakes.

Yes industrial strength compilers usually issue warnings for names declared but not referenced. (And even have sophisticated guards like: suppress those warnings in this section of the program or for particular declarations.)

Indeed, I think a warning about not using an introduced name in a WITH -- whether expression or proposed statement form -- is useful.

Generally prohibiting do-nothing code is not.

In fact, it's common to write scaffolding with do-nothing blocks to be filled in later. It's effectively a form of runnable note to yourself -- a "strong form" of comment -- that says we're not going to implement this now, but we've got to implement (or finishing implementing) it later.

I can imagine frequently creating a WITH statement having an empty code block, just to set up some useful constants that I intend to use eventually.

But with Tutorial D declarations for relation and tuple types, I see a couple of difficulties.

  • Quite possibly your WITH is introducing a shorthand for a relational expression. Then that expression effectively declares a bunch of attribute names -- although they're only visible in 'open expressions' in the body that the WITH is prefixed to. If some particular attribute name is not used within any such 'open expression', issuing a warning is probably too much nannying; OTOH if none of the attribute names are used, that does suggest shome mishtake.
  • The WITH-introduced relational expression probably references database relvars, then they (or rather, their attribute names) might also be in scope just outside the WITH; then introduced attribute names will shadow those just outside. To adapt an example from earlier in the thread:
EXTEND S :
{ WITH ( temp := ( SP MATCHING REL{ TUP{ S# S# } } ) WHERE QTY > 500 AND NOT ( PNO = 'P1' ) JOIN P) :
  A := SUM ( temp , QTY ) ,
  B := MAX ( temp , CITY ) ,     // beware!
  C := MIN ( temp , QTY ) ,
  D := COUNT ( temp ) ,
  E := TOUPPER(CITY) }                 // different CITY!
temp's heading includes attribute CITY, because of the JOIN P. Then in MAX( temp, CITY ), the CITY from temp shadows the in-scope CITY from the EXTEND S. That's a daft example; but I could probably contrive some nastier example where confusion will reign. It's all getting rather beyond tutorial level.

I imagine it's possible to construct all manner of horrific naming/shadowing examples, even without WITH. Bad code can be written in anything and Tutorial D is certainly no exception.

Though there is perhaps an argument for not having WITH at all, either in expression or statement form. Instead, provide CONST as an alternative to VAR, with precisely the same syntax and rules, only immutable.

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 25, 2020, 8:13 am
Quote from AntC on July 25, 2020, 5:09 am
Quote from dandl on July 25, 2020, 1:28 am
Quote from Dave Voorhis on July 24, 2020, 4:48 pm
Quote from Hugh on July 24, 2020, 2:26 pm
Quote from Dave Voorhis on July 23, 2020, 5:06 pm

 

In the same email he pointed out that, e.g., WITH ( X := 1 ) : COMMIT; is useless and in his opinion (not necessarily mine) should be prohibited.

In this example, is its uselessness -- and thus the rationale for prohibition -- the fact that X is not referenced, or something specific to COMMIT, or something else?

(I'm quite sure I know the answer, but since the biggest mistakes often come from the most obvious assumptions...)

 

The introduced constant (via WITH) should shadow the variable name (perhaps with a warning about shadowing) and the attempted assignment should fail.

You might disagree, of course, but I'd alos like to know how you fell about the multiple redefinitions of X as a constant, arguably all at the same level of nesting (or do you think they are nested, even if ineffectually?).

I'd consider them to be different nesting levels. This:

Is equivalent to: <snip>

 

 

Re the second, I think it's the uselessness thereof, but personally I don't agree with Chris.  I've asked him his opinion on this example:

WITH ( X := 1 ) : BEGIN; COMMIT; END;

That appears to be doubly useless.  A useless constant definition and a useless COMMIT of no updates.

Hugh

There are already a potentially infinite number of possible do-nothing programs. I'm not sure preventing this particular one without preventing all the others makes sense, particularly as detecting some infinitely large subset of all do-nothing programs is almost certainly a variation on the Halting Problem.

There is absolutely no point making this an error, but it might be reasonable to issue a warning if a declaration has not been used when the scope is closed. The aim here is to help programmers find their own mistakes.

Yes industrial strength compilers usually issue warnings for names declared but not referenced. (And even have sophisticated guards like: suppress those warnings in this section of the program or for particular declarations.)

Indeed, I think a warning about not using an introduced name in a WITH -- whether expression or proposed statement form -- is useful.

Generally prohibiting do-nothing code is not.

In fact, it's common to write scaffolding with do-nothing blocks to be filled in later. It's effectively a form of runnable note to yourself -- a "strong form" of comment -- that says we're not going to implement this now, but we've got to implement (or finishing implementing) it later.

I can imagine frequently creating a WITH statement having an empty code block, just to set up some useful constants that I intend to use eventually.

But with Tutorial D declarations for relation and tuple types, I see a couple of difficulties.

  • Quite possibly your WITH is introducing a shorthand for a relational expression. Then that expression effectively declares a bunch of attribute names -- although they're only visible in 'open expressions' in the body that the WITH is prefixed to. If some particular attribute name is not used within any such 'open expression', issuing a warning is probably too much nannying; OTOH if none of the attribute names are used, that does suggest shome mishtake.
  • The WITH-introduced relational expression probably references database relvars, then they (or rather, their attribute names) might also be in scope just outside the WITH; then introduced attribute names will shadow those just outside. To adapt an example from earlier in the thread:
EXTEND S :
{ WITH ( temp := ( SP MATCHING REL{ TUP{ S# S# } } ) WHERE QTY > 500 AND NOT ( PNO = 'P1' ) JOIN P) :
  A := SUM ( temp , QTY ) ,
  B := MAX ( temp , CITY ) ,     // beware!
  C := MIN ( temp , QTY ) ,
  D := COUNT ( temp ) ,
  E := TOUPPER(CITY) }                 // different CITY!
temp's heading includes attribute CITY, because of the JOIN P. Then in MAX( temp, CITY ), the CITY from temp shadows the in-scope CITY from the EXTEND S. That's a daft example; but I could probably contrive some nastier example where confusion will reign. It's all getting rather beyond tutorial level.

I imagine it's possible to construct all manner of horrific naming/shadowing examples, even without WITH. Bad code can be written in anything and Tutorial D is certainly no exception.

Though there is perhaps an argument for not having WITH at all, either in expression or statement form. Instead, provide CONST as an alternative to VAR, with precisely the same syntax and rules, only immutable.

Thanks for all these observations and opinions.  Chris's main objection to having WITH on statements was that he didn't want us to have to define the semantics.  Although we have avoided giving scoping details elsewhere, he thought that would be too much of a cop-out in this case.

He has also said we should support CONST, but so far I have resisted that on the grounds that WITH is sufficient for that purpose.  Having said that, I was the one who originally wanted those WITH statements (equivalent to CONST) that we once had but deleted some time ago (sorry, can't remember why).

Btw, nobody twitted me for my idiotic remark o BEGIN; COMMIT; END; to the effect that the COMMIT was "useless", there being no updates to commit.  That COMMIT, albeit surrounded by BEGIN and END, commits all updates made since the most recent START TRANSACTION, simultaneously ending the transaction.  Just like it did in Business System 12, in fact, back in 1980.

Hugh

Coauthor of The Third Manifesto and related books.
Quote from Hugh on July 25, 2020, 1:13 pm
Quote from Dave Voorhis on July 25, 2020, 8:13 am
Quote from AntC on July 25, 2020, 5:09 am
Quote from dandl on July 25, 2020, 1:28 am
Quote from Dave Voorhis on July 24, 2020, 4:48 pm
Quote from Hugh on July 24, 2020, 2:26 pm
Quote from Dave Voorhis on July 23, 2020, 5:06 pm

 

In the same email he pointed out that, e.g., WITH ( X := 1 ) : COMMIT; is useless and in his opinion (not necessarily mine) should be prohibited.

In this example, is its uselessness -- and thus the rationale for prohibition -- the fact that X is not referenced, or something specific to COMMIT, or something else?

(I'm quite sure I know the answer, but since the biggest mistakes often come from the most obvious assumptions...)

 

The introduced constant (via WITH) should shadow the variable name (perhaps with a warning about shadowing) and the attempted assignment should fail.

You might disagree, of course, but I'd alos like to know how you fell about the multiple redefinitions of X as a constant, arguably all at the same level of nesting (or do you think they are nested, even if ineffectually?).

I'd consider them to be different nesting levels. This:

Is equivalent to: <snip>

 

 

Re the second, I think it's the uselessness thereof, but personally I don't agree with Chris.  I've asked him his opinion on this example:

WITH ( X := 1 ) : BEGIN; COMMIT; END;

That appears to be doubly useless.  A useless constant definition and a useless COMMIT of no updates.

Hugh

There are already a potentially infinite number of possible do-nothing programs. I'm not sure preventing this particular one without preventing all the others makes sense, particularly as detecting some infinitely large subset of all do-nothing programs is almost certainly a variation on the Halting Problem.

There is absolutely no point making this an error, but it might be reasonable to issue a warning if a declaration has not been used when the scope is closed. The aim here is to help programmers find their own mistakes.

Yes industrial strength compilers usually issue warnings for names declared but not referenced. (And even have sophisticated guards like: suppress those warnings in this section of the program or for particular declarations.)

Indeed, I think a warning about not using an introduced name in a WITH -- whether expression or proposed statement form -- is useful.

Generally prohibiting do-nothing code is not.

In fact, it's common to write scaffolding with do-nothing blocks to be filled in later. It's effectively a form of runnable note to yourself -- a "strong form" of comment -- that says we're not going to implement this now, but we've got to implement (or finishing implementing) it later.

I can imagine frequently creating a WITH statement having an empty code block, just to set up some useful constants that I intend to use eventually.

But with Tutorial D declarations for relation and tuple types, I see a couple of difficulties.

  • Quite possibly your WITH is introducing a shorthand for a relational expression. Then that expression effectively declares a bunch of attribute names -- although they're only visible in 'open expressions' in the body that the WITH is prefixed to. If some particular attribute name is not used within any such 'open expression', issuing a warning is probably too much nannying; OTOH if none of the attribute names are used, that does suggest shome mishtake.
  • The WITH-introduced relational expression probably references database relvars, then they (or rather, their attribute names) might also be in scope just outside the WITH; then introduced attribute names will shadow those just outside. To adapt an example from earlier in the thread:
EXTEND S :
{ WITH ( temp := ( SP MATCHING REL{ TUP{ S# S# } } ) WHERE QTY > 500 AND NOT ( PNO = 'P1' ) JOIN P) :
  A := SUM ( temp , QTY ) ,
  B := MAX ( temp , CITY ) ,     // beware!
  C := MIN ( temp , QTY ) ,
  D := COUNT ( temp ) ,
  E := TOUPPER(CITY) }                 // different CITY!
temp's heading includes attribute CITY, because of the JOIN P. Then in MAX( temp, CITY ), the CITY from temp shadows the in-scope CITY from the EXTEND S. That's a daft example; but I could probably contrive some nastier example where confusion will reign. It's all getting rather beyond tutorial level.

I imagine it's possible to construct all manner of horrific naming/shadowing examples, even without WITH. Bad code can be written in anything and Tutorial D is certainly no exception.

Though there is perhaps an argument for not having WITH at all, either in expression or statement form. Instead, provide CONST as an alternative to VAR, with precisely the same syntax and rules, only immutable.

Thanks for all these observations and opinions.  Chris's main objection to having WITH on statements was that he didn't want us to have to define the semantics.  Although we have avoided giving scoping details elsewhere, he thought that would be too much of a cop-out in this case.

I think you could safely bow out of defining (detailed) semantics and let them be as implementation-dependent as other scoping issues, given WITH has nothing to do with the relational model per se and it isn't a core feature of Tutorial D.

Presumably, for the purpose of texts, the semantics would be self-evident from the context, given it's just a sensible way to avoid having to repeat yourself in example code.

For the purposes of Rel and those who use it, I'm sure I can come up with reasonable and (hopefully mostly) unsurprising semantics.

He has also said we should support CONST, but so far I have resisted that on the grounds that WITH is sufficient for that purpose.  Having said that, I was the one who originally wanted those WITH statements (equivalent to CONST) that we once had but deleted some time ago (sorry, can't remember why).

A benefit of CONST is that you can define a global CONST that applies to the whole database. Indeed, as was already mentioned in this thread, that's what DEE and DUM are.

WITH is definitely handy for avoiding repetition in a complex expression or in a given operator definition, but although WITH and CONST both define constants, CONST can replace WITH but WITH can't really replace CONST.  That's because WITH can only apply to code within a given operator definition or expression, but can't apply to multiple -- or all -- operator definitions and expressions, whilst a given CONST can.

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 25, 2020, 8:13 am

Though there is perhaps an argument for not having WITH at all, either in expression or statement form. Instead, provide CONST as an alternative to VAR, with precisely the same syntax and rules, only immutable.

FWIW, those semantics might clash with those intuitively expected by people who are familiar with CONST keyword in other languages, where it can be used only for compile-time constants, not for "immutable vars that can be initialized only at run-time because some other variable is needed to do so".