On 4/29/07, Jeffrey Yasskin <[EMAIL PROTECTED]> wrote: > On 4/28/07, Baptiste Carvello <[EMAIL PROTECTED]> wrote: > > 2) In the PEP, the concepts are used *inconsistently*. Complex derives from > > Ring > > because the set of complex numbers *is a* ring. Int derives from Complex > > because > > integer are complex numbers (or, alternatively, the set of integers *is > > included > > in* the set of complex numbers). The consistent way could be to make the > > Complex > > class an instance of Ring, not a subclass. > > Good point. In this structure, isinstance(3, Ring) really means that 3 > is a member of some (unspecified) ring, not that 3 isa Ring,
To ask whether x is a Ring, you'd use issubclass(x, Ring). Now, in a different context (still in Python) you might define a class Ring whose *instances* are rings; but in the current draft of PEP 3141, Ring is a class whose subclasses are rings. [BTW "isa" is not an English word, nor used anywhere in Python. If "isa" means "is a" you might as well write proper English; if it has additional connotations, they're likely lost to this crowd so you can't count on your readers knowing the distinction.] > but the ambiguity there is probably the root cause of the problem with > mixed-mode operations. (Where by mixed-mode operations you mean e.g. trying to add or multiply members of two *different* rings, right?) > We should also say that isinstance(3, Complex) > means that 3 is a member of some subring of the complex numbers, which > preserves the claim that Complex is a subtype of Ring. Hm... it's beginning to look like binary operations in the mathematical sense just don't have an exact equivalent in OO type theory. (Or vice versa.) There really isn't a way to define an operation binop(a: T, b: T) -> T in such a way that it is clear what should happen if a and b are members of two different subtypes of T, named T1 and T2. Classic OO seems to indicate that this must be defined, and there are plenty of examples that seem to agree, e.g. when T1 and T2 are trivial subtypes of T (maybe each adding a different inessential method). OTOH we have the counter-example where T==Ring and T1 and T2 are two different, unrelated Rings, and the result may not be defined. Hmm... Maybe the conclusion to draw from this is that we shouldn't make Ring a class? Maybe it ought to be a metaclass, so we could ask isinstance(Complex, Ring)? Perhaps a similar line of reasoning migtht apply to PartiallyOrdered and TotallyOrdered. > Up to here, things make sense, but because of how ABCs work, we need > issubclass(rational, Complex). I suppose that's true too, since > isinstance(3.4, rational) means "3.4 is a member of the rational > subring of the complex numbers", which implies that "3.4 is a member > of some subring of the complex numbers." > > There may be better names for these concepts. Perhaps suffixing every > numeric ABC with "Element"? Do you have suggestions? Maybe we should stop trying to capture radically different mathematical number systems using classes or types, and limit ourselves to capturing the systems one learns in high school: C, R, Q, Z, and (perhaps) N (really N0). The concrete types would be complex <: C, float<:R, Decimal<:R, int<:Z. NumPy would have many more. One could argue that float and Decimal are <:Q, but I'm not sure if that makes things better pragmatically; I guess I'm coming from the old Algol school where float was actually called real (and in retrospect I wish I'd called it that in Python). I'd rather reserve membership of Q for an infinite precision rational type (which many people have independently implemented). > Jason Orendorff points out that Haskell typeclasses capture the fact > that complex is an instance of Ring. I think imitating them as much as > possible would indeed imply making the numeric ABCs into metaclasses > (in Haskell terminology, "kinds"). To tell if the arguments to a > function were in the same total order, you'd check if they had any > common superclasses that were themselves instances of TotallyOrdered. > I don't know enough about how metaclasses are typically used to know > how that would conflict. The more I think about it, it sounds like the right thing to do. To take PartiallyOrdered (let's say PO for brevity) as an example, the Set class should specify PO as a metaclass. The PO metaclass could require that the class implement __lt__ and __le__. If it found a class that didn't implement them, it could make the class abstract by adding the missing methods to its __abstractmethods__ attribute. Or, if it found that the class implemented one but not the other, it could inject a default implementation of the other in terms of the one and __eq__. This leaves us with the question of how to check whether an object is partially orderable. Though that may really be the wrong question -- perhaps you should ask whether two objects are partially orderable relative to each other. For that, you would first have to find the most derived common base class (if that is even always a defined operation(*)), and then check whether that class is an instance of PO. It seems easier to just try the comparison -- duck typing isn't dead yet! I don't think this is worth introducing a new inspection primitive ('ismetainstance(x, PO)'). The PO class may still be useful for introspection: at the meta-level, it may be useful occasionally to insist that or inquire whether a given *class* is PO. (Or TO, or a Ring, etc.) Now, you could argue that Complex should also be a metaclass. While that may mathematically meaningful (for all I know there are people doing complex number theory using Complex[Z/n]), for Python's numeric classes I think it's better to make Complex a regular class representing all the usual complex numbers (i.e. a pair of Real numbers). I expect that the complex subclasses used in practice are all happy under mixed arithmetic using the usual definition of mixed arithmetic: convert both arguments to a common base class and compute the operation in that domain. (*) consider classes AB derived from (B, A) and BA derived from (A, B). Would A or B be the most derived base class? Or would we have to skip both and continue the search with A's and B's base classes? -- --Guido van Rossum (home page: http://www.python.org/~guido/) _______________________________________________ Python-3000 mailing list Python-3000@python.org http://mail.python.org/mailman/listinfo/python-3000 Unsubscribe: http://mail.python.org/mailman/options/python-3000/archive%40mail-archive.com