|
From: Dima <dim...@go...> - 2009-09-26 15:35:47
|
I still think we need a little wrapper instead of the pure optional class.
It is not convenient to dereference the optional object in the code by
writing
// -------------------------------------
optional<double> a(1.1);
double b=2.2;
double res;
QL_REQUIRE(a,"Empty a")
res=b*a.get();
// -------------------------------------
Would require a lot of rewriting of old Null class code too. How about the
following alternative:
template <class Type>
class Optional{
public:
Optional(){}
Optional(Type val):val_(val) {}
operator Type() const {
return val_.get();
}
bool isEmpty() const{
return !val_;
}
bool isInitialized() const{
return !isEmpty();
}
void reset(const Type& val){
val_.reset(val);
}
void reset(){
val_.reset();
}
bool operator==(Type const& x){
return x==val_;
}
bool operator==(Optional<Type> const& x){
return x==val_;
}
private:
boost::optional<Type> val_;
};
Here, Optional has a cast operator to the template class. So we would
check isInitialized() and then use the class without dereferencing. Here is
some example code
Optional<double> a(2.0);
Optional<double> b;
double c=1.1;
std::cout << "------------" << std::endl;
std::cout << "a empty:" << a.isEmpty() << std::endl;
std::cout << "b empty:" << b.isEmpty() << std::endl;
std::cout << "------------" << std::endl;
std::cout << "a initialized:" << a.isInitialized() << std::endl;
std::cout << "b initialized:" << b.isInitialized() << std::endl;
std::cout << "------------" << std::endl;
b.reset(c);
std::cout << "b initialized:" << b.isInitialized() << std::endl;
std::cout << "------------" << std::endl;
b.reset();
std::cout << "b initialized:" << b.isInitialized() << std::endl;
std::cout << "------------" << std::endl;
// simple multiplication, as if a is a double
std::cout << "c*a: " << c*a << std::endl;
// comparison of a with a double
a.reset(c);
std::cout << "a==c: " << (a==c) << std::endl;
Gives
------------
a empty:0
b empty:1
------------
a initialized:1
b initialized:0
------------
b initialized:1
------------
b initialized:0
------------
c*a: 2.2
a==c: 1
A QuantLib rewriting example for the Instrument class:
// instead of
//---------------------------------------------------------------------------
public:
inline Instrument::Instrument()
: NPV_(Null<Real>()), errorEstimate_(Null<Real>()) {}
private:
Real NPV_
inline Real Instrument::NPV() const {
calculate();
QL_REQUIRE(NPV_ != Null<Real>(), "NPV not provided");
return NPV_;
}
//---------------------------------------------------------------------------
// Optional version
//---------------------------------------------------------------------------
public:
inline Instrument::Instrument(){} // no initialization of member needed
private:
// make NPV_ an Optional variable
Optional<Real> NPV_
inline Real Instrument::NPV() const {
calculate();
QL_REQUIRE(NPV_.isInitialized(), "NPV not provided");
return NPV_;
}
//---------------------------------------------------------------------------
Of course, the Optional class has to be polished. Thoughts?
2009/9/25 Luigi Ballabio <lui...@gm...>
> On Fri, 2009-09-25 at 07:58 +0200, Jose Aparicio-Navarro wrote:
> > > > I'm aware of boost::optional and think it could be the way to go.
> > > > However, I don't see an easy way to incorporate it in the current
> Null
> > > > design.
> > >
> > > Neither do I. It would replace Null entirely.
> > >
> >
> > Should we start dropping Null<> and move to optional then?
>
> Moving to optional for new functionality---yes.
> Dropping Null in existing code---no. At this point we keep
> compatibility.
>
> Luigi
>
>
> --
>
> Green's Law of Debate:
> Anything is possible if you don't know what you're talking about.
>
>
>
|