Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

How can I use unqualified names? (Possibly hard or impossible?)

23 views
Skip to first unread message

Alf P. Steinbach

unread,
Jul 19, 2009, 11:12:46 AM7/19/09
to
Original problem: a pack of options that may contain a great many simple
numerical and bitset options (defined by external API), and that should be (1)
extensible for at least two levels, like class derivation, (2) easy to define,
(3) easily constructible specifying only those options of interest, defaulting
on the rest, (4) clean notation for accessing options, with compile time
checking, and (5) if possible as efficient as possible access of options.

My silly idea: represent option names as types, and support creation notation like

Options() << x(42) << alpha(3.14)

where 'x' and 'alpha' and other option names are type names. This allows compile
time access of options via notation like 'options::x.member' or e.g.
'options.member<x>', with efficiency as for ordinary member access. Defining a
set of options is reasonably simple, given a little template-based support.

Problem: long qualified option names are impractical and unreadable, but short
good names like 'x' can easily conflict with client code. Especially where that
client code cretating an Options instance is a constructor initializer list a
'using namespace...' isn't practical (as far as I can see, but I may be wrong).
I started thinking in terms of ADL and such, but no dice: my brain cannot come
up with good solution, even now after having slept on it!

Any help appreciated.

Test-of-concept-code, although perhaps best ignored since it constitutes the box
that I'm unable to break out of (I'm not using typelists cause this is just
testing, and also because that would possibly complicate usage):

<code>
template< typename OptionValues >
class Options_: public OptionValues
{
public:
template< typename OptionType >
Options_& operator<<( OptionType const& option )
{
//STATIC_ASSERT( IS_DERIVED_AND_BASE( Options_, OptionType ) );
static_cast<OptionType&>(*this) = option;
return *this;
}

template< typename OptionType >
OptionType const& as() const
{
//STATIC_ASSERT( IS_DERIVED_AND_BASE( Options_, OptionType ) );
return static_cast<OptionType const&>( *this );
}
};

template< typename T, typename Unique >
struct OptionsMember_
{
T member;
OptionsMember_(): member() {}
OptionsMember_( T const& aValue ): member( aValue ) {}
operator T& () { return member; }
operator T const& () const { return member; }
};

struct Nix {};

template<
class T,
class U = Nix,
class V = Nix,
class W = Nix,
class X = Nix,
class Y = Nix,
class Z = Nix
>
struct WithMembers_;

template< class T, class U, class V, class W, class X, class Y, class Z >
struct WithMembers_: T, U, V, W, X, Y, Z {};

template< class T, class U, class V, class W, class X, class Y >
struct WithMembers_<T, U, V, W, X, Y>: T, U, V, W, X, Y {};

template< class T, class U, class V, class W, class X >
struct WithMembers_<T, U, V, W, X>: T, U, V, W, X {};

template< class T, class U, class V, class W >
struct WithMembers_<T, U, V, W>: T, U, V, W {};

template< class T, class U, class V >
struct WithMembers_<T, U, V>: T, U, V {};

template< class T, class U >
struct WithMembers_<T, U>: T, U {};

template< class T >
struct WithMembers_<T>: T {};

//------------------------ Usage:

#include <iostream>

typedef OptionsMember_<double, struct UniqueTypeFor_x> x;
typedef OptionsMember_<double, struct UniqueTypeFor_y> y;
typedef Options_< WithMembers_<x, y> > XYOptions;

void foo( XYOptions const& options )
{
using namespace std;
cout << options.x::member << endl;
cout << options.y::member << endl;
}


typedef OptionsMember_<double, struct UniqueTypeFor_z> z;
typedef Options_< WithMembers_<XYOptions, z> > XYZOptions;

void foo( XYZOptions const& options )
{
using namespace std;
foo( options.as<XYOptions>() );
cout << std::endl;
cout << options.x::member << endl;
cout << options.y::member << endl;
cout << options.z::member << endl;
}


int main()
{
foo( XYZOptions() << x(3.14) << z(42) );
}
</code>


Cheers & TIA for any help,

- Alf

Jonathan Lee

unread,
Jul 19, 2009, 11:47:22 AM7/19/09
to
On Jul 19, 11:12 am, "Alf P. Steinbach" <al...@start.no> wrote:
> My silly idea: represent option names as types, and support creation notation like
>
>    Options() << x(42) << alpha(3.14)

Not sure how valuable my advice is, but here are my thoughts:

- Have your options derive from a base Options class
- Define operator& between two different Options-derived
classes to produce another Options-derived class that
combines the two into a single object
- Input the "and-ed" options to your destination object
via operator<< or similar

For example, suppose "foo" is to receive the options:

foo << (x(3.14) & z(42.0))

I would read this as "foo" should have x equal to 3.14
*and* z equal to 42.0 (*and* blah blah). I personally
like the & notation. Reminds me of combining bit flags
with | but it sounds better to say "and" than "or" :/

x would be something like Options<x> and z would be
Options<z> and the result of 'and-ing' them would be
Options<x,z>. Continue indefinitely so you build up
an object of type Options<x,z,w,t,v> or whatever. So
it should be extensible.

It also gets rid of the need for a dummy Options()
object to start the chain.

I don't know if this can be done; I'm no good at
templates. But that's my idea.

--Jonathan

Jonathan Lee

unread,
Jul 19, 2009, 11:52:16 AM7/19/09
to
On Jul 19, 11:47 am, Jonathan Lee <cho...@shaw.ca> wrote:
> Not sure how valuable my advice is, but here are my thoughts:

Sorry, afterthought. Defining more and more Options
classes w/ templates might be possible if there is a
single-type version and double-type version.

i.e.
Options<x>
and Options<x,y>

then Options<x,y,z> would really be

Options<Options<x,y>, z>

and the number of cases for overloading << would be
small (well, 2).

--Jonathan

Jonathan Lee

unread,
Jul 19, 2009, 12:39:30 PM7/19/09
to
On Jul 19, 11:52 am, Jonathan Lee <cho...@shaw.ca> wrote:
> On Jul 19, 11:47 am, Jonathan Lee <cho...@shaw.ca> wrote:
>
> > Not sure how valuable my advice is, but here are my thoughts:

So the following works, but it's kinda ugly. OK, it's really ugly. I
had to introduce a partial specialization of Options<type1, type2> to
get it to compile. I chose void* as type2; I don't really know how to
get around this. This means that I had to define a operator<<(void*)
on the test class Bar. And, basically there are void*'s scattered all
over. But the usage is as I described above.

I also defined trivial classes to wrap double (called xbase, zbase)
and int (called ybase). Maybe a typedef is sufficient?

// code -----------------------------------------

#include <iostream>

class xbase {
public:
double x;
xbase(double y) : x(y) {}
};

class ybase {
public:
int y;
ybase(int x) : y(x) {}
};

class zbase {
public:
double z;
zbase(double y) : z(y) {}
};

template<typename T, typename U>
class Options {
public:
T val;
U other;
Options(T t, U u) : val(t), other(u) { }
};

template<typename T>
class Options<T, void*> {
public:
T val;
void* other;
Options(T x) : val(x) {}
};

template<typename T, typename U, typename V>
Options<Options<T, U>, V> operator&(Options<T, U> t, Options<V, void*>
u) {
return Options<Options<T, U>, V>(t,u.val); }

class Bar {
xbase x1;
zbase z1;
ybase y1;
public:
Bar() : x1(0.0), z1(0.0), y1(0) { }
void print() {
std::cout << x1.x << std::endl;
std::cout << y1.y << std::endl;
std::cout << z1.z << std::endl;
}

Bar& operator<<(zbase zz) {
z1 = zz;
return (*this);
}

Bar& operator<<(xbase xx) {
x1 = xx;
return (*this);
}

Bar& operator<<(ybase yy) {
y1 = yy;
return (*this);
}

Bar& operator<<(void*) {
return (*this);
}

template<typename T, typename U>
Bar& operator<<(Options<T, U> otu) {
operator<<(otu.val);
operator<<(otu.other);
return (*this);
}
};

typedef Options<xbase, void*> xtype;
typedef Options<zbase, void*> ztype;
typedef Options<ybase, void*> ytype;

int main() {
Bar foo;
foo << (xtype(1.0) & ztype(2.0) & ytype(18));
foo.print();
return 0;
}

Alf P. Steinbach

unread,
Jul 19, 2009, 9:53:54 PM7/19/09
to
* Alf P. Steinbach:

>
> Problem: long qualified option names are impractical and unreadable, but
> short good names like 'x' can easily conflict with client code.
> Especially where that client code cretating an Options instance is a
> constructor initializer list a 'using namespace...' isn't practical (as
> far as I can see, but I may be wrong). I started thinking in terms of
> ADL and such, but no dice: my brain cannot come up with good solution,
> even now after having slept on it!

First, thanks to Jonathan Lee (else-thread) for a different tack on the option
pack problem, the problem that led to the above. Yeah, I'm using that and'ing
scheme for simpler options, those that are encoded as bit-fields. But I don't
quite see how it helps with the above.

Anyway, I found a sort of almost-solution, shown below.

It doesn't get rid of qualification as I wanted, but it reduces qualification to
only one qualifier, which can be freely named within a usage class.

It's sort of like if one could have 'using namespace foo=' within a class. :-)

Might be a useful technique on its own.

struct Nix {};

//------------------------ Usage:

#include <iostream>

namespace blahblah {
namespace reallyLongName {
namespace california {
namespace pos2 {


typedef OptionsMember_<double, struct UniqueTypeFor_x> x;
typedef OptionsMember_<double, struct UniqueTypeFor_y> y;

typedef Options_< WithMembers_<x, y> > Options;

struct Names
{
typedef pos2::Options Options;
typedef pos2::x x;
typedef pos2::y y;
};
}}}} // namespace blahblah::reallyLongName::california::pos2


struct UserClass1
{
//using namespace pos2 = blahblah::reallyLongName::california::pos2;
typedef ::blahblah::reallyLongName::california::pos2::Names pos2;

UserClass1( pos2::Options const& options )
{
using namespace std;
cout << options.pos2::x::member << endl;
cout << options.pos2::y::member << endl;
}
};


namespace blahblah {
namespace reallyLongName {
namespace california {
namespace pos3 {


typedef OptionsMember_<double, struct UniqueTypeFor_z> z;

typedef Options_< WithMembers_<pos2::Options, z> > Options;

struct Names: pos2::Names
{
typedef pos3::Options Options;
typedef pos3::z z;
};
}}}} // namespace blahblah::reallyLongName::california::pos3


struct UserClass2: UserClass1
{
//using namespace pos3 = blahblah::reallyLongName::california::pos3;
typedef ::blahblah::reallyLongName::california::pos3::Names pos3;

UserClass2( pos3::Options const& options )
: UserClass1( options )
{
using namespace std;
cout << std::endl;
cout << options.pos3::x::member << endl;
cout << options.pos3::y::member << endl;
cout << options.pos3::z::member << endl;
}
};

int main()
{
//using namespace pos3 = blahblah::reallyLongName::california::pos3;
typedef UserClass2::pos3 pos3;
UserClass2( pos3::Options() << pos3::x(3.14) << pos3::z(42) );
}
</code>


Now, if I could just see some way to use e.g. macros to make the option pack
definitions less verbose & more readable...


Cheers,

- Alf

Alf P. Steinbach

unread,
Jul 19, 2009, 10:06:32 PM7/19/09
to
* Alf P. Steinbach:

> * Alf P. Steinbach:
>>
>> Problem: long qualified option names are impractical and unreadable,
>> but short good names like 'x' can easily conflict with client code.
>> Especially where that client code cretating an Options instance is a
>> constructor initializer list a 'using namespace...' isn't practical
>> (as far as I can see, but I may be wrong). I started thinking in terms
>> of ADL and such, but no dice: my brain cannot come up with good
>> solution, even now after having slept on it!
>
> First, thanks to Jonathan Lee (else-thread) for a different tack on the
> option pack problem, the problem that led to the above. Yeah, I'm using
> that and'ing scheme for simpler options, those that are encoded as
> bit-fields. But I don't quite see how it helps with the above.
>
> Anyway, I found a sort of almost-solution, shown below.
>
> It doesn't get rid of qualification as I wanted, but it reduces
> qualification to only one qualifier, which can be freely named within a
> usage class.
>
> It's sort of like if one could have 'using namespace foo=' within a
> class. :-)
>
> Might be a useful technique on its own.

Uh oh, I should have tested with MSVC.

MSVC 7.1 doesn't accept the 'typedef'. But it does accept a class derivation.
However, results are incorrect relative to what I expect: I expect the output
that compilation with g++ produces.

Results g++ versus MSVC are posted below after the new adjusted-for-MSVC code.

struct Nix {};

//------------------------ Usage:

#include <iostream>

struct pos2: ::blahblah::reallyLongName::california::pos2::Names {};

UserClass1( pos2::Options const& options )
{
using namespace std;
cout << options.pos2::x::member << endl;
cout << options.pos2::y::member << endl;
}
};


namespace blahblah {
namespace reallyLongName {
namespace california {
namespace pos3 {
typedef OptionsMember_<double, struct UniqueTypeFor_z> z;
typedef Options_< WithMembers_<pos2::Options, z> > Options;

struct Names: pos2::Names
{
typedef pos3::Options Options;
typedef pos3::z z;
};
}}}} // namespace blahblah::reallyLongName::california::pos3


struct UserClass2: UserClass1
{
//using namespace pos3 = blahblah::reallyLongName::california::pos3;

struct pos3: ::blahblah::reallyLongName::california::pos3::Names {};

UserClass2( pos3::Options const& options )
: UserClass1( options )
{
using namespace std;
cout << std::endl;
cout << options.pos3::x::member << endl;
cout << options.pos3::y::member << endl;
cout << options.pos3::z::member << endl;
}
};

int main()
{
//using namespace pos3 = blahblah::reallyLongName::california::pos3;
typedef UserClass2::pos3 pos3;
UserClass2( pos3::Options() << pos3::x(3.14) << pos3::z(42) );
}
</code>


<example>
C:\temp> gnuc x.cpp -o a && a
3.14
0

3.14
0
42

C:\temp> msvc x.cpp -o b && b
x.cpp
3.14
3.14

3.14
3.14
3.14

C:\temp>
</example>


Does this mean that the code above has UB?

And if not, can one conclude that MSVC 7.1 is wrong?


Cheers & TIA.,

- Alf

James Kanze

unread,
Jul 20, 2009, 3:54:57 AM7/20/09
to
On Jul 19, 5:12 pm, "Alf P. Steinbach" <al...@start.no> wrote:
> Original problem: a pack of options that may contain a great
> many simple numerical and bitset options (defined by external
> API), and that should be (1) extensible for at least two
> levels, like class derivation, (2) easy to define, (3) easily
> constructible specifying only those options of interest,
> defaulting on the rest, (4) clean notation for accessing
> options, with compile time checking, and (5) if possible as
> efficient as possible access of options.

Sounds like something in a GUI:-).

> My silly idea: represent option names as types, and support
> creation notation like

> Options() << x(42) << alpha(3.14)

> where 'x' and 'alpha' and other option names are type names.
> This allows compile time access of options via notation like
> 'options::x.member' or e.g. 'options.member<x>', with
> efficiency as for ordinary member access. Defining a set of
> options is reasonably simple, given a little template-based
> support.

Not silly at all. It's very similar to the "standard" solution,
which would also use an Options class, but with member functions
which chain (i.e. return an Options&):

Options().x( 42 ).alpha( 3.14 ) ...

I usually provide a copy constructor for Options as well, so
that the client can set up special defaults for specific cases,
e.g.:

Options( warningPopup ).x( 42 )

(where warningPopup is a static variable of type Options, with
some different set of options than the usual default).

> Problem: long qualified option names are impractical and
> unreadable, but short good names like 'x' can easily conflict
> with client code. Especially where that client code cretating
> an Options instance is a constructor initializer list a 'using
> namespace...' isn't practical (as far as I can see, but I may
> be wrong). I started thinking in terms of ADL and such, but
> no dice: my brain cannot come up with good solution, even now
> after having slept on it!

The member function solution works for me. The one disadvantage
I can see is that you have to type out all of the member
functions; I'll usually use a simple AWK script to generate the
class, so I don't even have to do this. (The script will
convert a file containing lines something like:
optionName optionType defaultValue
into a complete class definition, with all of the necessary
access functions and the member variables.)

--
James Kanze (GABI Software) email:james...@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Alf P. Steinbach

unread,
Jul 25, 2009, 2:28:19 AM7/25/09
to
* James Kanze:

> On Jul 19, 5:12 pm, "Alf P. Steinbach" <al...@start.no> wrote:
>> Original problem: a pack of options that may contain a great
>> many simple numerical and bitset options (defined by external
>> API), and that should be (1) extensible for at least two
>> levels, like class derivation, (2) easy to define, (3) easily
>> constructible specifying only those options of interest,
>> defaulting on the rest, (4) clean notation for accessing
>> options, with compile time checking, and (5) if possible as
>> efficient as possible access of options.
>
> Sounds like something in a GUI:-).

Right on. :-)

I let it simmer for a time, actually I think it's been a week now, hoping for
fresh ideas.

But in the end I now just combined your member routines suggestion with my
previous idea of options as types.

Uh huh? Why not macros & templates & stuff? Pure C++ solution?


> (The script will
> convert a file containing lines something like:
> optionName optionType defaultValue
> into a complete class definition, with all of the necessary
> access functions and the member variables.)

My test usage code for all-C++ solution now looks like this:


<code>
//------------------------ Usage:

#include <iostream>

namespace blahblah {
namespace reallyLongName {
namespace california {

CPPX_DEFINE_OPTION( x, double )
CPPX_DEFINE_OPTION( y, double )
CPPX_DEFINE_2OPTIONCLASS( Pos2Options, cppx::options::NoBase, x, y )

CPPX_DEFINE_OPTION( z, double )
CPPX_DEFINE_1OPTIONCLASS( Pos3Options, Pos2Options, z )


}}} // namespace blahblah::reallyLongName::california

struct UserClass1
{
typedef ::blahblah::reallyLongName::california::Pos2Options
Pos2Options;

UserClass1( Pos2Options const& options )
{
using namespace std;
cout << options.x() << endl;
cout << options.y() << endl;
}
};

struct UserClass2: UserClass1
{
typedef ::blahblah::reallyLongName::california::Pos3Options
Pos3Options;

UserClass2( Pos3Options const& options )
: UserClass1( options )
{
using namespace std;
cout << std::endl;
cout << options.x() << endl;
cout << options.y() << endl;
cout << options.z() << endl;
}
};

int main()
{
typedef UserClass2::Pos3Options Pos3Options;
UserClass2( Pos3Options().x( 3.14 ).z( 42 ) );
}
</code>


<results>
3.14
0

3.14
0
42
</results>


Works with both g++ and MSVC.

I'm interested in whether anyone can find a /simple/ way to do it, because the
support needed to get that final

Pos3Options().x( 3.14 ).z( 42 )

expression to work turned out, with the way I did it, to be a little in-elegant
(I guess that's what some folks call "too smart" code)...


Cheers, & thanks,

- Alf

James Kanze

unread,
Jul 25, 2009, 4:37:09 AM7/25/09
to
On Jul 25, 8:28 am, "Alf P. Steinbach" <al...@start.no> wrote:
> * James Kanze:

> > On Jul 19, 5:12 pm, "Alf P. Steinbach" <al...@start.no> wrote:
> >> Original problem: a pack of options that may contain a
> >> great many simple numerical and bitset options (defined by
> >> external API), and that should be (1) extensible for at
> >> least two levels, like class derivation, (2) easy to
> >> define, (3) easily constructible specifying only those
> >> options of interest, defaulting on the rest, (4) clean
> >> notation for accessing options, with compile time checking,
> >> and (5) if possible as efficient as possible access of
> >> options.

> > Sounds like something in a GUI:-).

> Right on. :-)

> I let it simmer for a time, actually I think it's been a week
> now, hoping for fresh ideas.

I've found that often to be a good idea as well.

> >> Options() << x(42) << alpha(3.14)

I didn't consider templates, perhaps because when I did it, C++
didn't have templates, but I don't really see where they would
help; since my attributes don't have different types, I don't
quite see how you could trigger the correct template use. You
certainly could do it just as well with macros, but I found an
external code generator simpler and cleaner (if nothing else,
for the default values).

> > (The script will
> > convert a file containing lines something like:
> > optionName optionType defaultValue
> > into a complete class definition, with all of the necessary
> > access functions and the member variables.)

> My test usage code for all-C++ solution now looks like this:

> <code>
> //------------------------ Usage:

> #include <iostream>

> namespace blahblah {
> namespace reallyLongName {
> namespace california {
> CPPX_DEFINE_OPTION( x, double )

I suppose that this is your macro, but I'm not sure what it's
supposed to generate. In a macro based solution, I would have
expected to see something like:

#define MYPREFIX_DEFINE_OPTION( name, type )\
public: \
Options& name( type new_ ## name ) \
{ \
my_ ## name = new_ ## name ; \
return *this ; \
} \
type name() const \
{ \
return my_ ## name ; \
} \
private: \
type my_ ## name

class Options
{
MYPREFIX_DEFINE_OPTION( y, double ) ;
// ...
} ;

#undef MYPREFIX_DEFINE_OPTION

That still leaves having to list all of the defaults in the
constructor. (The AWK script would only be a few lines longer
than the above, and would also generate the constructor.)

> <results>
> 3.14
> 0

> 3.14
> 0
> 42
> </results>

I don't know. I don't really understand what's going on,
without seeing the definitions of the macros you're using.

Alf P. Steinbach

unread,
Jul 25, 2009, 5:23:02 AM7/25/09
to
* James Kanze:
> On Jul 25, 8:28 am, "Alf P. Steinbach" <al...@start.no> wrote:
>> * James Kanze:
>
>>> On Jul 19, 5:12 pm, "Alf P. Steinbach" <al...@start.no> wrote:
>>>> Original problem: a pack of options that may contain a
>>>> great many simple numerical and bitset options (defined by
>>>> external API), and that should be (1) extensible for at
>>>> least two levels, like class derivation, (2) easy to
>>>> define, (3) easily constructible specifying only those
>>>> options of interest, defaulting on the rest, (4) clean
>>>> notation for accessing options, with compile time checking,
>>>> and (5) if possible as efficient as possible access of
>>>> options.


[snip]

Well, one beauty of having each option as a type is that each option has its own
constructor, so that the default can be specified along with the "declaration"
of the option, like

CPPX_DEFINE_OPTION_AND_DEFAULT( y, double, 12345 )

They're ugly! :-)

Or "in-elegant"...

Hence the plea for simpler pure-C++ solution that supports the same, in
particular extension and simple notation (client code).


<code>
#include <boost/mpl/clear.hpp>
#include <boost/mpl/front.hpp>
#include <boost/mpl/inherit.hpp>
#include <boost/mpl/inherit_linearly.hpp>
#include <boost/mpl/list.hpp>
#include <boost/mpl/pop_front.hpp>

namespace cppx { namespace typelist {

typedef boost::mpl::clear< boost::mpl::list<> >::type Empty;

template< class TypeList >
struct InheritLinearly_
{
typedef typename boost::mpl::inherit_linearly<
TypeList,
boost::mpl::inherit< boost::mpl::_1, boost::mpl::_2 >
>::type Type;
};

template< class TypeList >
struct Car
{
typedef typename boost::mpl::front< TypeList >::type Type;
};

template< class TypeList >
struct Cdr
{
typedef typename boost::mpl::pop_front< TypeList >::type Type;
};

} } // namespace cppx::typelist

namespace cppx { namespace options {

template< class T, class UniqueIdType >
class Value_
{
private:
T myValue;

public:
Value_(): myValue() {}
Value_( T const& v ): myValue( v ) {}

T const& value() const { return myValue; }
void setValue( T const& v ) { myValue = v; }

operator T const& () const { return value(); }

Value_& operator=( T const& v )
{
setValue( v ); return *this;
}
};

class NoBase {};

template< class SetterResult, class TopBase >
class NoBase_TemplatedSetters_: public TopBase {};

template<
class OptionTypes,
class SetterResult,
class TopBase,
template< class, class, class > class OptionSetter_
>
class TemplatedSetters_;

template<
class SetterResult,
class TopBase,
template< class, class, class > class OptionSetter_
>
class TemplatedSetters_<
cppx::typelist::Empty, SetterResult, TopBase, OptionSetter_
>
: public TopBase
{};

template<
class OptionTypes,
class SetterResult,
class TopBase,
template< class, class, class > class OptionSetter_
>
class TemplatedSetters_
: public OptionSetter_<
typename cppx::typelist::Car<OptionTypes>::Type,
SetterResult,
TemplatedSetters_<
typename cppx::typelist::Cdr<OptionTypes>::Type,
SetterResult,
TopBase,
OptionSetter_
>
>
{};

#define CPPX_OPTION( name ) OptionValue_##name

#define CPPX_DEFINE_OPTION_SETTER( name, type ) \
template< class OptionValue, class SetterResult, class Base > \
class OptionSetter_; \
\
template< class SetterResult, class Base > \
class OptionSetter_<CPPX_OPTION( name ), SetterResult, Base> \
: public Base \
{ \
public: \
type const& name() const \
{ return CPPX_OPTION( name )::value(); } \
\
SetterResult& name( type const& value ) \
{ \
CPPX_OPTION( name )::setValue( value ); \
return static_cast<SetterResult&>( *this ); \
} \
};

#define CPPX_DEFINE_OPTION( name, type ) \
typedef ::cppx::options::Value_< \
type, struct UniqueIdTypeFor_##name \
> CPPX_OPTION( name ); \
CPPX_DEFINE_OPTION_SETTER( name, type )

#define CPPX_DEFINE_OPTION_AND_DEFAULT( name, type, defValue ) \
class CPPX_OPTION( name ) \
: public ::cppx::options::Value_< \
type, struct UniqueIdTypeFor_##name \
> \
{ \
typedef ::cppx::options::Value_< \
type, struct UniqueIdTypeFor_##name \
> Base; \
public: \
CPPX_OPTION( name )(): Base( defValue ) {} \
CPPX_OPTION( name )( type const& v ): Base( v ) {} \
}; \
CPPX_DEFINE_OPTION_SETTER( name, type )

#define CPPX_DEFINE_VALUECLASS( name, base ) \
class name##_Values \
: public base \
, public ::cppx::typelist::InheritLinearly_< \
name##_OptionTypes \
>::Type \
{};

#define CPPX_DEFINE_TEMPLATED_SETTERS( name ) \
template< class SetterResult, class TopBase > \
class name##_TemplatedSetters_ \
: public ::cppx::options::TemplatedSetters_< \
name##_OptionTypes, \
SetterResult, \
TopBase, \
OptionSetter_ \
> \
{};

#define CPPX_DEFINE_OPTIONCLASS( name, base ) \
class name \
: public name##_TemplatedSetters_< \
name, \
base##_TemplatedSetters_<name, name##_Values> \
> \
{};

#define CPPX_DEFINE_VTANDO( name, base ) \
CPPX_DEFINE_VALUECLASS( name, base ) \
CPPX_DEFINE_TEMPLATED_SETTERS( name ) \
CPPX_DEFINE_OPTIONCLASS( name, base )

#define CPPX_DEFINE_1OPTIONCLASS( name, base, option1 ) \
typedef ::boost::mpl::list< \
CPPX_OPTION( option1 ) \
> name##_OptionTypes; \
CPPX_DEFINE_VTANDO( name, base )

#define CPPX_DEFINE_2OPTIONCLASS( name, base, option1, option2 ) \
typedef ::boost::mpl::list< \
CPPX_OPTION( option1 ), \
CPPX_OPTION( option2 ) \
> name##_OptionTypes; \
CPPX_DEFINE_VTANDO( name, base )

// ...
} } // namespace cppx::options
</code>


Cheers,

- Alf (he he, I *mean* it when I say something's "ugly" :-) )
(but then, the ugly beast is easy to ride, good tempered animal)

James Kanze

unread,
Jul 26, 2009, 4:29:18 AM7/26/09
to
On Jul 25, 11:23 am, "Alf P. Steinbach" <al...@start.no> wrote:
> * James Kanze:
> > I don't know. I don't really understand what's going on,
> > without seeing the definitions of the macros you're using.

> They're ugly! :-)

> Or "in-elegant"...

> Hence the plea for simpler pure-C++ solution that supports the
> same, in particular extension and simple notation (client
> code).

Just curious, but why does it have to be "pure-C++"? As I said
earlier, a short AWK script does the job just fine.

BTW: What is the Windows equivalent of AWK? There must be one,
or do all Windows programmers have CygWin or something similar
installed? Or Perl---you could easily do it in Perl, if you
can stand Perl? Or probably Python or Ruby, or just about any
"small language" that's text oriented. (All of the Windows
programmers I know do use CygWin, so maybe there is something
essential for program development missing in Windows.)

Anyway...

> <code>
> #include <boost/mpl/clear.hpp>
> #include <boost/mpl/front.hpp>
> #include <boost/mpl/inherit.hpp>
> #include <boost/mpl/inherit_linearly.hpp>
> #include <boost/mpl/list.hpp>
> #include <boost/mpl/pop_front.hpp>

> namespace cppx { namespace typelist {

> typedef boost::mpl::clear< boost::mpl::list<> >::type Empty;

You've already lost me. I don't have the slightest knowledge of
Boost::mpl, and in general, I find most of the advanced
meta-programming idioms too complicated for general use.

At any rate, you've something like 200 lines of very complicated
code, to do something that can be done much simpler outside of
the language, or even with macros. Whereas something like:

#! /usr/bin/awk -f
/ *#/ { next }

NF == 3 || (NF > 3 && $4 ~ /^#/) {
++ optionCount
names[ optionCount ] = $1
types[ optionCount ] = $2
defaults[ optionCount ] = $3
next
}

{
printf( "[%s:%d]: syntax error\n", FILENAME, FNR ) > "/dev/
stderr"
}

END {
printf( "class Options\n" )
printf( "{\n" )
printf( "public:\n" )
printf( " Options::Options()\n" )
for ( i = 1 ; i <= optionCount ; ++ i ) {
printf( " %c %s( %s )\n", i == 1 ? ":" : "," ,names
[ i ], defaults[ i ] )
}
printf( " {\n" )
printf( " }\n" )
for ( i = 1 ; i <= optionCount ; ++ i ) {
name = names[ i ]
type = types[ i ]
printf( " %s %s() const\n", type, name )
printf( " {\n" )
printf( " return my_%s;\n", name )
printf( " }\n" )
printf( " Options& %s( %s new_%s )\n", name, type,
name )
printf( " {\n" )
printf( " my_%s = new_%s ;\n", name, name )
printf( " return *this ;\n" )
printf( " }\n" )
}
printf( "private:\n" )
for ( i = 1 ; i <= optionCount ; ++ i ) {
printf( " %s my_%s ;\n", types[ i ], names[ i ] )
}
printf( "} ;\n" )
}

, invoked with "genOptions.awk -v className=Options
options.lst", is less than 50 lines (and would be less if I'd
compromize on the formatting of the generated class), and is a
lot simpler. (For one time use, this could be made even
simpler, by dropping support for comments, error checking, etc.
Or with very little effort and additional code, it could be made
more generic, supporting more than one specification in the same
file, with the class name specified in the file, and generating
two files, a header and source, for each class.

For that matter, if you're willing to use macros, what does your
solution buy you over:

#define MYPREFIX_DECLARE_ATTR( class ,name, type,
defaultValue ) \

private: \
Fallible< type > my_ ##
name ; \

public: \
type name()
const \

{ \
return my ## name.elseDefaultTo
( defaultValue ) ; \
}
\
class& name( type new_ ##
name ) \

{ \
my ## name.validate( new_ ##
name ) ; \
return
*this ; \
}

class Options
{
#define MYPREFIX_OPTION( name, type, defaultValue ) \
MYPREFIX_DECLARE_ATTR( Options, name, type, defaultValue )
MYPREFIX_OPTION( x, double, 3.14159 ) ;
MYPREFIX_OPTION( y, int, 42 ) ;
// ...
#undef MYPREFIX_OPTION
} ;

? The resulting class will be bigger than necessary (since each
Fallible requires an additional bool), and slightly slower, at
least if the types involved are cheap to construct, but I doubt
that it really matters in most cases.

Alf P. Steinbach

unread,
Jul 26, 2009, 5:11:44 AM7/26/09
to
* James Kanze:

> On Jul 25, 11:23 am, "Alf P. Steinbach" <al...@start.no> wrote:
>> * James Kanze:
>>> I don't know. I don't really understand what's going on,
>>> without seeing the definitions of the macros you're using.
>
>> They're ugly! :-)
>
>> Or "in-elegant"...
>
>> Hence the plea for simpler pure-C++ solution that supports the
>> same, in particular extension and simple notation (client
>> code).
>
> Just curious, but why does it have to be "pure-C++"? As I said
> earlier, a short AWK script does the job just fine.

Why not pure C++?

If something as simple as this can't be expressed easily, then at least we can
(perhaps, hopefully) find out where the flaws in the language are.


> BTW: What is the Windows equivalent of AWK?

VBScript.


> There must be one,
> or do all Windows programmers have CygWin or something similar
> installed?

Yes. Plus freestanding *nix tools for Windows. And there must be some who run
Microsoft Services for Unix (SFU), which gives you *nix in Windows, with g++
redistributed by Microsoft...


> Or Perl---you could easily do it in Perl, if you
> can stand Perl? Or probably Python or Ruby, or just about any
> "small language" that's text oriented. (All of the Windows
> programmers I know do use CygWin, so maybe there is something
> essential for program development missing in Windows.)

Not so much that Windows is missing stuff (it is, e.g. backquoting is horrible)
so much that e.g. most build scripts for libraries depend on *nix tools.


> Anyway...
>
>> <code>
>> #include <boost/mpl/clear.hpp>
>> #include <boost/mpl/front.hpp>
>> #include <boost/mpl/inherit.hpp>
>> #include <boost/mpl/inherit_linearly.hpp>
>> #include <boost/mpl/list.hpp>
>> #include <boost/mpl/pop_front.hpp>
>
>> namespace cppx { namespace typelist {
>
>> typedef boost::mpl::clear< boost::mpl::list<> >::type Empty;
>
> You've already lost me. I don't have the slightest knowledge of
> Boost::mpl, and in general, I find most of the advanced
> meta-programming idioms too complicated for general use.

I don't have the slightest knowledge either. I just used the MPL typelist,
checking the docs as I wrote, instead of locating or downloading new version of
Loki, or writing one from scratch (it's pretty simple, really). The above
expression is probably overkill for its purpose: it addresses that the type of
'mpl::list<>', a logically empty list of types, is not the same as the type of
an empty list produced by reduction of a list. Probably just

typedef boost::mpl::list<>::type Empty;

would suffice to define the "real" empty list type.

But I don't know, I've never used that typelist implementation before, and was a
bit surprised that this was necessary.

Well 150 lines of code isn't much to talk about, really. :-)


> and is a lot simpler.

Only where it doesn't matter: for producing that support code in the first place.

For using it I think an all C++ solution such as my Friday code is much simpler,
both with respect to using it from scratch, with respect to maintainance (no
redundancy), and with respect to build configuration.

This does not produce an extensible class.

In particular it can not, AFAICS, be used to produce the two option classes in
my example usage code shown earlier in thread (natural modifications OK, of
course), which you'll see if you try.

But you make me wonder: what does the script buy you over the above, which
AFAICS offers the same functionality with less code and easier maintainance?


> The resulting class will be bigger than necessary (since each
> Fallible requires an additional bool), and slightly slower, at
> least if the types involved are cheap to construct, but I doubt
> that it really matters in most cases.

If that's all that you require of the class then that scheme is superb, because
it's simple. :-) But the little inefficiency is not necessary. Just replace
Fallible with a class that constructs the contained value with the specified
default. Of course you need one such class per option, even when the options are
of the same type. And then you have the basic options-as-types scheme... ;-)

But the above is not a superb solution to my little problem, for it does not let
you extend the resulting class except by requiring the code that uses the
setters to always use base class setters last, which to me feels very wrong.

I think that problem indicates that there's a missing feature in C++, because it
"should" be trivial to express, and indeed is trivial in any scripting language.

Jerry Coffin

unread,
Jul 26, 2009, 11:14:09 AM7/26/09
to
In article <c0805f61-3f00-4730-92b0-
c98e03...@c29g2000yqd.googlegroups.com>, james...@gmail.com
says...

[ ... ]

> BTW: What is the Windows equivalent of AWK? There must be one,
> or do all Windows programmers have CygWin or something similar
> installed?

Nah -- various versions of AWK have been compiled natively for
Windows (and even MS-DOS) for years. One project that has ported a
reasonable number of the major GNU utilities to Windows (native, not
Cygwin) is at:

http://unxutils.sourceforge.net/

This includes both gawk and m4, either of which would be quite
adequate for jobs like this.

--
Later,
Jerry.

James Kanze

unread,
Jul 26, 2009, 11:15:36 AM7/26/09
to
On Jul 26, 11:11 am, "Alf P. Steinbach" <al...@start.no> wrote:
> * James Kanze:

> > On Jul 25, 11:23 am, "Alf P. Steinbach" <al...@start.no> wrote:
> >> * James Kanze:
> >>> I don't know. I don't really understand what's going on,
> >>> without seeing the definitions of the macros you're using.

> >> They're ugly! :-)

> >> Or "in-elegant"...

> >> Hence the plea for simpler pure-C++ solution that supports
> >> the same, in particular extension and simple notation
> >> (client code).

> > Just curious, but why does it have to be "pure-C++"? As I
> > said earlier, a short AWK script does the job just fine.

> Why not pure C++?

Because some other tool does the job better? "Pure C++" isn't a
particular goal in my mind, any more than "pure OO" or pure
anything else. I use the tools best fitted for the job.

> If something as simple as this can't be expressed easily, then
> at least we can (perhaps, hopefully) find out where the flaws
> in the language are.

Why is it necessarily a flaw in the language? No tool can be
perfect for everything. Use the most appropriate tool.

> > BTW: What is the Windows equivalent of AWK?

> VBScript.

> > There must be one, or do all Windows programmers have
> > CygWin or something similar installed?

> Yes. Plus freestanding *nix tools for Windows. And there must
> be some who run Microsoft Services for Unix (SFU), which gives
> you *nix in Windows, with g++ redistributed by Microsoft...

OK. (I'm starting a new job in September, in a purely Windows
environment. It will be the first time in my life I've been in
a purely Windows environment.)

> > Or Perl---you could easily do it in Perl, if you can stand
> > Perl? Or probably Python or Ruby, or just about any "small
> > language" that's text oriented. (All of the Windows
> > programmers I know do use CygWin, so maybe there is
> > something essential for program development missing in
> > Windows.)

> Not so much that Windows is missing stuff (it is, e.g.
> backquoting is horrible) so much that e.g. most build scripts
> for libraries depend on *nix tools.

In a way, I'm happy to hear that. It means that I already know
a significant (and for me important) part of the environment
where I'm going:-).

> > Anyway...

> >> namespace cppx { namespace typelist {

Well, that sounds like another reason to use something else. I
wouldn't use a tool that I didn't at least vaguely understand.
(It's a difficult issue, of course---I suspect that most C++
programmers wouldn't be capable of writing a C++ compiler, and
they shouldn't need that knowledge. But I don't even know what
Boost::mpl---or anything in Loki---really does.)

If it's fairly trivial and easy to understand:-).

> > and is a lot simpler.

> Only where it doesn't matter: for producing that support code
> in the first place.

> For using it I think an all C++ solution such as my Friday
> code is much simpler, both with respect to using it from
> scratch, with respect to maintainance (no redundancy), and
> with respect to build configuration.

For using it, there is one argument in favor of all C++, if it's
straightforward: presumable new people on the project will
understand it immediately. IMHO, as soon as you use Boost::mpl,
or Loki, you've lost that advantage. As for maintenance: the
input file for my AWK script looks something like:

x double 3.14159
y int 42
# ...

It's hard for me to imagine anything easier to maintain---to add
a new attribute, it's one line. (In the form I actually use,
the AWK script is about twice as long, and the input has the
form:

[Option] # the class name...
x double 3.14159
y int 42
# ...

The results are two files, Option.hh and Option.cc.)

Of course, if you really want pure C++... I've also got classes
to facilitate used C++ programs to generate C++, and with even a
minimum of the usual C++ stuff, rewriting the AWK in C++
shouldn't pose any great problem. In this case, the AWK doesn't
really use any of the special functionality of AWK. It's just
that for me, for such small programs, I find AWK simpler. (I
have cases where the generation is significantly more complex,
in which case, I do use C++.)

> > public: \
> > type name()
> > const \

> > ?

Extensible in what way?

> In particular it can not, AFAICS, be used to produce the two
> option classes in my example usage code shown earlier in
> thread (natural modifications OK, of course), which you'll see
> if you try.

I'll look at it, but I'll admit that I've never found any reason
to "extend" an options class. They're normally one-of sort of
things.

> But you make me wonder: what does the script buy you over the
> above, which AFAICS offers the same functionality with less
> code and easier maintainance?

First, the AWK stuff doesn't use macros, so doesn't impinge on
the global namespace in anyway. (My actual AWK script handles
options to specify the namespace in which to build the class,
files to include, etc.) And the AWK stuff generates a complete
class; there's absolutely nothing else to do. Still, for a
one-of use, I'd use the above; the AWK script came about because
it fulfilled a more or less recurrent need.

> > The resulting class will be bigger than necessary (since
> > each Fallible requires an additional bool), and slightly
> > slower, at least if the types involved are cheap to
> > construct, but I doubt that it really matters in most cases.

> If that's all that you require of the class then that scheme
> is superb, because it's simple. :-) But the little
> inefficiency is not necessary. Just replace Fallible with a
> class that constructs the contained value with the specified
> default.

But then you have to maintain the default outside of the macro
declarations. IMHO, it's not usually a big deal, but it does
mean that you have to cite the name of the attribute twice, and
update in two locations if you add one.

> Of course you need one such class per option, even when the
> options are of the same type. And then you have the basic
> options-as-types scheme... ;-)

I'm not sure I follow. You need one class for each distinct set
of options. Typically, in a GUI, there will only be one or two
distinct sets of options... in a lot of GUI's, there will only
be one (although some components may ignore certain options).

> But the above is not a superb solution to my little problem,
> for it does not let you extend the resulting class except by
> requiring the code that uses the setters to always use base
> class setters last, which to me feels very wrong.

> I think that problem indicates that there's a missing feature
> in C++, because it "should" be trivial to express, and indeed
> is trivial in any scripting language.

The basic problem is that you're "generating" code. Which is
fairly simple to express in interpreted languages like Lisp or
the shell, which can interpret the code you've just generated.
(In classical computer science, this is called "self modifying
code", and has a very bad reputation with regards to
maintainability. There are very good reasons why such
interpreted languages aren't used for critical systems.) I've
one or two applications which use such techniques, but they're
written in Unix shell, not in C++. (In one case, I have the
moral equivalent of "awk -f someProgram.awk file1 | awk -f -
file2 | isql", the awk script "someProgram.awk" reads a
configuration file to generate an awk script which is used to
generate SQL. It some ways, it's very elegant, but it can be a
real pain in the ass to maintain. Finding a bug in the SQL is a
pain, when the SQL is generated dynamically at each execution.)

Alf P. Steinbach

unread,
Jul 26, 2009, 4:35:09 PM7/26/09
to
* James Kanze:
> On Jul 26, 11:11 am, "Alf P. Steinbach" <al...@start.no> wrote:
>> * James Kanze:
>
>>> On Jul 25, 11:23 am, "Alf P. Steinbach" <al...@start.no> wrote:
>>>> * James Kanze:
>>>>> I don't know. I don't really understand what's going on,
>>>>> without seeing the definitions of the macros you're using.
>
>>>> They're ugly! :-)
>
>>>> Or "in-elegant"...
>
>>>> Hence the plea for simpler pure-C++ solution that supports
>>>> the same, in particular extension and simple notation
>>>> (client code).
>
>>> Just curious, but why does it have to be "pure-C++"? As I
>>> said earlier, a short AWK script does the job just fine.
>
>> Why not pure C++?
>
> Because some other tool does the job better? "Pure C++" isn't a
> particular goal in my mind, any more than "pure OO" or pure
> anything else. I use the tools best fitted for the job.

Avoiding extra languages is a worthwhile goal.

With extra languages other people need to be familiar with them; you have code
generation which means that you have extra files that must be managed and must
not be modified; the build process needs to accomodate the code and you have at
least one extra build step; anyone wishing to use your code needs the tools for
the extra language, which may not be easily available; so on.

I see that as just needless complication & restriction.


>> If something as simple as this can't be expressed easily, then
>> at least we can (perhaps, hopefully) find out where the flaws
>> in the language are.
>
> Why is it necessarily a flaw in the language? No tool can be
> perfect for everything. Use the most appropriate tool.

Simple things should be simple to express.

C++ isn't an inappropriate language, but that's only due to the factors that
count against using physical code generation.


[snip]

*Hark*.

I find it difficult to believe that you're unfamiliar with typelists.

But anyway, a pencil is a pencil is a pencil, there is nothing mysterious about
them. If the pencil you grab to write something with is covered with very small
cactus-like things that hurt your fingers, then, after looking around to check
whether there's any other pencil near you, you simply wrap the pencil in
something, and perhaps remark: "huh, that's odd, why the heck did they design
the pencil that way". It's less work to wrap than to go buy a set of pencils.


> (It's a difficult issue, of course---I suspect that most C++
> programmers wouldn't be capable of writing a C++ compiler, and
> they shouldn't need that knowledge.

In contrast it's trivial to write a typelist implementation that provides basic
functionality, and any C++ programmer should be able to do so: any C++
programmer should be able to just sit down and write it without any second thought.


> But I don't even know what
> Boost::mpl---or anything in Loki---really does.)

Boost::mpl is much more than typelists.

But.

A typelist is a list of types. There are two main ways to build a typelist:
using the idea of a list as a head + a tail, which is a recursive definition,
and using the idea of a list as an array, which requires defaulting on template
parameters. The latter is what MPL does for the general 'list' type constructor,
which is the reason that a computed MPL empty list has a different type.


[snip]

> For using it, there is one argument in favor of all C++, if it's
> straightforward: presumable new people on the project will
> understand it immediately. IMHO, as soon as you use Boost::mpl,
> or Loki, you've lost that advantage.

Do you need to understand the details of the innards of your TV to use it?

I haven't found any need to be TV engineer (whatever) in order to use a TV.

Similarly, one does not need to understand template metaprogramming in order to
use something (such as my code) that uses that internally.

If you start looking at the inner parts that you don't understand, and think
that the high-voltage thingies etc. make the TV very dangerous, and that the
complexity of the circuitry inside makes the TV unsuable, well that's wrong.

Simply don't peer into the innards, use the controls at the front of the TV! :-)


> As for maintenance: the
> input file for my AWK script looks something like:
>
> x double 3.14159
> y int 42
> # ...
>
> It's hard for me to imagine anything easier to maintain---to add
> a new attribute, it's one line. (In the form I actually use,
> the AWK script is about twice as long, and the input has the
> form:
>
> [Option] # the class name...
> x double 3.14159
> y int 42
> # ...
>
> The results are two files, Option.hh and Option.cc.)

With C++ you add one line and modify the line that defines the class, e.g., with
JK as James Kanze macro prefix:

JK_DEF_OPT( x, 3.14159 )
JK_DEF_OPT( y, int, 42 )
JK_DEF_OPT_CLS_2( Option, nobase, x, y )

The result is generated code at the point of those macro invocations, no extra
files to care about and manage, no generated files to remember to not modify.

E.g. the code can be generated inside any desired namespace or class.


[snip]
> Extensible in what way?

My up-thread usage example's definition was

CPPX_DEFINE_OPTION( x, double )


CPPX_DEFINE_OPTION( y, double )
CPPX_DEFINE_2OPTIONCLASS( Pos2Options, cppx::options::NoBase, x, y )

CPPX_DEFINE_OPTION( z, double )
CPPX_DEFINE_1OPTIONCLASS( Pos3Options, Pos2Options, z )

where the last line expresses a base-derived class relationship.


>> In particular it can not, AFAICS, be used to produce the two
>> option classes in my example usage code shown earlier in
>> thread (natural modifications OK, of course), which you'll see
>> if you try.
>
> I'll look at it, but I'll admit that I've never found any reason
> to "extend" an options class. They're normally one-of sort of
> things.

So, this isn't the problem you've been dealing with. :-)


>> But you make me wonder: what does the script buy you over the
>> above, which AFAICS offers the same functionality with less
>> code and easier maintainance?
>
> First, the AWK stuff doesn't use macros, so doesn't impinge on
> the global namespace in anyway. (My actual AWK script handles
> options to specify the namespace in which to build the class,
> files to include, etc.) And the AWK stuff generates a complete
> class; there's absolutely nothing else to do. Still, for a
> one-of use, I'd use the above; the AWK script came about because
> it fulfilled a more or less recurrent need.

Namespace contamination is a valid concern, but it's minimal.

That the AWK stuff generates a complete class is not an argument in its favor.
It only indicates that there something so AWKward ;-) about it that generating a
complete class is somehow seen as an accomplishment. The C++ macros I presented
of course also generate a complete class.

And the C++ macros that I presented don't suffer from the problems of the AWK
script, i.e. with a proper C++ solution

* you don't generate extra files to worry about,

* you don't have extra tool requirements and extra tools usage, and

* you don't restrict the generated class' namespace or container class,
which with C++ is just where you invoke the macro.


>>> The resulting class will be bigger than necessary (since
>>> each Fallible requires an additional bool), and slightly
>>> slower, at least if the types involved are cheap to
>>> construct, but I doubt that it really matters in most cases.
>
>> If that's all that you require of the class then that scheme
>> is superb, because it's simple. :-) But the little
>> inefficiency is not necessary. Just replace Fallible with a
>> class that constructs the contained value with the specified
>> default.
>
> But then you have to maintain the default outside of the macro
> declarations.

No.


> IMHO, it's not usually a big deal, but it does
> mean that you have to cite the name of the attribute twice, and
> update in two locations if you add one.
>
>> Of course you need one such class per option, even when the
>> options are of the same type. And then you have the basic
>> options-as-types scheme... ;-)
>
> I'm not sure I follow. You need one class for each distinct set
> of options. Typically, in a GUI, there will only be one or two
> distinct sets of options... in a lot of GUI's, there will only
> be one (although some components may ignore certain options).

The reason you're not sure you follow is probably that you've interjected
comments so as to take the statement you don't follow out of context.

I was taking about replacing the Fallible class you used in your example.

I.e. replacing Fallible with something that for the purpose is simpler and more
efficient (actually I've already presented complete code for that).


>> But the above is not a superb solution to my little problem,
>> for it does not let you extend the resulting class except by
>> requiring the code that uses the setters to always use base
>> class setters last, which to me feels very wrong.
>
>> I think that problem indicates that there's a missing feature
>> in C++, because it "should" be trivial to express, and indeed
>> is trivial in any scripting language.
>
> The basic problem is that you're "generating" code. Which is
> fairly simple to express in interpreted languages like Lisp or
> the shell, which can interpret the code you've just generated.
> (In classical computer science, this is called "self modifying
> code", and has a very bad reputation with regards to
> maintainability.

Uh oh, careful now. The code isn't self-modifying. The code isn't the kind that
has a bad reputation. :-)


Cheers,

- Alf

Alf P. Steinbach

unread,
Jul 27, 2009, 1:44:22 AM7/27/09
to
* Alf P. Steinbach:
> * James Kanze:

>
> [snip]
>> Extensible in what way?
>
> My up-thread usage example's definition was
>
> CPPX_DEFINE_OPTION( x, double )
> CPPX_DEFINE_OPTION( y, double )
> CPPX_DEFINE_2OPTIONCLASS( Pos2Options, cppx::options::NoBase, x, y )
>
> CPPX_DEFINE_OPTION( z, double )
> CPPX_DEFINE_1OPTIONCLASS( Pos3Options, Pos2Options, z )
>
> where the last line expresses a base-derived class relationship.
>
>
>>> In particular it can not, AFAICS, be used to produce the two
>>> option classes in my example usage code shown earlier in
>>> thread (natural modifications OK, of course), which you'll see
>>> if you try.
>>
>> I'll look at it, but I'll admit that I've never found any reason
>> to "extend" an options class. They're normally one-of sort of
>> things.
>
> So, this isn't the problem you've been dealing with. :-)

Perhaps an example can help you/others understand the intentded usage.

In MainWindow constructor (this is just ephemeral try-it-out code) there is

new Edit( *this, Edit::Params()
.text( L"Blah blah" )
.position( Point( 10, 10 ) )
.size( Point( 300, 20 ) )
);
new Button( *this, Button::Params()
.text( L"My button" )
.position( Point( 10, 40 ) )
.size( Point( 160, 24 ) )
.isDefault( true )
);

where the Params passed to the Edit control and the Params passed to the Button
control have the same .text, .position and .size elements, because they're
derived from the same base general window Params class.

The Params passed to the Button control have an additional .isDefault, which is
not meaningful for the Edit control and hence doesn't exist in Edit::Params.

In class Button the extra .isDefault option is added thusly, in a nested class
ApiWindowFactory:

class ApiWindowFactory
: public Outer::Base::ApiWindowFactory
{
typedef Outer::Base::ApiWindowFactory Base;
private:
bool myIsDefaultButton;

public:
CPPX_DEFINE_OPTION_VALUE( isDefault, bool, false )
CPPX_DEFINE_1OPTIONCLASS( Params, Base::Params, isDefault )

ApiWindowFactory(
Window& parentWindow,
Params const& params = Params()
)
: Base( parentWindow, params )
, myIsDefaultButton( params.isDefault() )
{}

virtual ButtonKind::Enum apiButtonKind() const
{
CPPX_IS_OVERRIDE_OF( Base::apiButtonKind );
return (myIsDefaultButton? ButtonKind::defPushButton :
ButtonKind::pushButton);
}
};

As you can see defining the derived Params with an extra .isDefault, adding in
derived class setters for all the base class elements (.text, .position, .size
etc.), is very very simple, two lines of code, placed right where the definition
is desired -- and no external script or extra files or ... :-)

There is a limitation of the macro implementations I posted earlier that the
base class can't be specified via typedef, but I don't consider that a problem;
rather, the problem is that I would want a simpler macro implementation.


Cheers,

- Alf

James Kanze

unread,
Jul 27, 2009, 4:40:23 AM7/27/09
to
On Jul 26, 10:35 pm, "Alf P. Steinbach" <al...@start.no> wrote:
> * James Kanze:

> > On Jul 26, 11:11 am, "Alf P. Steinbach" <al...@start.no> wrote:
> >> * James Kanze:

> >>> On Jul 25, 11:23 am, "Alf P. Steinbach" <al...@start.no> wrote:
> >>>> * James Kanze:
> >>>>> I don't know. I don't really understand what's going on,
> >>>>> without seeing the definitions of the macros you're using.

> >>>> They're ugly! :-)

> >>>> Or "in-elegant"...

> >>>> Hence the plea for simpler pure-C++ solution that supports
> >>>> the same, in particular extension and simple notation
> >>>> (client code).

> >>> Just curious, but why does it have to be "pure-C++"? As I
> >>> said earlier, a short AWK script does the job just fine.

> >> Why not pure C++?

> > Because some other tool does the job better? "Pure C++" isn't a
> > particular goal in my mind, any more than "pure OO" or pure
> > anything else. I use the tools best fitted for the job.

> Avoiding extra languages is a worthwhile goal.

Why?

> With extra languages other people need to be familiar with
> them;

True. In the end, it's a trade-off. But anyone who knows C++
can learn AWK in an hour or so, and it's a generally useful
tool. And of course, you'll end up using extra languages
anyway; you're not going to write all of the C++ by hand.

Also, of course, with the correct tool kit, the AWK can be
transcribed into C++ with little extra work. (See things like
FieldArray, at my site. That's really all you'd need in this
case, but I also have a class for creating C++ sources, which
manages namespaces and include files, and automatically
generates the header (with copyright), footer (with
configuration information for emacs and vim), and if the
filename ends with .*hh, .hpp, .hxx, .h or .H, the include
guards. (Which means that the results would be more complete
than with my AWK script.)

Again. If it's just a one-of situation, I'd just use the
macros. If it's something that may occur again, investing a
little more time (not much) and using an external generator is
probably more effective in the long run.

> you have code generation which means that you have extra
> files that must be managed and must not be modified; the build
> process needs to accomodate the code and you have at least one
> extra build step; anyone wishing to use your code needs the
> tools for the extra language, which may not be easily
> available; so on.

But in any non-trivial project, you're going to have code
generation anyway. The only question is what tool to use. That
was behind my question as to what Windows programmers habitually
use.

> I see that as just needless complication & restriction.

> >> If something as simple as this can't be expressed easily,
> >> then at least we can (perhaps, hopefully) find out where
> >> the flaws in the language are.

> > Why is it necessarily a flaw in the language? No tool can
> > be perfect for everything. Use the most appropriate tool.

> Simple things should be simple to express.

It is simple to express. In AWK. Or in C++, if you've got the
right tools available. What you seem to want, however, is that
the program to generate the code be expressed in the same
program which it generates; that's what creates the complexity.

That always creates a complexity. If you need to do it (e.g.
because the program generating the code needs information, such
as type information, resulting from compiling other parts of the
code), then you do it. Otherwise, using an external program is
generally preferable for all but the simplest generation. It
does add a little bit of complexity to the build
procedure---when I do such things, I usually have to add two or
three lines to the makefile, manually. But keeping the
generation logic separate from the rest of the program makes
things much easier to read and understand.

> C++ isn't an inappropriate language, but that's only due to
> the factors that count against using physical code generation.

C++ isn't an inappropriate language, really. It's just a little
heavy, given the simplicity of the generation program---using
C++ for the external generation complicates the build procedure
even more.

What complicates your code is the fact that you're trying to
embed two totally independent things---the code generation, and
the program you want to compile in the end---in a single source
file. My experience with this sort of thing (e.g. TeX, or the
text macros in Intel's original ASM-86) is that it rapidly
becomes confusing.

> >>>> namespace cppx { namespace typelist {

> *Hark*.

I've heard the name, but that's about it. I don't doubt that I
could learn them, if I had any reason to, but until now, I've
not had any reason to.

> But anyway, a pencil is a pencil is a pencil, there is nothing
> mysterious about them. If the pencil you grab to write
> something with is covered with very small cactus-like things
> that hurt your fingers, then, after looking around to check
> whether there's any other pencil near you, you simply wrap the
> pencil in something, and perhaps remark: "huh, that's odd, why
> the heck did they design the pencil that way". It's less work
> to wrap than to go buy a set of pencils.

But I've already got lot's of other pencils laying around:-).
For starters, AWK is installed on all of the machines I have
access to, and I know it pretty well. And if for some reason I
didn't want to use AWK, one of the first things I did when I
started using C++ was write classes to support most of what AWK
does: String (this was long before std::string existed),
RegularExpression and FieldArray (which breaks a string up into
fields). Again, the toolset is there---you could, in fact,
easily implement what I did in AWK using nothing more than
iostream and std::string (although I'd probably throw in
boost::regex for good measure).

For a number of historical reasons, my code is designed to be
built in a Unix-like environment. AWK is there, I know it, and
it is simpler to insert into the build process than C++ code
(which means you have to compile and link a separate program).
So I use it. But the important aspect, in my mind, is that the
code which generates the code is completely separate from what
it generates.

> > (It's a difficult issue, of course---I suspect that most C++
> > programmers wouldn't be capable of writing a C++ compiler, and
> > they shouldn't need that knowledge.

> In contrast it's trivial to write a typelist implementation
> that provides basic functionality, and any C++ programmer
> should be able to do so: any C++ programmer should be able to
> just sit down and write it without any second thought.

Maybe. Given that all I know about it is the name, I can't
judge. I don't really even know what it does, exactly. (I'm
guessing that it's some sort of list of types, but I don't
really know what that means, or how it is used.)

> > But I don't even know what
> > Boost::mpl---or anything in Loki---really does.)

> Boost::mpl is much more than typelists.

> But.

> A typelist is a list of types. There are two main ways to
> build a typelist: using the idea of a list as a head + a tail,
> which is a recursive definition, and using the idea of a list
> as an array, which requires defaulting on template parameters.
> The latter is what MPL does for the general 'list' type
> constructor, which is the reason that a computed MPL empty
> list has a different type.

The former sounds like Lisp:-).

> [snip]

> > For using it, there is one argument in favor of all C++, if
> > it's straightforward: presumable new people on the project
> > will understand it immediately. IMHO, as soon as you use
> > Boost::mpl, or Loki, you've lost that advantage.

> Do you need to understand the details of the innards of your
> TV to use it?

> I haven't found any need to be TV engineer (whatever) in order
> to use a TV.

> Similarly, one does not need to understand template
> metaprogramming in order to use something (such as my code)
> that uses that internally.

> If you start looking at the inner parts that you don't
> understand, and think that the high-voltage thingies etc. make
> the TV very dangerous, and that the complexity of the
> circuitry inside makes the TV unsuable, well that's wrong.

> Simply don't peer into the innards, use the controls at the
> front of the TV! :-)

But someone has to maintain the code. If it's part of an
externally provided library, then the library clients don't have
to understand it---I don't usually look at the internals of the
libraries I use. (The one exception is std::string of g++.
Because I was told it used reference counting, and was fully
thread safe. And it was suggested by other people, e.g. Herb
Sutter, that this wasn't possible. And in fact, g++'s
implementation of std::string isn't thread safe.)

> > As for maintenance: the input file for my AWK script looks
> > something like:

> > x double 3.14159
> > y int 42
> > # ...

> > It's hard for me to imagine anything easier to maintain---to add
> > a new attribute, it's one line. (In the form I actually use,
> > the AWK script is about twice as long, and the input has the
> > form:

> > [Option] # the class name...
> > x double 3.14159
> > y int 42
> > # ...

> > The results are two files, Option.hh and Option.cc.)

> With C++ you add one line and modify the line that defines the
> class, e.g., with JK as James Kanze macro prefix:

> JK_DEF_OPT( x, 3.14159 )
> JK_DEF_OPT( y, int, 42 )
> JK_DEF_OPT_CLS_2( Option, nobase, x, y )

> The result is generated code at the point of those macro
> invocations, no extra files to care about and manage, no
> generated files to remember to not modify.

You're still mentionning x and y twice:-). So you have to
insert one line, and modify another; in my version (both macros
and AWK), you just insert a single line.

Anyway: I'm supposing that the _2 in the last line specifies the
number of attributes. IMHO, that's error prone, but get rid of
that, and I think I could buy it.

Don't forget that I developped my solution with AWK before
compilers supported templates. Of any sort. And it works, so
I've had no motivation to change it. And I still suspect that
the AWK code, even with all of the options I've given it, is a
lot simpler to understand and maintain than your templates and
macros.

> E.g. the code can be generated inside any desired namespace or
> class.

My AWK script actually handles that as well:-). But that does
make it more complicated. The alternative is to include the
generated code in the context you want.

> [snip]

> > Extensible in what way?

> My up-thread usage example's definition was

> CPPX_DEFINE_OPTION( x, double )
> CPPX_DEFINE_OPTION( y, double )
> CPPX_DEFINE_2OPTIONCLASS( Pos2Options, cppx::options::NoBase, x, y )

> CPPX_DEFINE_OPTION( z, double )
> CPPX_DEFINE_1OPTIONCLASS( Pos3Options, Pos2Options, z )

> where the last line expresses a base-derived class relationship.

I could easily add that to my script, but I've never needed it.
(It's already implicitly there with the macro solution.)

> >> In particular it can not, AFAICS, be used to produce the two
> >> option classes in my example usage code shown earlier in
> >> thread (natural modifications OK, of course), which you'll see
> >> if you try.

> > I'll look at it, but I'll admit that I've never found any reason
> > to "extend" an options class. They're normally one-of sort of
> > things.

> So, this isn't the problem you've been dealing with. :-)

As I said, I've never needed it.

> >> But you make me wonder: what does the script buy you over the
> >> above, which AFAICS offers the same functionality with less
> >> code and easier maintainance?

> > First, the AWK stuff doesn't use macros, so doesn't impinge on
> > the global namespace in anyway. (My actual AWK script handles
> > options to specify the namespace in which to build the class,
> > files to include, etc.) And the AWK stuff generates a complete
> > class; there's absolutely nothing else to do. Still, for a
> > one-of use, I'd use the above; the AWK script came about because
> > it fulfilled a more or less recurrent need.

> Namespace contamination is a valid concern, but it's minimal.

Agreed. All those prefixes don't look pretty, but the get the
job done, and they don't occur in the middle of complex
expressions, or other places where they would lead to confusion.

> That the AWK stuff generates a complete class is not an
> argument in its favor. It only indicates that there something
> so AWKward ;-) about it that generating a complete class is
> somehow seen as an accomplishment. The C++ macros I presented
> of course also generate a complete class.

When I said "generates a complete class", I meant that it
generates everything you'd write if you wrote a class yourself:
a header file and a source file, with all of the includes, etc.
necessary.

> And the C++ macros that I presented don't suffer from the
> problems of the AWK script, i.e. with a proper C++ solution

> * you don't generate extra files to worry about,

If it's a separate class, don't you want it in a separate
header, with a separate source file?

(Seriously, I think it depends on the application. In my case,
the generated class was an important class in a fairly large
library, and it definitely made sense for it to behave vis-a-vis
client code like any other class in the library, with it's own
header, etc. I can imagine that in other cases, other solutions
would be preferred.)

> * you don't have extra tool requirements and extra tools
> usage, and

To which I say: so what? In practice, I already have the tool
requirements, since I require GNU make for my makefiles, and a
number of other Unix tools for things like generating and
running test suites, cleaning up flex output so it passes modern
C++ compilers, generating the documentation (using Doxygen, but
with significant pre- and post-processing), etc.

You can't develop a project with just a compiler; you need a
tool kit of some kind. (Again, that was why I asked what
Windows programmers use. You do need something.)

> * you don't restrict the generated class' namespace or container class,
> which with C++ is just where you invoke the macro.

My personal scripts allow for this as well (although they won't
generated the class as a nested class), but I'll admit that your
solution does seem simpler in this respect.

> No.

OK. You mean using a separate type for each option (and, I
suppose, putting the default value in the constructor for the
type). I'd missed that.

You still have to declare that type, before declaring the
option.

> >> But the above is not a superb solution to my little problem,
> >> for it does not let you extend the resulting class except by
> >> requiring the code that uses the setters to always use base
> >> class setters last, which to me feels very wrong.

> >> I think that problem indicates that there's a missing feature
> >> in C++, because it "should" be trivial to express, and indeed
> >> is trivial in any scripting language.

> > The basic problem is that you're "generating" code. Which is
> > fairly simple to express in interpreted languages like Lisp or
> > the shell, which can interpret the code you've just generated.
> > (In classical computer science, this is called "self modifying
> > code", and has a very bad reputation with regards to
> > maintainability.

> Uh oh, careful now. The code isn't self-modifying. The code
> isn't the kind that has a bad reputation. :-)

Well, yours isn't self modifying in the traditional sense,
because in C++, templates are completely evaluated by the
compiler, but the Lisp versions are, sort of. More importantly,
while neither is really considered the self-modifying that has
the bad reputation, IMHO, there's a real sense that at least
some meta-programming is: when you look at the source code, what
you see is not what you get. (I don't think that your code, at
least as I finally understand it, suffers from this---at least
not if you've documented the macros sufficiently.)

James Kanze

unread,
Jul 27, 2009, 4:47:30 AM7/27/09
to

OK. I rather suspect that this could have been used in my case
as well. In my case, most of the components shared a very large
set of options, and have few, if any, additional options (one or
two at the most), so we just used an Options class for the
common options, and additional arguments (with defaults) for the
one or two additional attributes, when present. But your
solution seems more elegant.

Yep. And my solution doesn't support generating a nested class
(and making it do so would be almost impossible).

I still don't agree with your objections because an extra tool
is used---I'd rather use an extra tool than do extra work
myself. But in this case, you've pretty much convinced me that
your solution does something the "simpler" solution with the
extra tool can't, which is a strong argument in its favor.

James Kanze

unread,
Jul 27, 2009, 4:54:08 AM7/27/09
to
On Jul 26, 5:14 pm, Jerry Coffin <jerryvcof...@yahoo.com> wrote:
> In article <c0805f61-3f00-4730-92b0-
> c98e03534...@c29g2000yqd.googlegroups.com>, james.ka...@gmail.com
> says...

> [ ... ]

> > BTW: What is the Windows equivalent of AWK? There must be
> > one, or do all Windows programmers have CygWin or something
> > similar installed?

> Nah -- various versions of AWK have been compiled natively for
> Windows (and even MS-DOS) for years.

I know that. I was using a Unix-like tool kit under MS-DOS in
the late 1908's. But I'm hardly a typical Windows user; I was
wondering what typical Windows developers use.

> One project that has ported a reasonable number of the major
> GNU utilities to Windows (native, not Cygwin) is at:

> http://unxutils.sourceforge.net/

> This includes both gawk and m4, either of which would be quite
> adequate for jobs like this.

Yes. I mentioned CygWin more as a placeholder for any Unix-like
tool kit, rather than with the idea of CygWin, and only CygWin.
I'm aware of at least three others: UWin, MSys and MKS (the
latter commercial, and rather expensive---although it wasn't too
expensive in the MS-DOS days), and I don't doubt that there are
others. (I'm still looking for one which integrates well,
however. Most of them seem to go out of their way to make it
difficult to use tools other than those in the toolset. And if
I'm running Windows, and not Linux, on a machine, it's because I
want to use the Windows tools when appropriate.)

Alf P. Steinbach

unread,
Jul 27, 2009, 5:28:04 AM7/27/09
to
* James Kanze:
> On Jul 26, 10:35 pm, "Alf P. Steinbach" <al...@start.no> wrote:
>
>> I find it difficult to believe that you're unfamiliar with
>> typelists.
>
> I've heard the name, but that's about it. I don't doubt that I
> could learn them, if I had any reason to, but until now, I've
> not had any reason to.

[snip]


>
>> In contrast it's trivial to write a typelist implementation
>> that provides basic functionality, and any C++ programmer
>> should be able to do so: any C++ programmer should be able to
>> just sit down and write it without any second thought.
>
> Maybe. Given that all I know about it is the name, I can't
> judge. I don't really even know what it does, exactly. (I'm
> guessing that it's some sort of list of types, but I don't
> really know what that means, or how it is used.)

Typelists were popularized by Andrei. I think he invented them independently but
they already had some history. What Andrei did was to show how all the usual run
time control structures had analogs in template metaprogramming, and to build up
from that to a framework handling types just as for run time you handle values.

I made a basic example "the minimal typelist" :-), shown below.

It may interest other readers of the group (of course what this example does is
very simple, intentionally, whereas the inheritance over a list of types in the
option macro stuff I posted earlier is one or two degrees more complex):


<code>
#include <iostream>
#include <limits>

struct NoSuch {};

// General Lisp-like typelist
template< class HeadType, class TailType = NoSuch >
struct Typelist_
{
typedef HeadType Head;
typedef TailType Tail;
};

template< class T >
void showMaxValue()
{
using namespace std;
cout << numeric_limits<T>::max() << endl;
}

template< class Typelist >
void showMaxValues()
{
showMaxValue< typename Typelist::Head >();
showMaxValues< typename Typelist::Tail >();
}

template<> void showMaxValues<NoSuch>() {}

int main()
{
typedef Typelist_<int, Typelist_<float, Typelist_<double> > > Types;
showMaxValues<Types>();
}
</code>


Cheers,

- Alf

James Kanze

unread,
Jul 27, 2009, 9:27:42 AM7/27/09
to
On Jul 27, 11:28 am, "Alf P. Steinbach" <al...@start.no> wrote:
> * James Kanze:

> > On Jul 26, 10:35 pm, "Alf P. Steinbach" <al...@start.no>
> > wrote:

> >> I find it difficult to believe that you're unfamiliar with
> >> typelists.

> > I've heard the name, but that's about it. I don't doubt
> > that I could learn them, if I had any reason to, but until
> > now, I've not had any reason to.

> [snip]

> >> In contrast it's trivial to write a typelist implementation
> >> that provides basic functionality, and any C++ programmer
> >> should be able to do so: any C++ programmer should be able
> >> to just sit down and write it without any second thought.

> > Maybe. Given that all I know about it is the name, I can't
> > judge. I don't really even know what it does, exactly.
> > (I'm guessing that it's some sort of list of types, but I
> > don't really know what that means, or how it is used.)

> Typelists were popularized by Andrei. I think he invented them
> independently but they already had some history. What Andrei
> did was to show how all the usual run time control structures
> had analogs in template metaprogramming, and to build up from
> that to a framework handling types just as for run time you
> handle values.

If what he did was to show how all the usual run time control
structures had analogs in template metaprogramming, I think Todd
Veldhuizen and David Vandevoorde beat him to it. :-)

If I understand what you're doing, at least in this case,
typelists are mainly a work-around for the absence of variadic
arguments for templates, which has been added to the next
version of the standard. (There's more to what you've written
than that, I know. But variadic arguments for templates and
macros would make it a lot, lot simpler, I think.)

Martin Eisenberg

unread,
Jul 27, 2009, 5:55:42 PM7/27/09
to
Alf P. Steinbach wrote:

> What Andrei did was to show how all the usual run time control
> structures had analogs in template metaprogramming, and to build
> up from that to a framework handling types just as for run time
> you handle values.

I believe that credit should go to Czarnecki and Eisenecker, whom
MC++D also references.


Martin

--
Quidquid latine scriptum est, altum videtur.

Alf P. Steinbach

unread,
Jul 27, 2009, 6:23:40 PM7/27/09
to
* Martin Eisenberg:

> Alf P. Steinbach wrote:
>
>> What Andrei did was to show how all the usual run time control
>> structures had analogs in template metaprogramming, and to build
>> up from that to a framework handling types just as for run time
>> you handle values.
>
> I believe that credit should go to Czarnecki and Eisenecker, whom
> MC++D also references.

As I wrote and you snipped, typelists already had some history.

The game of credit (and of snippage) is very silly.

I've never heard of Czarnecki and Eisenecker, and I doubt any reader here will
be helped by that reference. On the other hand, readers might find it useful to
know what Andrei did, in order to decide whether to buy that book. It also
contains a lot of generic implementations of patterns, which perhaps was its
main innovation, and at least a main reason for its popularity, but, due to the
game of credit etc. (uh oh, those wouldn't be /patterns/ anymore, bye GoF!),
goes to pains to point out that patterns cannot be generically implemented. :-)


Cheers & hth.,

- Alf

Alf P. Steinbach

unread,
Jul 28, 2009, 12:17:41 AM7/28/09
to
* Alf P. Steinbach:

> Original problem: a pack of options that may contain a great many simple
> numerical and bitset options (defined by external API), and that should
> be (1) extensible for at least two levels, like class derivation, (2)
> easy to define, (3) easily constructible specifying only those options
> of interest, defaulting on the rest, (4) clean notation for accessing
> options, with compile time checking, and (5) if possible as efficient as
> possible access of options.

I extended the solution posted else-thread so that it now supports arbitrary
levels of extension (I've only tested with two levels, though, as shown below).

That amounted to removing two lines, and inserting two lines. :-)

So, for those interested in trying it out, or commenting,


<code>
#include <boost/mpl/clear.hpp>
#include <boost/mpl/front.hpp>
#include <boost/mpl/inherit.hpp>
#include <boost/mpl/inherit_linearly.hpp>
#include <boost/mpl/list.hpp>
#include <boost/mpl/pop_front.hpp>

namespace cppx { namespace typelist {

typedef boost::mpl::list<>::type Empty;

template< class TypeList >
struct InheritLinearly_
{
typedef typename boost::mpl::inherit_linearly<
TypeList,
boost::mpl::inherit< boost::mpl::_1, boost::mpl::_2 >
>::type Type;
};

template< class TypeList >
struct Car_


{
typedef typename boost::mpl::front< TypeList >::type Type;
};

template< class TypeList >
struct Cdr_


{
typedef typename boost::mpl::pop_front< TypeList >::type Type;
};

#define CPPX_TYPELIST_ ::boost::mpl::list

} } // namespace cppx::typelist

namespace cppx { namespace options {

template< class T, class UniqueIdType >
class Value_
{
private:
T myValue;

public:
Value_(): myValue() {}
Value_( T const& v ): myValue( v ) {}

T const& value() const { return myValue; }
void setValue( T const& v ) { myValue = v; }

operator T const& () const { return value(); }

Value_& operator=( T const& v )
{
setValue( v ); return *this;
}
};

class NoBase {};

template< class SetterResult, class TopBase >

class NoBase_InheritTemplatedSetters_: public TopBase {};

template<
class OptionTypes,
class SetterResult,
class TopBase,
template< class, class, class > class OptionSetter_
>

class InheritTemplatedSetters_;

template<
class SetterResult,
class TopBase,
template< class, class, class > class OptionSetter_
>

class InheritTemplatedSetters_<


cppx::typelist::Empty, SetterResult, TopBase, OptionSetter_
>
: public TopBase
{};

template<
class OptionTypes,
class SetterResult,
class TopBase,
template< class, class, class > class OptionSetter_
>

class InheritTemplatedSetters_
: public OptionSetter_<
typename cppx::typelist::Car_<OptionTypes>::Type,
SetterResult,
InheritTemplatedSetters_<
typename cppx::typelist::Cdr_<OptionTypes>::Type,
SetterResult,
TopBase,
OptionSetter_
>
>
{};

#define CPPX_OPTION( name ) OptionValue_##name

#define CPPX_DEFINE_OPTIONSETTER( name, type ) \


template< class OptionValue, class SetterResult, class Base > \
class OptionSetter_; \
\
template< class SetterResult, class Base > \
class OptionSetter_<CPPX_OPTION( name ), SetterResult, Base> \
: public Base \
{ \
public: \
type const& name() const \
{ return CPPX_OPTION( name )::value(); } \
\
SetterResult& name( type const& value ) \
{ \
CPPX_OPTION( name )::setValue( value ); \
return static_cast<SetterResult&>( *this ); \
} \
};

#define CPPX_DEFINE_OPTION_( name, type ) \


typedef ::cppx::options::Value_< \
type, struct UniqueIdTypeFor_##name \
> CPPX_OPTION( name ); \

CPPX_DEFINE_OPTIONSETTER( name, type )

#define CPPX_DEFINE_OPTIONV( name, type, defValue ) \


class CPPX_OPTION( name ) \
: public ::cppx::options::Value_< \
type, struct UniqueIdTypeFor_##name \
> \
{ \
typedef ::cppx::options::Value_< \
type, struct UniqueIdTypeFor_##name \
> Base; \
public: \
CPPX_OPTION( name )(): Base( defValue ) {} \
CPPX_OPTION( name )( type const& v ): Base( v ) {} \
}; \

CPPX_DEFINE_OPTIONSETTER( name, type )

#define CPPX_DEFINE_VALUECLASS( name, base ) \
class name##_Values \
: public base \
, public ::cppx::typelist::InheritLinearly_< \
name##_OptionTypes \
>::Type \
{};

#define CPPX_DEFINE_TEMPLATED_SETTERS_INHERITANCE( name, base ) \


template< class SetterResult, class TopBase > \

class name##_InheritTemplatedSetters_ \
: public ::cppx::options::InheritTemplatedSetters_< \
name##_OptionTypes, \
SetterResult, \
base##_InheritTemplatedSetters_< \
SetterResult, TopBase \
>, \
OptionSetter_ \
> \
{};

#define CPPX_DEFINE_OPTIONCLASS( name, base ) \
class name \

: public name##_InheritTemplatedSetters_< \
name, \
name##_Values \
> \
{};

#define CPPX_DEFINE_VTANDO( name, base ) \
CPPX_DEFINE_VALUECLASS( name, base ) \

CPPX_DEFINE_TEMPLATED_SETTERS_INHERITANCE( name, base ) \
CPPX_DEFINE_OPTIONCLASS( name, base )

#define CPPX_DEFINE_1OPTIONCLASS( name, base, option1 ) \

typedef CPPX_TYPELIST_< \


CPPX_OPTION( option1 ) \
> name##_OptionTypes; \
CPPX_DEFINE_VTANDO( name, base )

#define CPPX_DEFINE_2OPTIONCLASS( name, base, option1, option2 ) \

typedef CPPX_TYPELIST_< \


CPPX_OPTION( option1 ), \
CPPX_OPTION( option2 ) \
> name##_OptionTypes; \
CPPX_DEFINE_VTANDO( name, base )

} } // namespace cppx::options


//------------------------ Usage:

#include <iostream>

namespace blahblah {
namespace reallyLongName {
namespace california {

struct desert
{
CPPX_DEFINE_OPTION_( x, double )
CPPX_DEFINE_OPTIONV( y, double, 12345 )


CPPX_DEFINE_2OPTIONCLASS( Pos2Options, cppx::options::NoBase, x, y )

};


}}} // namespace blahblah::reallyLongName::california

namespace blahblah {
namespace reallyLongName {
namespace texas {
struct rose
{
CPPX_DEFINE_OPTION_( z, double )
CPPX_DEFINE_1OPTIONCLASS( Pos3Options, california::desert::Pos2Options, z )
};
}}} // namespace blahblah::reallyLongName::texas

namespace blahblah {
namespace reallyLongName {
namespace washington {
struct dc
{
CPPX_DEFINE_OPTIONV( a, double, 666 )
CPPX_DEFINE_1OPTIONCLASS( Pos4Options, texas::rose::Pos3Options, a )
};
}}} // namespace blahblah::reallyLongName::washington

struct UserClass1
{
typedef ::blahblah::reallyLongName::california::desert::Pos2Options
Pos2Options;

UserClass1( Pos2Options const& options )
{
using namespace std;


cout << options.x() << endl;
cout << options.y() << endl;
}
};

struct UserClass2: UserClass1
{
typedef ::blahblah::reallyLongName::texas::rose::Pos3Options
Pos3Options;

UserClass2( Pos3Options const& options )

: UserClass1( options )
{
using namespace std;


cout << std::endl;
cout << options.x() << endl;
cout << options.y() << endl;
cout << options.z() << endl;
}
};

struct UserClass3: UserClass2
{
typedef ::blahblah::reallyLongName::washington::dc::Pos4Options
Pos4Options;

UserClass3( Pos4Options const& options )
: UserClass2( options )
{
using namespace std;


cout << std::endl;
cout << options.x() << endl;
cout << options.y() << endl;
cout << options.z() << endl;

cout << options.a() << endl;
}
};

int main()
{
using namespace std;
typedef UserClass3::Pos4Options Pos4Options;
UserClass3( Pos4Options().x( 3.14 ).z( 42 ) );

Pos4Options o;
cout << endl;
cout << typeid(o).name() << endl;
cout << "x: " << typeid(o.x(6)).name() << endl;
cout << "y: " << typeid(o.y(6)).name() << endl;
cout << "z: " << typeid(o.z(6)).name() << endl;
cout << "a: " << typeid(o.a(6)).name() << endl;
}
</code>


Cheers, & thanks to James for nudge in direction of using member routines,

- Alf


PS: Disclaimer: I haven't moved those changes back to the app I'm using this in.
So perhaps there are Issues. The only issue I know (I chose not to support that)
is that a base class can't be specified via any other name than the original.

James Kanze

unread,
Jul 28, 2009, 4:22:04 AM7/28/09
to
On Jul 28, 12:23 am, "Alf P. Steinbach" <al...@start.no> wrote:
> * Martin Eisenberg:

> > Alf P. Steinbach wrote:

> >> What Andrei did was to show how all the usual run time
> >> control structures had analogs in template metaprogramming,
> >> and to build up from that to a framework handling types
> >> just as for run time you handle values.

> > I believe that credit should go to Czarnecki and Eisenecker,
> > whom MC++D also references.

> As I wrote and you snipped, typelists already had some history.

> The game of credit (and of snippage) is very silly.

> I've never heard of Czarnecki and Eisenecker, and I doubt any
> reader here will be helped by that reference.

Why not? They *are* the authors of one of the original
reference works concerning meta-programming.

> On the other hand, readers might find it useful to know what
> Andrei did, in order to decide whether to buy that book. It
> also contains a lot of generic implementations of patterns,
> which perhaps was its main innovation, and at least a main
> reason for its popularity,

It would be interesting to know why one book becomes popular,
and another not. Maybe Andrei is a better writer than some
others.

Todd Veldhuizen had shown that templates in C++ formed a Turing
complete language as early as 1995; from personal discussions
with David Vandevoorde, I believe that he was doing similar work
at about the same time. In this regard, Andrei is more or less
a latecomer to the field. But perhaps is book presents a more
easily understandable synthesis than earlier works.

Alf P. Steinbach

unread,
Jul 29, 2009, 2:27:11 AM7/29/09
to
* James Kanze:
> On Jul 26, 10:35 pm, "Alf P. Steinbach" <al...@start.no> wrote:
>> * James Kanze:
>

I thought about it and I think you're right. Especially with respect to later
switching over to some other option class generator it's better to just have a
single macro. So I created wrapper macros, so that I now write e.g.

CPPX_DEFINE_2OPTIONCLASS(
Params, Base::Params,
is3State, bool, false,
isAuto, bool, true
)


> Anyway: I'm supposing that the _2 in the last line specifies the
> number of attributes. IMHO, that's error prone, but get rid of
> that, and I think I could buy it.

I don't think one can get rid of that number without variadic macros, which are
currently non-standard, or perhaps Boost-like macro magic, which is
incomprehensible, counter-intuitive and probably would require supporing macro
definitions around each usage, making the notation more awkward.

I think the number, writing "2" or "3" or whatever, is very low cost.

If you use the wrong number you just get compilation error.


Cheers,

- Alf

Jerry Coffin

unread,
Jul 29, 2009, 8:56:44 PM7/29/09
to
In article <5477e597-b39d-440b-b1d1-
c70dcb...@d4g2000yqa.googlegroups.com>, james...@gmail.com
says...

[ ... ]

> I know that. I was using a Unix-like tool kit under MS-DOS in
> the late 1908's. But I'm hardly a typical Windows user; I was
> wondering what typical Windows developers use.

That's a tougher question -- I'm honestly not sure about typical
developers. Personally, I use a rather hodgepodge collection of
"stuff". In fact, it was only quite recently (with a switch to 64-bit
Windows) that I quit using some utilities that were written for MS-
DOS...

[ ... ]

> Yes. I mentioned CygWin more as a placeholder for any Unix-like
> tool kit, rather than with the idea of CygWin, and only CygWin.
> I'm aware of at least three others: UWin, MSys and MKS (the
> latter commercial, and rather expensive---although it wasn't too
> expensive in the MS-DOS days), and I don't doubt that there are
> others. (I'm still looking for one which integrates well,
> however. Most of them seem to go out of their way to make it
> difficult to use tools other than those in the toolset. And if
> I'm running Windows, and not Linux, on a machine, it's because I
> want to use the Windows tools when appropriate.)

That's where I see a substantial difference between the set I
mentioned and something like Cygwin. It at least attempts to make
some concessions to looking and acting a little bit like it was
written for Windows. Cygwin, at least from my viewpoint, simply
attempts to act like Windows is just a rather strange version of Unix
that takes more than the usual porting effort -- but that it should
still do its best to BE Unix, regardless of the oddities of the
kernel on which it's running.

--
Later,
Jerry.

James Kanze

unread,
Jul 30, 2009, 5:03:08 AM7/30/09
to
On Jul 30, 2:56 am, Jerry Coffin <jerryvcof...@yahoo.com> wrote:
> In article <5477e597-b39d-440b-b1d1-
> c70dcbfe4...@d4g2000yqa.googlegroups.com>, james.ka...@gmail.com
> says...

> [ ... ]


> That's where I see a substantial difference between the set I
> mentioned and something like Cygwin. It at least attempts to
> make some concessions to looking and acting a little bit like
> it was written for Windows. Cygwin, at least from my
> viewpoint, simply attempts to act like Windows is just a
> rather strange version of Unix that takes more than the usual
> porting effort -- but that it should still do its best to BE
> Unix, regardless of the oddities of the kernel on which it's
> running.

Exactly. And that's also a problem with most of the other
Unix-like tool kits I've used. Where as, if I wanted Unix, I'd
use Linux, and drop Windows entirely. What I want is Windows,
but with most of the tools I'm familiar with. I recognize that
they will have to work somewhat differently---it wouldn't bother
me too much if they adopted the / for options, for example,
rather than the -, and used \ for the directory separator (with
some other character---whatever is usual under Windows---for the
escape). Handling white space in filenames is a bit trickier,
and might require some compromises, but for the rest, there's no
real reason to pretend you're under Unix when you're not.

James Kanze

unread,
Jul 30, 2009, 5:06:26 AM7/30/09
to
On Jul 30, 2:56 am, Jerry Coffin <jerryvcof...@yahoo.com> wrote:
> In article <5477e597-b39d-440b-b1d1-
> c70dcbfe4...@d4g2000yqa.googlegroups.com>, james.ka...@gmail.com
> says...

[...]


> That's where I see a substantial difference between the set I
> mentioned and something like Cygwin. It at least attempts to
> make some concessions to looking and acting a little bit like
> it was written for Windows.

I've looked a little bit more at it. I don't see a shell.
Using Unix-like tools means linking them together---the shell is
the glue. And the default Windows command interpreter (what
executes .bat files) is pretty weak. What do Windows users use
for this?

Jerry Coffin

unread,
Jul 30, 2009, 2:07:29 PM7/30/09
to
In article <44d89351-f9aa-4e63-8860-f11499fa4477
@s31g2000yqs.googlegroups.com>, james...@gmail.com says...

>
> On Jul 30, 2:56 am, Jerry Coffin <jerryvcof...@yahoo.com> wrote:
> > In article <5477e597-b39d-440b-b1d1-
> > c70dcbfe4...@d4g2000yqa.googlegroups.com>, james.ka...@gmail.com
> > says...
>
> [...]
> > That's where I see a substantial difference between the set I
> > mentioned and something like Cygwin. It at least attempts to
> > make some concessions to looking and acting a little bit like
> > it was written for Windows.
>
> I've looked a little bit more at it. I don't see a shell.
> Using Unix-like tools means linking them together---the shell is
> the glue. And the default Windows command interpreter (what
> executes .bat files) is pretty weak. What do Windows users use
> for this?

It does actually include an sh.exe, but I'll admit I've never used it
(I haven't looked carefully to figure out why, but with Windows'
"Data Execution Prevention" turned it, it crashes quite
consistently).

The cmd.exe that's been used for quite a while isn't nearly as
"weak" as command.com used to be. Microsoft also has what they call
the Windows PowerShell, which is a free download from:

http://www.microsoft.com/windowsserver2003/technologies/management/po
wershell/download.mspx

This has quite a different character from the typical Unix shells
though, so even at best it'll take a while to get used to it.

Of course, there are quite a few other shells around for Windows as
well, but I haven't used any of them enough (at least recently) to
say much about them.

--
Later,
Jerry.

Jerry Coffin

unread,
Jul 30, 2009, 2:11:10 PM7/30/09
to
In article <544cd89d-fde4-41fb-90df-
1a0007...@w6g2000yqw.googlegroups.com>, james...@gmail.com
says...

[ ... ]

> Exactly. And that's also a problem with most of the other
> Unix-like tool kits I've used. Where as, if I wanted Unix, I'd
> use Linux, and drop Windows entirely. What I want is Windows,
> but with most of the tools I'm familiar with. I recognize that
> they will have to work somewhat differently---it wouldn't bother
> me too much if they adopted the / for options, for example,
> rather than the -, and used \ for the directory separator (with
> some other character---whatever is usual under Windows---for the
> escape). Handling white space in filenames is a bit trickier,
> and might require some compromises, but for the rest, there's no
> real reason to pretend you're under Unix when you're not.

Windows normally leaves almost all parsing of command lines to the
individual programs, so there's almost never any need for escaping
things. White space in file names (or whatever) is normally just
handled by enclosing the string in double quotes.

That brings up the one situation where escaping is needed (at least
semi-routinely): if you want to include a quote in a quoted string,
you normally escape the included quote with a backslash.

--
Later,
Jerry.

Gerhard Fiedler

unread,
Jul 30, 2009, 9:17:07 PM7/30/09
to
James Kanze wrote:

> I've looked a little bit more at it. I don't see a shell. Using
> Unix-like tools means linking them together---the shell is the glue.
> And the default Windows command interpreter (what executes .bat
> files) is pretty weak. What do Windows users use for this?

Typically cmd.exe; as Jerry says, it's not that weak, it's just that
most people don't know how to use it :)

(On a side note: If you want to surprise a typical Windows "power" user,
bring up a listing of the .exe files in the Windows system32 directory.
Most are command line tools, and many don't know a tenth of it.)

Besides what Jerry wrote, there are native builds of many Unix shells.
If you already know how to use them, this may be the way for you.

There's also 4NT from jpsoft.com, which is sort of a more powerful
cmd.exe, backwards compatible. But their extensions are custom and not
commonly known or used.

Also note that many Windows command line tools use or accept the dash as
option separator and the forward slash as path separator. (AFAIK all of
the Win32 API accepts the forward slash as path separator.)

Gerhard

James Kanze

unread,
Jul 31, 2009, 4:47:44 AM7/31/09
to
On Jul 30, 8:11 pm, Jerry Coffin <jerryvcof...@yahoo.com> wrote:
> In article <544cd89d-fde4-41fb-90df-
> 1a000743b...@w6g2000yqw.googlegroups.com>, james.ka...@gmail.com
> says...

> [ ... ]

> > Exactly. And that's also a problem with most of the other
> > Unix-like tool kits I've used. Where as, if I wanted Unix,
> > I'd use Linux, and drop Windows entirely. What I want is
> > Windows, but with most of the tools I'm familiar with. I
> > recognize that they will have to work somewhat
> > differently---it wouldn't bother me too much if they adopted
> > the / for options, for example, rather than the -, and used
> > \ for the directory separator (with some other
> > character---whatever is usual under Windows---for the
> > escape). Handling white space in filenames is a bit
> > trickier, and might require some compromises, but for the
> > rest, there's no real reason to pretend you're under Unix
> > when you're not.

> Windows normally leaves almost all parsing of command lines to
> the individual programs, so there's almost never any need for
> escaping things. White space in file names (or whatever) is
> normally just handled by enclosing the string in double
> quotes.

And filenames can't contain quotes:-).

I rather like the Microsoft documentation in this regard
(http://msdn.microsoft.com/en-us/library/aa365247%28VS.85%29.aspx):
"Use almost any character in the current code page for a name
[...] except the following [...] -- Any other character that the
target file system does not allow." Very informative:-). And
oh so useful---what is the "current code page" for a program
running as a demon (what Unix would call a cron job)? (But in a
certain sense, what more can they say? The problem is that the
filename conventions depend largely on the file server, and not
on the OS you're running under. And with SMB, you can use
pretty much anything as a server.)

> That brings up the one situation where escaping is needed (at
> least semi-routinely): if you want to include a quote in a
> quoted string, you normally escape the included quote with a
> backslash.

Which would be ambiguous in a filename---are you escaping the
quote, or is it a directory separator? Which is probably why
filenames can't contain quotes.

Actually, they probably are right in forbidding the usual
meta-characters ('<', '>', ':', '"', '/', '\\', '|', '?' and
'*') in filenames. And doing so explicitly, and expecting all
programs to handle anything else. Under Unix, the only
characters forbidden are '/' and '\0', but most programs will
mishandle a lot of others. (Although the real problem is
probably more because the shell does so much. Once you start
passing parameters from one shell to a subscript, etc., with
each sub-shell stripping out it's quotes and escapes, you
quickly loose track of how many escapes you need. Add to that
that there are about a dozen different shells, each with its own
particularities, and there are often subtle differences between
different versions or implementations of the same shell, and
it's almost enough to make you want to switch to perl:-).)

James Kanze

unread,
Jul 31, 2009, 5:07:18 AM7/31/09
to
On Jul 31, 3:17 am, Gerhard Fiedler <geli...@gmail.com> wrote:
> James Kanze wrote:
> > I've looked a little bit more at it. I don't see a shell. Using
> > Unix-like tools means linking them together---the shell is the glue.
> > And the default Windows command interpreter (what executes .bat
> > files) is pretty weak. What do Windows users use for this?

> Typically cmd.exe; as Jerry says, it's not that weak, it's
> just that most people don't know how to use it :)

OK. It sounds like something I'll have to learn. (Starting in
September, I'll be working almost exclusively under Windows.)

> (On a side note: If you want to surprise a typical Windows
> "power" user, bring up a listing of the .exe files in the
> Windows system32 directory. Most are command line tools, and
> many don't know a tenth of it.)

ls /usr/bin will have the same effect on Unix users. Under
Linux (which for some stupid reason puts everything in
/usr/bin), even I don't know most of them (and I'm pretty much a
power user under Unix). Some I can guess, more or less, but
others... (a2p was always Ascii to Postscript---something to
output program sources to a Postscript printer. But the man
page on my current Linux says it's Awk to Perl. And I needed
the man pages to learn that lz is to list gzipped files, and js
to start Rhino, whatever that is. Unix naming traditions aren't
always obvious to outsiders, and sometimes not even to insiders
like myself.)

> Besides what Jerry wrote, there are native builds of many Unix
> shells. If you already know how to use them, this may be the
> way for you.

It depends. I'm a team player, and if I'm writing scripts, my
collegues have to be able to understand them. Which means I
have to adapt to their language (both natural and programming),
and not vice versa.

> There's also 4NT from jpsoft.com, which is sort of a more
> powerful cmd.exe, backwards compatible. But their extensions
> are custom and not commonly known or used.

> Also note that many Windows command line tools use or accept
> the dash as option separator and the forward slash as path
> separator. (AFAIK all of the Win32 API accepts the forward
> slash as path separator.)

Luckily:-). At home, I'm using MSys (I wanted to try it, and
haven't had time yet to get rid of it, and install something
else), and its implementation of the shell converts any word
starting with a / to it's mapping of the root directory,
something starting with c:... One of my first attempts was "cl
/help", and the error message about a missing file rather
surprised me. And my libraries (which I use to parse argv and
argc) adapt to the local conventions---I had to modify them so
that they'd accept more than one character as the option
id. (Accepting the forward slash is a bit more fundamental,
since it allows avoiding the C string escape character, which is
also wide spread as an escape character in other contexts.)

James Kanze

unread,
Jul 31, 2009, 5:24:25 AM7/31/09
to
On Jul 31, 3:17 am, Gerhard Fiedler <geli...@gmail.com> wrote:
> James Kanze wrote:
> > I've looked a little bit more at it. I don't see a shell. Using
> > Unix-like tools means linking them together---the shell is the glue.
> > And the default Windows command interpreter (what executes .bat
> > files) is pretty weak. What do Windows users use for this?

> Typically cmd.exe; as Jerry says, it's not that weak, it's just that
> most people don't know how to use it :)

One last question for you and Jerry (although I know this isn't
really the right place): could you recommend a good book about
this shell? (I'll be visiting the local technical bookshop
tomorrow afternoon, and would buy it immediately if they have
it.)

Alf P. Steinbach

unread,
Jul 31, 2009, 5:40:33 AM7/31/09
to
* James Kanze:
>
> Actually, [Microsoft] probably are right in forbidding the usual

> meta-characters ('<', '>', ':', '"', '/', '\\', '|', '?' and
> '*') in filenames. And doing so explicitly, and expecting all

Actually ':' isn't forbidden. :-)

But it has very special meaning so can't be used anywhere you please (see [1]).

But this is completely off-topic, and so I'm setting follow-ups to Windows
programming group.


Cheers,

- Alf

Notes:
[1]
<quote
src="From intro chapter to Alf's never-completes book manuscript">
Some names can’t or shouldn’t be used as filenames because they have special
meanings. They act as named data streams that you can send data to and/or
receive data from, and since they stem from old DOS they’re called DOS devices,
even at the Windows API level. DOS had at least one that doesn’t exist in
Windows, namely a “device” representing the clock, and at least in early DOS you
wrote a colon after any device name, which isn’t necessary in Windows, but
otherwise it’s the same:

Name(s): Short for: Represents:
nul Always empty for reading, and a black hole for writing.
con console The console window.
com1 … com9 communication Serial communication port n (sort of like old times’ USB).
aux auxiliary One of the comn ports, connected to a terminal.
lpt1 … lpt9 line printer Parallel port n, typically printer connections (in old
days).
prn printer One of the lptn ports, the default printer. This name
is defined/configured by the print command (obsolete).

Hackers sometimes have fun breaking into others’ computers and e.g. creating
directories with such names, which ordinary users find impossible to remove. The
hacker who is more than just a script-kiddie will then typically also ensure
that the path is longer than the maximum 260 characters that most Windows
programs (including Windows Explorer and the command interpreter) can handle…

E.g. you risk this if you open your machine for FTP access with Microsoft’s IIS
as FTP server.

C:\test> md con
The directory name is invalid. //Nah, can’t call a directory (or file) “con”.

C:\test> md \\?\c:\test\con //But, well, if one is a hacker then one can
do that after all…
C:\test> dir
Volume in drive C is maindisk
Volume Serial Number is C469-4FA2

Directory of C:\test

05.07.2009 17:22 <DIR> .
05.07.2009 17:22 <DIR> ..
05.07.2009 17:22 <DIR> con // He he.
0 File(s) 0 bytes
3 Dir(s) 15 264 759 808 bytes free

C:\test> rd con
The system cannot find the file specified.

C:\test> rd \\?\c:\test\con

C:\test> _

You may perhaps recognize the path [\\?\c:\test\con] as being very similar to
the notation used to refer to a network share to establish a drive mapping with
net use. And it’s the same notation family, a very Windows-specific notation
where various special kinds of paths start with a double backslash, \\.

Technically the \\?\ prefix tells a file- or directory-handling API routine to
support paths that break the usual Windows limitations both regarding length and
what can be in them, and since the command interpreter evidently doesn’t detect
and reject the \\, the hack works.

Apart from avoiding using the DOS device names for files and directories, in
practical work it’s mostly only the nul device that is of practical interest.
First and foremost, nul is a convenient trash can for unwanted error messages,
like …

C:\test> del nosuch
Could Not Find C:\test\nosuch

C:\test> del nosuch 2>nul //Getting rid of unwanted output.

C:\test> _

Second, since nul is always empty for reading, “copying” nul is a simple way to
create an empty file:

C:\test> copy nul alfa
1 file(s) copied.

C:\test> dir | find "alfa"
05.07.2009 17:57 0 alfa

C:\test> _

A more idiomatic to do the same is to type the (non-existent) contents of nul,
and redirect that non-existent output to the file one wants to create:

C:\test> type nul >beta //Idiomatic way to create an empty file.

C:\test> dir | find "beta"
05.07.2009 18:00 0 beta

C:\test> _

Here type nul is just a command that doesn’t produce any output. Any command
that doesn’t produce any output, e.g. cmd /c exit, would do. It’s the
redirection operator > that creates – or empties – the file.

If you want to create a file with just a few lines of text then that can also be
done in about the same way, namely by typeing the con device, which for input is
just your keyboard, and redirecting the text to a file – the idiomatic “poor
man’s editor”:

C:\test> type con >gamma
Programmers do the most amazing things via commands.
Instead of mousing they use their hands.
^Z

C:\test> dir | find "gamma"
05.07.2009 18:34 96 gamma

C:\test> type gamma
Programmers do the most amazing things via commands.
Instead of mousing they use their hands.

C:\test> _

OK, it’s a poor man’s poem, too!  I meant to write “Instead of mousing they use
the keyboard”, but that didn’t rhyme. Oh well…

Anyway, with 2 empty files and one little two-line text file at hand I can
demonstrate the final special naming convention that you may – or may not –
encounter. Namely, that for filesystems that support it, and the default Windows
NTFS filesystem does support this, a Windows file may not just have the normal
“main” content that’s reported by the size shown by the dir command and in
Windows Explorer, but may additionally have hidden alternate streams of data.
For example, that’s where Windows Explorer stores additional file property
information.

For example, the [alfa] file that we made above has absolutely no main content.
But you can add a stream named “sillypoem” and copy the contents of [gamma]
there. The full name of that stream is then [alfa:sillypoem] , and even though
it contains 96 bytes of data – the poem text – it doesn’t show up in the
reported file size of [alfa]:

C:\test> type gamma >alfa:poemtext

C:\test> del gamma

C:\test> dir
Volume in drive C is maindisk
Volume Serial Number is C469-4FA2

Directory of C:\test

05.07.2009 18:45 <DIR> .
05.07.2009 18:45 <DIR> ..
05.07.2009 18:45 0 alfa
05.07.2009 18:00 0 beta
2 File(s) 0 bytes
2 Dir(s) 15 201 169 408 bytes free

C:\test> more <alfa:poemtext
Programmers do the most amazing things via commands.
Instead of mousing they use their hands.

C:\test> _

The ordinary commands don’t accept the “:” notation for specifying stream
names, which is why I had to use the redirection operators (and hence, there’s
no way to delete an alternate stream by using standard commands). So at the
command interpreter level the alternate streams are not very practically useful,
except perhaps as a way to hide stuff – then for binary data using e.g. a
*nix-like cat command. But in programming you will sooner or later need to know
about this functionality, if for nothing else then as “common knowledge” and to
avoid using the colon!


 Suggested exercises:
1. Find out which characters are not allowed in ordinary file- and directory-names.
2. Create empty files via commands (as opposed to using e.g. an editor).
3. On the theme of hacking, which the limited abilities of the Windows command
interpreter sometimes force people to do, one old trick for checking whether a
path is a directory path (as opposed to being a file path) is to check whether
the “file” nul exists in the assumed-to-be directory. Test this using if and
echo. For basic information about if, see that command’s quickhelp.
</quote>

Jerry Coffin

unread,
Jul 31, 2009, 11:19:22 AM7/31/09
to
In article <6beeee10-6959-4cae-8a28-
d0a214...@o6g2000yqj.googlegroups.com>, james...@gmail.com
says...

>
> On Jul 31, 3:17 am, Gerhard Fiedler <geli...@gmail.com> wrote:
> > James Kanze wrote:
> > > I've looked a little bit more at it. I don't see a shell. Using
> > > Unix-like tools means linking them together---the shell is the glue.
> > > And the default Windows command interpreter (what executes .bat
> > > files) is pretty weak. What do Windows users use for this?
>
> > Typically cmd.exe; as Jerry says, it's not that weak, it's just that
> > most people don't know how to use it :)
>
> One last question for you and Jerry (although I know this isn't
> really the right place): could you recommend a good book about
> this shell? (I'll be visiting the local technical bookshop
> tomorrow afternoon, and would buy it immediately if they have
> it.)

There are lots of them, but I can't honestly recommend any of them.
I'd puzzled out most of what I know from the MSDN documentation (and
such) long before most of the books had been written, so I've never
really looked at them. In all honesty, I probably should take a look;
there are undoubtedly gaping holes in what I know on the subject...

--
Later,
Jerry.

Gerhard Fiedler

unread,
Aug 1, 2009, 1:35:32 AM8/1/09
to
Jerry Coffin wrote:

>>> James Kanze wrote:
>>>> I've looked a little bit more at it. I don't see a shell. Using
>>>> Unix-like tools means linking them together---the shell is the
>>>> glue. And the default Windows command interpreter (what executes
>>>> .bat files) is pretty weak. What do Windows users use for this?
>>
>>> Typically cmd.exe; as Jerry says, it's not that weak, it's just that
>>> most people don't know how to use it :)
>>
>> One last question for you and Jerry (although I know this isn't
>> really the right place): could you recommend a good book about this
>> shell? (I'll be visiting the local technical bookshop tomorrow
>> afternoon, and would buy it immediately if they have it.)
>
> There are lots of them, but I can't honestly recommend any of them.
> I'd puzzled out most of what I know from the MSDN documentation (and
> such) long before most of the books had been written, so I've never
> really looked at them.

A long time ago I bought the "Windows 2000 Commands Pocket Reference"
(O'Reilly, http://oreilly.com/catalog/9780596001483/ -- they now also
have newer XP and Vista revisions). Inexpensive and useful if you like
paper. Otherwise there's the online help and your favorite search engine
:)

One quick thing: in a cmd.exe window click on the application icon and
select properties (or select the properties of a shortcut to a command
line program, like cmd.exe) and edit to your liking. If you do command
line work, the standard window is probably too small, and possibly
doesn't have the right colors.

Gerhard

0 new messages