Path: csiph.com!eternal-september.org!reader02.eternal-september.org!.POSTED!not-for-mail From: Tim Rentsch Newsgroups: comp.lang.c++ Subject: Re: This code is effective for modest-sized numbers, but can you tell what it does? Date: Sat, 04 Jun 2022 07:57:04 -0700 Organization: A noiseless patient Spider Lines: 81 Message-ID: <864k101npb.fsf@linuxsc.com> References: <0c3601f0-fc8c-4bb9-a8b3-598ea1ca4a79n@googlegroups.com> <86fsm18i1c.fsf@linuxsc.com> <86mtfp4gjw.fsf@linuxsc.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Injection-Info: reader02.eternal-september.org; posting-host="55f2d0e912e24ddeae6d6d333543dfff"; logging-data="1621"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1+HrzwXiock0N3z2l5StqY6a/ZKpRSFmTc=" User-Agent: Gnus/5.11 (Gnus v5.11) Emacs/22.4 (gnu/linux) Cancel-Lock: sha1:JDy55LrQNaqvCllDqBiaP4Q3X+E= sha1:15nsgXeERq5RnTgSszz7ym8giUg= Xref: csiph.com comp.lang.c++:84531 Paavo Helde writes: > 10.05.2022 17:18 Tim Rentsch kirjutas: > >> Paavo Helde writes: >> >>> So, in order to not lose these useful warnings in the avalanche of >>> non-useful ones, one should use matching types in such simple code, >>> it does not cost anything. >> >> That seems plainly false. Any change that incurs some programming >> effort and disturbs what code is written obviously costs something. >> A claim could be made that the cost is worth the benefit, but >> clearly the cost is greater than zero. > > One can argue that it's using of mismatching types in a comparison > which means non-zero programming effort. That contrast is different than what I was talking about, but let me respond to your comments here. > If the types used in a comparison are of different types and > especially of different signedness, the programmer needs to know the > promotion rules which might depend on the operand sizes, which in > turn might depend on the platform/implementation. This is an overstatement. Comparing two signed types, or two unsigned types, is always safe, regardless of the widths of the types involved. It's only when one type is signed and the other type is unsigned, and the unsigned type is "larger" than int, that there is even just possibly a problem; for example, comparing a signed type against an unsigned char, or unsigned short, or unsigned bit-field whose width is less than the width of unsigned int, will never give a result different than what the unconverted values would indicate. > The programmer needs to think through what happens when the signed > operand becomes negative. Is it possible and what happens then? These questions do need to be considered but that doesn't mean they are difficult necessarily. If we see a code fragment like int a[] = { ... }; for( Index i = 0; i < sizeof a / sizeof a[0]; i++ ){ ... } it's immediately obvious that the value in 'i' is non-negative, no matter whether the type Index is signed or unsigned. Almost no mental effort is needed. > Even more to the point, when a maintenance programmer comes around > and sees the code, they have to think it through again, every time. > Why are incompatible types used in comparison? Was it an oversight > and is it possible it might cause problems? This observation doesn't change the argument. Any factors needing consideration for the original developer still need consideration for maintenance work. The same kind of response applies. > I will see that as a significant programming effort. YMMV. No one is saying that there is no programming effort involved. Whether the effort is _significant_ in each case is a different question. Furthermore, the comments you make are looking at only one side of the equation. It isn't always practicable to choose the two types involved so that they must be the same; for example, one type could be dictated by the type of a third party function interface, and the other type could be dictated by language semantics (subtracting one pointer from another gives a signed type, but sizeof gives an unsigned type). Even when it is feasible to give the two types the same signedness, doing that may entail other tradeoffs that have their own costs. For example, if a parameter 'n' has an unsigned type, we know that it has a non-negative value. Changing the type of 'n' to be a signed type would mean either more code in the function to accommodate a possible negative value of 'n', or more mental effort during development or maintenance to consider whether such code is needed, etc (and quite possibly both). A proposed rule that comparands should /always/ have the same signedness tacitly assumes that this factor always outweighs all other factors. That assumption simply isn't right: sometimes it does, but sometimes it doesn't.