The signature of the proc is
proc `+`[T: SomeInteger](x, y: T): T
T is bound to uint32 in the first case, and we can convert uint16 to uint32 losslessly. In the second case, T is bound to uint16 and we can't convert uint32 to uint16 losslessly.
there is module in standard library: lenientops.
it should help
you can define your own + operator for your case
proc `+`(x: uint16, y: uint32): uint32 = x.uint32 + y
But then the definition then become tedious if you have to define another with
proc `+`(x: uint32, y: uint64): uint64 = x.uint64 + y
again and again. So the + is defined as generic. Since generic doesn't know which type should it bind to, so it's logical choice to bind to first argument.
I'd also add to @mashingan answer than Nim is a strongly typed language. Lossless conversion are made explicit for safety reason, we don't want you to lose information or data by something done under-the-hood and very time-consuming to debug.
Other strongly typed languages might just plain prevent you from promoting uint16 to uint32 implicitly.
@mashingan >tldr; if the size of integer is important, always opt to explicit conversion That seems to be very good advice. I was considering defining my own operators, but it seems like the first option is the most sensible.
@mratsim I had never actually considered C to be a 'weakly typed' language. There seem to be various opinions on that particular subject both for and against. I can see what you are saying though, C is definitely more weakly typed than Nim, and I had not considered the differences in philosophy.
Thanks again everyone for your advice.
I had never actually considered C to be a 'weakly typed' language. There seem to be various opinions on that particular subject both for and against.
There is far less debate about whether C is weakly typed than there is about what the term means. I used the language for 40 years and served on the C language standards committee and I've never seen any sign of a debate on this issue -- no one has ever called C strongly typed. I could point to printf and casting of pointers to other pointer types (or to and from void* without even needing a cast) or even to integers (when I started using C you didn't even need a cast) as glaring examples.