2016-08-28 0:04 GMT-07:00 Steven D'Aprano < steve+comp.lang.pyt...@pearwood.info>:
> On Sunday 28 August 2016 15:56, Juan Pablo Romero Méndez wrote: > > > 2016-08-27 21:30 GMT-07:00 Steve D'Aprano <steve+pyt...@pearwood.info>: > [...] > >> Now it is true that speaking in full generality, classes and types > refer to > >> different things. Or to be perhaps more accurate, *subclassing* and > >> *subtyping* are different things: > >> > >> http://c2.com/cgi/wiki?SubTypingAndSubClassing > >> > >> Many languages treat them the same, but fundamentally they are > different. > > > > Oh, I don't think he is thinking in terms of OO "classes", I think he > meant > > two different "kinds" or "varieties" of values (although kind has a > > technical meaning) > > That's not quite right either. "Two different kinds or varieties" is what > both > subclassing and subtyping aim to describe, in different ways: e.g. dogs and > cats are two different kinds of mammal. > > What you are describing here: > > > In TypeScript terms what he is saying can be described like this: > > > > type Complex = > > { real: number, i: number } > > | { r: number, φ: number} > > > > const c1: Complex = { real: 1, i: 1 } > > const c2: Complex = { r: 1, φ: 0.5 } > > > > You have two values of the same type but different representation. > > seems to be more like what is called "variant record" in Pascal. > > http://www.freepascal.org/docs-html/ref/refsu16.html > > > I'm not familiar with TypeScript. How does this work? If I say: > > const c1: Complex = {real: 1, imag: 1 } > > print c1.r > print c1.φ > > what do I get? If r and φ are merely alternative names for "real" and > "imag", > that's not good enough. Given real=1, imag=1, then we need to get > r=1.414213 > and φ = pi/4 without any extra effort on the part of the user. > > Here's a more complete example: type CartesianC = { real: number, i: number } type PolarC = { r: number, φ: number} type Complex = PolarC | CartesianC const c1: Complex = { real: 1, i: 1 }; const c2: Complex = { r: 1, φ: 0.5 }; // This is called a Type Guard function isCartesian(c: Complex): c is CartesianC { return (<CartesianC> c).real !== undefined; } if(isCartesian(c1)) { // c1 is a CartesianC here c1.real } else { // and a PolarC here. Using c1.real is a compile error c1.r } TypeScript doesn't support pattern matching so there's some boilerplate involved: you need to define a TypeGuard so that inside the if branch TS allows you to treat c1 as a CartesianC; within the else branch it is treated as a PolarC. > > The point is, the complex number (1, 1) in Cartesian coordinates and > (sqrt(2), > pi/4) in polar coordinates aren't two different kinds of things, they are > two > different ways of writing the same value. Like writing 1A in hex and 26 in > decimal. Somebody may choose to implement this as two different classes > ("CartesianComplex" and "PolarComplex") but that's a limitation of their > code, > or of their language, it doesn't reflect a real difference between two > different kinds of things. > Well conceptually you might think of c1 as the abstract representation of a complex number but at runtime they have very different constitutions. > > Another way to put it: > > If you were programming a first person shooter game, you might choose each > of > the enemies as an object. Let's say you have an enemy called the Grue. You > can > view the Grue from the front or from the back, depending on which way it is > standing when you see it. Would you implement this as two different > classes? > > GrueSeenFromFront > > GrueSeenFromBack > > I should hope not. It's the same object, the same Grue, it just looks > different > depending on which way you approach it. > > > > > > -- > Steve > > -- > https://mail.python.org/mailman/listinfo/python-list > -- https://mail.python.org/mailman/listinfo/python-list