Why does the Arduino documentation never show types of return values of functions?

C is a strongly typed language. Implicit casting, particularly between signed and unsigned values, can cause all kinds of hard-to-debug problems in programs. Yet the Arduino documentation never shows return types.

Just as an example, SoftwareSerial::available() says:

Returns

The number of bytes available to read.

Great. So is this a signed value or an unsigned value? Is it a byte, 16 bits, 32 bits? Because the documentation is silent. These things matter.

It's so pervasive in the documentation I have to conclude it was a conscious choice. But why?

1 Like

Arduino is for beginners and I guess the documentation has been written with that in mind.

And FYI, it returns an int; as if you can have a negative number of bytes in the buffer :wink:

Some documentation is correct; e.g. documentation for print and write state that they return a size_t.

You can report the issue here: https://www.arduino.cc/en/contact-us. I've done so in the past and the documentation does get fixed.

That just doesn't make sense. How does a beginner benefit from having that hidden from him?

Strong typing is a really, really important concept in C. Imagine a beginner assuming that available() returns an unsigned value -- the documentation doesn't mention that it could return -1, after all. So they put it the return value into an unsigned variable. Then they check for it being greater than zero. When the return value is -1 their program is going to blow up.

There is a request for documenting the types in the Arduino Language Reference here:

Is the mentioned github issue the place where it should be reported? As an alternative to the "contact us".

Can somebody from the community (like me) correct it? If yes, how?

When it comes to C, it is not strongly typed. While it does have a static type system, it allows many implicit conversions between types, permits casting between incompatible types (including between pointers and integers), and offers mechanisms like unions and void* that bypass type safety. These features make it weakly typed compared to languages with stricter type enforcement.

So not really in C. C++ (which we use) is indeed more stringent but still pretty permissive.

For exemple Swift enforces strict type matching in arithmetic, so mixing types like Int and Float requires explicit conversion. It rejects implicit numeric promotions that C++ allows freely, where an int can automatically become a float or vice versa.

This strictness in Swift prevents unintended loss of precision, rounding errors, or logic bugs that can arise in C++ when implicit conversions silently change how values are interpreted or calculated.

2 Likes

FWIW, various code assistance features in the IDE show the signatures, based on the source. More reliable than documentation
image

For the ESP32 HTTPClient, a request stream can be merely temporarily empty; only when less-than-nothing is available (or the total-to-write len, if any, is satisfied) is it done

    // read all data from stream and send it to server
    while (connected() && (stream->available() > -1) && (len > 0 || len == -1)) {

      // get available data size
      int sizeAvailable = stream->available();

      if (sizeAvailable) {
1 Like

if you dig into the core for HardwareSerial on ESP32, available returns an int

int HardwareSerial::available(void) {
  return uartAvailable(_uart);
}

but really underneath uartAvailable() returns a size_t promoted to uint32_t (which is the same on ESP32)

uint32_t uartAvailable(uart_t *uart) {

  if (uart == NULL) {
    return 0;
  }

  UART_MUTEX_LOCK();
  size_t available;
  uart_get_buffered_data_len(uart->num, &available);
  if (uart->has_peek) {
    available++;
  }
  UART_MUTEX_UNLOCK();
  return available;
}

so weird stuff in the code... ( When a uint32_t value is implicitly converted to a 32-bit signed int , the bit pattern remains the same but the value is interpreted as signed. If the uint32_t value is greater than INT_MAX (2,147,483,647), the resulting int will be negative due to overflow in two's complement representation. This never happens due to the size of our buffers, but it's not great IMHO).

Generic C types are anything but strong.

Not all (char...) have a signdness and none has a strict byte count. That sloppyness lead to many weak standard functions with mixed up types (int instead of char...). And that weak typing had to be propagated into any new C version. Stronger types only have been introduced in header files which can be changed in any new version.

Can somebody explain what is so strong in C types?

variables must be declared with a type - it's a strong requirement :slight_smile:

(joke aside, agree with you)

1 Like

Nothing is perfect and I can say as a beginner these things were never an issue ( everything was 8 bits , so bytes were obvious )

Stuff has expanded rapidly since those times and we now have 16 and 32 bit processors , dual cores etc and maybe documentation has been left behind is some places.

In practice it’s not been an issue for me - if I’m not sure what a function returns , i try it and then I know , and different processors may respond differently and some functions designed at while back , not work at all .

It’s a rare issue anyway and you soon pick up any perceived “ vagueness “- but next week it may change !!

l don’t think Arduino is alone with this .

The thing is that when it’s not in the documentation then it can change as you say and if you took it for granted that things would be a certain way, then you might be in for a sometimes costly surprise…

I don't think so. The reason is the Arduino Language Reference system was recently reworked and that repository is no longer the source from which the content is generated. I'm not sure whether the documentation team monitors the previous repository so raising an issue may be fruitless.

The new repository where the source is hosted and developed is private, so there is no longer a public issue tracker where the community can check to see whether a given issue has already been reported.

Unfortunately it is no longer possible for the community to participate in the development of the Arduino Language Reference.

It's not like "knowing" that Serial.available() returns an "int" actually lets you know whether it's 16 or 32 bits, or ever returns a negative number... For a "typed" language, "int" is ... very vague.

True, there are better types like size_t or uint16_t or int_fast8_t in modern specs, but then you're starting to require a more "advanced" understanding of ... things. (*int_fast*_t types seem woefully underused, when considered objectively. Probably because it's "too much typing." :-1:

That doesn't mean that the documentation shouldn't say "returns an int"

1 Like

The exact byte count should be left to the machine library. That's the original idea behind those vague types.

At these days even the size of a byte could be anything between 5 to 12 bits, that's why "char" was the replacement type for a byte, and a 8-bit "byte" now is named "octet" in French language.

I really admire the Delphi "subrange" type, which gives the exact range of allowed values. The compiler allocates enough bytes for such a type and (optionally) checks for out-of-bounds errors in assignments. One obvious use is the index range of an array.

It's from original Pascal, isn't it?

1 Like

If Arduino wanted to position itself as a simplified subset of C++ -- which it seems to be trying to do -- one logical thing would be to enforce that the libraries, at least in their public interfaces, use a simplified and greatly reduced set of types. I'd rather conceal from the programmer what the size of an int is than what functions return.

My IDE (Windows) doesn't show the signatures, just the function names.

You can see the signature in the Arduino IDE 2.x hover:

I have 2.3.6 for Windows and don't get that hover.