TTM's IM: a 'solution' to a question nobody asked; then how else to express squares are rectangles?
Quote from AntC on October 25, 2019, 5:52 amThis is part 1 of a 2-part post covering the two parts of the title. The second part is a response to Dave's request for elaboration of my sketch for a 'domain'-based type system. I wanted first to motivate why I see TTM's IM as having missed the point about squares/rectangles/etc.
To clear something out of the way first: the IM does provide a way to implement tagged unions within TTM. Tagged unions are a useful feature of a type system. (Dave has demonstrated them for temperature readings, to capture the °F vs °C calibration of the device, or whether the reading was problematic.) Most modern type systems support tagged unions; you don't need the IM to express them; and indeed expressing them via the IM is somewhat disergonomic. So I say a type system (incl for data recorded in relations) should support tagged unions directly.
I've always felt that trying to counter TTM's IM point-by-point is somehow missing the mark. There's some assumptions D&D made behind/before the IM; and it's those I disagree with. Except they're unstated and hard to pin down. So I'm going to riff on writings I can find that best exposes them; I couldn't say exactly 'expresses' them. The quotes are from TIRT Chapter 1 second page [numbered 4].
First blunder: "INHERITANCE ARISES NATURALLY"
[The title of the section I'm quoting from.]
Consider taxonomies of the natural world. The Linnaean hierarchy has classes Mammals, Amphibians, Birds, ... Is there something "natural" about that? No: more modern approaches classify by 'clades' in terms of evolutionary ancestry. There are other "natural" bases for classification such as limbed vs finned vs winged (and subdividing by number of limbs/legs, which cuts across Linnaeus's classes).
The only thing "natural" here is human propensity to divide up the world. Then classifying squares as a type of rectangle is a deliberate choice, there could be other equally valid/equally "natural" classifications. Classifying squares as a type of regular polygon, for example.
Second blunder: confusing an entity with its representation in the database/data structure
"since every square is in fact a rectangle, it surely makes sense to say that type SQUARE is a subtype of type RECTANGLE."
Neither that "in fact" nor "surely" nor "makes sense" is an appeal to logic: it's pure bluster. Accepting that every square is a rectangle provides no evidence that every data structure representing a SQUARE has any necessary relationship to data structures representing a RECTANGLE. For example if we represent squares using a data structure that says they're 4-sided regular polygons, there's no clear way in which that data type is a 'sub-' representation for rectangles-in-general.
let T and T′ be RECTANGLE (the set of all rectangles) and SQUARE (the set of all squares), respectively.
Nope:
RECTANGLE
might be the set of all representations of rectangles; it's not the set of rectangles.Third blunder: each abstraction has exactly one representation in the database/data structure
We might have a variety of entities represented in the database. For definiteness, say we're representing office furniture for a floorplan. Those entities (desks, tables, cupboards, ...) exhibit a 'footprint' which might be rectangular or square. That doesn't mean all the representations have a component shape of type
RECTANGLE
of which a subset we want to identify asSQUARE
. Data modelling just isn't as straitjacketed as that. There might be several representations from which we can abstract rectangularity or squareness.What we do want to say is: any data structure that represents rectangularity (of footprint) must have such-and-such characteristics; any data structure that represents squareness (of footprint) must have those characteristics plus some. In which "have ... characteristics" we can implement as: supports an API (methods) for obtaining length, width, ....
Fourth blunder: 'subtype' means subset type; and subset is an applicable classification
it seems intuitively obvious and reasonable to say that “subtypes are subsets.”
(More bluster in the "intuitively obvious", "reasonable".) Words mean what they're commonly used/agreed to mean. Yes the IT industry is notorious for inventing jargon whose meaning is neither intuitive nor obvious nor reasonable; get over it. 'Subtype' was already in use before the IM was published; it carried and continues to carry a variety of meanings; the 'sub-' in it is only vaguely related to the 'sub-' in 'subset' (quality dictionaries have upwards of half a dozen senses for that prefix).
If the data structure for representing
SQUARE
has a single component side where that forRECTANGLE
has two for width, height, the set of values withinSQUARE
is not just not a subset of those withinRECTANGLE
, it's not even comparable.Conclusion
I can sorta agree, but I'm going to emend the wording of "The point is this:"
Any operation that can be applied to values of type RECTANGLE can be applied to values of type SQUARE as well (because squares are rectangles).
Any operation supported by the API for rectangularity must also be supported by the API for squareness.
Any operation? Actually no: an operation that modifies the width but not the length/height can't be supported by the API for squareness. (Just as: although the Integers are a subset of the Rationals, not every operation for Rationals can be supported for Integers: division, for example.)
Thus, we can say that operators that apply to values of type T are inherited by values of type T′.
No. As if anything in software happens automatically: inheriting is a matter of declarations/definitions/implementations (operator overloading in this case). We (the programmer) can insist/declare that if this operator applies for values of type
T
, that operator must also apply. For example anyT
for which comparison operators<, >
apply, equality comparison=
must apply. AnyT
for which squareness operators apply, rectangularity operators must apply. I talked about a single type there; what's inherited are properties/methods.
This is part 1 of a 2-part post covering the two parts of the title. The second part is a response to Dave's request for elaboration of my sketch for a 'domain'-based type system. I wanted first to motivate why I see TTM's IM as having missed the point about squares/rectangles/etc.
To clear something out of the way first: the IM does provide a way to implement tagged unions within TTM. Tagged unions are a useful feature of a type system. (Dave has demonstrated them for temperature readings, to capture the °F vs °C calibration of the device, or whether the reading was problematic.) Most modern type systems support tagged unions; you don't need the IM to express them; and indeed expressing them via the IM is somewhat disergonomic. So I say a type system (incl for data recorded in relations) should support tagged unions directly.
I've always felt that trying to counter TTM's IM point-by-point is somehow missing the mark. There's some assumptions D&D made behind/before the IM; and it's those I disagree with. Except they're unstated and hard to pin down. So I'm going to riff on writings I can find that best exposes them; I couldn't say exactly 'expresses' them. The quotes are from TIRT Chapter 1 second page [numbered 4].
First blunder: "INHERITANCE ARISES NATURALLY"
[The title of the section I'm quoting from.]
Consider taxonomies of the natural world. The Linnaean hierarchy has classes Mammals, Amphibians, Birds, ... Is there something "natural" about that? No: more modern approaches classify by 'clades' in terms of evolutionary ancestry. There are other "natural" bases for classification such as limbed vs finned vs winged (and subdividing by number of limbs/legs, which cuts across Linnaeus's classes).
The only thing "natural" here is human propensity to divide up the world. Then classifying squares as a type of rectangle is a deliberate choice, there could be other equally valid/equally "natural" classifications. Classifying squares as a type of regular polygon, for example.
Second blunder: confusing an entity with its representation in the database/data structure
"since every square is in fact a rectangle, it surely makes sense to say that type SQUARE is a subtype of type RECTANGLE."
Neither that "in fact" nor "surely" nor "makes sense" is an appeal to logic: it's pure bluster. Accepting that every square is a rectangle provides no evidence that every data structure representing a SQUARE has any necessary relationship to data structures representing a RECTANGLE. For example if we represent squares using a data structure that says they're 4-sided regular polygons, there's no clear way in which that data type is a 'sub-' representation for rectangles-in-general.
let T and T′ be RECTANGLE (the set of all rectangles) and SQUARE (the set of all squares), respectively.
Nope: RECTANGLE
might be the set of all representations of rectangles; it's not the set of rectangles.
Third blunder: each abstraction has exactly one representation in the database/data structure
We might have a variety of entities represented in the database. For definiteness, say we're representing office furniture for a floorplan. Those entities (desks, tables, cupboards, ...) exhibit a 'footprint' which might be rectangular or square. That doesn't mean all the representations have a component shape of type RECTANGLE
of which a subset we want to identify as SQUARE
. Data modelling just isn't as straitjacketed as that. There might be several representations from which we can abstract rectangularity or squareness.
What we do want to say is: any data structure that represents rectangularity (of footprint) must have such-and-such characteristics; any data structure that represents squareness (of footprint) must have those characteristics plus some. In which "have ... characteristics" we can implement as: supports an API (methods) for obtaining length, width, ....
Fourth blunder: 'subtype' means subset type; and subset is an applicable classification
it seems intuitively obvious and reasonable to say that “subtypes are subsets.”
(More bluster in the "intuitively obvious", "reasonable".) Words mean what they're commonly used/agreed to mean. Yes the IT industry is notorious for inventing jargon whose meaning is neither intuitive nor obvious nor reasonable; get over it. 'Subtype' was already in use before the IM was published; it carried and continues to carry a variety of meanings; the 'sub-' in it is only vaguely related to the 'sub-' in 'subset' (quality dictionaries have upwards of half a dozen senses for that prefix).
If the data structure for representing SQUARE
has a single component side where that for RECTANGLE
has two for width, height, the set of values within SQUARE
is not just not a subset of those within RECTANGLE
, it's not even comparable.
Conclusion
I can sorta agree, but I'm going to emend the wording of "The point is this:"
Any operation that can be applied to values of type RECTANGLE can be applied to values of type SQUARE as well (because squares are rectangles).
Any operation supported by the API for rectangularity must also be supported by the API for squareness.
Any operation? Actually no: an operation that modifies the width but not the length/height can't be supported by the API for squareness. (Just as: although the Integers are a subset of the Rationals, not every operation for Rationals can be supported for Integers: division, for example.)
Thus, we can say that operators that apply to values of type T are inherited by values of type T′.
No. As if anything in software happens automatically: inheriting is a matter of declarations/definitions/implementations (operator overloading in this case). We (the programmer) can insist/declare that if this operator applies for values of type T
, that operator must also apply. For example any T
for which comparison operators <, >
apply, equality comparison =
must apply. Any T
for which squareness operators apply, rectangularity operators must apply. I talked about a single type there; what's inherited are properties/methods.
Quote from Erwin on October 25, 2019, 10:36 amThere's actually piles and lots of irony to be found here imo.
Blunder 1 : TTM inheritance being of the multiple kind, it does not prohibit squares to be regarded as "regular polygons" ***as well as*** rectangles (as well as rhombuses etc etc). (Preferring "regarded as" to "representation" for reasons to follow.) I can agree that having to opt for a particular taxonomy is problematic, but that is only so in single inheritance, which is the kind TTM IM even ***mandates*** to avoid. So maybe you could explain how this remark of yours can constitute a valid criticism of TTM IM.
Blunder 2 : "Accepting that every square is a rectangle provides no evidence that every data structure representing a SQUARE has any necessary relationship to data structures representing a RECTANGLE." But that is almost exactly the point TTM IM is making !!! By definition, if a SQUARE is regarded as being (/defined to be) all of RECTANGLE, RHOMBUS, REG_POLY, then it will "inherit" all defined "structure representations" (= possreps) from all three. (e.g. height/width from RECTANGLE, long_diag/short_diag from RHOMBUS, side_len/sice_count from REG_POLY. And any possreps defined for itself (just side_len) will indeed not necessarily have any obvious relationship with the inherited ones (except perhaps possibly through the type constraint, e.g. "side_count = 4").
Blunder 3 : While multiple possreps have been bashed for ages on this forum by some subset of participants (don't know if that includes you), you are now seemingly arguing that the IM assumes single possrep and that that is a "blunder". "What we do want to say is" ... exactly what the possreps already allow us to say !!! imho.
Blunder 4 : That the "data structures" (the possreps) per se are not necessarily type-compatible ("comparable") does not imply that the ***values*** (the abstractions themselves) aren't (/cannot be) either. In fact, making it so that they are is the whole point of the entire IM !!! imho.
Conclusion : "Any operation? Actually no: an operation that modifies ..." But at least DTATRM spends a whole separate section "update operator inheritance" to point this very thing out !!!
And in case you are now on the verge of starting a vitriol-laden rant, I'll add that I fully agree with that final observation "No. As if anything in software happens automatically: inheriting is a matter of declarations/definitions/implementations (operator overloading in this case).", and that I see actually using the IM in the intended way (i.e. ***doing*** those declarations/definitions/implementations - and also the impact analyses when doing maintenance/modifications) as "probably problematic" in that ***setting up*** type hierarchies is probably going to turn out still way more labour-intensive than anyone finds acceptable. (I also think the argument about "having to compute MST all the time" is flawed, but never have been able to show where&how, so I also think the "leads to bad performance of necessity" pundits might have a valid point even if they can't prove it.)
There's actually piles and lots of irony to be found here imo.
Blunder 1 : TTM inheritance being of the multiple kind, it does not prohibit squares to be regarded as "regular polygons" ***as well as*** rectangles (as well as rhombuses etc etc). (Preferring "regarded as" to "representation" for reasons to follow.) I can agree that having to opt for a particular taxonomy is problematic, but that is only so in single inheritance, which is the kind TTM IM even ***mandates*** to avoid. So maybe you could explain how this remark of yours can constitute a valid criticism of TTM IM.
Blunder 2 : "Accepting that every square is a rectangle provides no evidence that every data structure representing a SQUARE has any necessary relationship to data structures representing a RECTANGLE." But that is almost exactly the point TTM IM is making !!! By definition, if a SQUARE is regarded as being (/defined to be) all of RECTANGLE, RHOMBUS, REG_POLY, then it will "inherit" all defined "structure representations" (= possreps) from all three. (e.g. height/width from RECTANGLE, long_diag/short_diag from RHOMBUS, side_len/sice_count from REG_POLY. And any possreps defined for itself (just side_len) will indeed not necessarily have any obvious relationship with the inherited ones (except perhaps possibly through the type constraint, e.g. "side_count = 4").
Blunder 3 : While multiple possreps have been bashed for ages on this forum by some subset of participants (don't know if that includes you), you are now seemingly arguing that the IM assumes single possrep and that that is a "blunder". "What we do want to say is" ... exactly what the possreps already allow us to say !!! imho.
Blunder 4 : That the "data structures" (the possreps) per se are not necessarily type-compatible ("comparable") does not imply that the ***values*** (the abstractions themselves) aren't (/cannot be) either. In fact, making it so that they are is the whole point of the entire IM !!! imho.
Conclusion : "Any operation? Actually no: an operation that modifies ..." But at least DTATRM spends a whole separate section "update operator inheritance" to point this very thing out !!!
And in case you are now on the verge of starting a vitriol-laden rant, I'll add that I fully agree with that final observation "No. As if anything in software happens automatically: inheriting is a matter of declarations/definitions/implementations (operator overloading in this case).", and that I see actually using the IM in the intended way (i.e. ***doing*** those declarations/definitions/implementations - and also the impact analyses when doing maintenance/modifications) as "probably problematic" in that ***setting up*** type hierarchies is probably going to turn out still way more labour-intensive than anyone finds acceptable. (I also think the argument about "having to compute MST all the time" is flawed, but never have been able to show where&how, so I also think the "leads to bad performance of necessity" pundits might have a valid point even if they can't prove it.)
Quote from Dave Voorhis on October 25, 2019, 11:06 amQuote from Erwin on October 25, 2019, 10:36 am(I also think the argument about "having to compute MST all the time" is flawed, but never have been able to show where&how, so I also think the "leads to bad performance of necessity" pundits might have a valid point even if they can't prove it.)
The MST shouldn't have to be computed any more often than computing the parameter type(s) and best invocation target has to be done in any multiple-dispatch system, since that's what it is. I.e, it only has to be computed when the invocation target (i.e., the specific operator implementation to call) is otherwise ambiguous. Alternatively, it can be computed once when a value is selected.
But it may be more expensive than typical multiple-dispatch when subtyping-by-constraint is in effect, particularly if computing the criteria for being a subtype is expensive.
As I recall, the usual argument for it not causing any performance overhead was that you could simply dispense with run-time polymorphism, at least when using subtyping-by-constraint. Just invoke operators defined and dispatched on declared types, because all subtypes of declared types are, by definition, the "same type" as the declared type.
Unfortunately, that doesn't make sense if you're coding to abstract interfaces and creating polymorphic implementations that are automatically selected (by the run-time type, i.e., MST) at run-time. You define subtypes because there will exist at least one operator -- with, yes, the same semantics as the others, per Liskov's Substitution Principle -- where the distinction between subtypes matters in some fashion. Otherwise, if you treat every invocation as being on the declared type, why bother with subtypes at all?
When this was raised before, the suggestion was to use stacks of 'IF' statements, 'CASE' statements, etc. to explicitly achieve something notionally equivalent.
No. That's the reason for coding to abstract interfaces and creating polymorphic implementations in the first place: to avoid clumsy and error-prone stacks of 'IF' statements.
Quote from Erwin on October 25, 2019, 10:36 am(I also think the argument about "having to compute MST all the time" is flawed, but never have been able to show where&how, so I also think the "leads to bad performance of necessity" pundits might have a valid point even if they can't prove it.)
The MST shouldn't have to be computed any more often than computing the parameter type(s) and best invocation target has to be done in any multiple-dispatch system, since that's what it is. I.e, it only has to be computed when the invocation target (i.e., the specific operator implementation to call) is otherwise ambiguous. Alternatively, it can be computed once when a value is selected.
But it may be more expensive than typical multiple-dispatch when subtyping-by-constraint is in effect, particularly if computing the criteria for being a subtype is expensive.
As I recall, the usual argument for it not causing any performance overhead was that you could simply dispense with run-time polymorphism, at least when using subtyping-by-constraint. Just invoke operators defined and dispatched on declared types, because all subtypes of declared types are, by definition, the "same type" as the declared type.
Unfortunately, that doesn't make sense if you're coding to abstract interfaces and creating polymorphic implementations that are automatically selected (by the run-time type, i.e., MST) at run-time. You define subtypes because there will exist at least one operator -- with, yes, the same semantics as the others, per Liskov's Substitution Principle -- where the distinction between subtypes matters in some fashion. Otherwise, if you treat every invocation as being on the declared type, why bother with subtypes at all?
When this was raised before, the suggestion was to use stacks of 'IF' statements, 'CASE' statements, etc. to explicitly achieve something notionally equivalent.
No. That's the reason for coding to abstract interfaces and creating polymorphic implementations in the first place: to avoid clumsy and error-prone stacks of 'IF' statements.
Quote from Erwin on October 25, 2019, 12:14 pmQuote from Dave Voorhis on October 25, 2019, 11:06 amQuote from Erwin on October 25, 2019, 10:36 am(I also think the argument about "having to compute MST all the time" is flawed, but never have been able to show where&how, so I also think the "leads to bad performance of necessity" pundits might have a valid point even if they can't prove it.)
The MST shouldn't have to be computed any more often than computing the parameter type(s) and best invocation target has to be done in any multiple-dispatch system, since that's what it is. I.e, it only has to be computed when the invocation target (i.e., the specific operator implementation to call) is otherwise ambiguous. Alternatively, it can be computed once when a value is selected.
That's the whole issue. The former is at any operator invocation site, the latter is at any operator return site. Both are all over the place.
(And also, given that types of parameters are part of the identifying signature of any "invocation target", how do you decide it could be "ambiguous" if you haven't computed all the MST's.)
Quote from Dave Voorhis on October 25, 2019, 11:06 amQuote from Erwin on October 25, 2019, 10:36 am(I also think the argument about "having to compute MST all the time" is flawed, but never have been able to show where&how, so I also think the "leads to bad performance of necessity" pundits might have a valid point even if they can't prove it.)
The MST shouldn't have to be computed any more often than computing the parameter type(s) and best invocation target has to be done in any multiple-dispatch system, since that's what it is. I.e, it only has to be computed when the invocation target (i.e., the specific operator implementation to call) is otherwise ambiguous. Alternatively, it can be computed once when a value is selected.
That's the whole issue. The former is at any operator invocation site, the latter is at any operator return site. Both are all over the place.
(And also, given that types of parameters are part of the identifying signature of any "invocation target", how do you decide it could be "ambiguous" if you haven't computed all the MST's.)
Quote from AntC on October 25, 2019, 12:14 pmQuote from Erwin on October 25, 2019, 10:36 amThere's actually piles and lots of irony to be found here imo.
Thank you Erwin. I think your points can be answered (unironically) by reading on to the next section of TIRT 'A FUNDAMENTAL CONCEPT' (note the "only if ... both"):
[The Manifesto] regards type T′ as a subtype of type T if, but only if, both of the following conditions are satisfied:
1. Every value of type T′ is a value of type T (i.e., “T′ is a subset of T”).
2. A value of type T is a value of type T′ if and only if it satisfies a certain constraint, where the constraint in question is such that it can be tested for any given value of type T by examining just those properties that are intrinsic to values of type T in general.There's no point 0. to the effect
T′
andT
have some PossRep in common, and under that PossRep ...1.'s "subset" (of the set of values for a type) requires the two type's values to be represented in comparable format. Specifically, a format that enables 2.'s constraint to be tested. If my only declared PossRep for squares is with a single component side whereas my only PossRep for rectangles has components length, width I might write a constraint on the rectangles type, but that won't help bringing the squares type into the inheritance hierarchy. Then the bit I quote "since every square is in fact a rectangle ..." by all means applies to entities 'in the world', but doesn't apply to the representations recorded in the database.
Blunder 1 : TTM inheritance being of the multiple kind, it does not prohibit squares to be regarded as "regular polygons" ***as well as*** rectangles (as well as rhombuses etc etc). (Preferring "regarded as" to "representation" for reasons to follow.) I can agree that having to opt for a particular taxonomy is problematic, but that is only so in single inheritance, which is the kind TTM IM even ***mandates*** to avoid. So maybe you could explain how this remark of yours can constitute a valid criticism of TTM IM.
Because my representation within the database is not bound to use multiple PossReps for all polygons such that there's at least one PossRep in common amongst them all by which they can be placed in a hierarchy. This isn't so much about efficiency (why would I represent two dimensions for squares when they're always equal?) as about faithfulness to the mini-world I'm modelling (avoiding redundancy of concepts).
Or ... the model has to use weasel words like your "regarded as" or the above "intrinsic to values of type T" to suggest there's a common PossRep that you might have declared but didn't. Or ... is the hierarchy to be built by subsetting of fictitious PossReps?
Blunder 2 : "Accepting that every square is a rectangle provides no evidence that every data structure representing a SQUARE has any necessary relationship to data structures representing a RECTANGLE." But that is almost exactly the point TTM IM is making !!! By definition, if a SQUARE is regarded as being (/defined to be) all of RECTANGLE, RHOMBUS, REG_POLY, then it will "inherit" all defined "structure representations" (= possreps) from all three. (e.g. height/width from RECTANGLE, long_diag/short_diag from RHOMBUS, side_len/sice_count from REG_POLY. And any possreps defined for itself (just side_len) will indeed not necessarily have any obvious relationship with the inherited ones (except perhaps possibly through the type constraint, e.g. "side_count = 4").
Blunder 3 : While multiple possreps have been bashed for ages on this forum by some subset of participants (don't know if that includes you), you are now seemingly arguing that the IM assumes single possrep and that that is a "blunder". "What we do want to say is" ... exactly what the possreps already allow us to say !!! imho.
Yes I am amongst those who bash multiple PossReps; but no I didn't ignore them for this thread; neither did I assume them into existence unless told to. If the IM requires multiple PossReps (and specifically at least one common PossRep for all types to be placed in a hierarchy), then it needs to say so; and up front in Chapter 1. (Chapter 1 includes a great deal of 'picking the daisies' material. Not a skerrick about PossReps nor multiple PossReps.)
Part 2 of my 2-part post will show (when I can make time to write it) that you can express the abstract property 'rectangularity', 'squareness' without needing multiple PossReps; and that you can capture the abstract in-commonness in a protean way for any data structure that includes an aspect or combination of components that can be interpreted as rectangular/etc.
Blunder 4 : That the "data structures" (the possreps) per se are not necessarily type-compatible ("comparable") does not imply that the ***values*** (the abstractions themselves) aren't (/cannot be) either. In fact, making it so that they are is the whole point of the entire IM !!! imho.
The IM isn't about "abstractions". It's about subsets of the values DECLARED for the types. The only way any type model can deal with abstractions is if they're represented by values/data structures/characteristic patterns of values.
Conclusion : "Any operation? Actually no: an operation that modifies ..." But at least DTATRM spends a whole separate section "update operator inheritance" to point this very thing out !!!
It's not only about update. That's why I also mentioned the division operation for Integers vs Rationals. (Or are you of the school that the Integers are not a subset of the Rationals? -- which might be what that meandering Chapter 22 in DBE is about.) If Date wants to say that
RAT
is represented as a pair ofINT
, but thatINT
is represented as a single component with no alternative PossRep as a pair, that's rather made my point for me about representing Squares vs Rectangles.And in case you are now on the verge of starting a vitriol-laden rant, ...
You mean a level of emotion to match the amount of bluster ("intuitively obvious", "reasonable", "makes sense", "logical and natural consequence") in that short section of TIRT? No need for me to.
I'll add that I fully agree with that final observation "No. As if anything in software happens automatically: inheriting is a matter of declarations/definitions/implementations (operator overloading in this case).", and that I see actually using the IM in the intended way (i.e. ***doing*** those declarations/definitions/implementations - and also the impact analyses when doing maintenance/modifications) as "probably problematic" in that ***setting up*** type hierarchies is probably going to turn out still way more labour-intensive than anyone finds acceptable. (I also think the argument about "having to compute MST all the time" is flawed, but never have been able to show where&how, so I also think the "leads to bad performance of necessity" pundits might have a valid point even if they can't prove it.)
I wasn't going to make an argument based on ergonomics of data definitions/programming. Because there's no such thing as a free lunch. (And my proposed alternative isn't for free either.) But I agree with your implication that supporting multiple PossReps is onerous for the compiler implementor, just as much as for the user/programmer.
The ergonomic benefit I hope to show for my alternative is that you define your data structures first, in a way that's appropriate within each; then afterwards declare how each structure represents rectangularity/squareness. One way to see that is that multiple PossReps are 'bolted on' afterwards rather than having to be 'built in'. That's what we call 'loose coupling' in software engineering.
Quote from Erwin on October 25, 2019, 10:36 amThere's actually piles and lots of irony to be found here imo.
Thank you Erwin. I think your points can be answered (unironically) by reading on to the next section of TIRT 'A FUNDAMENTAL CONCEPT' (note the "only if ... both"):
[The Manifesto] regards type T′ as a subtype of type T if, but only if, both of the following conditions are satisfied:
1. Every value of type T′ is a value of type T (i.e., “T′ is a subset of T”).
2. A value of type T is a value of type T′ if and only if it satisfies a certain constraint, where the constraint in question is such that it can be tested for any given value of type T by examining just those properties that are intrinsic to values of type T in general.
There's no point 0. to the effect T′
and T
have some PossRep in common, and under that PossRep ...
1.'s "subset" (of the set of values for a type) requires the two type's values to be represented in comparable format. Specifically, a format that enables 2.'s constraint to be tested. If my only declared PossRep for squares is with a single component side whereas my only PossRep for rectangles has components length, width I might write a constraint on the rectangles type, but that won't help bringing the squares type into the inheritance hierarchy. Then the bit I quote "since every square is in fact a rectangle ..." by all means applies to entities 'in the world', but doesn't apply to the representations recorded in the database.
Blunder 1 : TTM inheritance being of the multiple kind, it does not prohibit squares to be regarded as "regular polygons" ***as well as*** rectangles (as well as rhombuses etc etc). (Preferring "regarded as" to "representation" for reasons to follow.) I can agree that having to opt for a particular taxonomy is problematic, but that is only so in single inheritance, which is the kind TTM IM even ***mandates*** to avoid. So maybe you could explain how this remark of yours can constitute a valid criticism of TTM IM.
Because my representation within the database is not bound to use multiple PossReps for all polygons such that there's at least one PossRep in common amongst them all by which they can be placed in a hierarchy. This isn't so much about efficiency (why would I represent two dimensions for squares when they're always equal?) as about faithfulness to the mini-world I'm modelling (avoiding redundancy of concepts).
Or ... the model has to use weasel words like your "regarded as" or the above "intrinsic to values of type T" to suggest there's a common PossRep that you might have declared but didn't. Or ... is the hierarchy to be built by subsetting of fictitious PossReps?
Blunder 2 : "Accepting that every square is a rectangle provides no evidence that every data structure representing a SQUARE has any necessary relationship to data structures representing a RECTANGLE." But that is almost exactly the point TTM IM is making !!! By definition, if a SQUARE is regarded as being (/defined to be) all of RECTANGLE, RHOMBUS, REG_POLY, then it will "inherit" all defined "structure representations" (= possreps) from all three. (e.g. height/width from RECTANGLE, long_diag/short_diag from RHOMBUS, side_len/sice_count from REG_POLY. And any possreps defined for itself (just side_len) will indeed not necessarily have any obvious relationship with the inherited ones (except perhaps possibly through the type constraint, e.g. "side_count = 4").
Blunder 3 : While multiple possreps have been bashed for ages on this forum by some subset of participants (don't know if that includes you), you are now seemingly arguing that the IM assumes single possrep and that that is a "blunder". "What we do want to say is" ... exactly what the possreps already allow us to say !!! imho.
Yes I am amongst those who bash multiple PossReps; but no I didn't ignore them for this thread; neither did I assume them into existence unless told to. If the IM requires multiple PossReps (and specifically at least one common PossRep for all types to be placed in a hierarchy), then it needs to say so; and up front in Chapter 1. (Chapter 1 includes a great deal of 'picking the daisies' material. Not a skerrick about PossReps nor multiple PossReps.)
Part 2 of my 2-part post will show (when I can make time to write it) that you can express the abstract property 'rectangularity', 'squareness' without needing multiple PossReps; and that you can capture the abstract in-commonness in a protean way for any data structure that includes an aspect or combination of components that can be interpreted as rectangular/etc.
Blunder 4 : That the "data structures" (the possreps) per se are not necessarily type-compatible ("comparable") does not imply that the ***values*** (the abstractions themselves) aren't (/cannot be) either. In fact, making it so that they are is the whole point of the entire IM !!! imho.
The IM isn't about "abstractions". It's about subsets of the values DECLARED for the types. The only way any type model can deal with abstractions is if they're represented by values/data structures/characteristic patterns of values.
Conclusion : "Any operation? Actually no: an operation that modifies ..." But at least DTATRM spends a whole separate section "update operator inheritance" to point this very thing out !!!
It's not only about update. That's why I also mentioned the division operation for Integers vs Rationals. (Or are you of the school that the Integers are not a subset of the Rationals? -- which might be what that meandering Chapter 22 in DBE is about.) If Date wants to say that RAT
is represented as a pair of INT
, but that INT
is represented as a single component with no alternative PossRep as a pair, that's rather made my point for me about representing Squares vs Rectangles.
And in case you are now on the verge of starting a vitriol-laden rant, ...
You mean a level of emotion to match the amount of bluster ("intuitively obvious", "reasonable", "makes sense", "logical and natural consequence") in that short section of TIRT? No need for me to.
I'll add that I fully agree with that final observation "No. As if anything in software happens automatically: inheriting is a matter of declarations/definitions/implementations (operator overloading in this case).", and that I see actually using the IM in the intended way (i.e. ***doing*** those declarations/definitions/implementations - and also the impact analyses when doing maintenance/modifications) as "probably problematic" in that ***setting up*** type hierarchies is probably going to turn out still way more labour-intensive than anyone finds acceptable. (I also think the argument about "having to compute MST all the time" is flawed, but never have been able to show where&how, so I also think the "leads to bad performance of necessity" pundits might have a valid point even if they can't prove it.)
I wasn't going to make an argument based on ergonomics of data definitions/programming. Because there's no such thing as a free lunch. (And my proposed alternative isn't for free either.) But I agree with your implication that supporting multiple PossReps is onerous for the compiler implementor, just as much as for the user/programmer.
The ergonomic benefit I hope to show for my alternative is that you define your data structures first, in a way that's appropriate within each; then afterwards declare how each structure represents rectangularity/squareness. One way to see that is that multiple PossReps are 'bolted on' afterwards rather than having to be 'built in'. That's what we call 'loose coupling' in software engineering.
Quote from Dave Voorhis on October 25, 2019, 12:33 pmQuote from AntC on October 25, 2019, 12:14 pmYes I am amongst those who bash multiple PossReps; but no I didn't ignore them for this thread; neither did I assume them into existence unless told to. If the IM requires multiple PossReps (and specifically at least one common PossRep for all types to be placed in a hierarchy), then it needs to say so; and up front in Chapter 1. (Chapter 1 includes a great deal of 'picking the daisies' material. Not a skerrick about PossReps nor multiple PossReps.)
I don't think they're required, and I think too much is made of multiple possreps in general. They're a language feature that many programmers might never use -- roughly like 'volatile' in C/C++/C#/Java -- though more of a convenience than a necessity, at least compared to 'volatile'.
They also appear to be intended to provide the same notional functionality as a class with multiple constructors in C++/C#/Java and other object-oriented languages.
Quote from AntC on October 25, 2019, 12:14 pmYes I am amongst those who bash multiple PossReps; but no I didn't ignore them for this thread; neither did I assume them into existence unless told to. If the IM requires multiple PossReps (and specifically at least one common PossRep for all types to be placed in a hierarchy), then it needs to say so; and up front in Chapter 1. (Chapter 1 includes a great deal of 'picking the daisies' material. Not a skerrick about PossReps nor multiple PossReps.)
I don't think they're required, and I think too much is made of multiple possreps in general. They're a language feature that many programmers might never use -- roughly like 'volatile' in C/C++/C#/Java -- though more of a convenience than a necessity, at least compared to 'volatile'.
They also appear to be intended to provide the same notional functionality as a class with multiple constructors in C++/C#/Java and other object-oriented languages.
Quote from Dave Voorhis on October 25, 2019, 12:39 pmQuote from Erwin on October 25, 2019, 12:14 pmQuote from Dave Voorhis on October 25, 2019, 11:06 amQuote from Erwin on October 25, 2019, 10:36 am(I also think the argument about "having to compute MST all the time" is flawed, but never have been able to show where&how, so I also think the "leads to bad performance of necessity" pundits might have a valid point even if they can't prove it.)
The MST shouldn't have to be computed any more often than computing the parameter type(s) and best invocation target has to be done in any multiple-dispatch system, since that's what it is. I.e, it only has to be computed when the invocation target (i.e., the specific operator implementation to call) is otherwise ambiguous. Alternatively, it can be computed once when a value is selected.
That's the whole issue. The former is at any operator invocation site, the latter is at any operator return site. Both are all over the place.
Same as any multiple dispatch system. That's the price you inevitably pay for multiple dispatch. Implementations usually cache invocation references -- i.e., cache JIT-compiled code -- to improve performance.
Quote from Erwin on October 25, 2019, 12:14 pm(And also, given that types of parameters are part of the identifying signature of any "invocation target", how do you decide it could be "ambiguous" if you haven't computed all the MST's.)
Any operator with only a single signature / implementation is potentially unambiguous if its parameters are all a supertype of the arguments' declared type.
Quote from Erwin on October 25, 2019, 12:14 pmQuote from Dave Voorhis on October 25, 2019, 11:06 amQuote from Erwin on October 25, 2019, 10:36 am(I also think the argument about "having to compute MST all the time" is flawed, but never have been able to show where&how, so I also think the "leads to bad performance of necessity" pundits might have a valid point even if they can't prove it.)
The MST shouldn't have to be computed any more often than computing the parameter type(s) and best invocation target has to be done in any multiple-dispatch system, since that's what it is. I.e, it only has to be computed when the invocation target (i.e., the specific operator implementation to call) is otherwise ambiguous. Alternatively, it can be computed once when a value is selected.
That's the whole issue. The former is at any operator invocation site, the latter is at any operator return site. Both are all over the place.
Same as any multiple dispatch system. That's the price you inevitably pay for multiple dispatch. Implementations usually cache invocation references -- i.e., cache JIT-compiled code -- to improve performance.
Quote from Erwin on October 25, 2019, 12:14 pm(And also, given that types of parameters are part of the identifying signature of any "invocation target", how do you decide it could be "ambiguous" if you haven't computed all the MST's.)
Any operator with only a single signature / implementation is potentially unambiguous if its parameters are all a supertype of the arguments' declared type.
Quote from Erwin on October 25, 2019, 1:11 pmAll possreps ***are*** common between any type and any of its subtypes (all possreps of the supertype at hand, that is, of course).
Bringing SQUARE into the RECTANGLE hierarchy is done exactly by writing TYPE SQUARE IS RECTANGLE CONSTRAINT the_length(...)=the_width(...).
Now SQUARE has the length,width possrep (or slightly more precisely it has all the operators that come with that possrep). There's no "assuming it into existence" because types (such as RECTANGLE) have possreps, per the prescriptions of TTM sans IM. No "weasel words" needed to "suggest" any such thing.
It feels slightly like you are thinking of physical representation, and indeed if you ***want*** a physical possrep for SQUARE holding only one 'sideLength' value, then additional machinery is needed to make RECTANGLE's required THE_WIDTH() and THE_LENGTH() available again (contractual obligation prescribed by the model). I believe TIRT does discuss that somewhere. But at any rate such considerations are beyond the purview of the model per se.
And I believe I've written at least once on the old forum that ***if*** you make INT a subtype of RAT then you do "inherit" a division operator that takes two INTs and returns a RAT. If you want the traditional integer division besides that, than that's ***another*** operator needing its own signature. Meaning, because the parameters' types part is identical, another name (/invocation symbol), say IDIV. I know that's hard to swallow for people who [want to] see/write just '/' and say "that's division" and want to have the system make up all the rest correctly "from context", but well, there you have it. (It's another operator because RATIONAL DIV has the tuple (7,2,3.5) and INT DIV has the tuple (7,2,3) (both ignoring attribute names)) The "school that says the integers cannot be defined as an IM subtype of the rationals", that was Date in DBE ch. 22. Don't know whether you've read it. I don't fully agree with the conclusion. All I say is "choose and live with the consequences".
All possreps ***are*** common between any type and any of its subtypes (all possreps of the supertype at hand, that is, of course).
Bringing SQUARE into the RECTANGLE hierarchy is done exactly by writing TYPE SQUARE IS RECTANGLE CONSTRAINT the_length(...)=the_width(...).
Now SQUARE has the length,width possrep (or slightly more precisely it has all the operators that come with that possrep). There's no "assuming it into existence" because types (such as RECTANGLE) have possreps, per the prescriptions of TTM sans IM. No "weasel words" needed to "suggest" any such thing.
It feels slightly like you are thinking of physical representation, and indeed if you ***want*** a physical possrep for SQUARE holding only one 'sideLength' value, then additional machinery is needed to make RECTANGLE's required THE_WIDTH() and THE_LENGTH() available again (contractual obligation prescribed by the model). I believe TIRT does discuss that somewhere. But at any rate such considerations are beyond the purview of the model per se.
And I believe I've written at least once on the old forum that ***if*** you make INT a subtype of RAT then you do "inherit" a division operator that takes two INTs and returns a RAT. If you want the traditional integer division besides that, than that's ***another*** operator needing its own signature. Meaning, because the parameters' types part is identical, another name (/invocation symbol), say IDIV. I know that's hard to swallow for people who [want to] see/write just '/' and say "that's division" and want to have the system make up all the rest correctly "from context", but well, there you have it. (It's another operator because RATIONAL DIV has the tuple (7,2,3.5) and INT DIV has the tuple (7,2,3) (both ignoring attribute names)) The "school that says the integers cannot be defined as an IM subtype of the rationals", that was Date in DBE ch. 22. Don't know whether you've read it. I don't fully agree with the conclusion. All I say is "choose and live with the consequences".
Quote from johnwcowan on October 25, 2019, 5:40 pmQuote from AntC on October 25, 2019, 5:52 amSecond blunder: confusing an entity with its representation in the database/data structure
"since every square is in fact a rectangle, it surely makes sense to say that type SQUARE is a subtype of type RECTANGLE."
Neither that "in fact" nor "surely" nor "makes sense" is an appeal to logic: it's pure bluster. Accepting that every square is a rectangle provides no evidence that every data structure representing a SQUARE has any necessary relationship to data structures representing a RECTANGLE. For example if we represent squares using a data structure that says they're 4-sided regular polygons, there's no clear way in which that data type is a 'sub-' representation for rectangles-in-general.
Of course not. But look at the definition of type from Ch. 3 of the TTM book: "So what is a type? Essentially, it is a named, finite set of values." I think the restriction to finite sets is unnecessary, but I see why they do it. So for TTM purposes types are sets with additional qualifications.
Nope:
RECTANGLE
might be the set of all representations of rectangles; it's not the set of rectangles.It certainly is not the former, because each rectangle has a countably infinite number of representations, making the set of all representations of all rectangles uncountable. Rather, if we take finiteness seriously, there are a finite set of rectangles of interest (say, all the possible rectangles that can be drawn on a pixelated screen, or on a floor that has been measured to a certain finite precision). These are the members of the set (which is to say the type, since it is finite and named)
RECTANGLE
. Representations are not yet involved.There might be several representations from which we can abstract rectangularity or squareness.
If rectangularity (wlg) is merely abstracted from the representation, what is it that the representation is supposed to represent? I'd put it thus: rectangularity may be represented in a variety of ways.
Fourth blunder: 'subtype' means subset type; and subset is an applicable classification
Words mean what they're commonly used/agreed to mean.
Often it's the case that there is not a common agreement. Type is a notorious instance: for some the subset definition (which is certainly not original with D & D, being the Lisp viewpoint among many others) is the most important one; for others, type is about the meaning of fragments of code. This is isomorphic to, and may be exactly the same as, the distinction between objectual and substitutional quantification in the interpretation of predicate logic:
A sentence containing a quantifier is usually interpreted by assigning values to the variable it contains. Values are thought of as ‘objects’; hence this is termed objectual quantification. By contrast, the quantifier is interpreted substitutionally if expressions are substituted for the variable, and the result evaluated according to whether any of the substitutions produce a true sentence. Substitutional quantifiers are frequently written Σ and Π. (Σx)(logicians are x) would be evaluated as true, with the quantifier interpreted substitutionally, if there is a sentence ‘logicians are…’ which is true."
To continue...
If the data structure for representing
SQUARE
has a single component side where that forRECTANGLE
has two for width, height, the set of values withinSQUARE
is not just not a subset of those withinRECTANGLE
, it's not even comparable.It's only not comparable if you think two things with different representations cannot be comparable. But every object is comparable to itself, and if an object may have two different representations, then squares and rectangles are indeed comparable, because a square may be represented in either of two ways. This is precisely the point of talking about possible representations: they are one way to do it, not the way in which it is actually done.
Any operation? Actually no: an operation that modifies the width but not the length/height can't be supported by the API for squareness.
Modification is out of the picture: recurring to the definition of type given above, it is a set of values, and values are not modifiable in TTM.
Thus, we can say that operators that apply to values of type T are inherited by values of type T′.
No. As if anything in software happens automatically: inheriting is a matter of declarations/definitions/implementations (operator overloading in this case). We (the programmer) can insist/declare that if this operator applies for values of type
T
, that operator must also apply. For example anyT
for which comparison operators<, >
apply, equality comparison=
must apply.That's not the programmer's choice, it follows from the definitions of the operators, assuming they really are those operators and not different ones by the same name. If they are truly
< > =
then the trichotomy law applies, and soa = b
meansnot (a < b) and not(a > b)
.Any
T
for which squareness operators apply, rectangularity operators must apply. I talked about a single type there; what's inherited are properties/methods.If an operator applies to every member of a set S, it applies to every member of any subset of S. This gets a name (the Liskov Substitution Principle) in accordance with the Name Principle, but it's a trivial consequence of predicate logic and finite set theory. It doesn't of course mean that INT / INT = INT; as you point out, that is a distinct operator, not division at all. In fact it's at least six distinct useful operators returning (quotient, remainder) pairs, but few languages bother to discriminate: in C for example it is truncate, but in Basic it is floor.
Quote from AntC on October 25, 2019, 5:52 amSecond blunder: confusing an entity with its representation in the database/data structure
"since every square is in fact a rectangle, it surely makes sense to say that type SQUARE is a subtype of type RECTANGLE."
Neither that "in fact" nor "surely" nor "makes sense" is an appeal to logic: it's pure bluster. Accepting that every square is a rectangle provides no evidence that every data structure representing a SQUARE has any necessary relationship to data structures representing a RECTANGLE. For example if we represent squares using a data structure that says they're 4-sided regular polygons, there's no clear way in which that data type is a 'sub-' representation for rectangles-in-general.
Of course not. But look at the definition of type from Ch. 3 of the TTM book: "So what is a type? Essentially, it is a named, finite set of values." I think the restriction to finite sets is unnecessary, but I see why they do it. So for TTM purposes types are sets with additional qualifications.
Nope:
RECTANGLE
might be the set of all representations of rectangles; it's not the set of rectangles.
It certainly is not the former, because each rectangle has a countably infinite number of representations, making the set of all representations of all rectangles uncountable. Rather, if we take finiteness seriously, there are a finite set of rectangles of interest (say, all the possible rectangles that can be drawn on a pixelated screen, or on a floor that has been measured to a certain finite precision). These are the members of the set (which is to say the type, since it is finite and named) RECTANGLE
. Representations are not yet involved.
There might be several representations from which we can abstract rectangularity or squareness.
If rectangularity (wlg) is merely abstracted from the representation, what is it that the representation is supposed to represent? I'd put it thus: rectangularity may be represented in a variety of ways.
Fourth blunder: 'subtype' means subset type; and subset is an applicable classification
Words mean what they're commonly used/agreed to mean.
Often it's the case that there is not a common agreement. Type is a notorious instance: for some the subset definition (which is certainly not original with D & D, being the Lisp viewpoint among many others) is the most important one; for others, type is about the meaning of fragments of code. This is isomorphic to, and may be exactly the same as, the distinction between objectual and substitutional quantification in the interpretation of predicate logic:
A sentence containing a quantifier is usually interpreted by assigning values to the variable it contains. Values are thought of as ‘objects’; hence this is termed objectual quantification. By contrast, the quantifier is interpreted substitutionally if expressions are substituted for the variable, and the result evaluated according to whether any of the substitutions produce a true sentence. Substitutional quantifiers are frequently written Σ and Π. (Σx)(logicians are x) would be evaluated as true, with the quantifier interpreted substitutionally, if there is a sentence ‘logicians are…’ which is true."
To continue...
If the data structure for representing
SQUARE
has a single component side where that forRECTANGLE
has two for width, height, the set of values withinSQUARE
is not just not a subset of those withinRECTANGLE
, it's not even comparable.
It's only not comparable if you think two things with different representations cannot be comparable. But every object is comparable to itself, and if an object may have two different representations, then squares and rectangles are indeed comparable, because a square may be represented in either of two ways. This is precisely the point of talking about possible representations: they are one way to do it, not the way in which it is actually done.
Any operation? Actually no: an operation that modifies the width but not the length/height can't be supported by the API for squareness.
Modification is out of the picture: recurring to the definition of type given above, it is a set of values, and values are not modifiable in TTM.
Thus, we can say that operators that apply to values of type T are inherited by values of type T′.
No. As if anything in software happens automatically: inheriting is a matter of declarations/definitions/implementations (operator overloading in this case). We (the programmer) can insist/declare that if this operator applies for values of type
T
, that operator must also apply. For example anyT
for which comparison operators<, >
apply, equality comparison=
must apply.
That's not the programmer's choice, it follows from the definitions of the operators, assuming they really are those operators and not different ones by the same name. If they are truly < > =
then the trichotomy law applies, and so a = b
means not (a < b) and not(a > b)
.
Any
T
for which squareness operators apply, rectangularity operators must apply. I talked about a single type there; what's inherited are properties/methods.
If an operator applies to every member of a set S, it applies to every member of any subset of S. This gets a name (the Liskov Substitution Principle) in accordance with the Name Principle, but it's a trivial consequence of predicate logic and finite set theory. It doesn't of course mean that INT / INT = INT; as you point out, that is a distinct operator, not division at all. In fact it's at least six distinct useful operators returning (quotient, remainder) pairs, but few languages bother to discriminate: in C for example it is truncate, but in Basic it is floor.
Quote from AntC on October 25, 2019, 11:53 pmQuote from johnwcowan on October 25, 2019, 5:40 pmQuote from AntC on October 25, 2019, 5:52 amSecond blunder: confusing an entity with its representation in the database/data structure
"since every square is in fact a rectangle, it surely makes sense to say that type SQUARE is a subtype of type RECTANGLE."
Neither that "in fact" nor "surely" nor "makes sense" is an appeal to logic: it's pure bluster. Accepting that every square is a rectangle provides no evidence that every data structure representing a SQUARE has any necessary relationship to data structures representing a RECTANGLE. For example if we represent squares using a data structure that says they're 4-sided regular polygons, there's no clear way in which that data type is a 'sub-' representation for rectangles-in-general.
Of course not. But look at the definition of type from Ch. 3 of the TTM book: "So what is a type? Essentially, it is a named, finite set of values." I think the restriction to finite sets is unnecessary, but I see why they do it. So for TTM purposes types are sets with additional qualifications.
John you seem to be suffering from the same conflations as the bits I'm quoting from TIRT: something may be true of objects-in-the-world; it might also be true of some representation we can imagine for those objects (indeed if the representations are faithful to the external object, they're bound to be); but I'm saying they're not necessarily true of the actual software artefacts declared/implemented in the actual data model/program. (Unless Date is requiring declarations in a certain form, which at least isn't mentioned in Ch 1.)
wrt "set of values" there are "additional qualifications": we are in multi-sorted logic here (that's something else not explicit). So the values within one declared type are not comparable with the values in a differently-named type -- unless those two types are explicitly declared as being subset-types of some common supertype. And if they're so declared, they must have in common some PossRep with constraint(s) declared over it, by which we can compare the values.
Nope:
RECTANGLE
might be the set of all representations of rectangles; it's not the set of rectangles.It certainly is not the former, because each rectangle has a countably infinite number of representations, making the set of all representations of all rectangles uncountable.
OK to clarify: might be the set of all representations of rectangles declared within the program. You seem again to want to shift to-and-fro between the abstract/mathematic/imaginary and the software artefacts.
Rather, if we take finiteness seriously, there are a finite set of rectangles of interest (say, all the possible rectangles that can be drawn on a pixelated screen, or on a floor that has been measured to a certain finite precision). These are the members of the set (which is to say the type, since it is finite and named)
RECTANGLE
. Representations are not yet involved.
RECTANGLE
(from the context in TIRT) must be a name of a type declared in a program, which is why I put it in code format/in TIRT it's in block capitals. It must have a finite number of representations declared for it. Otherwise it isn't a type (as a software artefact). What precisely those representations are, or how many of them isn't germane to this bit of the argument.There might be several representations from which we can abstract rectangularity or squareness.
If rectangularity (wlg) is merely abstracted from the representation, what is it that the representation is supposed to represent? I'd put it thus: rectangularity may be represented in a variety of ways.
Our database might be recording office furniture. For each piece, it records length, width, height aot. There is no attribute with type
RECTANGLE
but I can see three examples of rectangularity: length x width (ie floorplan); length x height (ie front profile); width x height (ie side profile). There's no merit in using an attribute of typeRECTANGLE
, because there's no priority amongst those possible rectangle profiles; and to record them as 3RECTANGLE
s would be redundant/lead to update anomalies/etc. Within the database we might have a distinct relvar for recording square tables/desk pedestals, with only side, height.Fourth blunder: 'subtype' means subset type; and subset is an applicable classification
Words mean what they're commonly used/agreed to mean.
Often it's the case that there is not a common agreement. Type is a notorious instance: for some the subset definition (which is certainly not original with D & D, being the Lisp viewpoint among many others) is the most important one; for others, type is about the meaning of fragments of code. This is isomorphic to, and may be exactly the same as, the distinction between objectual and substitutional quantification in the interpretation of predicate logic:
Another notorious instance is 'subtype' (which was my point). But of the many senses of 'subtype' AFAICT it never meant 'subset type'/specialisation by constraint until TTM poked its nose in.
A sentence containing a quantifier is usually interpreted by assigning values to the variable it contains. Values are thought of as ‘objects’; hence this is termed objectual quantification. By contrast, the quantifier is interpreted substitutionally if expressions are substituted for the variable, and the result evaluated according to whether any of the substitutions produce a true sentence. Substitutional quantifiers are frequently written Σ and Π. (Σx)(logicians are x) would be evaluated as true, with the quantifier interpreted substitutionally, if there is a sentence ‘logicians are…’ which is true."
To continue...
If the data structure for representing
SQUARE
has a single component side where that forRECTANGLE
has two for width, height, the set of values withinSQUARE
is not just not a subset of those withinRECTANGLE
, it's not even comparable.It's only not comparable if you think two things with different representations cannot be comparable.
I do think two things with no common declared representation cannot be comparable. We're talking about software artefacts.
But every object is comparable to itself, and if an object may have two different representations, then squares and rectangles are indeed comparable, because a square may be represented in either of two ways. This is precisely the point of talking about possible representations: they are one way to do it, not the way in which it is actually done.
No that isn't "possible" in some abstract mathematical sense. It's in the sense declared PossRep for the type.
Any operation? Actually no: an operation that modifies the width but not the length/height can't be supported by the API for squareness.
Modification is out of the picture: recurring to the definition of type given above, it is a set of values, and values are not modifiable in TTM.
OK. Consider a function that takes a rectangle('s representation) as argument and returns a rectangle('s representation) by adding 30cm to its length.
Thus, we can say that operators that apply to values of type T are inherited by values of type T′.
No. As if anything in software happens automatically: inheriting is a matter of declarations/definitions/implementations (operator overloading in this case). We (the programmer) can insist/declare that if this operator applies for values of type
T
, that operator must also apply. For example anyT
for which comparison operators<, >
apply, equality comparison=
must apply.That's not the programmer's choice,
Again I'm not talking in some abstract/mathematicians sense; but about declared software artefacts. So it's nobody else's choice but the programmer's (the compiler implementor or library provider of the methods).
it follows from the definitions of the operators, assuming they really are those operators and not different ones by the same name. If they are truly
< > =
then the trichotomy law applies, and soa = b
meansnot (a < b) and not(a > b)
.Does your program actually police those laws? Has it checked your compiler follows those laws for every possible
a, b
? I thought not. There's no "truly< >=
" in software, there's only what's declared.Any
T
for which squareness operators apply, rectangularity operators must apply. I talked about a single type there; what's inherited are properties/methods.If an operator applies to every member of a set S, it applies to every member of any subset of S.
In software, we only recognise some (named) type's values is a subset type of
S
if it's declared as such.This gets a name (the Liskov Substitution Principle) in accordance with the Name Principle, but it's a trivial consequence of predicate logic and finite set theory. It doesn't of course mean that INT / INT = INT; as you point out, that is a distinct operator, not division at all.
I've disagreed with you on that already on a previous thread. Operator
/
in some language behaves as per its declaration in that language. Your appeal to "predicate logic and finite set theory" is about as much use as Date's appealing to "makes sense".In fact it's at least six distinct useful operators returning (quotient, remainder) pairs, but few languages bother to discriminate: in C for example it is truncate, but in Basic it is floor.
Quote from johnwcowan on October 25, 2019, 5:40 pmQuote from AntC on October 25, 2019, 5:52 amSecond blunder: confusing an entity with its representation in the database/data structure
"since every square is in fact a rectangle, it surely makes sense to say that type SQUARE is a subtype of type RECTANGLE."
Neither that "in fact" nor "surely" nor "makes sense" is an appeal to logic: it's pure bluster. Accepting that every square is a rectangle provides no evidence that every data structure representing a SQUARE has any necessary relationship to data structures representing a RECTANGLE. For example if we represent squares using a data structure that says they're 4-sided regular polygons, there's no clear way in which that data type is a 'sub-' representation for rectangles-in-general.
Of course not. But look at the definition of type from Ch. 3 of the TTM book: "So what is a type? Essentially, it is a named, finite set of values." I think the restriction to finite sets is unnecessary, but I see why they do it. So for TTM purposes types are sets with additional qualifications.
John you seem to be suffering from the same conflations as the bits I'm quoting from TIRT: something may be true of objects-in-the-world; it might also be true of some representation we can imagine for those objects (indeed if the representations are faithful to the external object, they're bound to be); but I'm saying they're not necessarily true of the actual software artefacts declared/implemented in the actual data model/program. (Unless Date is requiring declarations in a certain form, which at least isn't mentioned in Ch 1.)
wrt "set of values" there are "additional qualifications": we are in multi-sorted logic here (that's something else not explicit). So the values within one declared type are not comparable with the values in a differently-named type -- unless those two types are explicitly declared as being subset-types of some common supertype. And if they're so declared, they must have in common some PossRep with constraint(s) declared over it, by which we can compare the values.
Nope:
RECTANGLE
might be the set of all representations of rectangles; it's not the set of rectangles.It certainly is not the former, because each rectangle has a countably infinite number of representations, making the set of all representations of all rectangles uncountable.
OK to clarify: might be the set of all representations of rectangles declared within the program. You seem again to want to shift to-and-fro between the abstract/mathematic/imaginary and the software artefacts.
Rather, if we take finiteness seriously, there are a finite set of rectangles of interest (say, all the possible rectangles that can be drawn on a pixelated screen, or on a floor that has been measured to a certain finite precision). These are the members of the set (which is to say the type, since it is finite and named)
RECTANGLE
. Representations are not yet involved.
RECTANGLE
(from the context in TIRT) must be a name of a type declared in a program, which is why I put it in code format/in TIRT it's in block capitals. It must have a finite number of representations declared for it. Otherwise it isn't a type (as a software artefact). What precisely those representations are, or how many of them isn't germane to this bit of the argument.
There might be several representations from which we can abstract rectangularity or squareness.
If rectangularity (wlg) is merely abstracted from the representation, what is it that the representation is supposed to represent? I'd put it thus: rectangularity may be represented in a variety of ways.
Our database might be recording office furniture. For each piece, it records length, width, height aot. There is no attribute with type RECTANGLE
but I can see three examples of rectangularity: length x width (ie floorplan); length x height (ie front profile); width x height (ie side profile). There's no merit in using an attribute of type RECTANGLE
, because there's no priority amongst those possible rectangle profiles; and to record them as 3 RECTANGLE
s would be redundant/lead to update anomalies/etc. Within the database we might have a distinct relvar for recording square tables/desk pedestals, with only side, height.
Fourth blunder: 'subtype' means subset type; and subset is an applicable classification
Words mean what they're commonly used/agreed to mean.
Often it's the case that there is not a common agreement. Type is a notorious instance: for some the subset definition (which is certainly not original with D & D, being the Lisp viewpoint among many others) is the most important one; for others, type is about the meaning of fragments of code. This is isomorphic to, and may be exactly the same as, the distinction between objectual and substitutional quantification in the interpretation of predicate logic:
Another notorious instance is 'subtype' (which was my point). But of the many senses of 'subtype' AFAICT it never meant 'subset type'/specialisation by constraint until TTM poked its nose in.
A sentence containing a quantifier is usually interpreted by assigning values to the variable it contains. Values are thought of as ‘objects’; hence this is termed objectual quantification. By contrast, the quantifier is interpreted substitutionally if expressions are substituted for the variable, and the result evaluated according to whether any of the substitutions produce a true sentence. Substitutional quantifiers are frequently written Σ and Π. (Σx)(logicians are x) would be evaluated as true, with the quantifier interpreted substitutionally, if there is a sentence ‘logicians are…’ which is true."
To continue...
If the data structure for representing
SQUARE
has a single component side where that forRECTANGLE
has two for width, height, the set of values withinSQUARE
is not just not a subset of those withinRECTANGLE
, it's not even comparable.It's only not comparable if you think two things with different representations cannot be comparable.
I do think two things with no common declared representation cannot be comparable. We're talking about software artefacts.
But every object is comparable to itself, and if an object may have two different representations, then squares and rectangles are indeed comparable, because a square may be represented in either of two ways. This is precisely the point of talking about possible representations: they are one way to do it, not the way in which it is actually done.
No that isn't "possible" in some abstract mathematical sense. It's in the sense declared PossRep for the type.
Any operation? Actually no: an operation that modifies the width but not the length/height can't be supported by the API for squareness.
Modification is out of the picture: recurring to the definition of type given above, it is a set of values, and values are not modifiable in TTM.
OK. Consider a function that takes a rectangle('s representation) as argument and returns a rectangle('s representation) by adding 30cm to its length.
Thus, we can say that operators that apply to values of type T are inherited by values of type T′.
No. As if anything in software happens automatically: inheriting is a matter of declarations/definitions/implementations (operator overloading in this case). We (the programmer) can insist/declare that if this operator applies for values of type
T
, that operator must also apply. For example anyT
for which comparison operators<, >
apply, equality comparison=
must apply.That's not the programmer's choice,
Again I'm not talking in some abstract/mathematicians sense; but about declared software artefacts. So it's nobody else's choice but the programmer's (the compiler implementor or library provider of the methods).
it follows from the definitions of the operators, assuming they really are those operators and not different ones by the same name. If they are truly
< > =
then the trichotomy law applies, and soa = b
meansnot (a < b) and not(a > b)
.
Does your program actually police those laws? Has it checked your compiler follows those laws for every possible a, b
? I thought not. There's no "truly < >=
" in software, there's only what's declared.
Any
T
for which squareness operators apply, rectangularity operators must apply. I talked about a single type there; what's inherited are properties/methods.If an operator applies to every member of a set S, it applies to every member of any subset of S.
In software, we only recognise some (named) type's values is a subset type of S
if it's declared as such.
This gets a name (the Liskov Substitution Principle) in accordance with the Name Principle, but it's a trivial consequence of predicate logic and finite set theory. It doesn't of course mean that INT / INT = INT; as you point out, that is a distinct operator, not division at all.
I've disagreed with you on that already on a previous thread. Operator /
in some language behaves as per its declaration in that language. Your appeal to "predicate logic and finite set theory" is about as much use as Date's appealing to "makes sense".
In fact it's at least six distinct useful operators returning (quotient, remainder) pairs, but few languages bother to discriminate: in C for example it is truncate, but in Basic it is floor.