3 ms·
Better than turns, radians, etc. is an `Angle` newtype AKA wrapper class. It completely eliminates misinterpretation of the value, miscalculation from [angle =
by armchairhacker 4y ago
Better than turns, radians, etc. is an `Angle` newtype AKA wrapper class.
It completely eliminates misinterpretation of the value, miscalculation from [angle = angle + tau*n] as all angles are normalized, is more descriptive, and in a decent language is zero-cost.
Programmers should not be using (radians: float) in modern languages which support wrapper classes
- tsimionescu 4y agoThis has nothing to do with the article, and it is equally applicable to degrees, radians, or turns. It neither solves nor hinders the simplicity or performance issues the article was talking about.
- londons_explore 4y agoI disagree. By wrapping an angle in an Angle class, the internal representation need never be exposed to the programmer. Rather than every programmer needing to read this blog post to see the performance benefits of using 'turns', instead now just a few library developers need to.
- tsimionescu 4y agoTypes are just labels applied to variables. Their only power is type-checking a program to see whether every variable use is consistent. Wrapping something in a type doesn't magically change its value. Not to mention, Angle is a particularly poor name, since radians, degrees and turns are all different measures of angles. Say I have this program: x : Angle = 90 y : Angle = pi/4 z : Angle = 1/4 sin : Angle -> Real sin x //what will this print? sin y //how about this? sin z // ?
- kadoban 4y ago> Wrapping something in a type doesn't magically change its value. It changes its meaning and operations. `x : Angle = 90` and friends should just be illegal. `x : Angle = Degrees(90)` is better. Then the programmer can use whatever is convenient.
- ratorx 4y agoParent proposed a wrapper, rather than an alias. One way to handle this with an Angle type is to not allow an automatic cast from float/double/int. instead, you expose methods that normalise the input and internally can represent it as whatever, i.e. from_degrees, from_turns, from_radians or similar that force the programmer to be explicit about their unit, when the angle is constructed. Alternatively, Angle could be the base class and each unit gets its own class that Angle inherits from.
- morelisp 4y agoYou are right that `Angle` is the wrong name for a newtype but wrong that this is not a job for types. > Wrapping something in a type doesn't magically change its value. Most formal definitions of value disagree, e.g. from Stepanov & McJones: A value type is a correspondence between a species (abstract or concrete) and a set of datums. A datum corresponding to a particular entity is called a representation of the entity; the entity is called the interpretation of the datum. We refer to a datum together with its interpretation as a value. In this case the species is abstract, rotational measurement - and the interpretation is the unit. 2pi radians, 360 degrees, and 1 turn all correspond to the same abstract entity; radians, degrees, and turns are types. But you can also find the mistake just based on your own comment, where you've taken an unjustified leap from variable to value: > Types are just labels applied to variables... Wrapping something in a type doesn't magically change its value. Types are labels applied to variables, specifically in order to produce a particular value from the contents of some memory region (what Stepanov & McJones call "datum"). If changing types didn't change values, types would be near-useless (cf, as a concrete example, C's near-useless type system).
- mcv 4y agoWhy is Angle a poor name? The fact that radians, degrees and turns are all different ways to represent angles is exactly the point. Despite their different format, they represent the exact same thing, and sin(90 degrees) should return exactly the same as sin(1/4) or sin(pi/4). From a mathematical perspective where people don't care about types, this is weird, but from an OOP perspective with polymorphism this is exactly right. So in that sense, instead of storing angles as just a number where the programmer needs to keep checking whether it's in radians, degrees or turns, you should store it as an Angle object. And that object shouldn't use any approximations of pi, but understand what pi means. Angle.fromDegree(90) should be exactly, and not approximately Angle.fromRadian(4*PI).
- naniwaduni 4y ago> I disagree. By wrapping an angle in an Angle class, the internal representation need never be exposed to the programmer. Because nobody will ever instantiate one? At the end of the day, you're not implementing these as an exercise in hermetic design, you're trying to do arithmetic, presumably on numbers you have.
- munificent 4y agoBut what is the underlying representation in the wrapper class?
- morelisp 4y agoDoes this matter any more than the fact the underlying representation within sin is e.g. an 80 bit number no programming language can give you? `Angle` is a bad name for this example because a newtype should be named after the unit rather than what it models, but once you've newtyped it, what matters is that you call sin with the right one, not the actual representation.
- munificent 4y agoYes, the entire point of the article is that it does in fact matter. > what matters is that you call sin with the right one, not the actual representation. No, the actual representation does matter. At some point, arithmetic operations are being performed and those operations consume CPU cycles. If you care about the performance of the code, you care about having a representation that minimizes the number of those operations.
- morelisp 4y agoSo make sure you use `typeof sin[0]` or whatever the syntax is in your language for your own variables - in the end this still requires newtyping the thing. For performance in this context, the actual representation does not matter - only that your code and your sin code agree to avoid the conversion cost.
- munificent 4y agoI think you're confusing "representation" to mean just the number of bits allocated to the number, but the article and my comments also use it to mean what the numeric range of those values represents (hence "representation"). How that's modeled in the static type system is completely orthogonal to the underlying arithmetic operations that are performed and their efficiency. The article is entirely about the latter.