Other than that, Nimrod has been a pleasure to use. If you need a metaprogramming language to generate C, use Nimrod.
Other than that, Nimrod has been a pleasure to use. If you need a metaprogramming language to generate C, use Nimrod.
It's quite common to end up needing to use both signed and unsigned types in the same expression and to end up invoking undefined behaviour trying to protect yourself. C overflow semantics (i.e. undefined) in particular.
Signed types should be the default, and overflow should be defined as wrapping two's complement. There's very good reasons why C# and Java chose these defaults.
The places where unsigned numbers are justified are incredibly rare: bitwise operations, and working with >2GB heap sizes on 32-bit machines. That's about it. In almost every other circumstance, using a signed type (the next size up if the range is inadequate) is better.
Especially pernicious is using something like size_t for things like container entry counts. It's very common to add and subtract with container counts, and very easy to end up inadvertently wrapping or mixing with signed types in common container algorithms.
PS: my experience was deeply coloured while working on the Delphi RTL, making it overflow safe. It was not trivial.
PPS: it was revealing that the comments on the article arguing in favour of unsigned types repeatedly made programming errors and invoked undefined behaviour. That's because unsigned types are misunderstood and misused.
I take it you do not work with bare metal at all.
Most general purpose programming languages don't have features specific for web-programming imported by default.
Nimrod supports bare metal programming just as fine as C. You just have to import the relevant modules, just as you'd import the URL module if you were writing a web-server.
Nimrod aims at being approachable to some of the Python/Ruby crowd as well, who are used to numbers that are always signed and can't overflow. Defaulting to the biggest available signed integers, and discouraging library writers from throwing unsigned integers at you for no reason is a decent compromise.
Fourth case - situations in which you have a scalar quantity, and do not care about positive or negative.
Overflow is a separate issue and you must either make sure you either know the range of the data and pick an appropriately sized storage type, or explicitly check for overflows.
This is actually where you have to be really careful, because there can be corner cases surrounding zero. E.g.:
for (i=len-1; i>=0; i--) { ... }
Yes, either ints or unsigned numbers can overflow, but underflowing a natural number is much more common.Don't take my word for it, ask Bjarne Stroustrup or Chandler Carruth: http://stackoverflow.com/questions/18795453/why-prefer-signe...
I read that page, or at least some of it, it mostly seemed to be opinion rather than solid reason.
No. The code is correct in that regard if you use int for i and len. Having to check len is an artifact of using unsigned.
> I read that page, or at least some of it, it mostly seemed to be opinion rather than solid reason.
I'm not talking about the comments. I'm talking about what Bjarne Stroustrup (the designer of C++) and Chandler Carruth (Google's LLVM lead) are saying in the video (and which is summarized in the top comment).
I did not watch the video, no time right now. The top comment tells us what they think, not why.
Even iteration is not always over containers or some other structure in a way where the boundaries can be inferred and do not have to be computed, and not always in an order that is implemented by an iterator (for example, some in-place sorting algorithms).
for i := 0 to len-1 do begin ... end
This is counting up, not counting down, and len-1 is still going to be either 2^k-1 or result in an error when you're using unsigned integers.While loops also don't fix it (not to mention that they have their own problem, such as forgetting or misplacing the iteration step). The primary issue is that len-1 is underflowing. Yes, you can avoid calculating len-1, but by that token, no error is ever a problem, because they can all be avoided with enough diligence and foresight. In that universe, Heartbleed never happened and the Ariane 5 never blew up. It is, however, not the world we live in.
This is also a non-issue in C++ as you have iterators and counting loops are easy to abstract away using counting iterators or <algorithm> style functions.
I just started working on this kind of application (well, USB protocols, but same issues) in Nimrod.
First of all: just do "import unsigned" and you can work with unsigned just fine. I don't see why this is an issue, any more than that you have to do "import libusb".
Second: I found that, knowing that unsigned types are a second-class citizen lead me towards writing a much better library. It encourages you to expose only signed integers to the next level up in the app. The next thing I realized is that this will very quickly cause Nimrod programmers to write and adopt a "Protocol Buffers"-like library for dealing with network protocols, binary files and similar things. And that will be a much better solution than dealing with things like unsigned integers and endianess in manual code.
I don't really see how unsigned are that much of a problem that they have to be dealt with specially...
What do you mean by that? Don't you think that having to do "import unsigned" before they use unsigned types, make some people think twice? Don't you think a few people might think "Do I really understand this feature? Should I perhaps read the documentation for this module?"
More importantly though, not having unsigned types, as in Java, means that we have to use 16-bit int to store a byte, 32-bit int to store a 16-bit unsiged etc.
Btw, if you check any C code, you'll notice that is vast majority of cases negative values of int are actually invalid from the business logic point of view.
..., not having unsigned types, as in Java, ...
Unsinged integer exist in Nimrod, you just have to import unsigned
when you use them.