5 ms·
Their example of why Ada has better strong typing than Rust is that you can have floats for miles and floats for kilometers and not get them mixed up. News flas
by markasoftware 1y ago
Their example of why Ada has better strong typing than Rust is that you can have floats for miles and floats for kilometers and not get them mixed up. News flash, Rust has newtype structs, and you can also do basically the same thing in C++.
I don't know much about Ada. Is its type system any better than Rust's?
- forthac 1y agoThis was posted to about a day ago: https://github.com/johnperry-math/AoC2023/blob/master/More_Detailed_Comparison.md https://github.com/johnperry-math/AoC2023/blob/master/More_D... But a noteworthy excerpt: ``` Ada programs tend to define types of the problem to be solved. The compiler then adapts the low-level type to match what is requested. Rust programs tend to rely on low-level types. That may not be clear, so two examples may help: Ada programmers prefer to specify integer types in terms of the ranges of values they may take and/or the precision of floating-point types in terms of digits. I ended up doing this at least once, where on Day 23 I specified a floating-point type in terms of the number of digits it should reproduce accurately: Digits 18. The compiler automatically chose the most appropriate machine type for that. Ada arrays don't have to start from 0, nor even do they have to be indexed by integers. An example of this appears below. By contrast, the Rust programs I've seen tend to specify types in terms of low-level, machine types. Thus, I tried to address the same problem using an f64. In this particular case, there were repercussions, but usually that works fine as long as you know what the machine types can do. You can index Rust types with non-integers, but it takes quite a bit more work than Ada. ```
- Pet_Ant 1y ago> By contrast, the Rust programs I've seen tend to specify types in terms of low-level, machine types. This seems to be an artifact of the domain that Rust is currently being used in. I don't think it's anathema to Rust to evolve to be able to add some of these features. char indexed arrays are something I've used a lot (most via `char c - 'a'`\, but native support for it would be nice).
- sgsjchs 1y agoYou very rarely would actually want scalar types which don't map directly to hardware supported ones anyway.
- bestouff 1y agoYou can use TiVec to index with something other than usize. https://crates.io/crates/typed-index-collections https://crates.io/crates/typed-index-collections
- TheRealKing 1y agoAda's mechanism is what Fortran has been using and doing for decades.
- pklausler 1y agoF'77 added arbitrary lower bounds on arrays, including explicit-shaped and assumed-shaped dummy arrays. It is a useful and portable feature, though somewhat confusing to newcomers when they try to pass an array with non-default lower bounds as an actual argument and they don't work as one would expect. F'90 added arbitrary lower bounds on assumed-shape dummy arrays, as well as on allocatables and pointers. Still pretty portable, though more confusing cases were added. F'2003 then added automatic (re)allocation of allocatables, and the results continue to astonish users. And only two compilers get them right, so they're not portable, either. Ada's array indexing is part of its type system. Fortran's is not (for variables).
- citbl 1y agoYes and no, you need to look deeper into Ada to find that it can have compile time guarantees higher than what you can get from a struct named km and miles.
- bitwize 1y agoYou can actually do this in C as well. The Windows API has all sorts of handle types that were originally all one type: HANDLE; but by wrapping a HANDLE in various one-member structs were able to derive different handle types that couldn't be intermixed with each other in a type-safe way without some casting jiggery-pokery. It's just much, much easier and more ergonomic in Ada.
- pjmlp 1y agoFun fact, that many are not aware, mostly because this is Windows 3.x knowledge and one needed the right source to learn about this. There was a header only library on the Windows SDK that would wrap those HANDLEs into more specific types, that would still be compatible, while providing a more high level API to use them from C. Unfortunely there is not much left on the Internet about it, but this article provides some insight, https://www.codeguru.com/windows/using-message-crackers-in-the-win32-api-with-the-mcw-tool/ https://www.codeguru.com/windows/using-message-crackers-in-t... Naturally it was saner just to use TP/C++ alongside OWL, C++ with MFC back then, or VB.
- dlahoda 1y agonewtypes are not as good as native low level types. after typing a lot of code, one will find out that he needs nightly to get decent integration to avoid casting to low level and back all time.
- 112233 1y agoI'm super interested how you can do this in C++. Say, I need aggregate struct with a few 16 and 32 bit fields, some are little endian and some big endian. I do not want C++ to let me mix up endianness. How do I do it?
- platinumrad 1y agoC: struct be32_t { uint32_t _ }; struct le32_t { uint32_t _ }; C++: That, but with a billion operator overloads and conversion operators so they feel just like native integers.
- NekkoDroid 1y agoIn C++ you probably could even make a templated class that implements all possible operators for any type that supports it with concepts. Then you can just `using kilometer = unique_type<uint32_t, "kilometer">` without needing to create a custom type each time.
- bluGill 1y agoThough if you do that km times km isn't km it is a volume - so your custom type would be wrong to have all operations. what unit km times km should be isn't clear.
- pjmlp 1y agoThankfully some folks already thought that out, one possible library, https://mpusz.github.io/mp-units/latest/ https://mpusz.github.io/mp-units/latest/
- bluGill 1y agoI have seen several versions. I wrote two different ones myself - both not in use because the real world of units turned out far more complex. the multiplication thing is one simple example of the issuses but not a complete list
- boxed 1y agoAside from technical factors, there are social factors involved. For example, both Python and C++ has operator overloading. But in C++ that's horrible and you run screaming from it, while in Python land it's perfectly fine. What is the difference? Culture and taste.
- HelloNurse 1y agoIt isn't the same operator overloading. In C++ operator overloading can easily mess with fundamental mechanisms, often intentionally; in Python it is usually no more dangerous than defining regular functions and usually employed purposefully for types that form nice algebraic structures.
- pjmlp 1y agoI hardly see the difference, given the capabilities of operator overloading in Python, class MyNum(int): def __add__ (self, other): return super().__add__(other) * 10 n = MyNum(12) a = 45 print(n + a) # oops
- HelloNurse 1y agoThis type confusion would have been identical with a plain function, __add__ is only syntactic sugar: class MyNum(int): def ten_times_sum (self, other): return (self+other)* 10 n = MyNum(12) a = 45 print(n.ten_times_sum(a)) Compare with, for example, fouling the state of output streams from operator>> in C++.
- pjmlp 1y agoHardly any different, trying to pretend Python is somehow better. Operator overload is indeed syntactic sugar for function calls, regardless of the language. By the way, you can overload >> in Python via rshift(), or __rshift__() methods.
- 1y ago
- wolvesechoes 1y agoThere is no elegant solution in Rust to make something like type Temperature_K is digits 6 range 0 .. <whatever is reasonable upper bound in your domain>;
- bluGill 1y agoat least that is an unsigned (though there are no usigned hardware floats). If you said tempemerature C there you range starts at -273.15 and you want errors of some sort to happen if you go below that.
- estimator7292 1y agoIdeally, the program would freeze