Can verify. If you are doing production work with coordinate transforms strongly typing your points to their coord sys and _not_ allowing implicit conversion is a win.
I’ve not used this library (not Rust very much) but the principle is simple to implement and advisable to use whatever typed language you use. So; don’t store northing-easting pairs to vec2. Create a type for it. And call the other value northing, and the other easting. Implement all the algebra you need. I guarantee this will save you from so many headache causing bugs.
Why not allow implicit conversions from your own defined types?
It's the same sort of bug that killed that Mars mission and the same reason some people insist on keyword parameters instead of ordered parameters. People make mistakes, and implicit conversions allow those mistakes to silently propagate. Given how easy it is to strongly type everything and use explicit conversions, the default for most nontrivial software should be closer to TFA rather than allowing implicit conversions or overloading the semantics of a type.
GIS are particularly prone to these sort of human caused accidents. Example is that some GIS take coordinate input as LatLon and some take LonLat.
Another good example is that very often when working with GIS you collate data from multiple sources, as a sibling comment indicates. These sources may be available in all sorts of different coordinate systems and projections and it’s extremely easy to get bad results that are difficult to verify they are bad by these types of bugs.
You don't understand what implicit conversion is.
The Mars Climate Orbiter failed because an input was given in Newtons but expected in pounds, and the type of the variables was the same (float or whatever), so the compiler could not detect or prevent the error.
The root cause was using the same types for incompatible data, which allowed operations which should have been illegal.
If the variables had different types, then the compiler could use implicit conversion to automatically convert Newtons to pounds, and failure would be averted.
Implicit conversion does not allow mistakes to "silently propagate". It prevents the mistake in the first place.
> You don't understand what implicit conversion is.
Please be nice, and check the site guidelines [0] if it's not obvious what the problem with that phrasing is.
Yes, implicit conversions are narrowly defined to be the thing you describe. Along with overloaded types and positional arguments, they all have the same properties I outlined -- the compiler can't protect you from minor typos, that error will tend to propagate far from the erroneous callsite, and there are relatively easy coding patterns to alleviate those issues. I thought those examples might be more familiar to enough people that it would give their brains something to latch on to when considering the problems with implicit conversions.
And we seem to disagree on this point, but IME implicit conversions cause many more bugs than they fix. A smattering of examples:
1. You can't implicitly narrow a numeric type without losing precision.
2. You can't implicitly narrow types in general without losing data or having some sort of error handling system, or having some sort of compile-time guarantee that the conversion is safe for this specific instance of the wider type. Without a very advanced compiler (even then, not for every problem), this will manifest as runtime errors and crashes.
3. You can't implicitly widen a numeric type without opening up yourself to all sorts of bugs. E.g., when evaluating `data & mask` you likely don't want the mask to be implicitly widened to the size of the data, unless you got especially lucky and were only extracting the low bits. Those sorts of problems are very common with integers, but floating-point widening is similarly dangerous from time to time.
4. You often shouldn't implicitly widen types in general because there usually isn't a good default state for the missing data. In the mask example from (3), the problem is that we don't know what the missing bits ought to be in the context of this particular problem, but that same problem manifests with class hierarchies and any other way you might represent converting a smaller type to a larger type.
Your example of implicitly converting between "equivalent" types is perhaps the best use case, and by far the one I have the fewest problems with. It's still not flawless though, and it's not safer than having two separate types while requiring explicit conversions.
Implicit conversions in general are a very common source of bugs. C(++) implicit widening and narrowing and other such things have bitten me quite a few time. Instead of asking "why not allow" you should instead ask "why allow" and only implement such things when there is a compelling case for it.
Skill issue?
As are memory safety bugs. You still probably ought to use smart pointers unless you have a good reason not to.
Because you want to be explicit each time you change coordinate system. You want the code to be so obvious it looks dumb.
That doesn't really explain why, you're just saying that the thin you claimed was desirable is desirable.
(I don't disagree! I'm just saying: you haven't advanced your argument or answered GP's question.)
I'll throw a bit more flavour in with the sibling comment talking about transposing x and y.
The system I work on every day has:
- multiple GPS receivers that report latitude, longitude, altitude (MSL) and altitude (HAE)
- an interface to some GeoJSON data where coordinates are stored as longitude, latitude
- a geographically-local Cartesian coordinate frame that is an AEP (Azimuthal Equidistance Projection) with a latitude/longitude origin. The "XYZ" axes of this frame are a NED frame (north, east, down)
- an aircraft-local Cartesian frame with FRD (forward, right, down) axes
- an interface that provides map tiles with zoom/x/y coordinates
- a bunch of other sensors mounted on the aircraft that have their own FRD frames, except the camera which has an RDF (right, down, forward) frame because... reasons.
- terrain RADAR units mounted on the aircraft at specific FRD locations that provide AGL (above ground level) measurements independent of their rotation (the aircraft can be 20 degrees nose-up and we still get a measurement straight down to the ground)
- terrain LIDAR units mounted on the aircraft at specific FRD locations and orientations that provide a straight-line measurement to the ground - if we're over flat ground and the aircraft is 20 degrees nose-up, these report AGL/cos(20 deg)
Keeping track of what frame everything is in is... a daunting task and we've definitely had bugs due to accidentally using a coordinate from the wrong frame. I've been deep into a bunch of this code this week and have been strongly considering doing a zero-cost abstraction similar to what Sguaba is doing, but for C++. I'm pretty sure that we could do it using templates and type tags without really changing any of the underlying math and without implementing a bunch of custom operators but I'm not 100% convinced of that yet.
Another related issue that I don't think is addressed by Sguaba is time. We're hopefully going to get everything standardized to PTP timestamps everywhere but currently all of these sensors are running on unsynchronized clocks and we also have to be careful about keeping track of the origin of a given timestamp and making sure to convert it into the right scale before using it.
Ah, sorry.
So the reason _why_ we want the code to be explicit is that we want to be explicit always of the coordinate system we are in. Otherwise _extremely_ hard to find bugs can and will creep in - a float is a float.
The stuff I worked on input coordinates were left handed but the output coordinates were right handed.
> a float is a float
That's not what is happening here. With this software there are no raw floats; all variables are typed by the kind of coordinate system (WGS84, ECEF, etc.)
Using your example, the variables would be typed by left- or right-handed. So it is impossible to mix them up, e.g., perform some illegal operation combining them.
Whether implicit conversion is allowed is just saying, does the programmer have to call a function to convert type A -> B, or can the compiler do that for them?
For example,
void doFoo(LeftHandedVec3 v);
RightHandedVec3 myData;
// With explicit conversion.
doFoo(convertToLeftHanded(myData));
// With implicit conversion.
doFoo(myData);
Does one of these produce more bugs?In my experience for technical applications
doFoo(convertToLeftHanded(myData));
wins in every way.
This is a very good example of ”code that is so obvious it looks stupid” - and which would be the main style I would promote.
If I may...
Ex structures engineer, current programmer here.
The technique described keeps you, as a programmer, from transposing coordinate variables by type system enforcement. You might have variables x1, y1, x2, y2. If y1 and y2 have a different type than x1 and x2, it's much harder to transpose them. Large flying vehicles often have many coordinate systems. Enforcing types will keep you from using stage 1 variables in a stage 2 context without type conversion.
I left the aerospace industry in 1992. Before that, I did some work with a program called "BOSOR5" - "Buckling of Shells of Revolution" (https://shellbuckling.com/BOSOR5.php). The X,Y coordinates appears as Y,X in the output. Very confusing, lots of problems because everyone habitually reads X first, then Y, left-to-right.
Imagine how much trouble it was to work on a Saturn 5: https://oikofuge.com/coordinate-axes-apollo-saturn-1/ If you have a type system with different types for all the axes, you will incur far fewer programming-domain errors.
I just found a subtle bug caused by a vector expressed in the wrong coordinate frame. Been thinking a lot about something like this
Can confirm. Been working on a spaceship colony game still in prototype phase, the code isn't too clean to begin with. Ended up asking the AIs for typed Vector3 in C#, which gave me a starting point.
https://gist.github.com/mrkybe/efa70a9ddcba7b5bfe441dafce13e...
It's been a huge time-saver.
This is awesome. I think a problem to wider adoption of this is going to be verification.
This would be very useful for the aerospace industry. However the reason they still use things like MATLAB is less about “the best software in terms of efficiency or modern code structures is the stability and backing of it. I’ve seen stacks that are matlab transcompiled to Fortran loaded onto aircraft…as late as 2015.
The other detail, and without reading the documentation fully, is variable accuracy in types would be something interesting to have as a controlled set of options.
Oh, no, another Rust vector and matrix library. There's already "glam" and "nalgebra".
Having more than one vector and matrix library is as troublesome for geometry processing as multiple string types are for string processing.
Usual hints for language designers on type basics that become a headache as the language progresses:
- Have a "bool" type, and don't make it equivalent to an integer.
- Have types for vec2 through vec4, and mat2 through mat4. That covers the cases graphics people use constantly. Those are basic, and everyone agrees what they should do.
- Support multidimensional arrays as a standard language feature. Don't get too fancy. Just do it at least as well as FORTRAN does.
- Strings are checked UTF-8.
- Provide some standard error type, or error hierarchy, from which all errors are derived.
Get any of those wrong in the early days of a language and retrofits will become a time sink for users. Rust got three of those five wrong, and had to be retrofitted to fix them.
The article is about using nalgebra to create an intuitive library for tranforming between Earth's various coordinate systems. Not "another Rust matrix library".
OK, it's atop nalgebra. Of course, if you're using glam...