It is up to a compiler to choose what type has precedence. This is a choice whereby the one is not better than the other. The problem arises with higher level languages that programmers think in human terms rather than computer terms. It is a nice attempt to raise the computer to the level of humans, but it will never work. Therefore, programmers should know at least in basic terms how computers operate. It would save them many questions regarding the output of certain computations, both integer and real.
This is completely wrong. You need to know what the specification of your language says, not how you think the computer operates. Case in point c/c++. What do you think does this code do:
for (int i=1; i>0; i++) ...
It's UB, because the type int in C is defined that it can at least have values between -2^15-1 to 2^15-1. It does not state if it can overflow, how it overflows, what internal representation is used, etc. It could be internally implemented as a struct with a bool for the sign and a 43 bit Integer. It could be implemented using 80 bit float, 1 complement or 2 complement or sign and magnitude Integers, or even with unicorn farts. Fact of the matter is, you as programmer do not know how it will be executed afterwards, except for whats written in the specification. In fact if you write code like this the optimizer can detect that this is UB and make it to:
Because overflow is not defined, and by adding a number will never get smaller.
This is by design, because sure on x86_64 CPU's the best way to implement it is using the 2nd complement number representation supported by the ALU, but C is a high level language that should work on any CPU not only x86.
When using a high level language it's your job to write code for the compiler, and it's the job of the compiler to make it into a running program according to it's specification. If you start assuming how the computer will process it internally, you are writing broken code, because then it is highly likely that it will not work on any other machine. Sure some time this is neccessary, for example when writing really low level code, and sometimes it's also a fun exercise to optimize a program like this, but in general, if you assume things about the underlying execution, you write broken code.
For example, the Apollo guidance computer used in the Saturn V rocked during all of the apollo missions had 3 different number types, 15 bit one complement integers, 30 bit fixpoint integers with 2 sign bits (yeah thats really fucked up ) and 33 bit unsigned integers. A high level language should be able to compile for such a target without any changes to the code.
Thats the case with ISO C++. If you write your code only using ISO-C++ it will work on any machine using any compiler that supports ISO-C++.
So I would challange the Idea that a programmer should need to know about how a computer internally works, while it is helpful and most certainly interesting, this knowledge has nothing to do when using a higher level language. If you assume things about how it will work after the compilation you constrain the possibilities of the compiler and optimizer and you will most certainly write broken code.
PS: This example with int is btw. not true anymorefor C++20, as they now finally standardized 2 complement number representation. Before that C++ contained std::int32 which standardized the exact width (32 bit, not just at least 16 like int) and the use of 2 complement. However in C this is still UB and if you have code that relies on the exact width or overflow of int you simply wrote broken code