Wire.cpp implementation question

Hello, I noticed these lines in Wire.cpp file:

uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, uint8_t sendStop) {
	return requestFrom((uint8_t)address, (uint8_t)quantity, (uint32_t)0, (uint8_t)0, (uint8_t)sendStop);
}

uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity)
{
  return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)true);
}

uint8_t TwoWire::requestFrom(int address, int quantity)
{
  return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)true);
}

uint8_t TwoWire::requestFrom(int address, int quantity, int sendStop)
{
  return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)sendStop);
}

If I get it right, the requestFrom function can be called with different parameters and it will always be transformed to a valid call?

requestFrom((uint8_t)address, (uint8_t)quantity, (uint32_t)0, (uint8_t)0, (uint8_t)sendStop);

So based on these four types of requestFrom calls, no matter what, the first parameter will always be the address and the second will be quantity regardless of the type of the passed variable? (it will always be casted to uint8_t)

Yes, to the extent that the compiler can interpret the passed variables as matching the parameters in one of those overload function signatures. It would not be successful if you tried passing it a String object for example.

What are the overload function signatures in this example exactly? :slight_smile:

So if I write:

Wire.requestFrom(0x50, 1);

It becomes:

Wire.requestFrom((uint8_t)0x50, (uint8_t)1, (uint8_t)true);

Then it finally becomes the "full call":

requestFrom((uint8_t)0x50, (uint8_t)1, (uint32_t)0, (uint8_t)0, (uint8_t)true);

This will happen during compile, right?

you've listed them in your first post.

there are a limited number of ways -- # of parameters and parameter types, that requestFrom() can be called which is then translates into a "full" function call.

while the compiler could optimize this at compile time, there's no need. there would simply be a nested set of calls

Wire.cpp for the AVR boards (Uno, Mega) : https://github.com/arduino/ArduinoCore-avr/blob/master/libraries/Wire/src/Wire.cpp.

The "full call" is undocumented yet, but it can be used. It sets a starting register address and reads data. Some processors can do that in hardware.

It would be nice if the class or compiler would solve any combination of 'int', 'byte' and 'unsigned int', but according to Wire.h it is limited to these:

int8_t requestFrom(uint8_t, uint8_t);
uint8_t requestFrom(uint8_t, uint8_t, uint8_t);
uint8_t requestFrom(uint8_t, uint8_t, uint32_t, uint8_t, uint8_t);
uint8_t requestFrom(int, int);
uint8_t requestFrom(int, int, int);

Sometimes I see these constructions:

Wire.requestFrom( static_cast<uint8_t>(address), static_cast<uint8_t>(2), static_cast<uint8_t>(false));

Some think that the more complex the source code is, the better it must be. I think that is terribly ugly.

Doesn’t every overloaded function have its own code body, and so woukd simply be called directly?

There is no requirement that overloaded functions share anything. Except the function name.

One of the things that alarm me about C++ is the potential for writing overloaded things that completely ignore and subvert the ability to do really bad things… overload ‘+’ so it subtracts, write overload functions that do completely different thing called with ints vs doubles, &c.

a7

wouldn't that be redundant and consume more memory?

i've written code where a function needs s new argument. in order to maintain compatibility, the body of the old function is copied to a new function, possibly with overloaded arguments and the old function calls the new function with an additional hardcoded argument.

assume this isn't so uncommon and is why it's supported in c++ (must be other languages as well)

Yes. The function bodies can be completely different. Different overloads don't call each other or wrap a call to a "master" version .... unless of course that's what the coder implements.