Friday, October 26, 2007

Things Your Programming Language Never Told You - must read

Herb Sutter did it again:
Things Your Programming Language Never Told You

As he said himself, this is a must read for every modern programmer.
Nothing for me to add, just watch and be amazed...

Monday, October 22, 2007

Doxygen rules!

I'd like to give many thanks to Dimitri van Heesch, for his excellent programming tool : the Doxygen.

I finally got to add examples to Boost Logging Lib v2. Well, you can do some amazing things with doxygen:

Say you have a file which you want to use as an example:
  • You can add the description within the example itself
  • You can reference (link to) the example's description
  • You can add the example to the "Examples" tab
  • When clicking the example in the "Examples" tab, it will show its description
  • You can even have a page which will contain the source code for all examples
To achieve the above, within the example file, you'll do this:

/**
@example your_example_name.cpp

@copydoc your_example_name

@page your_example_name your_example_name.cpp Example

... (your documentation)

*/

Then, to reference the example's description, you'll do this:

/**
...

@copydoc your_example_name

...
*/

To create a page that will contain all the examples:

/**
@page all_examples All code examples

- @ref example_1
- @ref example_2
...

\n\n\n
@section example_1 My Example 1

@include example_1_source_file.cpp
\n\n\n


\n\n\n
@section example_2 My Example 2

@include example_2_source_file.cpp
\n\n\n

...
*/

The end result is really amazing. Check it out!

Friday, October 19, 2007

VS 2005 : It's great to get meaningful error messages...

When dealing with template programming, getting compiler errors can get pretty cryptic. However, VS 2005 did its best to help me:

(note: I replaced <> with { } - since the editor got pretty messed up)
(yes: the error is 5132 characters long)

1}mul_levels_one_logger.obj : error LNK2001: unresolved external symbol "struct boost::logging::detail::log_keeper{struct boost::logging::logger{struct boost::logging::process_msg{struct boost::logging::gather::ostream_like::return_str{class std::basic_ostringstream{char,struct std::char_traits{char},class std::allocator{char} } },struct boost::logging::writer::format_write{struct boost::logging::manipulator::base{class std::basic_string{char,struct std::char_traits{char},class std::allocator{char} } &,struct boost::logging::manipulator::detail::default_type},struct boost::logging::manipulator::base{class std::basic_string{char,struct std::char_traits{char},class std::allocator{char} } const &,struct boost::logging::manipulator::detail::default_type},struct boost::logging::format_and_write::simple{struct boost::remove_reference{class std::basic_string{char,struct std::char_traits{char},class std::allocator{char} } const &} },struct boost::logging::msg_route::simple{struct boost::logging::manipulator::base{class std::basic_string{char,struct std::char_traits{char},class std::allocator{char} } &,struct boost::logging::manipulator::detail::default_type},struct boost::logging::manipulator::base{class std::basic_string{char,struct std::char_traits{char},class std::allocator{char} } const &,struct boost::logging::manipulator::detail::default_type} },class boost::logging::array::shared_ptr_holder{struct boost::logging::manipulator::base{class std::basic_string{char,struct std::char_traits{char},class std::allocator{char} } &,struct boost::logging::manipulator::detail::default_type},class boost::logging::threading::mutex_win32},class boost::logging::array::shared_ptr_holder{struct boost::logging::manipulator::base{class std::basic_string{char,struct std::char_traits{char},class std::allocator{char} } const &,struct boost::logging::manipulator::detail::default_type},class boost::logging::threading::mutex_win32} } },struct boost::logging::filter::no_ts},&struct boost::logging::logger{struct boost::logging::process_msg{struct boost::logging::gather::ostream_like::return_str{class std::basic_ostringstream{char,struct std::char_traits{char},class std::allocator{char} } },struct boost::logging::writer::format_write{struct boost::logging::manipulator::base{class std::basic_string{char,struct std::char_traits{char},class std::allocator{char} } &,struct boost::logging::manipulator::detail::default_type},struct boost::logging::manipulator::base{class std::basic_string{char,struct std::char_traits{char},class std::allocator{char} } const &,struct boost::logging::manipulator::detail::default_type},struct boost::logging::format_and_write::simple{struct boost::remove_reference{class std::basic_string{char,struct std::char_traits{char},class std::allocator{char} } const &} },struct boost::logging::msg_route::simple{struct boost::logging::manipulator::base{class std::basic_string{char,struct std::char_traits{char},class std::allocator{char} } &,struct boost::logging::manipulator::detail::default_type},struct boost::logging::manipulator::base{class std::basic_string{char,struct std::char_traits{char},class std::allocator{char} } const &,struct boost::logging::manipulator::detail::default_type} },class boost::logging::array::shared_ptr_holder{struct boost::logging::manipulator::base{class std::basic_string{char,struct std::char_traits{char},class std::allocator{char} } &,struct boost::logging::manipulator::detail::default_type},class boost::logging::threading::mutex_win32},class boost::logging::array::shared_ptr_holder{struct boost::logging::manipulator::base{class std::basic_string{char,struct std::char_traits{char},class std::allocator{char} } const &,struct boost::logging::manipulator::detail::default_type},class boost::logging::threading::mutex_win32} } },struct boost::logging::filter::no_ts} & __cdecl g_l_boost_log_impl_(void)} g_l" (?g_l@@3U?$log_keeper@U?$logger@U?$process_msg@U?$return_str@V?$basic_ostringstream@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@ostream_like@gather@logging@boost@@U?$format_write@U?$base@AAV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@Udefault_type@detail@manipulator@logging@boost@@@manipulator@logging@boost@@U?$base@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@Udefault_type@detail@manipulator@logging@boost@@@234@U?$simple@U?$remove_reference@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@boost@@@format_and_write@34@U?$simple@U?$base@AAV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@Udefault_type@detail@manipulator@logging@boost@@@manipulator@logging@boost@@U?$base@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@Udefault_type@detail@manipulator@logging@boost@@@234@@msg_route@34@V?$shared_ptr_holder@U?$base@AAV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@Udefault_type@detail@manipulator@logging@boost@@@manipulator@logging@boost@@Vmutex_win32@threading@34@@array@34@V?$shared_ptr_holder@U?$base@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@Udefault_type@detail@manipulator@logging@boost@@@manipulator@logging@boost@@Vmutex_win32@threading@34@@array@34@@writer@45@@logging@boost@@Uno_ts@filter@23@@logging@boost@@$1?g_l_boost_log_impl_@@YAAAU123@XZ@detail@logging@boost@@A)

They must be using a group IQ...

Some company just thought that since copyright is such a cool thing, why not copyright as much as possible?

http://pubcit.typepad.com/clpblog/2007/10/you-hereby-agre.html

http://techdirt.com/articles/20071017/092927.shtml

Next thing, probably they'll copyright their javascript variable names...

Thursday, October 18, 2007

The email hell...

First, there's spamming - we all get that (forgive the pun).

And we all find ways to deal with it - but it seems that every email server has its own twisted way of making sure the right email never gets to you.

For instance, mine (and I didn't know that), did an email check on the sender - if the sender email is invalid, the email doesn't get through.

Alrighty! That should be cool, right? Well, not really... Because being afraid of spam, a lot of users purposely obfuscate their email address - and I don't get their email. Oh well - lets say we forget that, and move on... But wait, there's more! Even legitimate users, with legitimate emails can get into trouble:

Email verification can be used by spammers, to see if an email exists or not. Now, ain't that cute? Sooo... some email servers decided to get smart, and not respond to email verification. Sounds pretty reasonable, right?

Now, lets see how a server that requests an email verification of the sender plays along with a server that does not respond to it. Well - not good at all: the former server tries several times, and the latter thinks it's spam. End result: an email coming from the latter server will never get through. Aaaaand: you (your ip, email, etc) will end up in the latter server's spam list.

That's what happened to an email I got from Charles Brockman - anyway, I think that's sorted out (even though I'm still on AT&T's spam list :P )

I had my email provider remove that sender email verification for my address. And just when I though I was out of problems, here's an email I got, when answering to someone else:

    SMTP error from remote mail server after RCPT TO:<[...]@users.sf.net>:
host mail.sourceforge.net [66.35.250.206]: 550-Postmaster verification failed while checking [...]@torjo.com
550-Called: 72.52.140.12
550-Sent: RCPT TO:postmaster -at- torjo.com
550-Response: 550 No such email address
550-Several RFCs state that you are required to have a postmaster
550-mailbox for each mail domain. This host does not accept mail
550-from domains whose servers reject the postmaster address.

550 Sender verify failed

Oh well - back to the drawing board - I've emailed my provider - I'll get that "installed".

Sunday, October 14, 2007

Nigeria vs Bill Gates

This was one of those funnies - that you just can't believe could happen: Bill gates was denied visa for Nigeria.

The template< namespace> construct

2 days ago, I've discovered an interesting technique, which is equivalent to the
template< namespace> construct.

I will first show you an example, because talking about concepts combined with templates is kind of rough ;)

The need

I have a function 'write' - that can be overloaded for different types.
I have 3 namespaces in which this resides - and on each namespace, the meaning of 'write' is completely different:
  • prepend - prepends a string
  • append - appends a string
  • modify - modifies a string
I have several functors which get the namespace as template argument, and then call the write function. So what I want is something like this:

template< namespace convert = prepend>
struct write_time {

template
void operator()(const msg_type & msg) {

...
convert::write(msg, src);
}
};

Why template< namespace> ?

Of course, it would be easy to have the same concept as a template< class>. However, I want other libs/client code to be able to overload my function, and my functor classes to still have the same default (convert_format::prepend).

The construct

The solutions is simple: just defer to a class which forwards to your namespace:

namespace convert_format {
namespace prepend {
void write(const string_type & src, string & dest) {
dest.insert( dest.begin(), src.begin(), src.end() );
}
template< class string> void write(const string_type & src, cache_string_one_str<> & dest) {
dest.prepend_string(src);
}
...
}}

struct do_convert_format {
struct prepend {
template< class string>
void write(const string_type & src, string & dest) {
convert_format::prepend::write(src, dest);
}
};

struct append { ... };
struct modify { ... };
};


When implementing my functor classes, I just use:

template< class convert = do_convert_format::prepend>
struct write_time {
... };


I've used this in my Boost Logging Lib v2 : here.

I'm sure someone has used this before. Is it documented anywhere else?

Thursday, October 11, 2007

The mobile office - feedback

Have comments related to the Mobile office article?
Please post them here ;)

Boost Logging v2 - with documentation

I've added quite a bit more cool things to the lib, and added documentation.

http://torjo.com/log2/

http://torjo.com/log2/doc/html/

Enjoy ;)

Wednesday, October 3, 2007

Boost Logging v2

Well, it's been a looooong time... But I'm back!
I'm developing the Boost Logging Lib v2 - Check it out!

Feedback is most welcome!

Tuesday, October 2, 2007

Tip: commenting variables/constants

For too many times, I see code like this:

// we allow only 100 words
int allow_word_count = 100;

// we allow only up to 10 users
const int MAX_USER_COUNT = 10;



What's wrong with the above?

A program should stay flexible in the face of change. How would you like to see:


// we allow only 100 words
int allow_word_count = 245;

Not very pleasant - but it happens. So, make your comments descriptive, while avoiding to use the actual value in the comment:

// we allow only this many words
int allow_word_count = 100;

// we allow only up to this many users
const int MAX_USER_COUNT = 10;


Much better!