Sunday, 22 March 2015

Overloading of Binary operators with the example

Overloading of Binary operators with the example:

If we want to use binary operators very frequently like addition (+) operator, subtraction (-) operator and division (/) operator. Following example explains how addition (+) operator can be overloaded. Similar way, you can overload subtraction (-) and division (/) operators. Again, both global versions and member function versions are shown.

Let us see the below example:
#include "stdafx.h"
#include <iostream> #include <fstream> #include <string> using namespace std; class TestBinaryOperator { long iVal; public:   TestBinaryOperator(long lVal = 0) : iVal (lVal) {}   /* The below Operators are used to create new, modified valu*/   friend const TestBinaryOperator operator+  (const TestBinaryOperator& ocLeft, const TestBinaryOperator& ocRight);   friend const TestBinaryOperator operator-  (const TestBinaryOperator& ocLeft, const TestBinaryOperator& ocRight);   friend const TestBinaryOperator operator*  (const TestBinaryOperator& ocLeft, const TestBinaryOperator& ocRight);   friend const TestBinaryOperator operator/  (const TestBinaryOperator& ocLeft, const TestBinaryOperator& ocRight);   friend const TestBinaryOperator operator%  (const TestBinaryOperator& ocLeft, const TestBinaryOperator& ocRight);   friend const TestBinaryOperator operator^  (const TestBinaryOperator& ocLeft, const TestBinaryOperator& ocRight);   friend const TestBinaryOperator operator&  (const TestBinaryOperator& ocLeft, const TestBinaryOperator& ocRight);   friend const TestBinaryOperator operator|  (const TestBinaryOperator& ocLeft, const TestBinaryOperator& ocRight);   friend const TestBinaryOperator operator<< (const TestBinaryOperator& ocLeft, const TestBinaryOperator& ocRight);   friend const TestBinaryOperator operator>> (const TestBinaryOperator& ocLeft, const TestBinaryOperator& ocRight);   /* Assignment operators that modify & return lvalue  */   friend TestBinaryOperator& operator+= (TestBinaryOperator& ocLeft, const TestBinaryOperator& ocRight);   friend TestBinaryOperator& operator-= (TestBinaryOperator& ocLeft, const TestBinaryOperator& ocRight);   friend TestBinaryOperator& operator*= (TestBinaryOperator& ocLeft, const TestBinaryOperator& ocRight);   friend TestBinaryOperator& operator/= (TestBinaryOperator& ocLeft, const TestBinaryOperator& ocRight);   friend TestBinaryOperator& operator%= (TestBinaryOperator& ocLeft, const TestBinaryOperator& ocRight);   friend TestBinaryOperator& operator^= (TestBinaryOperator& ocLeft, const TestBinaryOperator& ocRight);   friend TestBinaryOperator& operator&= (TestBinaryOperator& ocLeft, const TestBinaryOperator& ocRight);   friend TestBinaryOperator& operator|= (TestBinaryOperator& ocLeft, const TestBinaryOperator& ocRight);   friend TestBinaryOperator& operator>>=(TestBinaryOperator& ocLeft, const TestBinaryOperator& ocRight);   friend TestBinaryOperator& operator<<=(TestBinaryOperator& ocLeft, const TestBinaryOperator& ocRight);   /* The below are the conditional operators return true/false */   friend int operator== (const TestBinaryOperator& ocLeft, const TestBinaryOperator& ocRight);   friend int operator!= (const TestBinaryOperator& ocLeft, const TestBinaryOperator& ocRight);   friend int operator<  (const TestBinaryOperator& ocLeft, const TestBinaryOperator& ocRight);   friend int operator>  (const TestBinaryOperator& ocLeft, const TestBinaryOperator& ocRight);   friend int operator<= (const TestBinaryOperator& ocLeft, const TestBinaryOperator& ocRight);   friend int operator>= (const TestBinaryOperator& ocLeft, const TestBinaryOperator& ocRight);   friend int operator&& (const TestBinaryOperator& ocLeft, const TestBinaryOperator& ocRight);   friend int operator|| (const TestBinaryOperator& ocLeft, const TestBinaryOperator& ocRight);   /* The below function is used to Write contents to an ostream: */   void Write2Stream (std::ostream& os) const { os << iVal; } };
Implemetation of the above functions that are decalred in  the TestBinaryOperator header file.
   The below Operators are used to create new, modified value
const TestBinaryOperator operator+ (const TestBinaryOperator& ocLeft, const TestBinaryOperator& ocRight)

  { return TestBinaryOperator(ocLeft.iVal + ocRight.iVal); }

const TestBinaryOperator operator-(const TestBinaryOperator& ocLeft, const TestBinaryOperator& ocRight)

  { return TestBinaryOperator(ocLeft.iVal - ocRight.iVal); }

const TestBinaryOperator operator*(const TestBinaryOperator& ocLeft, const TestBinaryOperator& ocRight)

  { return TestBinaryOperator(ocLeft.iVal * ocRight.iVal); }

const TestBinaryOperator operator/(const TestBinaryOperator& ocLeft, const TestBinaryOperator& ocRight)

  { return TestBinaryOperator(ocLeft.iVal / ocRight.iVal); }

const TestBinaryOperator operator%(const TestBinaryOperator& ocLeft, const TestBinaryOperator& ocRight)

  { return TestBinaryOperator(ocLeft.iVal % ocRight.iVal); }

const TestBinaryOperator operator^(const TestBinaryOperator& ocLeft, const TestBinaryOperator& ocRight)

  { return TestBinaryOperator(ocLeft.iVal ^ ocRight.iVal); }

const TestBinaryOperator operator&(const TestBinaryOperator& ocLeft, const TestBinaryOperator& ocRight)

  { return TestBinaryOperator(ocLeft.iVal & ocRight.iVal);  }

const TestBinaryOperator operator|(const TestBinaryOperator& ocLeft, const TestBinaryOperator& ocRight)

  { return TestBinaryOperator(ocLeft.iVal | ocRight.iVal); }

const TestBinaryOperator operator<< (const TestBinaryOperator& ocLeft, const TestBinaryOperator& ocRight)

  { return TestBinaryOperator (ocLeft.iVal << ocRight.iVal); }

const TestBinaryOperator operator>> (const TestBinaryOperator& ocLeft, const TestBinaryOperator& ocRight)

  { return TestBinaryOperator (ocLeft.iVal >> ocRight.iVal); }


The below are the Assignments modify & return lvalue:
TestBinaryOperator& operator+= (TestBinaryOperator& ocLeft, const TestBinaryOperator& ocRight)

{

  if (&ocLeft == &ocRight) {/*    */}

  ocLeft.iVal += ocRight.iVal;

  return ocLeft;
}

TestBinaryOperator& operator-= (TestBinaryOperator& ocLeft, const TestBinaryOperator& ocRight)

{

  if(&ocLeft == &ocRight) { }

  ocLeft.iVal -= ocRight.iVal;

  return ocLeft;

}

TestBinaryOperator& operator*= (TestBinaryOperator& ocLeft, const TestBinaryOperator& ocRight)

{

  if (&ocLeft == &ocRight) { }

  ocLeft.iVal *= ocRight.iVal;

  return ocLeft;

}

TestBinaryOperator& operator/=(TestBinaryOperator& ocLeft, const TestBinaryOperator& ocRight)

{

  if(&ocLeft == &ocRight) { }

  ocLeft.iVal /= ocRight.iVal;

  return ocLeft;

}

TestBinaryOperator& operator%=(TestBinaryOperator& ocLeft, const TestBinaryOperator& ocRight)

{

  if (&ocLeft == &ocRight) { }

  ocLeft.iVal %= ocRight.iVal;

  return ocLeft;

}

TestBinaryOperator& operator^=(TestBinaryOperator& ocLeft, const TestBinaryOperator& ocRight)

{

  if(&ocLeft == &ocRight) { }

  ocLeft.iVal ^= ocRight.iVal;

  return ocLeft;

}

TestBinaryOperator& operator&=(TestBinaryOperator& ocLeft, const TestBinaryOperator& ocRight)

{

  if(&ocLeft == &ocRight) { }

  ocLeft.iVal &= ocRight.iVal;

  return ocLeft;

}

TestBinaryOperator& operator|=(TestBinaryOperator& ocLeft, const TestBinaryOperator& ocRight)

{

  if(&ocLeft == &ocRight) { } 

  ocLeft.iVal |= ocRight.iVal;

  return ocLeft;

}

TestBinaryOperator& operator>>=(TestBinaryOperator& ocLeft, const TestBinaryOperator& ocRight)

{

  if(&ocLeft == &ocRight) { }

  ocLeft.iVal >>= ocRight.iVal;

  return ocLeft;

}

TestBinaryOperator& operator<<=(TestBinaryOperator& ocLeft, const TestBinaryOperator& ocRight)

{

  if(&ocLeft == &ocRight) { }

  ocLeft.iVal <<= ocRight.iVal;

  return ocLeft;

}


The below are Conditional operators return true/false and their implementation
int operator==(const TestBinaryOperator& ocLeft, const TestBinaryOperator& ocRight)

  { return ocLeft.iVal == ocRight.iVal; }
int operator!=(const TestBinaryOperator& ocLeft, const TestBinaryOperator& ocRight)

  { return ocLeft.iVal != ocRight.iVal; }

int operator<(const TestBinaryOperator& ocLeft, const TestBinaryOperator& ocRight)

  { return ocLeft.iVal < ocRight.iVal; }

int operator>(const TestBinaryOperator& ocLeft, const TestBinaryOperator& ocRight)

  { return ocLeft.iVal > ocRight.iVal; }

int operator<=(const TestBinaryOperator& ocLeft, const TestBinaryOperator& ocRight)

  { return ocLeft.iVal <= ocRight.iVal; }

int operator>=(const TestBinaryOperator& ocLeft, const TestBinaryOperator& ocRight)

  { return ocLeft.iVal >= ocRight.iVal; }

int operator&&(const TestBinaryOperator& ocLeft, const TestBinaryOperator& ocRight)

  { return ocLeft.iVal && ocRight.iVal; }

int operator||(const TestBinaryOperator& ocLeft, const TestBinaryOperator& ocRight)

  { return ocLeft.iVal || ocRight.iVal; }


ofstream out ("TestBinaryOperator.out");


Test function to test the binary operators
void  MyBinaryTestFun (TestBinaryOperator&  ocObj1, TestBinaryOperator&  ocObj2) {

  // A complex expressions:

 ocObj1 +=  ocObj1 *  ocObj2 +  ocObj2 %  ocObj1;

#define TESTFUN(OP) \

out << " ocObj1 = ";  ocObj1.Write2Stream (out); \

out << ",  ocObj2 = ";  ocObj2.Write2Stream (out); \

out << ";  ocObj1 " #OP "  ocObj2 produces "; \

( ocObj1 OP  ocObj2).Write2Stream (out); \

out << endl;

TESTFUN (+) TESTFUN(-) TESTFUN(*) TESTFUN(/)

TESTFUN (%) TESTFUN(^) TESTFUN(&) TESTFUN(|)

TESTFUN (<<) TESTFUN(>>) TESTFUN(+=) TESTFUN(-=)

TESTFUN (*=) TESTFUN(/=) TESTFUN(%=) TESTFUN(^=)

TESTFUN (&=) TESTFUN(|=) TESTFUN(>>=) TESTFUN(<<=)

// Conditionals expessions:

#define TESTCONDIIONAL(OP) \

out << " ocObj1 = ";  ocObj1.Write2Stream (out); \

out << ",  ocObj2 = ";  ocObj2.Write2Stream (out); \

out << ";  ocObj1 " #OP "  ocObj2 produces "; \

out << ( ocObj1 OP  ocObj2); \

out << endl;


TESTCONDIIONAL(<) TESTCONDIIONAL(>) TESTCONDIIONAL(==) TESTCONDIIONAL(!=) TESTCONDIIONAL(<=)

TESTCONDIIONAL(>=) TESTCONDIIONAL(&&) TESTCONDIIONAL(||)

}


Testing the code from main
int main ()

{

  cout << "friend functions" << endl;

  TestBinaryOperator  ocObj1(47),  ocObj2(9);

  MyBinaryTestFun (ocObj1,  ocObj2);

  getchar ();

  return 0;

}

The output of the above program is
ocObj1 = 479,  ocObj2 = 9;  ocObj1 +  ocObj2 produces 488

 ocObj1 = 479,  ocObj2 = 9;  ocObj1 -  ocObj2 produces 470

 ocObj1 = 479,  ocObj2 = 9;  ocObj1 *  ocObj2 produces 4311

 ocObj1 = 479,  ocObj2 = 9;  ocObj1 /  ocObj2 produces 53

 ocObj1 = 479,  ocObj2 = 9;  ocObj1 %  ocObj2 produces 2

 ocObj1 = 479,  ocObj2 = 9;  ocObj1 ^  ocObj2 produces 470

 ocObj1 = 479,  ocObj2 = 9;  ocObj1 &  ocObj2 produces 9

 ocObj1 = 479,  ocObj2 = 9;  ocObj1 |  ocObj2 produces 479

 ocObj1 = 479,  ocObj2 = 9;  ocObj1 <<  ocObj2 produces 245248

 ocObj1 = 479,  ocObj2 = 9;  ocObj1 >>  ocObj2 produces 0

 ocObj1 = 479,  ocObj2 = 9;  ocObj1 +=  ocObj2 produces 488

 ocObj1 = 488,  ocObj2 = 9;  ocObj1 -=  ocObj2 produces 479

 ocObj1 = 479,  ocObj2 = 9;  ocObj1 *=  ocObj2 produces 4311

 ocObj1 = 4311,  ocObj2 = 9;  ocObj1 /=  ocObj2 produces 479

 ocObj1 = 479,  ocObj2 = 9;  ocObj1 %=  ocObj2 produces 2

 ocObj1 = 2,  ocObj2 = 9;  ocObj1 ^=  ocObj2 produces 11

 ocObj1 = 11,  ocObj2 = 9;  ocObj1 &=  ocObj2 produces 9

 ocObj1 = 9,  ocObj2 = 9;  ocObj1 |=  ocObj2 produces 9

 ocObj1 = 9,  ocObj2 = 9;  ocObj1 >>=  ocObj2 produces 0

 ocObj1 = 0,  ocObj2 = 9;  ocObj1 <<=  ocObj2 produces 0

 ocObj1 = 0,  ocObj2 = 9;  ocObj1 <  ocObj2 produces 1

 ocObj1 = 0,  ocObj2 = 9;  ocObj1 >  ocObj2 produces 0

 ocObj1 = 0,  ocObj2 = 9;  ocObj1 ==  ocObj2 produces 0

 ocObj1 = 0,  ocObj2 = 9;  ocObj1 !=  ocObj2 produces 1

 ocObj1 = 0,  ocObj2 = 9;  ocObj1 <=  ocObj2 produces 1

 ocObj1 = 0,  ocObj2 = 9;  ocObj1 >=  ocObj2 produces 0

 ocObj1 = 0,  ocObj2 = 9;  ocObj1 &&  ocObj2 produces 0

 ocObj1 = 0,  ocObj2 = 9;  ocObj1 ||  ocObj2 produces 1


Bytes
#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
class TestBytes
{
unsigned char pchVal;
public:
TestBytes(unsigned char pszVal = 0) : pchVal(pszVal) {}
const TestBytes operator+(const TestBytes& ocRight) const

  { return TestBytes(pchVal + ocRight.pchVal); }

const TestBytes operator-(const TestBytes& ocRight) const

  { return TestBytes(pchVal - ocRight.pchVal); }

const TestBytes operator*(const TestBytes& ocRight) const 

  { return TestBytes(pchVal * ocRight.pchVal); }

const TestBytes operator/(const TestBytes& ocRight) const

  { return TestBytes(pchVal / ocRight.pchVal); }

const TestBytes operator%(const TestBytes& ocRight) const

  { return TestBytes(pchVal % ocRight.pchVal); }

const TestBytes operator^(const TestBytes& ocRight) const

 { return TestBytes(pchVal ^ ocRight.pchVal); }

const TestBytes operator&(const TestBytes& ocRight) const

  { return TestBytes(pchVal & ocRight.pchVal); }

const TestBytes operator|(const TestBytes& ocRight) const

  { return TestBytes(pchVal | ocRight.pchVal); }

const TestBytes operator<<(const TestBytes& ocRight) const

  { return TestBytes(pchVal << ocRight.pchVal); }

const TestBytes operator>>(const TestBytes& ocRight) const

  { return TestBytes(pchVal >> ocRight.pchVal); }

TestBytes& operator=(const TestBytes& ocRight)

{
  if (this == &ocRight) return *this;
  pchVal = ocRight.pchVal;
  return *this;
}

TestBytes& operator+=(const TestBytes& ocRight)

{
  if  (this == &ocRight) {/* Assign it self */}
  pchVal += ocRight.pchVal;
  return *this;
}

TestBytes& operator-=(const TestBytes& ocRight)

{
  if (this == &ocRight) {/* Assign it self */}
  pchVal -= ocRight.pchVal;
  return *this;
}
TestBytes& operator*=(const TestBytes& ocRight)
{
  if (this == &ocRight) {/* Assign it self */}
  pchVal *= ocRight.pchVal;
  return *this;
}

TestBytes& operator/=(const TestBytes& ocRight)

{
   if (this == &ocRight) {/* Assign it self */}
  pchVal /= ocRight.pchVal;
  return *this;
}

TestBytes& operator%=(const TestBytes& ocRight)

{
  if (this == &ocRight) {/* Assign it self */}
  pchVal %= ocRight.pchVal;
  return *this;
}

TestBytes& operator^=(const TestBytes& ocRight)

{
  if (this == &ocRight) {/* Assign it self */}
  pchVal ^= ocRight.pchVal;
  return *this;
}
TestBytes& operator&=(const TestBytes& ocRight)
{
  if (this == &ocRight) {/* Assign it self */}
  pchVal &= ocRight.pchVal;
  return *this;
}

TestBytes& operator|=(const TestBytes& ocRight)

{
  if (this == &ocRight) {/* Assign it self */}
  pchVal |= ocRight.pchVal;
  return *this;
}

TestBytes& operator>>=(const TestBytes& ocRight)

{
  if (this == &ocRight) {/* Assign it self */}
  pchVal >>= ocRight.pchVal;
  return *this;
}

TestBytes& operator<<=(const TestBytes& ocRight)

{
  if (this == &ocRight) {/* Assign it self */}
  pchVal <<= ocRight.pchVal;
  return *this;
}

int operator== (const TestBytes& ocRight) const

  { return pchVal == ocRight.pchVal; }

int operator!= (const TestBytes& ocRight) const

  { return pchVal != ocRight.pchVal; }

int operator< (const TestBytes& ocRight) const

  { return pchVal < ocRight.pchVal; }

int operator> (const TestBytes& ocRight) const

  { return pchVal > ocRight.pchVal; }

int operator<= (const TestBytes& ocRight) const

  { return pchVal <= ocRight.pchVal; }

int operator>= (const TestBytes& ocRight) const

  { return pchVal >= ocRight.pchVal; }

int operator&&  (const TestBytes& ocRight) const

  { return pchVal && ocRight.pchVal; }

int operator|| (const TestBytes& ocRight) const

  { return pchVal || ocRight.pchVal; }

void print (std::ostream& ocOutStream) const

  { ocOutStream << "0x" << std::hex << int(pchVal) << std::dec; }

};

ofstream out("TestBytesDoc.out");


Test function
void MyBinaryTestFun (TestBytes& ocObj1, TestBytes& ocObj2)
{
ocObj1 = ocObj1 * ocObj2 + ocObj2 % ocObj1;

#define TESTFUN(OUTPUT) \

out << "ocObj1 = "; ocObj1.print(out); \

out << ", ocObj2 = "; ocObj2.print(out); \

out << "; ocObj1 " #OUTPUT " ocObj2 produces "; \

(ocObj1 OUTPUT ocObj2).print(out); \

out << endl;

ocObj1 = 9; ocObj2 = 47;

TESTFUN(+) TESTFUN(-) TESTFUN(*) TESTFUN(/)

TESTFUN(%) TESTFUN(^) TESTFUN(&) TESTFUN(|)

TESTFUN(<<) TESTFUN(>>) TESTFUN(+=) TESTFUN(-=)

TESTFUN(*=) TESTFUN(/=) TESTFUN(%=) TESTFUN(^=)

TESTFUN(&=) TESTFUN(|=) TESTFUN(>>=) TESTFUN(<<=)

TESTFUN(=) 

#define TESTFUN2(OUTPUT) \

out << "ocObj1 = "; ocObj1.print(out); \

out << ", ocObj2 = "; ocObj2.print(out); \

out << "; ocObj1 " #OUTPUT " ocObj2 produces "; \

out << (ocObj1 OUTPUT ocObj2); \

out << endl;

ocObj1 = 19; ocObj2 = 17;

TESTFUN2(<) TESTFUN2(>) TESTFUN2(==) TESTFUN2(!=) TESTFUN2(<=)

TESTFUN2(>=) TESTFUN2(&&) TESTFUN2(||)

TestBytes ocObj3 = 112;

ocObj1 = ocObj2 = ocObj3;

}

Testing the bytes code by calling it in the main
int main ()

{
  TestBytes ocObj1(247), ocObj2(19);
  MyBinaryTestFun (ocObj1, ocObj2);
  getchar ();
  return 0;
}

The output of the above program is, i.e TestBytesDoc.out contains
ocObj1 = 0x9, ocObj2 = 0x2f; ocObj1 + ocObj2 produces 0x38

ocObj1 = 0x9, ocObj2 = 0x2f; ocObj1 - ocObj2 produces 0xda

ocObj1 = 0x9, ocObj2 = 0x2f; ocObj1 * ocObj2 produces 0xa7

ocObj1 = 0x9, ocObj2 = 0x2f; ocObj1 / ocObj2 produces 0x0

ocObj1 = 0x9, ocObj2 = 0x2f; ocObj1 % ocObj2 produces 0x9

ocObj1 = 0x9, ocObj2 = 0x2f; ocObj1 ^ ocObj2 produces 0x26

ocObj1 = 0x9, ocObj2 = 0x2f; ocObj1 & ocObj2 produces 0x9

ocObj1 = 0x9, ocObj2 = 0x2f; ocObj1 | ocObj2 produces 0x2f

ocObj1 = 0x9, ocObj2 = 0x2f; ocObj1 << ocObj2 produces 0x0

ocObj1 = 0x9, ocObj2 = 0x2f; ocObj1 >> ocObj2 produces 0x0

ocObj1 = 0x9, ocObj2 = 0x2f; ocObj1 += ocObj2 produces 0x38

ocObj1 = 0x38, ocObj2 = 0x2f; ocObj1 -= ocObj2 produces 0x9

ocObj1 = 0x9, ocObj2 = 0x2f; ocObj1 *= ocObj2 produces 0xa7

ocObj1 = 0xa7, ocObj2 = 0x2f; ocObj1 /= ocObj2 produces 0x3

ocObj1 = 0x3, ocObj2 = 0x2f; ocObj1 %= ocObj2 produces 0x3

ocObj1 = 0x3, ocObj2 = 0x2f; ocObj1 ^= ocObj2 produces 0x2c

ocObj1 = 0x2c, ocObj2 = 0x2f; ocObj1 &= ocObj2 produces 0x2c

ocObj1 = 0x2c, ocObj2 = 0x2f; ocObj1 |= ocObj2 produces 0x2f

ocObj1 = 0x2f, ocObj2 = 0x2f; ocObj1 >>= ocObj2 produces 0x0

ocObj1 = 0x0, ocObj2 = 0x2f; ocObj1 <<= ocObj2 produces 0x0

ocObj1 = 0x0, ocObj2 = 0x2f; ocObj1 = ocObj2 produces 0x2f

ocObj1 = 0x13, ocObj2 = 0x11; ocObj1 < ocObj2 produces 0

ocObj1 = 0x13, ocObj2 = 0x11; ocObj1 > ocObj2 produces 1

ocObj1 = 0x13, ocObj2 = 0x11; ocObj1 == ocObj2 produces 0

ocObj1 = 0x13, ocObj2 = 0x11; ocObj1 != ocObj2 produces 1

ocObj1 = 0x13, ocObj2 = 0x11; ocObj1 <= ocObj2 produces 0

ocObj1 = 0x13, ocObj2 = 0x11; ocObj1 >= ocObj2 produces 1

ocObj1 = 0x13, ocObj2 = 0x11; ocObj1 && ocObj2 produces 1

ocObj1 = 0x13, ocObj2 = 0x11; ocObj1 || ocObj2 produces 1


The above two examples handle the single type. It is also possible to handle the mixed types.

All of the operators shown in the previous two examples are overloaded to handle a single type. It is also possible to overload operators to handle mixed types, so we can add apples to bananas. before you start on an exhaustive overloading of operators, however, you should look at the section on automatic type conversion.

No comments: