First and second class citizens in TTM
Quote from dandl on November 3, 2018, 12:36 amThe terminology is as per Strachey: https://en.wikipedia.org/wiki/First-class_citizen. I'll use SCO and FCO.
In very broad terms, SCOs are fixed at compile time, FCOs after the program begins execution.Some languages cheat by allowing fragments of code to be compiled at runtime. I'll exclude those.
SCOs include:
- in virtually all languages, the tokens of the language itself (if, while, begin, end, etc)
- in most languages: variables, types and components of types (classes, fields, components in TTM)
- in many languages: methods/functions/operators in TTM.
Dynamic languages have more FCO. For example, JS objects and functions are just values. (JS has more interesting ways to shoot yourself in the foot than I ever dreamed of.)
The SCO in TTM are all those things that are given names and are not values of some type. They are:
- types RM Pre 1
- components RM Pre 5
- attributes RM Pre 9a
- variables RM Pre 11, 12, 13
- candidate key RM Pre 15 (*)
- database RM Pre 16
- operators RM Pre 18, 20 (*), 21, 22
- constraints RM Pre 23 (*)
Items marked (*) are required to be 'defined', which implies that they are given a name but might conceivably have some other interpretation.
IMO there are worthwhile use cases for dealing with variable, attribute, key, database, operator and constraint objects as something better than SCO. The example I gave before was for the 'types' list and lookup, which require an indirect reference to a relvar and/or attribute, but a 'dynamic TTM' would go further, by allowing these 6 kinds of object to be values and manipulated at runtime. If compile time checking is still required, then choosing a type is an important issue.
The terminology is as per Strachey: https://en.wikipedia.org/wiki/First-class_citizen. I'll use SCO and FCO.
In very broad terms, SCOs are fixed at compile time, FCOs after the program begins execution.Some languages cheat by allowing fragments of code to be compiled at runtime. I'll exclude those.
SCOs include:
- in virtually all languages, the tokens of the language itself (if, while, begin, end, etc)
- in most languages: variables, types and components of types (classes, fields, components in TTM)
- in many languages: methods/functions/operators in TTM.
Dynamic languages have more FCO. For example, JS objects and functions are just values. (JS has more interesting ways to shoot yourself in the foot than I ever dreamed of.)
The SCO in TTM are all those things that are given names and are not values of some type. They are:
- types RM Pre 1
- components RM Pre 5
- attributes RM Pre 9a
- variables RM Pre 11, 12, 13
- candidate key RM Pre 15 (*)
- database RM Pre 16
- operators RM Pre 18, 20 (*), 21, 22
- constraints RM Pre 23 (*)
Items marked (*) are required to be 'defined', which implies that they are given a name but might conceivably have some other interpretation.
IMO there are worthwhile use cases for dealing with variable, attribute, key, database, operator and constraint objects as something better than SCO. The example I gave before was for the 'types' list and lookup, which require an indirect reference to a relvar and/or attribute, but a 'dynamic TTM' would go further, by allowing these 6 kinds of object to be values and manipulated at runtime. If compile time checking is still required, then choosing a type is an important issue.
Quote from Dave Voorhis on November 3, 2018, 8:57 amI agree, I think an interesting D or D-like language could draw inspiration from languages that have done pervasive first-class-ness well, like the various LISPs (everything is first-class {and a list}) and Smalltalk (almost everything is first-class {and an object}).
I agree, I think an interesting D or D-like language could draw inspiration from languages that have done pervasive first-class-ness well, like the various LISPs (everything is first-class {and a list}) and Smalltalk (almost everything is first-class {and an object}).
Quote from Hugh on November 3, 2018, 5:15 pmDo those various RM Pres David has cited really militate against these things becoming first-class? If so, it's not a deliberate imposition by us, though I do remember Chris answering an early question from me by saying that he didn't want to have to deal explicitly with the issue of what he called "type type" (citing some early bad experiences in the development of PL/I).
A type comes to the knowledge of the system when it is "defined". When else?
Hugh
Do those various RM Pres David has cited really militate against these things becoming first-class? If so, it's not a deliberate imposition by us, though I do remember Chris answering an early question from me by saying that he didn't want to have to deal explicitly with the issue of what he called "type type" (citing some early bad experiences in the development of PL/I).
A type comes to the knowledge of the system when it is "defined". When else?
Hugh
Quote from Dave Voorhis on November 3, 2018, 9:30 pmQuote from Hugh on November 3, 2018, 5:15 pmA type comes to the knowledge of the system when it is "defined". When else?
Only when it's defined, but to be first-class, a type could also be a value (of type Type, which leads to some interesting things including the reasonable decision to avoid it) that can be assigned to a variable, passed as a parameter to a function, and returned by a function.
In general, a construct C is first-class if there exists a type T such that C ∈ T and values of type T can be instantiated or selected, assigned to a variable, passed as a parameter to a function, and returned by a function. In the usual Lisp implementations it's notably true that functions are first-class, and since every language construct is a function, it's essentially true of every language construct.
Quote from Hugh on November 3, 2018, 5:15 pmA type comes to the knowledge of the system when it is "defined". When else?
Only when it's defined, but to be first-class, a type could also be a value (of type Type, which leads to some interesting things including the reasonable decision to avoid it) that can be assigned to a variable, passed as a parameter to a function, and returned by a function.
In general, a construct C is first-class if there exists a type T such that C ∈ T and values of type T can be instantiated or selected, assigned to a variable, passed as a parameter to a function, and returned by a function. In the usual Lisp implementations it's notably true that functions are first-class, and since every language construct is a function, it's essentially true of every language construct.
Quote from Hugh on November 5, 2018, 2:55 pmQuote from Dave Voorhis on November 3, 2018, 9:30 pmQuote from Hugh on November 3, 2018, 5:15 pmA type comes to the knowledge of the system when it is "defined". When else?
Only when it's defined, but to be first-class, a type could also be a value (of type Type, which leads to some interesting things including the reasonable decision to avoid it) that can be assigned to a variable, passed as a parameter to a function, and returned by a function.
In general, a construct C is first-class if there exists a type T such that C ∈ T and values of type T can be instantiated or selected, assigned to a variable, passed as a parameter to a function, and returned by a function. In the usual Lisp implementations it's notably true that functions are first-class, and since every language construct is a function, it's essentially true of every language construct.
Yes, I know what first-class means, but I don't know what it is about RM Pre 1 that prohibits type Type. Is it the requirement for a type to be named? If so, why? I would assume that Type would be a system-defined type. I also assume it would include itself as a member.
Suppose variable TV is assigned the type named INTEGER. What would likely appear on my screen if I asked for TV to be displayed?
Hugh
Quote from Dave Voorhis on November 3, 2018, 9:30 pmQuote from Hugh on November 3, 2018, 5:15 pmA type comes to the knowledge of the system when it is "defined". When else?
Only when it's defined, but to be first-class, a type could also be a value (of type Type, which leads to some interesting things including the reasonable decision to avoid it) that can be assigned to a variable, passed as a parameter to a function, and returned by a function.
In general, a construct C is first-class if there exists a type T such that C ∈ T and values of type T can be instantiated or selected, assigned to a variable, passed as a parameter to a function, and returned by a function. In the usual Lisp implementations it's notably true that functions are first-class, and since every language construct is a function, it's essentially true of every language construct.
Yes, I know what first-class means, but I don't know what it is about RM Pre 1 that prohibits type Type. Is it the requirement for a type to be named? If so, why? I would assume that Type would be a system-defined type. I also assume it would include itself as a member.
Suppose variable TV is assigned the type named INTEGER. What would likely appear on my screen if I asked for TV to be displayed?
Hugh
Quote from Dave Voorhis on November 5, 2018, 8:29 pmQuote from Hugh on November 5, 2018, 2:55 pmQuote from Dave Voorhis on November 3, 2018, 9:30 pmQuote from Hugh on November 3, 2018, 5:15 pmA type comes to the knowledge of the system when it is "defined". When else?
Only when it's defined, but to be first-class, a type could also be a value (of type Type, which leads to some interesting things including the reasonable decision to avoid it) that can be assigned to a variable, passed as a parameter to a function, and returned by a function.
In general, a construct C is first-class if there exists a type T such that C ∈ T and values of type T can be instantiated or selected, assigned to a variable, passed as a parameter to a function, and returned by a function. In the usual Lisp implementations it's notably true that functions are first-class, and since every language construct is a function, it's essentially true of every language construct.
Yes, I know what first-class means, but I don't know what it is about RM Pre 1 that prohibits type Type. Is it the requirement for a type to be named? If so, why? I would assume that Type would be a system-defined type. I also assume it would include itself as a member.
Suppose variable TV is assigned the type named INTEGER. What would likely appear on my screen if I asked for TV to be displayed?
Hugh
The explicit requirement for a type to be named could be interpreted as intentionally prohibiting first-class types, particularly as it's not uncommon for a language with a first class construct to only support anonymous definitions of that construct. If you need it to be named, you assign it to a named variable or constant and reference it via the variable or constant.
If you ask for TV to be displayed, the language designer might have decided it should display the definition of INTEGER, or a message like "<system-defined type>", or throw an exception.
Quote from Hugh on November 5, 2018, 2:55 pmQuote from Dave Voorhis on November 3, 2018, 9:30 pmQuote from Hugh on November 3, 2018, 5:15 pmA type comes to the knowledge of the system when it is "defined". When else?
Only when it's defined, but to be first-class, a type could also be a value (of type Type, which leads to some interesting things including the reasonable decision to avoid it) that can be assigned to a variable, passed as a parameter to a function, and returned by a function.
In general, a construct C is first-class if there exists a type T such that C ∈ T and values of type T can be instantiated or selected, assigned to a variable, passed as a parameter to a function, and returned by a function. In the usual Lisp implementations it's notably true that functions are first-class, and since every language construct is a function, it's essentially true of every language construct.
Yes, I know what first-class means, but I don't know what it is about RM Pre 1 that prohibits type Type. Is it the requirement for a type to be named? If so, why? I would assume that Type would be a system-defined type. I also assume it would include itself as a member.
Suppose variable TV is assigned the type named INTEGER. What would likely appear on my screen if I asked for TV to be displayed?
Hugh
The explicit requirement for a type to be named could be interpreted as intentionally prohibiting first-class types, particularly as it's not uncommon for a language with a first class construct to only support anonymous definitions of that construct. If you need it to be named, you assign it to a named variable or constant and reference it via the variable or constant.
If you ask for TV to be displayed, the language designer might have decided it should display the definition of INTEGER, or a message like "<system-defined type>", or throw an exception.
Quote from Hugh on November 6, 2018, 4:25 pmQuote from Dave Voorhis on November 5, 2018, 8:29 pmQuote from Hugh on November 5, 2018, 2:55 pmQuote from Dave Voorhis on November 3, 2018, 9:30 pmQuote from Hugh on November 3, 2018, 5:15 pmA type comes to the knowledge of the system when it is "defined". When else?
Only when it's defined, but to be first-class, a type could also be a value (of type Type, which leads to some interesting things including the reasonable decision to avoid it) that can be assigned to a variable, passed as a parameter to a function, and returned by a function.
In general, a construct C is first-class if there exists a type T such that C ∈ T and values of type T can be instantiated or selected, assigned to a variable, passed as a parameter to a function, and returned by a function. In the usual Lisp implementations it's notably true that functions are first-class, and since every language construct is a function, it's essentially true of every language construct.
Yes, I know what first-class means, but I don't know what it is about RM Pre 1 that prohibits type Type. Is it the requirement for a type to be named? If so, why? I would assume that Type would be a system-defined type. I also assume it would include itself as a member.
Suppose variable TV is assigned the type named INTEGER. What would likely appear on my screen if I asked for TV to be displayed?
Hugh
The explicit requirement for a type to be named could be interpreted as intentionally prohibiting first-class types, particularly as it's not uncommon for a language with a first class construct to only support anonymous definitions of that construct. If you need it to be named, you assign it to a named variable or constant and reference it via the variable or constant.
If you ask for TV to be displayed, the language designer might have decided it should display the definition of INTEGER, or a message like "<system-defined type>", or throw an exception.
Okay, I (sort of) understand. A realistic example, showing how an anonymous type comes in to existence and is subsequently used, would help.
I'm sorry that TTM militates against anonymous types for types, variables, attributes, constraints, etc. but I'm not going to suggest an overhaul to correct that omission now. If anybody comes up with an otherwise conforming implementation based on such types, I'd be willing to consider it as within the spirit of TTM, if not the letter.
Hugh
Quote from Dave Voorhis on November 5, 2018, 8:29 pmQuote from Hugh on November 5, 2018, 2:55 pmQuote from Dave Voorhis on November 3, 2018, 9:30 pmQuote from Hugh on November 3, 2018, 5:15 pmA type comes to the knowledge of the system when it is "defined". When else?
Only when it's defined, but to be first-class, a type could also be a value (of type Type, which leads to some interesting things including the reasonable decision to avoid it) that can be assigned to a variable, passed as a parameter to a function, and returned by a function.
In general, a construct C is first-class if there exists a type T such that C ∈ T and values of type T can be instantiated or selected, assigned to a variable, passed as a parameter to a function, and returned by a function. In the usual Lisp implementations it's notably true that functions are first-class, and since every language construct is a function, it's essentially true of every language construct.
Yes, I know what first-class means, but I don't know what it is about RM Pre 1 that prohibits type Type. Is it the requirement for a type to be named? If so, why? I would assume that Type would be a system-defined type. I also assume it would include itself as a member.
Suppose variable TV is assigned the type named INTEGER. What would likely appear on my screen if I asked for TV to be displayed?
Hugh
The explicit requirement for a type to be named could be interpreted as intentionally prohibiting first-class types, particularly as it's not uncommon for a language with a first class construct to only support anonymous definitions of that construct. If you need it to be named, you assign it to a named variable or constant and reference it via the variable or constant.
If you ask for TV to be displayed, the language designer might have decided it should display the definition of INTEGER, or a message like "<system-defined type>", or throw an exception.
Okay, I (sort of) understand. A realistic example, showing how an anonymous type comes in to existence and is subsequently used, would help.
I'm sorry that TTM militates against anonymous types for types, variables, attributes, constraints, etc. but I'm not going to suggest an overhaul to correct that omission now. If anybody comes up with an otherwise conforming implementation based on such types, I'd be willing to consider it as within the spirit of TTM, if not the letter.
Hugh
Quote from Dave Voorhis on November 6, 2018, 4:52 pmI'm not sure I can think of a realistic example, let alone a useful one, of an anonymous type. First-class operators are useful, and perhaps some other constructs, but I'm hard pressed to come up with a use case for an anonymous type.
As an aside, in Java anonymous classes are useful but are only distantly related.
That said, a hypothetical -- though perhaps neither realistic nor useful -- example might be something like this:
// Assign anonymous type to variable TV. VAR TV INIT(TYPE POSSREP {x CHAR CONSTRAINT LENGTH(x) = 3}); // Declare variable X to be of the type currently in variable TV. VAR X (TV); // Set X to a value. (Via anonymous selector??!?) X := ("ZAP");
I'm not sure I can think of a realistic example, let alone a useful one, of an anonymous type. First-class operators are useful, and perhaps some other constructs, but I'm hard pressed to come up with a use case for an anonymous type.
As an aside, in Java anonymous classes are useful but are only distantly related.
That said, a hypothetical -- though perhaps neither realistic nor useful -- example might be something like this:
// Assign anonymous type to variable TV. VAR TV INIT(TYPE POSSREP {x CHAR CONSTRAINT LENGTH(x) = 3}); // Declare variable X to be of the type currently in variable TV. VAR X (TV); // Set X to a value. (Via anonymous selector??!?) X := ("ZAP");
Quote from dandl on November 7, 2018, 1:16 pmQuote from Hugh on November 3, 2018, 5:15 pmDo those various RM Pres David has cited really militate against these things becoming first-class? If so, it's not a deliberate imposition by us, though I do remember Chris answering an early question from me by saying that he didn't want to have to deal explicitly with the issue of what he called "type type" (citing some early bad experiences in the development of PL/I).
I don't like or propose type "type". I've used such systems, not to good effect. Components are part of the type and as such are off limits too.
I do propose type "operator" as virtually a no-brainer. Dave has made good progress towards inserting that into Rel.
This post is really about a way to treat relvar, attribute, database and constraint as something closer to first class. So for example, if V1 and V2 are two relvars each of type T, then V3 might be a 'relvar reference' that can refer to (resolve to) V1 in one part of the program and V2 somewhere else. An operator with a parameter of type T might be called with an argument of V1 or V2, or even a relvar of the correct type created dynamically or retrieved dynamically from the database.
Likewise for attributes, database and constraint. The type of the object has to be known at compile time, but the binding to a specific object can be deferred to runtime.
TTM does not permit this because of the concrete way it requires these things to be individually named and defined and known by that name, but it would take only a minor change to open up the possibility.
Quote from Hugh on November 3, 2018, 5:15 pmDo those various RM Pres David has cited really militate against these things becoming first-class? If so, it's not a deliberate imposition by us, though I do remember Chris answering an early question from me by saying that he didn't want to have to deal explicitly with the issue of what he called "type type" (citing some early bad experiences in the development of PL/I).
I don't like or propose type "type". I've used such systems, not to good effect. Components are part of the type and as such are off limits too.
I do propose type "operator" as virtually a no-brainer. Dave has made good progress towards inserting that into Rel.
This post is really about a way to treat relvar, attribute, database and constraint as something closer to first class. So for example, if V1 and V2 are two relvars each of type T, then V3 might be a 'relvar reference' that can refer to (resolve to) V1 in one part of the program and V2 somewhere else. An operator with a parameter of type T might be called with an argument of V1 or V2, or even a relvar of the correct type created dynamically or retrieved dynamically from the database.
Likewise for attributes, database and constraint. The type of the object has to be known at compile time, but the binding to a specific object can be deferred to runtime.
TTM does not permit this because of the concrete way it requires these things to be individually named and defined and known by that name, but it would take only a minor change to open up the possibility.
Quote from Hugh on November 8, 2018, 11:43 amQuote from dandl on November 7, 2018, 1:16 pmQuote from Hugh on November 3, 2018, 5:15 pmDo those various RM Pres David has cited really militate against these things becoming first-class? If so, it's not a deliberate imposition by us, though I do remember Chris answering an early question from me by saying that he didn't want to have to deal explicitly with the issue of what he called "type type" (citing some early bad experiences in the development of PL/I).
I don't like or propose type "type". I've used such systems, not to good effect. Components are part of the type and as such are off limits too.
I do propose type "operator" as virtually a no-brainer. Dave has made good progress towards inserting that into Rel.
This post is really about a way to treat relvar, attribute, database and constraint as something closer to first class. So for example, if V1 and V2 are two relvars each of type T, then V3 might be a 'relvar reference' that can refer to (resolve to) V1 in one part of the program and V2 somewhere else. An operator with a parameter of type T might be called with an argument of V1 or V2, or even a relvar of the correct type created dynamically or retrieved dynamically from the database.
Likewise for attributes, database and constraint. The type of the object has to be known at compile time, but the binding to a specific object can be deferred to runtime.
TTM does not permit this because of the concrete way it requires these things to be individually named and defined and known by that name, but it would take only a minor change to open up the possibility.
Regarding relvars, your example is confusing. I take the roman symbols V1 and V2 to be variable names but V3 to denote a value (and so should be in italics). Anyway, V3 looks suspiciously like a pointer to me. TTM expressly bans visible pointers in the database, but if these can point at variables only, then such a pointer appearing as an attribute value could only be pointing at a relvar, these being the only persistent variables. Those aren't the kind of pointer Codd had in mind and I'm not sure Date and I have given much though to them. Nor can I think offhand of a good example of their use. Please give a concrete example of an expression denoting the value V3 as a reference to the variable V1 (I want to see what a selector for such such values looks like).
Actually, your references to "one part of the program" and "somewhere else [in the program]" suggest to me that you aren't necessarily thinking of allowing such values to appear in the database (though perhaps you are).
Regarding operators, the idea certainly seems attractive but I wonder if any problems arise when nameless ones are allowed to persist. I also wonder how well they can coexist with named operators. How would I assign the system-defined operator named "+" to a variable of type OPERATOR? How would that value appear in a printout?
Regarding attributes, I simply can't imagine such a thing as a nameless one, considering that multiple attributes of the same type can appear in a heading. Anyway, surely TTM doesn't prevent a D from allowing a program to build commands and queries dynamically, as SQL does and BS12 did? (No doubt I'm missing your point.)
Hugh
Quote from dandl on November 7, 2018, 1:16 pmQuote from Hugh on November 3, 2018, 5:15 pmDo those various RM Pres David has cited really militate against these things becoming first-class? If so, it's not a deliberate imposition by us, though I do remember Chris answering an early question from me by saying that he didn't want to have to deal explicitly with the issue of what he called "type type" (citing some early bad experiences in the development of PL/I).
I don't like or propose type "type". I've used such systems, not to good effect. Components are part of the type and as such are off limits too.
I do propose type "operator" as virtually a no-brainer. Dave has made good progress towards inserting that into Rel.
This post is really about a way to treat relvar, attribute, database and constraint as something closer to first class. So for example, if V1 and V2 are two relvars each of type T, then V3 might be a 'relvar reference' that can refer to (resolve to) V1 in one part of the program and V2 somewhere else. An operator with a parameter of type T might be called with an argument of V1 or V2, or even a relvar of the correct type created dynamically or retrieved dynamically from the database.
Likewise for attributes, database and constraint. The type of the object has to be known at compile time, but the binding to a specific object can be deferred to runtime.
TTM does not permit this because of the concrete way it requires these things to be individually named and defined and known by that name, but it would take only a minor change to open up the possibility.
Regarding relvars, your example is confusing. I take the roman symbols V1 and V2 to be variable names but V3 to denote a value (and so should be in italics). Anyway, V3 looks suspiciously like a pointer to me. TTM expressly bans visible pointers in the database, but if these can point at variables only, then such a pointer appearing as an attribute value could only be pointing at a relvar, these being the only persistent variables. Those aren't the kind of pointer Codd had in mind and I'm not sure Date and I have given much though to them. Nor can I think offhand of a good example of their use. Please give a concrete example of an expression denoting the value V3 as a reference to the variable V1 (I want to see what a selector for such such values looks like).
Actually, your references to "one part of the program" and "somewhere else [in the program]" suggest to me that you aren't necessarily thinking of allowing such values to appear in the database (though perhaps you are).
Regarding operators, the idea certainly seems attractive but I wonder if any problems arise when nameless ones are allowed to persist. I also wonder how well they can coexist with named operators. How would I assign the system-defined operator named "+" to a variable of type OPERATOR? How would that value appear in a printout?
Regarding attributes, I simply can't imagine such a thing as a nameless one, considering that multiple attributes of the same type can appear in a heading. Anyway, surely TTM doesn't prevent a D from allowing a program to build commands and queries dynamically, as SQL does and BS12 did? (No doubt I'm missing your point.)
Hugh