A TTM Tuple is not a Record
Quote from AntC on May 6, 2020, 7:16 amQuote from dandl on May 6, 2020, 4:11 amWhat I've sketched goes a long way beyond TTM's Pres and Pros. There are more things in type systems than are dreamt of in RM Pre 1, Horatio. We can perhaps say there are parts of the type system in the implementation/host language that are not visible in the D, but I think it would be hard to hermetically seal them off and I'm not going to try.
I like big ambitions. I'm just not sure what the goal is.
I want to say such a query can be expressed as polymorphic; because I want to type-check the body of the query to stop it (for example) trying to access attributes it hasn't asked for in its signature, or treat them as numeric when the signature says they're at
CHAR
.Agreed.
I also want to use this polymorphism instead of TTM's Selector structures/RM Pre 4 -- because Selectors need positional access; and Selectors have type-differentiable names, which cuts across the set-of-
<A, T>
semantics. Or perhaps I mean I want Selector structures to be implemented as non-positional TVAs, with an atomic name. Something like:
TYPE ALIAS Point = TUP{X RAT, Y RAT};
//ALIAS
means not a distinct/new type, but a shorthand
TYPE ALIAS Circle = TUP{Rad RAT, Centre Point}
//Point
TVA is nested insideCircle
TVAOr rather I want to get nearer structural typing than that:
TYPE ALIAS Point(r) = TUP{X RAT, Y RAT | r}
// ther
is a type parameter denoting 'other attributes', the|
says 'unioned', not positionally appended
TYPE ALIAS Circle(r) = Point( {Rad RAT | r} )
// aCircle
is aPoint
extended with aRad
and possibly more 'other attributes'Note that that unlike the first definition, this
Circle
is 'flat'/thePoint
is not nested, it's extended. 'Applying'Point
is something like macro expansion(?)
TUP{X RAT, Y RAT}
is a TTM (nonscalar) type;RAT
is a TTM scalar type. They're both inhabited by values, per RM Pre 1.Point(r)
is not a TTM type because it's not inhabited by values -- at least not until there's an argument supplied forr
. What to supply is not a TTM value; and it's not even a TTM type. I'll write that definition forPoint
more explicitly (so what I put previously was a shorthand):
TYPE ALIAS Point(r) = TUP( {X RAT, Y RAT} ∪ r )
- Firstly,
Point( )
is a parametric type, sometimes called a 'type scheme'.{X RAT, Y RAT}
is a Heading, not a TTM tuple type. Headings are sets, subsets of sets are sets, so subsets of Headings are Headings. Headings are neither scalar types nor nonscalar types because they're not inhabited by values. We might say (ref RM Pre 1) there are (many) more types than omega that are not inhabited by values, and for which we cannot give an example value. Or we say Headings are not types, then some other term needed.- Then
r
is also a Heading; also not inhabited by values.TUP( )
is a parametric type, in principle no different toPoint( )
.TUP( )
takes a Heading and returns a TTM (nonscalar) type -- i.e. inhabitable by values. TTM wants to call that a 'type generator'.Point( )
takes a Heading and returns a TTM (nonscalar) type, via a 'subroutine call' toTUP( )
.I'm OK with all this. But I would point out that for any given heading, TTM RM Pre 6 will always generate the same (unique) type named 'TUPLE H'. Do you plan something different? Is there such a thing as 'type equality' other than name equality in Haskell?
- There's another category of uninhabited types in
{X RAT, Y RAT}
:RAT
is a familiar, value-inhabited TTM scalar type.X, Y
and the ordered-pairing of them denoted by juxtaposition in Tutorial D are neither scalars nor non-scalars (because not inhabitable) neither are they Headings, they're elements of Headings.- So the ordered pair type scheme
< , >
is a type generator; it takes an Attribute-name type (which is neither scalar nor nonscalar, not inhabitable) and a familiar TTM type (scalar or nonscalar) and returns an element of a Heading.- What I've arrived at is type-of-type categories, these are mutually exclusive:
- scalar types;
- nonscalar types;
- Headings; -- sets of
<A, T>
types; of whichA
Attribute-name types.- In general, 'type generators' (or type-level functions) can take arguments of any type-of-type and return a result of any (not necessarily different) type-of-type. Static type-checking applies for Type generators just as much as for value-level functions; so type arguments must be well- type-of-typed.
Those elements can all be identified in TTM and in TD, but the implementation is good old slogging compiler code. Do you get something better/different by doing it in Haskell?
Doing it in vanilla/standard-compliant Haskell, no. Doing it in GHC with all its fancy asteroid-chasing type extensions, no. Doing it in Hugs/Trex from 2006 I've now wrangled my way past the type-wobbliness, then yes; clearly there's a (undocumented) idiom; and it could do with a bit of syntactic sugar -- in case anybody knows someone who's able to compile it from source and can tinker with yacc ...
type WPoint r = (x :: Float, y :: Float | r) -- Heading r extended "with Point" type WRadius r = (radius :: Float | r) type WColour r = (colour :: String | r) type ColouredCircle = Rec( WColour (WRadius (WPoint EmptyRow))) myColouredCircle = (x = 1.2, colour = "Red", y = 3.4, radius = 27) Main> show myColouredCircle -- show is Haskell for toString ====> "(colour = \"Red\", radius = 27, x = 1.2, y = 3.4)" -- is in canonical alphabetic label sequence -- For better 'plug and play', we want to compose those "with xxx" -- following code not currently valid: type ColouredCircle = TUP (WPoint ¤ WRadius ¤ WColour) -- using ¤ as function compose type TUP r = Rec( r EmptyRow )(As of my previous message, I wasn't able to
show
a tuple, because of the type-wobbles.)Read
WPoint r
asr
extended with a Point (i.e. two co-ordinates, not necessarily a single attribute). So we plug-and-play the fields to make a Heading (not a TTM type because not inhabitable with values), then to turn that into a TTM-style tuple, apply theTUP
type-generator, and close out the extensible Heading withEmptyRow
-- which is a Hugs-defined constant.Note re the
show
/toString
format: there's also a function to give you a list of pairs of label-as-String, value-as-String. So if you don't like alphabetical order, you can roll your own format.I have to fess up that this style of type-level 'function' in Haskell is not really a function; it's more like a macro. So there aren't type-level lambdas; there isn't really higher-order function composition. Hence all that ugly nesting of parens, making the thing look like LISP.
The semantics is perfect.
Quote from dandl on May 6, 2020, 4:11 amWhat I've sketched goes a long way beyond TTM's Pres and Pros. There are more things in type systems than are dreamt of in RM Pre 1, Horatio. We can perhaps say there are parts of the type system in the implementation/host language that are not visible in the D, but I think it would be hard to hermetically seal them off and I'm not going to try.
I like big ambitions. I'm just not sure what the goal is.
I want to say such a query can be expressed as polymorphic; because I want to type-check the body of the query to stop it (for example) trying to access attributes it hasn't asked for in its signature, or treat them as numeric when the signature says they're at
CHAR
.Agreed.
I also want to use this polymorphism instead of TTM's Selector structures/RM Pre 4 -- because Selectors need positional access; and Selectors have type-differentiable names, which cuts across the set-of-
<A, T>
semantics. Or perhaps I mean I want Selector structures to be implemented as non-positional TVAs, with an atomic name. Something like:
TYPE ALIAS Point = TUP{X RAT, Y RAT};
//ALIAS
means not a distinct/new type, but a shorthand
TYPE ALIAS Circle = TUP{Rad RAT, Centre Point}
//Point
TVA is nested insideCircle
TVAOr rather I want to get nearer structural typing than that:
TYPE ALIAS Point(r) = TUP{X RAT, Y RAT | r}
// ther
is a type parameter denoting 'other attributes', the|
says 'unioned', not positionally appended
TYPE ALIAS Circle(r) = Point( {Rad RAT | r} )
// aCircle
is aPoint
extended with aRad
and possibly more 'other attributes'Note that that unlike the first definition, this
Circle
is 'flat'/thePoint
is not nested, it's extended. 'Applying'Point
is something like macro expansion(?)
TUP{X RAT, Y RAT}
is a TTM (nonscalar) type;RAT
is a TTM scalar type. They're both inhabited by values, per RM Pre 1.Point(r)
is not a TTM type because it's not inhabited by values -- at least not until there's an argument supplied forr
. What to supply is not a TTM value; and it's not even a TTM type. I'll write that definition forPoint
more explicitly (so what I put previously was a shorthand):
TYPE ALIAS Point(r) = TUP( {X RAT, Y RAT} ∪ r )
- Firstly,
Point( )
is a parametric type, sometimes called a 'type scheme'.{X RAT, Y RAT}
is a Heading, not a TTM tuple type. Headings are sets, subsets of sets are sets, so subsets of Headings are Headings. Headings are neither scalar types nor nonscalar types because they're not inhabited by values. We might say (ref RM Pre 1) there are (many) more types than omega that are not inhabited by values, and for which we cannot give an example value. Or we say Headings are not types, then some other term needed.- Then
r
is also a Heading; also not inhabited by values.TUP( )
is a parametric type, in principle no different toPoint( )
.TUP( )
takes a Heading and returns a TTM (nonscalar) type -- i.e. inhabitable by values. TTM wants to call that a 'type generator'.Point( )
takes a Heading and returns a TTM (nonscalar) type, via a 'subroutine call' toTUP( )
.I'm OK with all this. But I would point out that for any given heading, TTM RM Pre 6 will always generate the same (unique) type named 'TUPLE H'. Do you plan something different? Is there such a thing as 'type equality' other than name equality in Haskell?
- There's another category of uninhabited types in
{X RAT, Y RAT}
:RAT
is a familiar, value-inhabited TTM scalar type.X, Y
and the ordered-pairing of them denoted by juxtaposition in Tutorial D are neither scalars nor non-scalars (because not inhabitable) neither are they Headings, they're elements of Headings.- So the ordered pair type scheme
< , >
is a type generator; it takes an Attribute-name type (which is neither scalar nor nonscalar, not inhabitable) and a familiar TTM type (scalar or nonscalar) and returns an element of a Heading.- What I've arrived at is type-of-type categories, these are mutually exclusive:
- scalar types;
- nonscalar types;
- Headings; -- sets of
<A, T>
types; of whichA
Attribute-name types.- In general, 'type generators' (or type-level functions) can take arguments of any type-of-type and return a result of any (not necessarily different) type-of-type. Static type-checking applies for Type generators just as much as for value-level functions; so type arguments must be well- type-of-typed.
Those elements can all be identified in TTM and in TD, but the implementation is good old slogging compiler code. Do you get something better/different by doing it in Haskell?
Doing it in vanilla/standard-compliant Haskell, no. Doing it in GHC with all its fancy asteroid-chasing type extensions, no. Doing it in Hugs/Trex from 2006 I've now wrangled my way past the type-wobbliness, then yes; clearly there's a (undocumented) idiom; and it could do with a bit of syntactic sugar -- in case anybody knows someone who's able to compile it from source and can tinker with yacc ...
type WPoint r = (x :: Float, y :: Float | r) -- Heading r extended "with Point" type WRadius r = (radius :: Float | r) type WColour r = (colour :: String | r) type ColouredCircle = Rec( WColour (WRadius (WPoint EmptyRow))) myColouredCircle = (x = 1.2, colour = "Red", y = 3.4, radius = 27) Main> show myColouredCircle -- show is Haskell for toString ====> "(colour = \"Red\", radius = 27, x = 1.2, y = 3.4)" -- is in canonical alphabetic label sequence -- For better 'plug and play', we want to compose those "with xxx" -- following code not currently valid: type ColouredCircle = TUP (WPoint ¤ WRadius ¤ WColour) -- using ¤ as function compose type TUP r = Rec( r EmptyRow )
(As of my previous message, I wasn't able to show
a tuple, because of the type-wobbles.)
Read WPoint r
as r
extended with a Point (i.e. two co-ordinates, not necessarily a single attribute). So we plug-and-play the fields to make a Heading (not a TTM type because not inhabitable with values), then to turn that into a TTM-style tuple, apply the TUP
type-generator, and close out the extensible Heading with EmptyRow
-- which is a Hugs-defined constant.
Note re the show
/toString
format: there's also a function to give you a list of pairs of label-as-String, value-as-String. So if you don't like alphabetical order, you can roll your own format.
I have to fess up that this style of type-level 'function' in Haskell is not really a function; it's more like a macro. So there aren't type-level lambdas; there isn't really higher-order function composition. Hence all that ugly nesting of parens, making the thing look like LISP.
The semantics is perfect.
Quote from AntC on May 6, 2020, 7:58 amQuote from dandl on May 6, 2020, 4:11 amWhat I've sketched goes a long way beyond TTM's Pres and Pros. There are more things in type systems than are dreamt of in RM Pre 1, Horatio. We can perhaps say there are parts of the type system in the implementation/host language that are not visible in the D, but I think it would be hard to hermetically seal them off and I'm not going to try.
I like big ambitions. I'm just not sure what the goal is.
I want to say such a query can be expressed as polymorphic; because I want to type-check the body of the query to stop it (for example) trying to access attributes it hasn't asked for in its signature, or treat them as numeric when the signature says they're at
CHAR
.Agreed.
I also want to use this polymorphism instead of TTM's Selector structures/RM Pre 4 -- because Selectors need positional access; and Selectors have type-differentiable names, which cuts across the set-of-
<A, T>
semantics. Or perhaps I mean I want Selector structures to be implemented as non-positional TVAs, with an atomic name. Something like:
TYPE ALIAS Point = TUP{X RAT, Y RAT};
//ALIAS
means not a distinct/new type, but a shorthand
TYPE ALIAS Circle = TUP{Rad RAT, Centre Point}
//Point
TVA is nested insideCircle
TVAOr rather I want to get nearer structural typing than that:
TYPE ALIAS Point(r) = TUP{X RAT, Y RAT | r}
// ther
is a type parameter denoting 'other attributes', the|
says 'unioned', not positionally appended
TYPE ALIAS Circle(r) = Point( {Rad RAT | r} )
// aCircle
is aPoint
extended with aRad
and possibly more 'other attributes'Note that that unlike the first definition, this
Circle
is 'flat'/thePoint
is not nested, it's extended. 'Applying'Point
is something like macro expansion(?)
TUP{X RAT, Y RAT}
is a TTM (nonscalar) type;RAT
is a TTM scalar type. They're both inhabited by values, per RM Pre 1.Point(r)
is not a TTM type because it's not inhabited by values -- at least not until there's an argument supplied forr
. What to supply is not a TTM value; and it's not even a TTM type. I'll write that definition forPoint
more explicitly (so what I put previously was a shorthand):
TYPE ALIAS Point(r) = TUP( {X RAT, Y RAT} ∪ r )
- Firstly,
Point( )
is a parametric type, sometimes called a 'type scheme'.{X RAT, Y RAT}
is a Heading, not a TTM tuple type. Headings are sets, subsets of sets are sets, so subsets of Headings are Headings. Headings are neither scalar types nor nonscalar types because they're not inhabited by values. We might say (ref RM Pre 1) there are (many) more types than omega that are not inhabited by values, and for which we cannot give an example value. Or we say Headings are not types, then some other term needed.- Then
r
is also a Heading; also not inhabited by values.TUP( )
is a parametric type, in principle no different toPoint( )
.TUP( )
takes a Heading and returns a TTM (nonscalar) type -- i.e. inhabitable by values. TTM wants to call that a 'type generator'.Point( )
takes a Heading and returns a TTM (nonscalar) type, via a 'subroutine call' toTUP( )
.I'm OK with all this. But I would point out that for any given heading, TTM RM Pre 6 will always generate the same (unique) type named 'TUPLE H'. Do you plan something different? Is there such a thing as 'type equality' other than name equality in Haskell?
(You can try this in your own Hugs, to prove there's nothing up my sleeves.)
type ColouredCircle = Rec( WColour (WRadius (WPoint EmptyRow))) myColouredCircle :: ColouredCircle myColouredCircle = (x = 1.2, colour = "Red", y = 3.4, radius = 27) -- different order of attributes type ColouredCircle2 = Rec( x :: Float, colour :: String, radius :: Float, y :: Float) -- different again myColouredCircle2 :: ColouredCircle2 myColouredCircle2 = myColouredCircle -- can assign OK Main> show (myColouredCircle `asTypeOf` (undefined :: Rec( x :: Float, colour :: String, radius :: Float, y :: Float))) ====> "(colour = \"Red\", radius = 27.0, x = 1.2, y = 3.4)" -- still show in canonical order Main> :type undefined `asTypeOf` myColouredCircle ====> asTypeOf undefined myColouredCircle :: Rec (colour :: [Char], radius :: Float, x :: Float, y :: Float)It'll need a bit of explaining the Haskell to see what's going on here:
- the TYPE ALIAS
ColouredCircle
is defined as one sequence of attributes.- the var
myColouredCircle
is given a signature of that type; but assigned a value with attributes in a different sequence.- TYPE ALIAS
ColouredCircle2
gives the same attributes direct, without all the fancy type macros; I give that as the signature for varmyColouredCircle2
; Hugs is happy to assign to it, providing the tuple has the same attributes and attribute types, irrespective of sequence.- In the
show
I'm giving an anonymous signature. The functionasTypeOf
says: cast the value on my left to the type on my right.- Irrespective of all those signatures;
show
gives the labels in alphabetical order.- The
:type undefined asTypeOf ...
is a diagnostic giving the type signature rather than the value; so we 'cast' the anonymous valueundefined
to some type, then ask what type we got. You can see it's again canonicalising the sequence of attribute names.So what's going on, and especially given I'm using TYPE ALIASs is that Hugs/Trex converts all structural types to canonical order: both types of values and of Headings that aren't inhabited.
So the same is going on as TTM "the type of the type shall be precisely TUPLE H". Where the H is a long and complex type-expression, not a bare/atomic name.
Rec( )
is Hugs/Trex's way of spellingTUP{ }
.
Quote from dandl on May 6, 2020, 4:11 amWhat I've sketched goes a long way beyond TTM's Pres and Pros. There are more things in type systems than are dreamt of in RM Pre 1, Horatio. We can perhaps say there are parts of the type system in the implementation/host language that are not visible in the D, but I think it would be hard to hermetically seal them off and I'm not going to try.
I like big ambitions. I'm just not sure what the goal is.
I want to say such a query can be expressed as polymorphic; because I want to type-check the body of the query to stop it (for example) trying to access attributes it hasn't asked for in its signature, or treat them as numeric when the signature says they're at
CHAR
.Agreed.
I also want to use this polymorphism instead of TTM's Selector structures/RM Pre 4 -- because Selectors need positional access; and Selectors have type-differentiable names, which cuts across the set-of-
<A, T>
semantics. Or perhaps I mean I want Selector structures to be implemented as non-positional TVAs, with an atomic name. Something like:
TYPE ALIAS Point = TUP{X RAT, Y RAT};
//ALIAS
means not a distinct/new type, but a shorthand
TYPE ALIAS Circle = TUP{Rad RAT, Centre Point}
//Point
TVA is nested insideCircle
TVAOr rather I want to get nearer structural typing than that:
TYPE ALIAS Point(r) = TUP{X RAT, Y RAT | r}
// ther
is a type parameter denoting 'other attributes', the|
says 'unioned', not positionally appended
TYPE ALIAS Circle(r) = Point( {Rad RAT | r} )
// aCircle
is aPoint
extended with aRad
and possibly more 'other attributes'Note that that unlike the first definition, this
Circle
is 'flat'/thePoint
is not nested, it's extended. 'Applying'Point
is something like macro expansion(?)
TUP{X RAT, Y RAT}
is a TTM (nonscalar) type;RAT
is a TTM scalar type. They're both inhabited by values, per RM Pre 1.Point(r)
is not a TTM type because it's not inhabited by values -- at least not until there's an argument supplied forr
. What to supply is not a TTM value; and it's not even a TTM type. I'll write that definition forPoint
more explicitly (so what I put previously was a shorthand):
TYPE ALIAS Point(r) = TUP( {X RAT, Y RAT} ∪ r )
- Firstly,
Point( )
is a parametric type, sometimes called a 'type scheme'.{X RAT, Y RAT}
is a Heading, not a TTM tuple type. Headings are sets, subsets of sets are sets, so subsets of Headings are Headings. Headings are neither scalar types nor nonscalar types because they're not inhabited by values. We might say (ref RM Pre 1) there are (many) more types than omega that are not inhabited by values, and for which we cannot give an example value. Or we say Headings are not types, then some other term needed.- Then
r
is also a Heading; also not inhabited by values.TUP( )
is a parametric type, in principle no different toPoint( )
.TUP( )
takes a Heading and returns a TTM (nonscalar) type -- i.e. inhabitable by values. TTM wants to call that a 'type generator'.Point( )
takes a Heading and returns a TTM (nonscalar) type, via a 'subroutine call' toTUP( )
.I'm OK with all this. But I would point out that for any given heading, TTM RM Pre 6 will always generate the same (unique) type named 'TUPLE H'. Do you plan something different? Is there such a thing as 'type equality' other than name equality in Haskell?
(You can try this in your own Hugs, to prove there's nothing up my sleeves.)
type ColouredCircle = Rec( WColour (WRadius (WPoint EmptyRow))) myColouredCircle :: ColouredCircle myColouredCircle = (x = 1.2, colour = "Red", y = 3.4, radius = 27) -- different order of attributes type ColouredCircle2 = Rec( x :: Float, colour :: String, radius :: Float, y :: Float) -- different again myColouredCircle2 :: ColouredCircle2 myColouredCircle2 = myColouredCircle -- can assign OK Main> show (myColouredCircle `asTypeOf` (undefined :: Rec( x :: Float, colour :: String, radius :: Float, y :: Float))) ====> "(colour = \"Red\", radius = 27.0, x = 1.2, y = 3.4)" -- still show in canonical order Main> :type undefined `asTypeOf` myColouredCircle ====> asTypeOf undefined myColouredCircle :: Rec (colour :: [Char], radius :: Float, x :: Float, y :: Float)
It'll need a bit of explaining the Haskell to see what's going on here:
- the TYPE ALIAS
ColouredCircle
is defined as one sequence of attributes. - the var
myColouredCircle
is given a signature of that type; but assigned a value with attributes in a different sequence. - TYPE ALIAS
ColouredCircle2
gives the same attributes direct, without all the fancy type macros; I give that as the signature for varmyColouredCircle2
; Hugs is happy to assign to it, providing the tuple has the same attributes and attribute types, irrespective of sequence. - In the
show
I'm giving an anonymous signature. The functionasTypeOf
says: cast the value on my left to the type on my right. - Irrespective of all those signatures;
show
gives the labels in alphabetical order. - The
:type undefined asTypeOf ...
is a diagnostic giving the type signature rather than the value; so we 'cast' the anonymous valueundefined
to some type, then ask what type we got. You can see it's again canonicalising the sequence of attribute names.
So what's going on, and especially given I'm using TYPE ALIASs is that Hugs/Trex converts all structural types to canonical order: both types of values and of Headings that aren't inhabited.
So the same is going on as TTM "the type of the type shall be precisely TUPLE H". Where the H is a long and complex type-expression, not a bare/atomic name. Rec( )
is Hugs/Trex's way of spelling TUP{ }
.
Quote from Dave Voorhis on May 6, 2020, 8:15 amQuote from dandl on May 6, 2020, 2:11 amTTM Pre 9 implies structural typing. "A heading H is a set of ordered pairs or attributes of the form <A, T> ..." etc. Nominative typing would be "A heading H is a named set of ordered pairs or attributes of the form <A, T> distinguished from each other by name" or similar.
I don't think so. TTM Pre 9 makes it clear that headings are a set of attributes, so the order of attributes does not matter, and since headings are not a type, they have no name.
Headings are indeed not a type -- they are a component of a type generation -- but that's not why have no name. They have no name because they are structural rather than nominative. The fact that TTM doesn't use these terms doesn't change that fact.
But RM Pre 6 is the one that defines a tuple type, and that says "the name of that type shall be, precisely, TUPLE H." So a tuple type does have a name, and for any given heading H there is only that one tuple type.
So the issue of structural/nominative does not arise, because (a) the tuple type is named but (b) there is only one with that heading.
I thik TD confuses things by not making it clear that tuple types as defined by {X,Y}, {Y,X}, {X,Y,Z ALLBUT Z} and {X,Y,W} JOIN {X,Y,Z} are not 'structurally equivalent', they are all exactly the same unique type.
"Structurally equivalent" and "the same unique type" are synonymous under structural typing.
It's not a big deal; I'm just curious how you've dealt with this oft-mentioned distinction between conventional programming languages like C# and, say, Tutorial D where TUPLE {x INT, y CHAR} is (type-compatible with) TUPLE {y CHAR, x INT}. If tuple type (and similarly relation type) distinction or equivalence is maintained by policy rather than mechanism, then that's reasonable and in the spirit of TTM if not confirming to the letter of TTM Pre 9. I'm sure it could be enforced but probably only at run-time, though it might be do-able at compile-time with Java annotations. I'd have to play with it to see if annotations can be used that way.
The rules for defining a tuple type are easy:
- a tuple type must define a unique heading
- the heading is an array of strings, which enables generic RA machinery
- there may not be two tuple types with the same heading
- inherits from a base type (which ensures it behaves as value (equals() and hashcode()))
- must declare getters, setters and a constructor that match the heading and comply with RM Pre 4,5,6
- must be immutable
public static RelS S = new RelS( new List<TupS> { new TupS( "S1", "Smith", 20, "London" ), new TupS( "S2", "Jones", 10, "Paris" ), new TupS( "S3", "Blake", 30, "Paris" ), new TupS( "S4", "Clark", 20, "London" ), new TupS( "S5", "Adams", 30, "Athens" ), }); Console.WriteLine(S.Select(t => t.Status < 20));Pretty much all of TTM except for RM Pre 18 is already there. I'm still working on that part (as well as codifying some rules).
This looks notionally similar to the Rel internals, though syntactically different and (for example) headings are declared programmatically by adding attributes to a Heading instance, but could certainly be used in a similar manner. I don't know that I would, though -- it's rather clunky.
The code required to declare a tuple type is similar in volume to the declaration of a POCO. The getters and constructor are roughly the same; the heading is an extra bit of code; on the plus side, you don't have to code for Equals() and HashCode() because they get inherited. And like POCOs, they can easily be generated.
The code required to declare a relation type is trivial: just the class name and a typed constructor.
The clunky bit is that you have to declare every type. RA operators generate new types behind the scenes in TD/Rel, but in C# you have to declare every tuple type and every relation type up front. That's definitely something that would benefit from code generation.
There is an interesting problem in TTM, which I completely missed until now. The very prescriptive language in RM Pre 6 talks about 'defining...operators of that type'. Then it talks about 'the applicable operators shall include...'. (The references to 'RENAME,project,etc' are obviously mistakes left over from an earlier iteration, but no matter.)
The problem is "(b) an operator for extracting a specified attribute value from a specified tuple (the tuple in question might be required to be of degree one—see RM Prescription 9". It's hard to see exactly what is intended here, or what will satisfy it, but I don't think as written it's what was intended. I think having getters is enough.
In Tutorial D, that's the FROM operator.
Where do you declare (or infer) your attribute types?
Or is that implicit in the property definitions?
Is the _values array necessary? Wouldn't it be cleaner to just declare properties and use reflection to iterate over their member variables?
The attribute types are defined by the constructor, and (indirectly) by the getters. The constructor guarantees type safety on construction, which is important. Storing the values in an array is a mechanism I chose specifically to avoid reflection in the generic relation operators. But yes, you are correct, this could all be done using POCOs and reflection, and I may even go back to doing that.
The key insight is just this one: forget 'structural equivalence', this is about uniqueness. There shall be only one tuple type and one relation type defined for any given heading, where a heading is a set of strings (attribute names). The rest is just coding.
Under structural typing, structural equivalence is uniqueness and vice versa.
Quote from dandl on May 6, 2020, 2:11 amTTM Pre 9 implies structural typing. "A heading H is a set of ordered pairs or attributes of the form <A, T> ..." etc. Nominative typing would be "A heading H is a named set of ordered pairs or attributes of the form <A, T> distinguished from each other by name" or similar.
I don't think so. TTM Pre 9 makes it clear that headings are a set of attributes, so the order of attributes does not matter, and since headings are not a type, they have no name.
Headings are indeed not a type -- they are a component of a type generation -- but that's not why have no name. They have no name because they are structural rather than nominative. The fact that TTM doesn't use these terms doesn't change that fact.
But RM Pre 6 is the one that defines a tuple type, and that says "the name of that type shall be, precisely, TUPLE H." So a tuple type does have a name, and for any given heading H there is only that one tuple type.
So the issue of structural/nominative does not arise, because (a) the tuple type is named but (b) there is only one with that heading.
I thik TD confuses things by not making it clear that tuple types as defined by {X,Y}, {Y,X}, {X,Y,Z ALLBUT Z} and {X,Y,W} JOIN {X,Y,Z} are not 'structurally equivalent', they are all exactly the same unique type.
"Structurally equivalent" and "the same unique type" are synonymous under structural typing.
It's not a big deal; I'm just curious how you've dealt with this oft-mentioned distinction between conventional programming languages like C# and, say, Tutorial D where TUPLE {x INT, y CHAR} is (type-compatible with) TUPLE {y CHAR, x INT}. If tuple type (and similarly relation type) distinction or equivalence is maintained by policy rather than mechanism, then that's reasonable and in the spirit of TTM if not confirming to the letter of TTM Pre 9. I'm sure it could be enforced but probably only at run-time, though it might be do-able at compile-time with Java annotations. I'd have to play with it to see if annotations can be used that way.
The rules for defining a tuple type are easy:
- a tuple type must define a unique heading
- the heading is an array of strings, which enables generic RA machinery
- there may not be two tuple types with the same heading
- inherits from a base type (which ensures it behaves as value (equals() and hashcode()))
- must declare getters, setters and a constructor that match the heading and comply with RM Pre 4,5,6
- must be immutable
public static RelS S = new RelS( new List<TupS> { new TupS( "S1", "Smith", 20, "London" ), new TupS( "S2", "Jones", 10, "Paris" ), new TupS( "S3", "Blake", 30, "Paris" ), new TupS( "S4", "Clark", 20, "London" ), new TupS( "S5", "Adams", 30, "Athens" ), }); Console.WriteLine(S.Select(t => t.Status < 20));Pretty much all of TTM except for RM Pre 18 is already there. I'm still working on that part (as well as codifying some rules).
This looks notionally similar to the Rel internals, though syntactically different and (for example) headings are declared programmatically by adding attributes to a Heading instance, but could certainly be used in a similar manner. I don't know that I would, though -- it's rather clunky.
The code required to declare a tuple type is similar in volume to the declaration of a POCO. The getters and constructor are roughly the same; the heading is an extra bit of code; on the plus side, you don't have to code for Equals() and HashCode() because they get inherited. And like POCOs, they can easily be generated.
The code required to declare a relation type is trivial: just the class name and a typed constructor.
The clunky bit is that you have to declare every type. RA operators generate new types behind the scenes in TD/Rel, but in C# you have to declare every tuple type and every relation type up front. That's definitely something that would benefit from code generation.
There is an interesting problem in TTM, which I completely missed until now. The very prescriptive language in RM Pre 6 talks about 'defining...operators of that type'. Then it talks about 'the applicable operators shall include...'. (The references to 'RENAME,project,etc' are obviously mistakes left over from an earlier iteration, but no matter.)
The problem is "(b) an operator for extracting a specified attribute value from a specified tuple (the tuple in question might be required to be of degree one—see RM Prescription 9". It's hard to see exactly what is intended here, or what will satisfy it, but I don't think as written it's what was intended. I think having getters is enough.
In Tutorial D, that's the FROM operator.
Where do you declare (or infer) your attribute types?
Or is that implicit in the property definitions?
Is the _values array necessary? Wouldn't it be cleaner to just declare properties and use reflection to iterate over their member variables?
The attribute types are defined by the constructor, and (indirectly) by the getters. The constructor guarantees type safety on construction, which is important. Storing the values in an array is a mechanism I chose specifically to avoid reflection in the generic relation operators. But yes, you are correct, this could all be done using POCOs and reflection, and I may even go back to doing that.
The key insight is just this one: forget 'structural equivalence', this is about uniqueness. There shall be only one tuple type and one relation type defined for any given heading, where a heading is a set of strings (attribute names). The rest is just coding.
Under structural typing, structural equivalence is uniqueness and vice versa.
Quote from Dave Voorhis on May 6, 2020, 8:29 amQuote from dandl on May 6, 2020, 12:52 amIt becomes D-like, maybe. I'm afraid I find your descriptions of how you're making C# into a D more baffling with each post. Now it looks to me like you're treating D compliance as a sort of word game, where you achieve D compliance by choosing the right set of words to describe it rather than using programming language constructs to implement it.
Now you've lost me. What is 'D-like'? TTM says:
D: The Manifesto makes repeated reference to a hypothetical language it calls D. However, the name D is
merely a useful generic label; any language that conforms to the principles laid down in the Manifesto is a
valid D (and any language that fails so to conform is not a valid D).I say that the proposal I put forward shows how a GP language can be made to largely conform to the principles laid down. What more would it need to do?
D-like would be meeting some pre/pro-scriptions but not others, but in the spirit of D if not the letter.
So that's a good thing. But I plan to satisfy all the Pre required features for D and its type system natively, within a GP language (currently C#). That's a better thing.
And I expect that it will be possible to meet all the Pre and Pro prohibitions by runtime checks and/or a preprocessor and/or modifying the compiler. That's a fully TTM compliant D.
[Note that the Pre requirements include a few that are really Pro, such as RM Pre 3a and d. They may have to go in the second category.]
I guess I'll have to wait to see the result, because the explanations aren't making sense to me.
As for efforts to create a new language, I see no reason to deprecate them, or to position efforts to turn an existing general-purpose language into a D or a D-like thing either above or below them. They're all equally worthwhile efforts, though like all choices in IT, each approach gains you some things and takes away others. Everything has its trade-offs.
I'm not deprecating, I'm saying that there have been several successful implementations and no-one wants to use them. If there is to be a D that others use, this is a way that might get there.
I get a reasonable number of Rel downloads and some forks on GitHub. I'm happy with what it's achieved, which is better than I expected when I started working on it.
But if you're talking about mass adoption, I think you need to consider what dramatic improvement a D of any kind will make over and above existing alternatives. Otherwise, it will only attract the usual niche audience of experimenters, hobbyists, and database obsessives like ourselves.
To make a market dent a D needs to make a dramatic difference. That's the problem with all the D implementations so far; they're perfectly adequate but none are disruptive. They don't make a big enough difference in day-to-day programming to unseat SQL or (facilities within) popular programming languages.
No, that isn't how it works. People take on new products and services that fill a pressing need or that solve a real problem. If you create the solution first and then go chase the problem you will likely fail. If you first find a real need/problem, then create something that will fill it/solve it, you have at least a chance to get to the next step, which is to figure out how to get people to try it and use it. That's how it works. Startups 101.
Exactly. Solving a real problem that wasn't solved before is a dramatic difference, but what we perceive as "new products and services that fill a pressing need or that solve a real problem" might not be perceived the same way by the typical developer.
I think there is unmet need in performing SQL-like operations on non-SQL data. I am in the phase of experimenting with different possible solutions for that problem, and only that problem. What pressing need or problem are you solving?
I'm not. My interests are scientific, an extended form of "what happens if I try this?"
That's why I created Rel. "What happens if I use a truly relational language?"
In doing so, I found it useful for general-purpose data-crunching, by mapping relvars to external data sources.
Now I want to see what happens if I replace the rather niche Tutorial D language with a general-purpose language like Java, under the hypothesis that the value of such an environment derives not from specifically (or only) having relations and a relational algebra, but from generally having a data abstraction and operators on that abstraction plus an agile environment.
The result of that will hopefully be personally useful, but also suggest interesting new directions to explore.
By way of analogy, people aren't willing to give up their old family Ford when all we're offering is the same car with a different engine that delivers the same fuel economy as the old one, and the grill's a pretty shape.
True. But when they get a family and have to carry kids and bikes and football gear they have a new problem, and they solve that by getting rid of the old sedan and buying an SUV. And when Dad gets a promotion and a fat bonus and needs to show off some status he solves that problem by getting rid of the Ford and buying a BMW or a Mercedes.That's how it works.
Yes, but I'm not convinced we're going from a Ford to a BMW or Mercedes here. I suspect it's more like going from a Toyota Avensis 2.0 to a Lexus IS200. That's significant if you're a Toyota/Lexus fan, but for the rest of the world it's the same car in different trim.
Quote from dandl on May 6, 2020, 12:52 amIt becomes D-like, maybe. I'm afraid I find your descriptions of how you're making C# into a D more baffling with each post. Now it looks to me like you're treating D compliance as a sort of word game, where you achieve D compliance by choosing the right set of words to describe it rather than using programming language constructs to implement it.
Now you've lost me. What is 'D-like'? TTM says:
D: The Manifesto makes repeated reference to a hypothetical language it calls D. However, the name D is
merely a useful generic label; any language that conforms to the principles laid down in the Manifesto is a
valid D (and any language that fails so to conform is not a valid D).I say that the proposal I put forward shows how a GP language can be made to largely conform to the principles laid down. What more would it need to do?
D-like would be meeting some pre/pro-scriptions but not others, but in the spirit of D if not the letter.
So that's a good thing. But I plan to satisfy all the Pre required features for D and its type system natively, within a GP language (currently C#). That's a better thing.
And I expect that it will be possible to meet all the Pre and Pro prohibitions by runtime checks and/or a preprocessor and/or modifying the compiler. That's a fully TTM compliant D.
[Note that the Pre requirements include a few that are really Pro, such as RM Pre 3a and d. They may have to go in the second category.]
I guess I'll have to wait to see the result, because the explanations aren't making sense to me.
As for efforts to create a new language, I see no reason to deprecate them, or to position efforts to turn an existing general-purpose language into a D or a D-like thing either above or below them. They're all equally worthwhile efforts, though like all choices in IT, each approach gains you some things and takes away others. Everything has its trade-offs.
I'm not deprecating, I'm saying that there have been several successful implementations and no-one wants to use them. If there is to be a D that others use, this is a way that might get there.
I get a reasonable number of Rel downloads and some forks on GitHub. I'm happy with what it's achieved, which is better than I expected when I started working on it.
But if you're talking about mass adoption, I think you need to consider what dramatic improvement a D of any kind will make over and above existing alternatives. Otherwise, it will only attract the usual niche audience of experimenters, hobbyists, and database obsessives like ourselves.
To make a market dent a D needs to make a dramatic difference. That's the problem with all the D implementations so far; they're perfectly adequate but none are disruptive. They don't make a big enough difference in day-to-day programming to unseat SQL or (facilities within) popular programming languages.
No, that isn't how it works. People take on new products and services that fill a pressing need or that solve a real problem. If you create the solution first and then go chase the problem you will likely fail. If you first find a real need/problem, then create something that will fill it/solve it, you have at least a chance to get to the next step, which is to figure out how to get people to try it and use it. That's how it works. Startups 101.
Exactly. Solving a real problem that wasn't solved before is a dramatic difference, but what we perceive as "new products and services that fill a pressing need or that solve a real problem" might not be perceived the same way by the typical developer.
I think there is unmet need in performing SQL-like operations on non-SQL data. I am in the phase of experimenting with different possible solutions for that problem, and only that problem. What pressing need or problem are you solving?
I'm not. My interests are scientific, an extended form of "what happens if I try this?"
That's why I created Rel. "What happens if I use a truly relational language?"
In doing so, I found it useful for general-purpose data-crunching, by mapping relvars to external data sources.
Now I want to see what happens if I replace the rather niche Tutorial D language with a general-purpose language like Java, under the hypothesis that the value of such an environment derives not from specifically (or only) having relations and a relational algebra, but from generally having a data abstraction and operators on that abstraction plus an agile environment.
The result of that will hopefully be personally useful, but also suggest interesting new directions to explore.
By way of analogy, people aren't willing to give up their old family Ford when all we're offering is the same car with a different engine that delivers the same fuel economy as the old one, and the grill's a pretty shape.
True. But when they get a family and have to carry kids and bikes and football gear they have a new problem, and they solve that by getting rid of the old sedan and buying an SUV. And when Dad gets a promotion and a fat bonus and needs to show off some status he solves that problem by getting rid of the Ford and buying a BMW or a Mercedes.That's how it works.
Yes, but I'm not convinced we're going from a Ford to a BMW or Mercedes here. I suspect it's more like going from a Toyota Avensis 2.0 to a Lexus IS200. That's significant if you're a Toyota/Lexus fan, but for the rest of the world it's the same car in different trim.
Quote from dandl on May 6, 2020, 8:32 amDoing it in Hugs/Trex from 2006 I've now wrangled my way past the type-wobbliness, then yes; clearly there's a (undocumented) idiom; and it could do with a bit of syntactic sugar -- in case anybody knows someone who's able to compile it from source and can tinker with yacc ...
My build of WinHugs seems to build yacc OK. What's the problem?
I have no idea whatever how to drive WinHugs, so I really can't test any changes I might make.
Doing it in Hugs/Trex from 2006 I've now wrangled my way past the type-wobbliness, then yes; clearly there's a (undocumented) idiom; and it could do with a bit of syntactic sugar -- in case anybody knows someone who's able to compile it from source and can tinker with yacc ...
My build of WinHugs seems to build yacc OK. What's the problem?
I have no idea whatever how to drive WinHugs, so I really can't test any changes I might make.
Quote from dandl on May 6, 2020, 8:44 amI thik TD confuses things by not making it clear that tuple types as defined by {X,Y}, {Y,X}, {X,Y,Z ALLBUT Z} and {X,Y,W} JOIN {X,Y,Z} are not 'structurally equivalent', they are all exactly the same unique type.
"Structurally equivalent" and "the same unique type" are synonymous under structural typing.
Pardon? That's either meaningless or wrong. Or something.
In TTM types are named. If two types have the same name, they're the same type. Otherwise they're not. There is no 'equivalence'.
In TTM a tuple type has the name 'TUPLE H' or equivalent. Two tuple types with the same heading are the same type, period.
In TTM every value belongs to exactly one type, never to 'equivalent' types. Just one.
There is an interesting problem in TTM, which I completely missed until now. The very prescriptive language in RM Pre 6 talks about 'defining...operators of that type'. Then it talks about 'the applicable operators shall include...'. (The references to 'RENAME,project,etc' are obviously mistakes left over from an earlier iteration, but no matter.)
The problem is "(b) an operator for extracting a specified attribute value from a specified tuple (the tuple in question might be required to be of degree one—see RM Prescription 9". It's hard to see exactly what is intended here, or what will satisfy it, but I don't think as written it's what was intended. I think having getters is enough.
In Tutorial D, that's the FROM operator.
I know, and in Andl it's a dot operator, but TD and Andl do not set the requirement. That's TTM's job (give or take the odd mistake). And this requirement is problematic (as written).
I thik TD confuses things by not making it clear that tuple types as defined by {X,Y}, {Y,X}, {X,Y,Z ALLBUT Z} and {X,Y,W} JOIN {X,Y,Z} are not 'structurally equivalent', they are all exactly the same unique type.
"Structurally equivalent" and "the same unique type" are synonymous under structural typing.
Pardon? That's either meaningless or wrong. Or something.
In TTM types are named. If two types have the same name, they're the same type. Otherwise they're not. There is no 'equivalence'.
In TTM a tuple type has the name 'TUPLE H' or equivalent. Two tuple types with the same heading are the same type, period.
In TTM every value belongs to exactly one type, never to 'equivalent' types. Just one.
There is an interesting problem in TTM, which I completely missed until now. The very prescriptive language in RM Pre 6 talks about 'defining...operators of that type'. Then it talks about 'the applicable operators shall include...'. (The references to 'RENAME,project,etc' are obviously mistakes left over from an earlier iteration, but no matter.)
The problem is "(b) an operator for extracting a specified attribute value from a specified tuple (the tuple in question might be required to be of degree one—see RM Prescription 9". It's hard to see exactly what is intended here, or what will satisfy it, but I don't think as written it's what was intended. I think having getters is enough.
In Tutorial D, that's the FROM operator.
I know, and in Andl it's a dot operator, but TD and Andl do not set the requirement. That's TTM's job (give or take the odd mistake). And this requirement is problematic (as written).
Quote from Dave Voorhis on May 6, 2020, 9:11 amQuote from dandl on May 6, 2020, 8:44 amI thik TD confuses things by not making it clear that tuple types as defined by {X,Y}, {Y,X}, {X,Y,Z ALLBUT Z} and {X,Y,W} JOIN {X,Y,Z} are not 'structurally equivalent', they are all exactly the same unique type.
"Structurally equivalent" and "the same unique type" are synonymous under structural typing.
Pardon? That's either meaningless or wrong. Or something.
No, it simply means that "same type" and "same structure" are the same thing.
In TTM types are named. If two types have the same name, they're the same type. Otherwise they're not. There is no 'equivalence'.
It might be more accurate to say that in TTM types are "named".
TUPLE {x INT, y CHAR} and TUPLE {y CHAR, x INT} are the "same name", so to (TTM) speak, but that's because they denote the same structure.
In TTM a tuple type has the name 'TUPLE H' or equivalent. Two tuple types with the same heading are the same type, period.
In TTM every value belongs to exactly one type, never to 'equivalent' types. Just one.
Yes, every value belongs to exactly one type, but two syntactically distinct headings -- which are provably syntactically distinct -- represent the same tuple/relation type or equivalent tuple/relation types. Again, these are synonyms. There is no semantic distinction.
There is an interesting problem in TTM, which I completely missed until now. The very prescriptive language in RM Pre 6 talks about 'defining...operators of that type'. Then it talks about 'the applicable operators shall include...'. (The references to 'RENAME,project,etc' are obviously mistakes left over from an earlier iteration, but no matter.)
The problem is "(b) an operator for extracting a specified attribute value from a specified tuple (the tuple in question might be required to be of degree one—see RM Prescription 9". It's hard to see exactly what is intended here, or what will satisfy it, but I don't think as written it's what was intended. I think having getters is enough.
In Tutorial D, that's the FROM operator.
I know, and in Andl it's a dot operator, but TD and Andl do not set the requirement. That's TTM's job (give or take the odd mistake). And this requirement is problematic (as written).
Ah, you mean the "the tuple in question might be required to be of degree one..."?
I presume "an operator for extracting a specified attribute value from a specified tuple" isn't controversial.
Yes, it looks like some notional equivalence has been drawn between TUPLE FROM only being able to obtain the tuple from a relation of cardinality 1, and FROM obtaining an attribute value from a tuple with degree 1. Rather impractical -- you'd have to project each attribute individually -- but maybe practicality wasn't a consideration here.
Perhaps this is something Hugh can address.
Quote from dandl on May 6, 2020, 8:44 amI thik TD confuses things by not making it clear that tuple types as defined by {X,Y}, {Y,X}, {X,Y,Z ALLBUT Z} and {X,Y,W} JOIN {X,Y,Z} are not 'structurally equivalent', they are all exactly the same unique type.
"Structurally equivalent" and "the same unique type" are synonymous under structural typing.
Pardon? That's either meaningless or wrong. Or something.
No, it simply means that "same type" and "same structure" are the same thing.
In TTM types are named. If two types have the same name, they're the same type. Otherwise they're not. There is no 'equivalence'.
It might be more accurate to say that in TTM types are "named".
TUPLE {x INT, y CHAR} and TUPLE {y CHAR, x INT} are the "same name", so to (TTM) speak, but that's because they denote the same structure.
In TTM a tuple type has the name 'TUPLE H' or equivalent. Two tuple types with the same heading are the same type, period.
In TTM every value belongs to exactly one type, never to 'equivalent' types. Just one.
Yes, every value belongs to exactly one type, but two syntactically distinct headings -- which are provably syntactically distinct -- represent the same tuple/relation type or equivalent tuple/relation types. Again, these are synonyms. There is no semantic distinction.
There is an interesting problem in TTM, which I completely missed until now. The very prescriptive language in RM Pre 6 talks about 'defining...operators of that type'. Then it talks about 'the applicable operators shall include...'. (The references to 'RENAME,project,etc' are obviously mistakes left over from an earlier iteration, but no matter.)
The problem is "(b) an operator for extracting a specified attribute value from a specified tuple (the tuple in question might be required to be of degree one—see RM Prescription 9". It's hard to see exactly what is intended here, or what will satisfy it, but I don't think as written it's what was intended. I think having getters is enough.
In Tutorial D, that's the FROM operator.
I know, and in Andl it's a dot operator, but TD and Andl do not set the requirement. That's TTM's job (give or take the odd mistake). And this requirement is problematic (as written).
Ah, you mean the "the tuple in question might be required to be of degree one..."?
I presume "an operator for extracting a specified attribute value from a specified tuple" isn't controversial.
Yes, it looks like some notional equivalence has been drawn between TUPLE FROM only being able to obtain the tuple from a relation of cardinality 1, and FROM obtaining an attribute value from a tuple with degree 1. Rather impractical -- you'd have to project each attribute individually -- but maybe practicality wasn't a consideration here.
Perhaps this is something Hugh can address.
Quote from dandl on May 6, 2020, 11:04 amQuote from Dave Voorhis on May 6, 2020, 9:11 amQuote from dandl on May 6, 2020, 8:44 amI thik TD confuses things by not making it clear that tuple types as defined by {X,Y}, {Y,X}, {X,Y,Z ALLBUT Z} and {X,Y,W} JOIN {X,Y,Z} are not 'structurally equivalent', they are all exactly the same unique type.
"Structurally equivalent" and "the same unique type" are synonymous under structural typing.
Pardon? That's either meaningless or wrong. Or something.
No, it simply means that "same type" and "same structure" are the same thing.
They're not. Structural equivalence means two separate types with different names but the same structure can be used interchangeably: a value of one type can be assigned to the other, either can be compared with the other, either can be passed as a parameter, etc. Module-3 has named types and structural equivalence between them. Name equivalence means that is possible for two type with different names to be defined to be the same type (an alias). C/C++ have that. Most languages including Java, C# and TTM/D have no type equivalence, every type is unique by name.
In TTM types are named. If two types have the same name, they're the same type. Otherwise they're not. There is no 'equivalence'.
It might be more accurate to say that in TTM types are "named".
TUPLE {x INT, y CHAR} and TUPLE {y CHAR, x INT} are the "same name", so to (TTM) speak, but that's because they denote the same structure.
No, that's a TD quirk. Those types are syntactically distinguishable, but they have the same name and they are the same type.
In TTM a tuple type has the name 'TUPLE H' or equivalent. Two tuple types with the same heading are the same type, period.
In TTM every value belongs to exactly one type, never to 'equivalent' types. Just one.
Yes, every value belongs to exactly one type, but two syntactically distinct headings -- which are provably syntactically distinct -- represent the same tuple/relation type or equivalent tuple/relation types. Again, these are synonyms. There is no semantic distinction.
They don't 'represent'. Those two syntactic forms define the same type by the same name. There is no type equivalence, because there are no separate types to be equivalent. Each tuple type is unique by heading.
There is an interesting problem in TTM, which I completely missed until now. The very prescriptive language in RM Pre 6 talks about 'defining...operators of that type'. Then it talks about 'the applicable operators shall include...'. (The references to 'RENAME,project,etc' are obviously mistakes left over from an earlier iteration, but no matter.)
The problem is "(b) an operator for extracting a specified attribute value from a specified tuple (the tuple in question might be required to be of degree one—see RM Prescription 9". It's hard to see exactly what is intended here, or what will satisfy it, but I don't think as written it's what was intended. I think having getters is enough.
In Tutorial D, that's the FROM operator.
I know, and in Andl it's a dot operator, but TD and Andl do not set the requirement. That's TTM's job (give or take the odd mistake). And this requirement is problematic (as written).
Ah, you mean the "the tuple in question might be required to be of degree one..."?
I presume "an operator for extracting a specified attribute value from a specified tuple" isn't controversial.
It's still somewhat problematic. The form of words implies that (a) there is to be only one such operator for each tuple type and (b) it should take an argument to 'specify' which attribute value is required. The wording for retrieving a component of a scalar component is better in this respect. I fail to see why TD has such disparate forms for these two relatively similar kinds of operators, but AFAICT something akin to idiomatic 'getters' in the target language will do just fine.
Yes, it looks like some notional equivalence has been drawn between TUPLE FROM only being able to obtain the tuple from a relation of cardinality 1, and FROM obtaining an attribute value from a tuple with degree 1. Rather impractical -- you'd have to project each attribute individually -- but maybe practicality wasn't a consideration here.
Perhaps this is something Hugh can address.
Agreed.
Quote from Dave Voorhis on May 6, 2020, 9:11 amQuote from dandl on May 6, 2020, 8:44 amI thik TD confuses things by not making it clear that tuple types as defined by {X,Y}, {Y,X}, {X,Y,Z ALLBUT Z} and {X,Y,W} JOIN {X,Y,Z} are not 'structurally equivalent', they are all exactly the same unique type.
"Structurally equivalent" and "the same unique type" are synonymous under structural typing.
Pardon? That's either meaningless or wrong. Or something.
No, it simply means that "same type" and "same structure" are the same thing.
They're not. Structural equivalence means two separate types with different names but the same structure can be used interchangeably: a value of one type can be assigned to the other, either can be compared with the other, either can be passed as a parameter, etc. Module-3 has named types and structural equivalence between them. Name equivalence means that is possible for two type with different names to be defined to be the same type (an alias). C/C++ have that. Most languages including Java, C# and TTM/D have no type equivalence, every type is unique by name.
In TTM types are named. If two types have the same name, they're the same type. Otherwise they're not. There is no 'equivalence'.
It might be more accurate to say that in TTM types are "named".
TUPLE {x INT, y CHAR} and TUPLE {y CHAR, x INT} are the "same name", so to (TTM) speak, but that's because they denote the same structure.
No, that's a TD quirk. Those types are syntactically distinguishable, but they have the same name and they are the same type.
In TTM a tuple type has the name 'TUPLE H' or equivalent. Two tuple types with the same heading are the same type, period.
In TTM every value belongs to exactly one type, never to 'equivalent' types. Just one.
Yes, every value belongs to exactly one type, but two syntactically distinct headings -- which are provably syntactically distinct -- represent the same tuple/relation type or equivalent tuple/relation types. Again, these are synonyms. There is no semantic distinction.
They don't 'represent'. Those two syntactic forms define the same type by the same name. There is no type equivalence, because there are no separate types to be equivalent. Each tuple type is unique by heading.
There is an interesting problem in TTM, which I completely missed until now. The very prescriptive language in RM Pre 6 talks about 'defining...operators of that type'. Then it talks about 'the applicable operators shall include...'. (The references to 'RENAME,project,etc' are obviously mistakes left over from an earlier iteration, but no matter.)
The problem is "(b) an operator for extracting a specified attribute value from a specified tuple (the tuple in question might be required to be of degree one—see RM Prescription 9". It's hard to see exactly what is intended here, or what will satisfy it, but I don't think as written it's what was intended. I think having getters is enough.
In Tutorial D, that's the FROM operator.
I know, and in Andl it's a dot operator, but TD and Andl do not set the requirement. That's TTM's job (give or take the odd mistake). And this requirement is problematic (as written).
Ah, you mean the "the tuple in question might be required to be of degree one..."?
I presume "an operator for extracting a specified attribute value from a specified tuple" isn't controversial.
It's still somewhat problematic. The form of words implies that (a) there is to be only one such operator for each tuple type and (b) it should take an argument to 'specify' which attribute value is required. The wording for retrieving a component of a scalar component is better in this respect. I fail to see why TD has such disparate forms for these two relatively similar kinds of operators, but AFAICT something akin to idiomatic 'getters' in the target language will do just fine.
Yes, it looks like some notional equivalence has been drawn between TUPLE FROM only being able to obtain the tuple from a relation of cardinality 1, and FROM obtaining an attribute value from a tuple with degree 1. Rather impractical -- you'd have to project each attribute individually -- but maybe practicality wasn't a consideration here.
Perhaps this is something Hugh can address.
Agreed.
Quote from Dave Voorhis on May 6, 2020, 1:10 pmQuote from dandl on May 6, 2020, 11:04 amQuote from Dave Voorhis on May 6, 2020, 9:11 amQuote from dandl on May 6, 2020, 8:44 amI thik TD confuses things by not making it clear that tuple types as defined by {X,Y}, {Y,X}, {X,Y,Z ALLBUT Z} and {X,Y,W} JOIN {X,Y,Z} are not 'structurally equivalent', they are all exactly the same unique type.
"Structurally equivalent" and "the same unique type" are synonymous under structural typing.
Pardon? That's either meaningless or wrong. Or something.
No, it simply means that "same type" and "same structure" are the same thing.
They're not. Structural equivalence means two separate types with different names but the same structure can be used interchangeably: a value of one type can be assigned to the other, either can be compared with the other, either can be passed as a parameter, etc. Module-3 has named types and structural equivalence between them. Name equivalence means that is possible for two type with different names to be defined to be the same type (an alias). C/C++ have that. Most languages including Java, C# and TTM/D have no type equivalence, every type is unique by name.
Structural typing simply means type-compatibility is determined by structure rather than by name. Tutorial D tuple/relation type-compatibility is determined structurally. Java and C# are nominative typing; different type names mean different types even if the structure is the same.
In TTM types are named. If two types have the same name, they're the same type. Otherwise they're not. There is no 'equivalence'.
It might be more accurate to say that in TTM types are "named".
TUPLE {x INT, y CHAR} and TUPLE {y CHAR, x INT} are the "same name", so to (TTM) speak, but that's because they denote the same structure.
No, that's a TD quirk. Those types are syntactically distinguishable, but they have the same name and they are the same type.
They might have the "same name", but that's a quirk of TTM and associated writings, reflective of their time. "Same type" and "same structure" are synonymous under structural typing.
In TTM a tuple type has the name 'TUPLE H' or equivalent. Two tuple types with the same heading are the same type, period.
In TTM every value belongs to exactly one type, never to 'equivalent' types. Just one.
Yes, every value belongs to exactly one type, but two syntactically distinct headings -- which are provably syntactically distinct -- represent the same tuple/relation type or equivalent tuple/relation types. Again, these are synonyms. There is no semantic distinction.
They don't 'represent'. Those two syntactic forms define the same type by the same name. There is no type equivalence, because there are no separate types to be equivalent. Each tuple type is unique by heading.
No, the same heading applied to two different tuples means they have the same type.
There is an interesting problem in TTM, which I completely missed until now. The very prescriptive language in RM Pre 6 talks about 'defining...operators of that type'. Then it talks about 'the applicable operators shall include...'. (The references to 'RENAME,project,etc' are obviously mistakes left over from an earlier iteration, but no matter.)
The problem is "(b) an operator for extracting a specified attribute value from a specified tuple (the tuple in question might be required to be of degree one—see RM Prescription 9". It's hard to see exactly what is intended here, or what will satisfy it, but I don't think as written it's what was intended. I think having getters is enough.
In Tutorial D, that's the FROM operator.
I know, and in Andl it's a dot operator, but TD and Andl do not set the requirement. That's TTM's job (give or take the odd mistake). And this requirement is problematic (as written).
Ah, you mean the "the tuple in question might be required to be of degree one..."?
I presume "an operator for extracting a specified attribute value from a specified tuple" isn't controversial.
It's still somewhat problematic. The form of words implies that (a) there is to be only one such operator for each tuple type and (b) it should take an argument to 'specify' which attribute value is required. The wording for retrieving a component of a scalar component is better in this respect. I fail to see why TD has such disparate forms for these two relatively similar kinds of operators, but AFAICT something akin to idiomatic 'getters' in the target language will do just fine.
Sure you're not reading more into it than what appears to have been intended?
The requirement seems simple and straightforward: you need a mechanism to retrieve an attribute value from a tuple. Somehow.
Quote from dandl on May 6, 2020, 11:04 amQuote from Dave Voorhis on May 6, 2020, 9:11 amQuote from dandl on May 6, 2020, 8:44 amI thik TD confuses things by not making it clear that tuple types as defined by {X,Y}, {Y,X}, {X,Y,Z ALLBUT Z} and {X,Y,W} JOIN {X,Y,Z} are not 'structurally equivalent', they are all exactly the same unique type.
"Structurally equivalent" and "the same unique type" are synonymous under structural typing.
Pardon? That's either meaningless or wrong. Or something.
No, it simply means that "same type" and "same structure" are the same thing.
They're not. Structural equivalence means two separate types with different names but the same structure can be used interchangeably: a value of one type can be assigned to the other, either can be compared with the other, either can be passed as a parameter, etc. Module-3 has named types and structural equivalence between them. Name equivalence means that is possible for two type with different names to be defined to be the same type (an alias). C/C++ have that. Most languages including Java, C# and TTM/D have no type equivalence, every type is unique by name.
Structural typing simply means type-compatibility is determined by structure rather than by name. Tutorial D tuple/relation type-compatibility is determined structurally. Java and C# are nominative typing; different type names mean different types even if the structure is the same.
In TTM types are named. If two types have the same name, they're the same type. Otherwise they're not. There is no 'equivalence'.
It might be more accurate to say that in TTM types are "named".
TUPLE {x INT, y CHAR} and TUPLE {y CHAR, x INT} are the "same name", so to (TTM) speak, but that's because they denote the same structure.
No, that's a TD quirk. Those types are syntactically distinguishable, but they have the same name and they are the same type.
They might have the "same name", but that's a quirk of TTM and associated writings, reflective of their time. "Same type" and "same structure" are synonymous under structural typing.
In TTM a tuple type has the name 'TUPLE H' or equivalent. Two tuple types with the same heading are the same type, period.
In TTM every value belongs to exactly one type, never to 'equivalent' types. Just one.
Yes, every value belongs to exactly one type, but two syntactically distinct headings -- which are provably syntactically distinct -- represent the same tuple/relation type or equivalent tuple/relation types. Again, these are synonyms. There is no semantic distinction.
They don't 'represent'. Those two syntactic forms define the same type by the same name. There is no type equivalence, because there are no separate types to be equivalent. Each tuple type is unique by heading.
No, the same heading applied to two different tuples means they have the same type.
There is an interesting problem in TTM, which I completely missed until now. The very prescriptive language in RM Pre 6 talks about 'defining...operators of that type'. Then it talks about 'the applicable operators shall include...'. (The references to 'RENAME,project,etc' are obviously mistakes left over from an earlier iteration, but no matter.)
The problem is "(b) an operator for extracting a specified attribute value from a specified tuple (the tuple in question might be required to be of degree one—see RM Prescription 9". It's hard to see exactly what is intended here, or what will satisfy it, but I don't think as written it's what was intended. I think having getters is enough.
In Tutorial D, that's the FROM operator.
I know, and in Andl it's a dot operator, but TD and Andl do not set the requirement. That's TTM's job (give or take the odd mistake). And this requirement is problematic (as written).
Ah, you mean the "the tuple in question might be required to be of degree one..."?
I presume "an operator for extracting a specified attribute value from a specified tuple" isn't controversial.
It's still somewhat problematic. The form of words implies that (a) there is to be only one such operator for each tuple type and (b) it should take an argument to 'specify' which attribute value is required. The wording for retrieving a component of a scalar component is better in this respect. I fail to see why TD has such disparate forms for these two relatively similar kinds of operators, but AFAICT something akin to idiomatic 'getters' in the target language will do just fine.
Sure you're not reading more into it than what appears to have been intended?
The requirement seems simple and straightforward: you need a mechanism to retrieve an attribute value from a tuple. Somehow.
Quote from dandl on May 7, 2020, 1:13 amQuote from Dave Voorhis on May 6, 2020, 1:10 pmQuote from dandl on May 6, 2020, 11:04 amQuote from Dave Voorhis on May 6, 2020, 9:11 amQuote from dandl on May 6, 2020, 8:44 amI thik TD confuses things by not making it clear that tuple types as defined by {X,Y}, {Y,X}, {X,Y,Z ALLBUT Z} and {X,Y,W} JOIN {X,Y,Z} are not 'structurally equivalent', they are all exactly the same unique type.
"Structurally equivalent" and "the same unique type" are synonymous under structural typing.
Pardon? That's either meaningless or wrong. Or something.
No, it simply means that "same type" and "same structure" are the same thing.
They're not. Structural equivalence means two separate types with different names but the same structure can be used interchangeably: a value of one type can be assigned to the other, either can be compared with the other, either can be passed as a parameter, etc. Module-3 has named types and structural equivalence between them. Name equivalence means that is possible for two type with different names to be defined to be the same type (an alias). C/C++ have that. Most languages including Java, C# and TTM/D have no type equivalence, every type is unique by name.
Structural typing simply means type-compatibility is determined by structure rather than by name.
Agreed. As per Module-3, two different types are interchangeable if they have the same structure. Note: different types, same structure, always substitutable.
Tutorial D tuple/relation type-compatibility is determined structurally.
No, in TD two declared types are the same type if they have the same heading. Note: different declarations, same type (so nothing to substitute).
Java and C# are nominative typing; different type names mean different types even if the structure is the same.
Agreed. Two different types are interchangeable under the limited rules of assignment, covariance and contra-variance. Note: different types, limited substitutability based on inheritance, not on structure.
I'm surprised you find this so hard to understand. Perhaps it's the odd wording in TTM.
Yes, every value belongs to exactly one type, but two syntactically distinct headings -- which are provably syntactically distinct -- represent the same tuple/relation type or equivalent tuple/relation types. Again, these are synonyms. There is no semantic distinction.
They don't 'represent'. Those two syntactic forms define the same type by the same name. There is no type equivalence, because there are no separate types to be equivalent. Each tuple type is unique by heading.
No, the same heading applied to two different tuples means they have the same type.
Correct! The very same type.
There is an interesting problem in TTM, which I completely missed until now. The very prescriptive language in RM Pre 6 talks about 'defining...operators of that type'. Then it talks about 'the applicable operators shall include...'. (The references to 'RENAME,project,etc' are obviously mistakes left over from an earlier iteration, but no matter.)
The problem is "(b) an operator for extracting a specified attribute value from a specified tuple (the tuple in question might be required to be of degree one—see RM Prescription 9". It's hard to see exactly what is intended here, or what will satisfy it, but I don't think as written it's what was intended. I think having getters is enough.
In Tutorial D, that's the FROM operator.
I know, and in Andl it's a dot operator, but TD and Andl do not set the requirement. That's TTM's job (give or take the odd mistake). And this requirement is problematic (as written).
Ah, you mean the "the tuple in question might be required to be of degree one..."?
I presume "an operator for extracting a specified attribute value from a specified tuple" isn't controversial.
It's still somewhat problematic. The form of words implies that (a) there is to be only one such operator for each tuple type and (b) it should take an argument to 'specify' which attribute value is required. The wording for retrieving a component of a scalar component is better in this respect. I fail to see why TD has such disparate forms for these two relatively similar kinds of operators, but AFAICT something akin to idiomatic 'getters' in the target language will do just fine.
Sure you're not reading more into it than what appears to have been intended?
The requirement seems simple and straightforward: you need a mechanism to retrieve an attribute value from a tuple. Somehow.
That isn't what it says. The form of words in RM Pre 5a is clear. The form in RM Pre 6 is very different, and in my view wrong. We both know what it ought to say, but it doesn't say that.
BTW I am abandoning my claim that started this thread. A TTM tuple type can be a record, providing (a) it declares a heading (b) that heading is unique. I still believe that in most cases the implementation will be simpler if it uses an internal structure that can be addressed positionally, but this is not a requirement.
Quote from Dave Voorhis on May 6, 2020, 1:10 pmQuote from dandl on May 6, 2020, 11:04 amQuote from Dave Voorhis on May 6, 2020, 9:11 amQuote from dandl on May 6, 2020, 8:44 amI thik TD confuses things by not making it clear that tuple types as defined by {X,Y}, {Y,X}, {X,Y,Z ALLBUT Z} and {X,Y,W} JOIN {X,Y,Z} are not 'structurally equivalent', they are all exactly the same unique type.
"Structurally equivalent" and "the same unique type" are synonymous under structural typing.
Pardon? That's either meaningless or wrong. Or something.
No, it simply means that "same type" and "same structure" are the same thing.
They're not. Structural equivalence means two separate types with different names but the same structure can be used interchangeably: a value of one type can be assigned to the other, either can be compared with the other, either can be passed as a parameter, etc. Module-3 has named types and structural equivalence between them. Name equivalence means that is possible for two type with different names to be defined to be the same type (an alias). C/C++ have that. Most languages including Java, C# and TTM/D have no type equivalence, every type is unique by name.
Structural typing simply means type-compatibility is determined by structure rather than by name.
Agreed. As per Module-3, two different types are interchangeable if they have the same structure. Note: different types, same structure, always substitutable.
Tutorial D tuple/relation type-compatibility is determined structurally.
No, in TD two declared types are the same type if they have the same heading. Note: different declarations, same type (so nothing to substitute).
Java and C# are nominative typing; different type names mean different types even if the structure is the same.
Agreed. Two different types are interchangeable under the limited rules of assignment, covariance and contra-variance. Note: different types, limited substitutability based on inheritance, not on structure.
I'm surprised you find this so hard to understand. Perhaps it's the odd wording in TTM.
Yes, every value belongs to exactly one type, but two syntactically distinct headings -- which are provably syntactically distinct -- represent the same tuple/relation type or equivalent tuple/relation types. Again, these are synonyms. There is no semantic distinction.
They don't 'represent'. Those two syntactic forms define the same type by the same name. There is no type equivalence, because there are no separate types to be equivalent. Each tuple type is unique by heading.
No, the same heading applied to two different tuples means they have the same type.
Correct! The very same type.
There is an interesting problem in TTM, which I completely missed until now. The very prescriptive language in RM Pre 6 talks about 'defining...operators of that type'. Then it talks about 'the applicable operators shall include...'. (The references to 'RENAME,project,etc' are obviously mistakes left over from an earlier iteration, but no matter.)
The problem is "(b) an operator for extracting a specified attribute value from a specified tuple (the tuple in question might be required to be of degree one—see RM Prescription 9". It's hard to see exactly what is intended here, or what will satisfy it, but I don't think as written it's what was intended. I think having getters is enough.
In Tutorial D, that's the FROM operator.
I know, and in Andl it's a dot operator, but TD and Andl do not set the requirement. That's TTM's job (give or take the odd mistake). And this requirement is problematic (as written).
Ah, you mean the "the tuple in question might be required to be of degree one..."?
I presume "an operator for extracting a specified attribute value from a specified tuple" isn't controversial.
It's still somewhat problematic. The form of words implies that (a) there is to be only one such operator for each tuple type and (b) it should take an argument to 'specify' which attribute value is required. The wording for retrieving a component of a scalar component is better in this respect. I fail to see why TD has such disparate forms for these two relatively similar kinds of operators, but AFAICT something akin to idiomatic 'getters' in the target language will do just fine.
Sure you're not reading more into it than what appears to have been intended?
The requirement seems simple and straightforward: you need a mechanism to retrieve an attribute value from a tuple. Somehow.
That isn't what it says. The form of words in RM Pre 5a is clear. The form in RM Pre 6 is very different, and in my view wrong. We both know what it ought to say, but it doesn't say that.
BTW I am abandoning my claim that started this thread. A TTM tuple type can be a record, providing (a) it declares a heading (b) that heading is unique. I still believe that in most cases the implementation will be simpler if it uses an internal structure that can be addressed positionally, but this is not a requirement.