[Ns-developers] Ipv4Address and Ipv4Mask, getting rid of "implicit" constructors

Gustavo Carneiro gjcarneiro at gmail.com
Wed May 14 04:54:18 PDT 2008


2008/5/14 <craigdo at ee.washington.edu>:

>
> > > I would like to make all these constructors "explicit",
> > thus you have to
> > > type Ipv4Address ("1.2.3.4") instead of "1.2.3.4".
> > >
> > > Comments?
> >
> > +1: avoids many implicit conversion traps.
>
> It's a lot of "extra" typing for manual address assignment, but now that
> we
> have automagic IP address generation in place I don't see it as being a
> huge
> nuisance.


Extra typing  but comes with extra readability.


> Of course, the tutorial uses this as an example of how type implicit type
> conversion works, so it's my turn to have the same reaction as Gustavo
> about
> API changes.  Every time we make a change like this it obsoletes large
> sections of documentation.  I suppose we could change the implicit type
> section to talk about node helpers, but it's more work.


Sorry.  I do hate API changes.  OTOH this would be really a minor change
compared to others we have seen... :-)

So, this is one argument against the change.


> What kind of traps are you trying to avoid?  Can you give me an
> illustration
> of what would be a plausible scenario that would be avoided?


My main gripe is that I do not expect automatic conversion and associated
compilation error messages always baffle me for a couple of minutes.  Maybe
it's because I'm no C++ guru that I don't expect this, I don't know.

Last time I saw this I was passing uint32_t to a function expecting
Ipv4Address[1] and it gave me such a strange error message.

Now I can also show an example of disabling builtin C++ type checking:

void CreateNode (const char *name, Ipv4Address mainAddress);

You could accidentally call it like this:

CreateNode ("10.0.0.1", "MobileTerminal");

It would compile perfectly and only fail in runtime (mysteriously if
Ipv4Address does poor parsing job).

Or:
   void AddInterface (Ipv4Address mainAddress, Ipv4Address mask);

   AddInterface ("255.255.0.0", "10.0.0.1");

The last example I can think of is problems with overloaded functions or
methods.  See for example:

------------------------------------------------------------------------------
#include <iostream>

class Ipv4Address
{
public:
  Ipv4Address (const char *addrString) {}
};

class Ipv4Mask
{
public:
  Ipv4Mask (const char *maskString) {}
};


void DoSomethingWithAddress (Ipv4Address addr)
{
  std::cout << __PRETTY_FUNCTION__ << std::endl;
}

void DoSomethingWithMask (Ipv4Mask addr)
{
  std::cout << __PRETTY_FUNCTION__ << std::endl;
}

void DoSomething (Ipv4Address addr)
{
  std::cout << __PRETTY_FUNCTION__ << std::endl;
}

int main ()
{
  DoSomethingWithAddress ("1.2.3.4");
  DoSomethingWithMask ("1.2.3.4");
  DoSomething ("1.2.3.4");

  return 0;
}
------------------------------------------------------------------------------

Suppose that main is the user code, and everything else is the NS-3
library.  The user code compiles fine.

Now suppose a new NS-3 release adds an overloaded method:

void DoSomething (Ipv4Mask addr)
{
  std::cout << __PRETTY_FUNCTION__ << std::endl;
}

Suddenly, and confusingly, the program stops compiling:

test1.cc: In function 'int main()':
test1.cc:40: error: call of overloaded 'DoSomething(const char [8])' is
ambiguous
test1.cc:26: note: candidates are: void DoSomething(Ipv4Address)
test1.cc:31: note:                 void DoSomething(Ipv4Mask)


[1] I had already disabled the implicit constructor from uint32_t because I
was bitten by lack of type checking before due to this implicit conversion.

-- 
Gustavo J. A. M. Carneiro
INESC Porto, Telecommunications and Multimedia Unit
"The universe is always one step beyond logic." -- Frank Herbert


More information about the Ns-developers mailing list