Go Down

Topic: Advice needed :How to avoid duplicate code? (Read 222 times) previous topic - next topic

Watcher

Hi all,

I am trying to avoid writing code for the same thing twice. For example consider:

Code: [Select]

   Serial.print ("Free RAM: ");Serial.print (freeRam());
   Serial.print ("IP Address : ");PrintIPAddress(IP);
   Serial.print ("Subnet Mask : ");PrintIPAddress(subnet);
   Serial.print ("Gateway ");PrintIPAddress(gateway);
   Serial.print ("Dns : ");PrintIPAddress(DNS);

and :

   client.print ("Free RAM: ");client.print (freeRam());
   client.print ("IP Address : ");PrintIPAddress(IP);
   client.print ("Subnet Mask : ");PrintIPAddress(subnet);
   client.print ("Gateway ");PrintIPAddress(gateway);
   client.print ("Dns : ");PrintIPAddress(DNS);



Is there a way of avoiding writing two separate functions for the above? In other words is it possible to re-direct the output from Serial to client without adding more code for the same functionality?

Thanks for your help..

Ps991

#1
Jun 27, 2015, 11:30 am Last Edit: Jun 27, 2015, 11:32 am by Ps991
First of all...how does PrintIPAddress know to print through serial or client?

just make 2 functions for each of those and call the functions instead...
If you can't write your program in plain english where anyone could understand it then you have no hope of writing code for it.  -Delta_G

Watcher

Quote
First of all...how does PrintIPAddress know to print through serial or client?
For now PrintIPAddress  only prints through Serial. I am looking at  ways to make it also print through client without writing an entirely separate function. The same applies for other functions as well. The above is only an example.


Ps991

#3
Jun 27, 2015, 11:42 am Last Edit: Jun 27, 2015, 11:43 am by Ps991
The only way I can think of doing that would be to make a function with a type of parameter, but the object types would need to be the same, but they are not...so you would need a new class, but from here it gets completely pointless...so I got nothing...
If you can't write your program in plain english where anyone could understand it then you have no hope of writing code for it.  -Delta_G

Watcher

I was also thinking that  maybe I could pass a parameter to a function which would somehow determine where the output goes. But then couldn't figure out how to actually do it from there.

Thanks for your help anyhow :)


PaulMurrayCbr

#5
Jun 27, 2015, 12:16 pm Last Edit: Jun 27, 2015, 12:18 pm by PaulMurrayCbr
In C++, you would do this using a polymorphic class:


Code: [Select]

class PrintThing {
  public:
    virtual void prints(char *);
    virtual void printi(int);

    void info() {
      prints ("Free RAM: ");
      printi(1);
      prints ("IP Address : ");
      printi(2);
      prints ("Subnet Mask : ");
      printi(3);
      prints ("Gateway ");
      printi(4);
      prints ("Dns : ");
      printi(5);
    }

};

class PrintToSerial : public PrintThing {
    void prints(char *s) {
      Serial.print(s);
    }
    void printi(int i) {
      Serial.print(i);
    }
} printToSerial;

class PrintToClient : public PrintThing {
    void prints(char *s) {
      /* implementation of client.prints */
    }
    void printi(int i) {
      /* implementation of client,printi */
    }
} printToClient;

void someFunction() {
  printToSerial.info();
  // or
  printToClient.info();

  // or choose a printer based on a boolean value

  PrintThing *thePrinter;
  if (1 > 2) {
    thePrinter = &printToSerial;
  }
  else {
    thePrinter = &printToClient;
  }

  thePrinter->info();
  thePrinter->prints("\n ==== END OF PRINTING ===\n");

}


Your client printer probably needs to take a "client" pointer in its constructor, and to save that value in a class variable.


guix

#6
Jun 27, 2015, 12:42 pm Last Edit: Jun 27, 2015, 01:52 pm by guix
Maybe something like this
Code: [Select]

const Stream * streams[] = { &Serial, &client };

...
template <typename T> void printToStreams( T val );
template <typename T> void printToStreams( T val )
{
  Stream * stream;
   
  for ( uint8_t i = 0; i < sizeof( streams ) / sizeof( Stream * ); i++)
  {
    stream = (Stream *) streams[i];
    stream->println( val );
  }
}

...

printToStreams( "Free RAM: " );
printToStreams( freeRam() );
...


Watcher


christop

You guys are over-complicating this. Both HardwareSerial and EthernetClient extend the Print class, which has the print and println methods. Just make your functions take a reference to an instance of the Print class.

Watcher


christop

#10
Jun 27, 2015, 10:36 pm Last Edit: Jun 27, 2015, 10:38 pm by christop
I'm on my phone so I can't test this example, but it should look something like this:
Code: [Select]

void printIt(Print& p)
{
    p.println("whatever");
}


Edit to add:

Then call it like this:
Code: [Select]
printIt(Serial);
printIt(client);

Watcher


Watcher

Success! Works perfect christop. Simple and easy.!

Thanks a lot!

Go Up