Re: Mixing OO and DB

From: David BL <davidbl_at_iinet.net.au>
Date: Mon, 18 Feb 2008 19:09:48 -0800 (PST)
Message-ID: <59008154-3b39-486a-be6f-f899a30193cf_at_e6g2000prf.googlegroups.com>


On Feb 19, 12:41 am, "Dmitry A. Kazakov" <mail..._at_dmitry-kazakov.de> wrote:
> On Mon, 18 Feb 2008 05:59:39 -0800 (PST), David BL wrote:
> > On Feb 18, 8:20 pm, "Dmitry A. Kazakov" <mail..._at_dmitry-kazakov.de>
> > wrote:
> >> 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.
>
> > I disagree. I'm talking about algorithms that are implicitly
> > parameterised over various value-types. LSP isn't even applicable for
> > value-types.
>
> How so? LSP defines behavioral notion of type as set of provable
> predicates. This clearly includes your parametrized types. The parameters
> are subjects of type substitution. It is pure LSP.

I have a more specific understanding of LSP. Let an object mean a variable that has identity, state and behavior, but isn't assumed to hold a value. If S,T are object types where S is a subtype of T then LSP states that if q(x) is a property provable about objects x of type T. Then q(y) should be true for objects y of type S.

In my mind LSP is inappropriate for value-types because it is concerned with variables rather than values.

> (The real problem with LSP is that unconditional substitutability is all
> thinkable context is impossible.)
>
> >>> 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.
>
> > That's not formal enough for me. It sounds like sub-typing can mean
> > anything you want it to mean.
>
> Right, it has to be this way. If I want to make square a subtype of train
> traffic, it is my business. I should provide the implementations of the
> corresponding operations and that is.

But subtyping affects what the compiler will and won't allow. Obviously you need to specify that. In the process you are defining the semantics of sub-typing.

> >>> 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.
>
> > Really! I can't understand that.
>
> I don't see how Date's conversions are any different from mine:
>
> S is an in-subtype of T in the operation f iff:
>
> 1. there exists f, operation on T denoted as T.f
>
> T.f : T -> <no matter>
>
> 2. there exists a conversion from S to T:
>
> S_to_T : S -> T
>
> 3. there exits f, operation on S denoted as S.f
>
> S.f : S -> <no matter>
>
> It is said that f is inherited by S iff
>
> S.f = T.f o S_to_T
>

I think we're better off with examples. At least I have some context!

Consider the following function that inverts a matrix parameterised in field T for the type of the matrix elements.

    template <class T> Matrix<T> Invert(Matrix<T> x)

Invert<R> is valid because R is a field, whereas Invert<Z> is not valid because Z is not a field.

According to C.Date's definition of sub-type, Z is a sub-type of R. This definition of sub-type doesn't allow you to assume you can replace R with Z in Invert<R> to yield Invert<Z>.

You are saying there is no difference in C.Date's notion of subtyping,  versus a definition of subtyping that allows you to substitute the type in a parameterisation. I cannot understand that.

> >>> 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.
>
> > Sorry, I just cannot understand your approach.
>
> You cannot convert, you can drop an exception. This makes things
> substitutable back. This is not mine approach, it is a widely used model.
> Consider float. You cannot convert max float + max float from R back to
> float. So you throw overflow, or use NaN, whatsoever. You add an ideal to
> the set of floats /= R.
>
> > You didn't answer my question: When a Rectangle value is converted to
> > a ColouredRectangle, what is the colour initialised to?
>
> It cannot be converted! For out-substitutability of Rectangle, it is out
> ColouredRectangle which is converted to Rectangle.

So you're saying slicing away the colour is respectable?

> In-substitutability of S to T in f() works as a composition f o S_to_T
> Out-substitutability of S to T in g() works as a composition S_from_T o g
>
> The conversion is not forward, it backward.
Received on Tue Feb 19 2008 - 04:09:48 CET

Original text of this message