Hacker News new | past | comments | ask | show | jobs | submit login
The Usual Arithmetic Confusions (shafik.github.io)
44 points by signa11 on Jan 29, 2022 | hide | past | favorite | 17 comments



And then some people are surprised when I tell them that I hate C and C++ even though I'm considered a 'C++ expert'..

Too bad, the DoD didn't have the foresight to create/sponsor a Free Ada compiler sooner..

And the lack of interest in Ada (even though there is now a Free compiler) makes me pessimistic for Rust, DasBetterC, Zig, Odin, V.. I hope that I'm wrong though!


> Too bad, the DoD didn't have the foresight to create/sponsor a Free Ada compiler sooner..

The US Air Force supposedly help fund the development of GNAT, the GCC front-end for Ada, from 1991 - 1994. It suffered from license problems with GCC and the myth you need a paid compiler to write non-GPL code.

The issue with Ada is that most people don't even know that it still exists. That, or they think it's going to be like writing COBOL. Instead it's a contemporary language to C++, which evolved through Pascal rather than C and has similarly received updates, Ada 2012 especially [0]. It even has a package manager now[1].

[0] : learn.adacore.com/

[1] : https://alire.ada.dev/


I'm very interested in Ada but 10+ years ago when I tried to look into I had trouble finding tutorials and implementations. I got the impression there was no real open source community around it, but maybe I was wrong?


Within the last couple years, last year especially, there's been a massive push by one the Ada companies, AdaCore, to releasing open source and proselytizing the language. That company contributes back to the GCC front-end for Ada called GNAT. They're also helping support and develop Ada's new package manager, called Alire.

It's a small, but interesting community. It has the feel of some of the newer programming language communities, but is an already mature language that's getting its tooling being massively contemporized since there's commercial money and full-time employees behind it.


I find Stephan T. Lavavej's explanation from "Core C++, 7 of n" [0] of Arithmetic Conversions a little more thorough. Also, it is memorable as it is told in the context of a bug in Microsoft's STL implementation.

[0] : https://www.youtube.com/watch?v=zXH18n_IVac


Which languages don’t have this confusion?

I believe CommonLisp and MACLISP (RIP) do not unless you specifically and laboriously constrain the type assumptions. But I believe the automatic type system handles numerics “properly”, at some runtime cost.

Not sure if any other languages do.


Rust's type conversions are explicit, so a lot of the examples that invoke "integral promotion" won't compile because there is no such promotion, you need to write down what you meant, giving you an opportunity to reconsider, hey, I want to subtract a large positive integer from a smaller positive integer I... huh, I guess these aren't unsigned after all, need to do some refactoring.

WUFFS types are constrained to specific ranges, so not only is there no implicit promotion or arithmetic conversion, overflow is also impossible. If it might overflow it simply won't compile.

WUFFS also doesn't believe in operator precedence, a + b * c won't compile because, what did you mean there? Write (a + b) * c or a + (b * c) depending on which you actually meant.


Ada doesn't. It also allows creating semantic versions of the same type which the type checked will catch if you mess them up. You can also add ranges to primitive types as well. If you want the wrapping behavior of an unsigned type, you can use "modular types" which are expressly designed for that behavior.

    -- You can't assign some value of type Apples to Oranges
    -- without a conversion
    type Apples is new Integer;
    type Oranges is new Integer;

    -- Only allow whole number ranges of a percentage.
    type Percentage is range 0 .. 100;


Haskell only allows arithmetic operators on like types, so you cannot add an Int to a Word32, subtract an Int16 from an Int64, or compare an Integer with an Int.

Operators are defined in typeclass Num, so the type of e.g. addition is

(+) :: Num a => a -> a -> a

while comparisons are define in typeclasses Eq and Ord, with types like

(/=) :: Eq a => a -> a -> Bool

(<=) :: Ord a => a -> a -> Bool


Javascript does not have this problem :D :D


A funny example I hadn’t considered. Smily indeed!


in fairness JS maths has other, different, problems :D


Go does not. It doesn't do any magic conversion. If you want to use different types together, you need to cast one of them, period.

Why C/C++ ever thought this was a good idea is beyond me. The whole point of strong typing to me, is that you should never be wondering what type something is. C thought they were adding convenience, but decades have shown that it only adds bugs, and forces people to memorize weird rules, or remember to use the right compiler warnings. Good riddance.


> Why C/C++ ever thought this was a good idea is beyond me.

Because C was evolved from BCPL, an untyped language, over the course of about 10 years, and then 10 more if you include refinements for what became ANSI C (C89). And at every iteration one of the concerns was maximizing source and binary compatibility with previous iterations; it was always actually being used in other projects rather than being developed to completion in a sandbox. In transitioning to stronger typing, most of the attention seems to have been spent on improving treatment of pointers and aggregate types (arrays, structs, etc).

There's a well known history of C, including design motivations, published by Dennis Ritchie in 1993: "The Development of the C Language", https://www.bell-labs.com/usr/dmr/www/chist.html

They were well aware of various other languages, the pros and cons of how they handled typing, and they actually had (and developed) quite strong opinions. See, for example, this 1981 note by Kernighan, "Why Pascal is Not My Favorite Programming Language", http://www.lysator.liu.se/c/bwk-on-pascal.html

And checkout this 1979, third-party comparison of C and Pascal by Prabhaker Mateti, "Pascal Versus C: A Subjective Comparison", https://link.springer.com/content/pdf/10.1007/3-540-09745-7_... Early on the author establishes a basic, still familiar measure: "One of the most important factors in choosing a language for a project should be the estimated debugging and maintenance costs." One of the points in fleshing that out is, "Permissive type checking should be outlawed." But see the two adjacent points in that section--"Simple things that could be done mechanically, without spending much thought, should be done by a program." and "It is dangerous to use our knowledge of the internal representation, as chosen by a compiler, of a data type."--and consider how they might relate to arithmetic conversions.


C has model of a machine where there's a bunch of ALUs that operate on homogeneous types of size >= int. So int x int -> int, uint x uint -> uint, etc. So an op first converts its arguments to a common type of the smallest necessary size, then sends them into the appropriate ALU.


Ada, the original "better C", similarly does not.


This is why I sometimes long for the good ole days of 6502 assembly where there was no data type, just the particular instructions you used. Or maybe it's because I was blissfully ignorant of these things back then...




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: