Date: Fri, 17 May 2019 12:23:46 +0300
This post is based on an experience which, I believe, is shared by many,
having to do with the concept of "extending" a base class rather than
"overriding" its functionality. Here are two directions for this concept.
First: It is common in class methods that perform some setup or cleanup
operations to require a derived class to invoke the corresponding base
class method, as in the following manner.
class Base
{
public:
virtual void setup()
{
// do some setup
}
virtual void cleanup()
{
// do some cleanup
}
};
class Derived : public Base
{
public
void setup() override
{
Base::setup();
// do my own setup
}
void cleanup() override
{
// do my own cleanup
Base::cleanup();
}
};
In current language, this is the only way to achieve it ,and it requires
the developer to explicitly make the call to the base class method, with
the risk of missing it. In principle, the existing compiler mechanism
could also support something such as the following.
class Base
{
public:
tail_extensible void setup()
{
// do some setup
}
head_extensible void cleanup()
{
// do some cleanup
}
};
class Derived
{
public:
void setup() extension
{
// Base::setup() is called automatically
// do my own setup
}
void cleanup() extension
{
// do my own cleanup
// Base::cleanup is called automatically
}
};
Semantically, the tail_extensible is similar to a virtual function,
including an identical signature for the base and derived method, and all
that is left is to forward the arguments passed to the derived method onto
the base by using the regular signature rules (i.e by-value will be
forwarded by value, by const reference will be forwarded as const
reference, etc.).
Second: It sometimes happens that I want to extend an existing class with
functionality only, but not with new members. For example, I want to have
a class that has all the functionality of a std::string and then some of my
own. This can be accomplished using composition or, probably more simply,
through inheritance. However, my class only needs the members of
std::string.
In the current language, I'd have to manually write all the constructors to
allow my class to be constructed from a string, or from anything that
constructs a string, assigned from a string, etc. Moreover, I'd have to
add the move constructor etc., whose defaults expire as soon as I define
the regular constructors. But all this is not really necessary, and
furthermore creates a risk of forgetting to do it.
Suppose we had an "extends" keyword whose semantics is: the extending class
cannot define new members (maybe more relaxed for static members), and in
return it does not have to specify all the mechanism of construction and
assignment, which is inherited from the base class.
class MySpecialString : public extends std::string
{
public:
// only new methods or overrides from the base, no members, no
constructors,
// no assignments, no operator overloading
};
This does pose some potential complications, such as would and how
overloaded operators be included in the extension semantics, what about
destructors? what to do with multiple extension (corresponding to multiple
inheritance) an so on. But I think that consistent rules can be developed
for this.
All this is more about simplifying a developer's life, reducing boilerplate
and making safer code. It's replacing what would be done manually with a
declarative form that implies clear semantics. I'd like to see this
standardized.
Regards
Ofri Sadowsky
having to do with the concept of "extending" a base class rather than
"overriding" its functionality. Here are two directions for this concept.
First: It is common in class methods that perform some setup or cleanup
operations to require a derived class to invoke the corresponding base
class method, as in the following manner.
class Base
{
public:
virtual void setup()
{
// do some setup
}
virtual void cleanup()
{
// do some cleanup
}
};
class Derived : public Base
{
public
void setup() override
{
Base::setup();
// do my own setup
}
void cleanup() override
{
// do my own cleanup
Base::cleanup();
}
};
In current language, this is the only way to achieve it ,and it requires
the developer to explicitly make the call to the base class method, with
the risk of missing it. In principle, the existing compiler mechanism
could also support something such as the following.
class Base
{
public:
tail_extensible void setup()
{
// do some setup
}
head_extensible void cleanup()
{
// do some cleanup
}
};
class Derived
{
public:
void setup() extension
{
// Base::setup() is called automatically
// do my own setup
}
void cleanup() extension
{
// do my own cleanup
// Base::cleanup is called automatically
}
};
Semantically, the tail_extensible is similar to a virtual function,
including an identical signature for the base and derived method, and all
that is left is to forward the arguments passed to the derived method onto
the base by using the regular signature rules (i.e by-value will be
forwarded by value, by const reference will be forwarded as const
reference, etc.).
Second: It sometimes happens that I want to extend an existing class with
functionality only, but not with new members. For example, I want to have
a class that has all the functionality of a std::string and then some of my
own. This can be accomplished using composition or, probably more simply,
through inheritance. However, my class only needs the members of
std::string.
In the current language, I'd have to manually write all the constructors to
allow my class to be constructed from a string, or from anything that
constructs a string, assigned from a string, etc. Moreover, I'd have to
add the move constructor etc., whose defaults expire as soon as I define
the regular constructors. But all this is not really necessary, and
furthermore creates a risk of forgetting to do it.
Suppose we had an "extends" keyword whose semantics is: the extending class
cannot define new members (maybe more relaxed for static members), and in
return it does not have to specify all the mechanism of construction and
assignment, which is inherited from the base class.
class MySpecialString : public extends std::string
{
public:
// only new methods or overrides from the base, no members, no
constructors,
// no assignments, no operator overloading
};
This does pose some potential complications, such as would and how
overloaded operators be included in the extension semantics, what about
destructors? what to do with multiple extension (corresponding to multiple
inheritance) an so on. But I think that consistent rules can be developed
for this.
All this is more about simplifying a developer's life, reducing boilerplate
and making safer code. It's replacing what would be done manually with a
declarative form that implies clear semantics. I'd like to see this
standardized.
Regards
Ofri Sadowsky
-- Ofri Sadowsky, PhD Computer Science Consulting and Training 7 Carmel St., #37 Rehovot 7630507 Israel Tel: +972-77-3436003 Mob: +972-54-3113572
Received on 2019-05-17 04:25:40