Re: Mixing OO and DB

From: Dmitry A. Kazakov <mailbox_at_dmitry-kazakov.de>
Date: Mon, 18 Feb 2008 12:20:11 +0100
Message-ID: <yua94zxg5jp.1vuke4ep81386$.dlg_at_40tude.net>


On Sun, 17 Feb 2008 19:12:50 -0800 (PST), David BL wrote:

> On Feb 16, 8:38 pm, "Dmitry A. Kazakov" <mail..._at_dmitry-kazakov.de>
> wrote:

>> On Fri, 15 Feb 2008 17:45:16 -0800 (PST), David BL wrote:
>>> On Feb 16, 5:24 am, "Dmitry A. Kazakov" <mail..._at_dmitry-kazakov.de>
>>> wrote:
>>>> On Fri, 15 Feb 2008 08:46:54 -0800 (PST), David BL wrote:

>
>>>>>Therefore, as Invert() has
>>>>> been written (1) is the only option.
>>
>>>> As a counterexample, consider C (complex) instead of Z.
>>
>>> Please provide more details.  Are you alluding to covariant return
>>> types?  ie
>>
>>> Complex Invert(Complex x);
>>> Real Invert(Real x);
>>
>> Yes. Covariant result for Real :> Complex inheritance is appropriate and
>> reasonable. But it is not for Real :> Integer. This is a mathematical fact,
>> rather than a property of some arbitrary types system. The problem is that
>> C is a field, Z is not. Thus the types system shall be able to capture what
>> behavior (mathematical structure in this case) you are going to inherit
>> upon derivation from R, a ring (for Z) or a field (for C). There is no way
>> to know it in advance, and if we restricted it to "all what R is", we would
>> get just another R.

>
> I assume the notation T :> S means S is a subtype of T. I think you
> are suggesting (a definition of subtyping) that T :> S implies that
> for any algorithm, all occurrences of T can be replaced by S.

This is a LSP notion.

> However, then there would be no valid subtyping relationships between
> Z,R and C. For example, R :> C isn't valid because R is an ordered
> field whereas C is not. C :> R isn't valid because C is an
> algebraically closed field, whereas R is not. Z isn't a subtype of
> either R of C because Z isn't a field. Neither R or C is a subtype
> of Z because only Z has the property that its positive elements are
> well-ordered.

Right. This is why I treat subtyping as mere a types relation such that an operation gets inherited. Inheritance means no more than that the compiler does not spill a type error and routinely applies appropriate conversions of the arguments. The conversions are user-defined or compiler-generated.

> I would suggest what you're after is some concept of abstract value-
> types like "Ring" and "Field". I can see it could be useful to write
> data structures and algorithms in their most generic sense without
> explicit parameterisation. For example matrices are defined on an
> abstract field. This still allows for many nontrivial functions to be
> written - eg matrix inverse. I can imagine indicating that R,C are
> subtypes of Field according to this parameterisation notion of sub-
> type.
>
> However independently of such as feature, I still believe it is
> important to capture the quite different concept of subtyping espoused
> by C.Date, because it concerns implicit conversions of value-types (as
> distinct from parameterisation), and that's very important.

I see no difference. To me it is the same notion of subtyping. Maybe the difference is that I also allow out conversions. But that is a natural generalization of.

Note also that conversions do not forbid by-reference semantics. In such case conversion would simply shift an internally maintained pointer. Neither they do mutable semantics. For out parameters the conversion is applied to the result.

> Treating Z as a subset of R, or R as a subset of C is very useful. A
> function that accepts a complex number can be passed a real number
> without explicit conversion. A function that returns a real number
> can used to initialise a complex variable. Implicit conversions are
> deemed valid if and only if *exactly the same logical value* is
> represented before and after the "conversion". This implies two
> things: the conversion cannot silently drop information, nor can it
> silently add information.

I would relax this too. Note that you can add exceptions as ideals to the set of values. This gives you an opportunity to convert non-substitutable

out-Circle for out-Ellipse into substitutable
out-Circle-or-else-Constraint_Error for
out-Ellipse-or-else-Constraint_Error.

> It follows that it is wrong to say that a ColouredRectangle is a
> subtype of a Rectangle, because a ColouredRectangle value is logically
> different to a Rectangle value.

Note that "logically different" makes no sense to me. There is only difference to me is in behavior. If in the given context the behavior is same, then in this context values are logically same (but physically different). We cannot dismiss subtyping on the basis that there might be contexts of non-substitutability, because such exist for any two non-trivial types.

> I think it's clear that slicing is
> suspect. Imagine a little movie of slicing and play it in reverse -
> isn't it equally suspect? I now think out-substitutability is just as
> suspicious as in-substitutability in this case. When one assigns a
> ColouredRectangle variable from a Rectangle value, how do you know
> what to initialise the colour to?

Clearly Rectangle is not in-substitutable for ColouredRectangle. It is as follows:

  1. Rectangle is out-substitutable for ColouredRectangle
  2. ColouredRectangle is in-substitutable for Rectangle

Equivalently:

  1. Rectangle is an out-subtype of ColouredRectangle
  2. ColouredRectangle is an in-subtype of Rectangle

Equivalently:

  1. You can safely inherit any out operations from ColouredRectangle by Rectangle per subtyping or else export them from ColouredRectangle to Rectangle per supertyping.
  2. You can safely inherit any in operations from Rectangle by ColouredRectangle per subtyping or else export them from Rectangle to ColouredRectangle per supertyping.

> Returning back to abstract value-types like "Field", it is important
> not to confuse them with "abstract" supertypes in the sense of C.Date,
> because the latter are *union types*, and represent the union of all
> possible values from its sub-types.

These I call polymorphic values. These are ones of the closure of the class.

> By contrast, a "Field" is actually a type of a type and I think the
> distinction is important.

Right. This is the distinction between polymorphic and specific = between the class closure (class-wide type) and a class member (specific type).

> The idea here is that a type like Complex
> is regarded as itself a value, which means you can have types defined
> over types. It would be interesting to some up with a suitable
> syntax and see whether the average programmer is able to comprehend
> it.

Yes. Complex is a specific type from the class Field. Complex values are non-polymorphic: 1+2j. The corresponding class-wide polymorphic values are tuples: (Complex, 1+2j). Field contains such values:

   (Real, 0)
   (Complex, 0+0j)
   etc

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de
Received on Mon Feb 18 2008 - 12:20:11 CET

Original text of this message