attack of silly coding standard?

I

Ian Collins

Interesting example. First, one notices there is a quite generic
and common "try to find and throw if not found" block screaming
"refactor me".

It will get extracted next time I need it!
 
B

Bart van Ingen Schenau

On Dec 7, 4:59 pm, Bart van Ingen Schenau <[email protected]>
wrote:

Perhaps misunderstanding. I claimed that RAII uses OOP to manage
resources not that OOP must use RAII nor that RAII is OOP.

And my claim is that RAII and OOP are independent concepts.
The concept of RAII can not possibly exist without constructors and
destructors.
And although, in particular, constructors make OOP a lot easier, they
are not a fundamental requirement for OOP. I have written OO programs
in C, which does not have constructors (at best, you can emulate them
by using conventions).
RAII is idiom that fits with OOP.

I don't think anyone contests that claim, least of all me.
But just because two concepts work well together does not mean they
always will/have to be used together.
For example, RAII works equally well with procedural programming.

Bart v Ingen Schenau
 
J

James Kanze

(e-mail address removed):
My 2 cents (will be converted to 0.1278 cents soon):
Exception RecoverExceptionInCatch() throw() {
try {
throw;
} catch(const Exception& e) {
return e;
} catch(const std::exception& e) {
return Exception("EX12", e.what());
} catch(const char* what) {
return Exception("EX14", what);
} catch( ... ) {
return Exception("EX16", "Unknown error");
}
}
-- and --
bool IpAddress::IsIpv4MappedIpv6() const {
const unsigned char ipv4_prefix[12] =
{0,0,0,0,0,0,0,0,0,0,255,255};
return af_==AF_INET6 && memcmp(ip_, ipv4_prefix, 12)==0;
}
bool IpAddress::eek:perator==(const IpAddress& b) const {
if (af_==b.af_) {
return memcmp(ip_, b.ip_, 16)==0;
} else if (af_==AF_INET) {
DEBUG_ASSERT(b.af_==AF_INET6);
return b.IsIpv4MappedIpv6() && memcmp(ip_, b.ip_+12, 4)==0;
} else {
DEBUG_ASSERT(b.af_==AF_INET);
DEBUG_ASSERT(af_==AF_INET6);
return IsIpv4MappedIpv6() && memcmp(b.ip_, ip_+12, 4)==0;
}
}

I'd consider both acceptable; in the second case, I would think
about putting each of the branches in a separate function, so
that the operator== would just consist of:
return af_ == b.af_
? memcmp(ip_, b.ip_, 16) == 0
: af_ == AF_INET
? compareMapped(ip_, b.ip_)
: compareMapped(b.ip_, ip_);
or something like that. For the first, however, I really don't
see any better alternative (but you'll have to admit that it's
a very special case).
 
Ö

Öö Tiib

And my claim is that RAII and OOP are independent concepts.
The concept of RAII can not possibly exist without constructors and
destructors.

OK. So you say that these are not OOP features that RAII uses to
manage resources? There i stand ground. These features are OOP
features. It does not matter that you can write spaghetti using them
and OO without using them.
And although, in particular, constructors make OOP a lot easier, they
are not a fundamental requirement for OOP.

You about prototype based OO languages with dynamic type systems?
Dynamically alter prototype to gain polymorphism and clone instead of
instantiation? That OO style is not supported by C++. There are other
languages that support it, but its pointless to discuss such OO here
too deeply.

In all class-based OO languages (SmallTalk, C++) you have classes
(sort of blueprints), and you *construct* instances of the classes.
You use encapsulation to prevent users from breaking the invariant of
classes and you use inheritance for polymorphism.
I have written OO programs
in C, which does not have constructors (at best, you can emulate them
by using conventions).

You *have* to emulate either classes or prototypes in languages that
do not naturally support OO (like C). How else to call it OOP what you
do?
 
K

Keith H Duggar

Why provide a good explanation?  Functions that contain switch
statements are often long and require no explanation.  The following
function of mine is over 100 lines long and requires no explanation:

[snip unbelievably naive and primitive mess]

Wow ... just wow ... that is a prime(evil) example of the horrific
code that poorly trained fanboys write when they lose all (or never
had any) rational perspective on code readability.

It's exactly the kind of stuff you see all over Micros$$t code so
I guess it's not so surprising in your specific case; but ... wow.

You are right about one thing though, no explanation should be
provided in this case. Instead the code should be instantaneously
rejected and the programmer sent to rehab.

KHD
 
R

red floyd

[snip unbelievably naive and primitive mess]
Wow ... just wow ... that is a prime(evil) example of the horrific
code that poorly trained fanboys write when they lose all (or never
had any) rational perspective on code readability.
It's exactly the kind of stuff you see all over Micros$$t code so
I guess it's not so surprising in your specific case; but ... wow.
You are right about one thing though, no explanation should be
provided in this case. Instead the code should be instantaneously
rejected and the programmer sent to rehab.

There is nothing wrong with the constructor I posted.  It contains no
branches (is therefore very simple) and all it does is construct objects
which is generally what constructors do.  It is also perfectly readable..

and it would be much clearer if it was table driven. All that nasty
inline stuff could be replaced by a loop and a table.
 
U

u2

There is nothing wrong with the constructor I posted.

Of course not.
 It contains no
branches (is therefore very simple) and all it does is construct objects
which is generally what constructors do.  It is also perfectly readable..

Perfectly.
 
I

Ian Collins

On 08/12/2010 20:19, Keith H Duggar wrote:



On 08/12/2010 16:59, Yannick Tremblay wrote:
So for example, although I do not beleive that there exists a number
of lines per functions that is the threshold between a bad and a good
function, in some evironment, it can be worthwhile to place a rule
that say that all "all functions must be less than XX lines unless a
good explanation is provided".

Why provide a good explanation? Functions that contain switch
statements are often long and require no explanation. The following
function of mine is over 100 lines long and requires no explanation:

[snip unbelievably naive and primitive mess]

Wow ... just wow ... that is a prime(evil) example of the horrific
code that poorly trained fanboys write when they lose all (or never
had any) rational perspective on code readability.

It's exactly the kind of stuff you see all over Micros$$t code so
I guess it's not so surprising in your specific case; but ... wow.

You are right about one thing though, no explanation should be
provided in this case. Instead the code should be instantaneously
rejected and the programmer sent to rehab.

KHD

There is nothing wrong with the constructor I posted. It contains no
branches (is therefore very simple) and all it does is construct objects
which is generally what constructors do. It is also perfectly readable.

and it would be much clearer if it was table driven. All that nasty
inline stuff could be replaced by a loop and a table.

Just to show that I am not immune to constructive criticsm (and to shut
the trolls up) I decided to rewrite the constructor so it uses a table
and luckily the use of templates made sure it wasn't too tedious:

This looks like a good candidate for code generation! When I read your
original, I thought it was generated code.

I don't think I have gained much though. :)

You may have made it worse!
 
I

Ian Collins

On 09/12/2010 02:24, Ian Collins wrote:

The kind of worse which happens to the codebase of companies which the
likes of Keith Duggar works for. The kind of worse that results from
religiously (blindly) following the doctrine of some suboptimal coding
standard: so my function fits into our standardized editor window (10
lines of code, big font) why not convert it into a table???

I think I will stick with the table version though; I can't be arsed
rolling it back as the difference between the two versions is marginal
by any sensible metric.

One problem I've often seen with single long initialisation functions is
refactoring patterns (to table or whatever) are hard to spot. If you
were to break it up into one function for each namespace, you might find
it easier to simplify (and read).
 
I

Ian Collins

That split would be too arbitrary IMO as the functions would be
semantically identical as they are all just creating a different subset
of a set of similar objects.

Exactly, that's how patterns emerge.
 
M

Michael Doubez

On 08/12/2010 20:19, Keith H Duggar wrote:
On 08/12/2010 16:59, Yannick Tremblay wrote:
So for example, although I do not beleive that there exists a number
of lines per functions that is the threshold between a bad and a good
function, in some evironment, it can be worthwhile to place a rule
that say that all "all functions must be less than XX lines unless a
good explanation is provided".
Why provide a good explanation?  Functions that contain switch
statements are often long and require no explanation.  The following
function of mine is over 100 lines long and requires no explanation:
[snip unbelievably naive and primitive mess]
Wow ... just wow ... that is a prime(evil) example of the horrific
code that poorly trained fanboys write when they lose all (or never
had any) rational perspective on code readability.
It's exactly the kind of stuff you see all over Micros$$t code so
I guess it's not so surprising in your specific case; but ... wow.
You are right about one thing though, no explanation should be
provided in this case. Instead the code should be instantaneously
rejected and the programmer sent to rehab.
There is nothing wrong with the constructor I posted.  It contains no
branches (is therefore very simple) and all it does is construct objects
which is generally what constructors do.  It is also perfectly readable.
and it would be much clearer if it was table driven.  All that nasty
inline stuff could be replaced by a loop and a table.

Just to show that I am not immune to constructive criticsm (and to shut
the trolls up) I decided to rewrite the constructor so it uses a table
and luckily the use of templates made sure it wasn't too tedious:

[snip]

Actually, I'd rather have a builder pattern:

// stores names functions
struct NamedFunction
{
std::wstring iName;
struct normal
{
normal(function* (*aCreator)()) : iCreator(aCreator) {}
function* (*iCreator)();
};
struct stdlib
{
// snip for brevity
};
typedef lib::variant<normal, stdlib> type_t;
type_t iType;
};

// stores namespace and their functions
struct NamespaceRepository
{
std::wstring iNamespaceName;
std::vector<NamedFunction> iMemberFunctions;

NamespaceRepository( std::wstring const & name )
: iNamespaceName(name)
{}
};
bool operator<(NamespaceRepository const & lhs, NamespaceRepository
const & rhs )
{
return lhs.iNamespaceName < rhs.iNamespaceName;
}

// persitancy root for namespaces
struct ByteCodeRepository
{
std::set<NamespaceRepository> _namespaces;

// builder of namespace list or related functions
struct Builder
{
mutable std::set<NamespaceRepository> _namespaces;
mutable NamespaceRepository * iNamespaceRepository;

Builder()
: iByteCodeRepository ()
, iNamespaceRepository()
{ }

Builder const & addNamespace(std::wstring const & name) const
{
iNamespaceRepository = &(*_namespaces.insert(name).first);
return *this;
}

template <typename T>
Builder const & addNormalFunction(std::wstring const &
name ) const
{
assert( iNamespaceRepository );
NamedFunction func;
func.iName = name;
func.iType = NamedFunction::normal(new T()); // or
whatever
iNamespaceRepository->push_back(func);
return *this;
}
template <typename T>
Builder const & addSystemFunction(std::wstring const &
name ) const
{
// ....
return *this;
}
};

ByteCodeRepository( Builder const & builder )
{
_namespaces.swap(builder._namespaces)
}
};

And then you can define:
ByteCodeRepository repository = ByteCodeRepository::Builder()
.addNamespace(L"")
.addNamespace(L"system"),
.addNormalFunction <wait_1>
( L"wait" )
.addNormalFunction <wait_2>
( L"wait" )
.addNormalFunction <create_thread_1>
( L"create_thread")
.addNormalFunction <create_thread_2>
( L"create_thread")
.addNormalFunction <send_object_1>
( L"send" )
.addNormalFunction <send_object_2>
( L"send" )
.addNormalFunction <post_object_1>
( L"post" )
.addNormalFunction <post_object_2>
( L"post" )
.addNormalFunction <available>
( L"available" )
.addNormalFunction <which>
( L"which" )
.addNormalFunction <get>
( L"get" )
.addNormalFunction <resource::file_open>
( L"open" )
.addNormalFunction <resource::file_read_1>
( L"read" )
.addNormalFunction <resource::file_read_2>
( L"read" )
.addNormalFunction <resource::file_read_line>
( L"read_line" )
.addNormalFunction <resource::file_write_1>
( L"write" )
.addNormalFunction <resource::file_write_2>
( L"write" )
.addNormalFunction <resource::file_write_line>
( L"write_line" )
.addNormalFunction <resource::file_seek_read_1>
( L"seek_read" )
.addNormalFunction <resource::file_seek_read_2>
( L"seek_read" )
.addNormalFunction <resource::file_tell_read>
( L"tell_read" )
.addNormalFunction <resource::file_seek_write_1>
( L"seek_write" )
.addNormalFunction <resource::file_seek_write_2>
( L"seek_write" )
.addNormalFunction <resource::file_tell_write>
( L"tell_write" )
.addNormalFunction <resource::file_is_good>
( L"is_good" )
.addNormalFunction <resource::file_close>
( L"close" )
.addNamespace(L"text"),
.addNormalFunction <tokens> ( L"tokens" )
.addNormalFunction <to_utf8> ( L"to_utf8" )
.addNormalFunction <from_utf8> ( L"from_utf8" )
.addNamespace(L"math"),
// ...
;
};

Hereafter it is not too hard to make a loop for registration.
But I agree that if it doesn't make sense to keep it afterward, you
could put that in a function and it can exceed the XX lines limit.
 
M

Michael Doubez

On 08/12/2010 21:34, red floyd wrote:
On 08/12/2010 20:19, Keith H Duggar wrote:
On 08/12/2010 16:59, Yannick Tremblay wrote:
So for example, although I do not beleive that there exists a number
of lines per functions that is the threshold between a bad and a good
function, in some evironment, it can be worthwhile to place a rule
that say that all "all functions must be less than XX lines unless a
good explanation is provided".
Why provide a good explanation?  Functions that contain switch
statements are often long and require no explanation.  The following
function of mine is over 100 lines long and requires no explanation:
[snip unbelievably naive and primitive mess]
Wow ... just wow ... that is a prime(evil) example of the horrific
code that poorly trained fanboys write when they lose all (or never
had any) rational perspective on code readability.
It's exactly the kind of stuff you see all over Micros$$t code so
I guess it's not so surprising in your specific case; but ... wow.
You are right about one thing though, no explanation should be
provided in this case. Instead the code should be instantaneously
rejected and the programmer sent to rehab.
There is nothing wrong with the constructor I posted.  It contains no
branches (is therefore very simple) and all it does is construct objects
which is generally what constructors do.  It is also perfectly readable.
and it would be much clearer if it was table driven.  All that nasty
inline stuff could be replaced by a loop and a table.
Just to show that I am not immune to constructive criticsm (and to shut
the trolls up) I decided to rewrite the constructor so it uses a table
and luckily the use of templates made sure it wasn't too tedious:

Actually, I'd rather have a builder pattern: [snip]
ByteCodeRepository repository = ByteCodeRepository::Builder()
  .addNamespace(L"")
  .addNamespace(L"system"),
     .addNormalFunction<wait_1>( L"wait"         )
     .addNormalFunction<wait_2>( L"wait"         ) [snip]
  .addNamespace(L"text"),
     .addNormalFunction<tokens>      ( L"tokens"     )
     .addNormalFunction<to_utf8>     ( L"to_utf8"    )
     .addNormalFunction<from_utf8>   ( L"from_utf8"  )
  .addNamespace(L"math"),
  // ...
  ;
};
Hereafter it is not too hard to make a loop for registration.
But I agree that if it doesn't make sense to keep it afterward, you
could put that in a function and it can exceed the XX lines limit.

I don't see how this is any better than the other two solutions.

I see the following advantages:
- the namespace string is not repeated, typing errors are reduced.
- the namespace.function tree becomes apparent which make reading
easier (you could also reorganize it into subinitialisation functions/
modules). In fact, syntactic sugar could be designed to make easier to
read.
- the init can be put into its own file, which separates the code
and the initialisation data.
- the structure can be reused/preprocessed/enhanced before
insertion: gives a base for future changes (in particular using more
than one insertion sequence).
 
K

Keith H Duggar

On 08/12/2010 21:34, red floyd wrote:
On 08/12/2010 20:19, Keith H Duggar wrote:
On 08/12/2010 16:59, Yannick Tremblay wrote:
So for example, although I do not beleive that there exists a number
of lines per functions that is the threshold between a bad and a
good
function, in some evironment, it can be worthwhile to place a rule
that say that all "all functions must be less than XX lines unless a
good explanation is provided".
Why provide a good explanation? Functions that contain switch
statements are often long and require no explanation. The following
function of mine is over 100 lines long and requires no explanation:
[snip unbelievably naive and primitive mess]
Wow ... just wow ... that is a prime(evil) example of the horrific
code that poorly trained fanboys write when they lose all (or never
had any) rational perspective on code readability.
It's exactly the kind of stuff you see all over Micros$$t code so
I guess it's not so surprising in your specific case; but ... wow.
You are right about one thing though, no explanation should be
provided in this case. Instead the code should be instantaneously
rejected and the programmer sent to rehab.
KHD
There is nothing wrong with the constructor I posted. It contains no
branches (is therefore very simple) and all it does is construct
objects
which is generally what constructors do. It is also perfectly readable.
and it would be much clearer if it was table driven. All that nasty
inline stuff could be replaced by a loop and a table.
Just to show that I am not immune to constructive criticsm (and to shut
the trolls up) I decided to rewrite the constructor so it uses a table
and luckily the use of templates made sure it wasn't too tedious:
This looks like a good candidate for code generation! When I read your
original, I thought it was generated code.
<Big Snip>
You may have made it worse!

The kind of worse which happens to the codebase of companies which the
likes of Keith Duggar works for.  The kind of worse that results from
religiously (blindly) following the doctrine of some suboptimal coding
standard: so my function fits into our standardized editor window (10
lines of code, big font) why not convert it into a table???

LOL ... no it's the kind of worse that results from a naive
poorly trained programmer who is totally ignorant of superior
solutions and how to implement them. You are getting a bit
closer though. Perhaps combined with hint's from Michael's
post, examining a particular boost library, and dare I say
some /thinking/ (instead of ranting and squirming) you might
figured it out.
I think I will stick with the table version though; I can't be
arsed rolling it back as the difference between the two versions
is marginal by any sensible metric.

You are right, the difference is marginal: they both still suck.
But, I think you will make more progress in coming weeks. Until
then I look forward to you digging your rant hole deeper so that,
when you finally have coded one of the superior solutions, you
can look back and see what a vociferous ignorant fool you were.

KHD
 
K

Keith H Duggar

Exactly, that's how patterns emerge.

Evidence suggests that Divine "It's Fine" Leigh has extreme
difficulty distinguishing between /arbitrary/ and /rational/,
between /just subsets/ and /patterns/. He is slowly making
some progress though and is intelligent so hope remains.

KHD
 
K

Keith H Duggar

On 09/12/2010 02:24, Ian Collins wrote:
On 12/ 9/10 02:32 PM, Leigh Johnston wrote:
On 08/12/2010 21:34, red floyd wrote:
On 08/12/2010 20:19, Keith H Duggar wrote:
On 08/12/2010 16:59, Yannick Tremblay wrote:
So for example, although I do not beleive that there exists a number
of lines per functions that is the threshold between a bad and a
good
function, in some evironment, it can be worthwhile to place a rule
that say that all "all functions must be less than XX lines unless a
good explanation is provided".
Why provide a good explanation? Functions that contain switch
statements are often long and require no explanation. The following
function of mine is over 100 lines long and requires no explanation:
[snip unbelievably naive and primitive mess]
Wow ... just wow ... that is a prime(evil) example of the horrific
code that poorly trained fanboys write when they lose all (or never
had any) rational perspective on code readability.
It's exactly the kind of stuff you see all over Micros$$t code so
I guess it's not so surprising in your specific case; but ... wow..
You are right about one thing though, no explanation should be
provided in this case. Instead the code should be instantaneously
rejected and the programmer sent to rehab.
KHD
There is nothing wrong with the constructor I posted. It contains no
branches (is therefore very simple) and all it does is construct
objects
which is generally what constructors do. It is also perfectly readable.
and it would be much clearer if it was table driven. All that nasty
inline stuff could be replaced by a loop and a table.
Just to show that I am not immune to constructive criticsm (and to shut
the trolls up) I decided to rewrite the constructor so it uses a table
and luckily the use of templates made sure it wasn't too tedious:
This looks like a good candidate for code generation! When I read your
original, I thought it was generated code.
<Big Snip>
I don't think I have gained much though. :)
You may have made it worse!
The kind of worse which happens to the codebase of companies which the
likes of Keith Duggar works for.  The kind of worse that results from
religiously (blindly) following the doctrine of some suboptimal coding
standard: so my function fits into our standardized editor window (10
lines of code, big font) why not convert it into a table???
LOL ... no it's the kind of worse that results from a naive
poorly trained programmer who is totally ignorant of superior
solutions and how to implement them. You are getting a bit
closer though. Perhaps combined with hint's from Michael's
post, examining a particular boost library, and dare I say
some /thinking/ (instead of ranting and squirming) you might
figured it out.
You are right, the difference is marginal: they both still suck.
But, I think you will make more progress in coming weeks. Until
then I look forward to you digging your rant hole deeper so that,
when you finally have coded one of the superior solutions, you
can look back and see what a vociferous ignorant fool you were.

I am ranting?

Rather obviously. Your "The kind of worse ..." paragraph is most
clearly a rant. But, as pointed out before, you ironically have
quite a difficult time understanding words and phrases from your
mother tongue.

Hehe ... I agree it remains humorous how poorly you understand
English.
You really are a pathetic troll;

If you believe I am a troll, then do you not realize that I "win"
everytime you respond to me? Furthermore, given that you continue
to respond I must be quite an /effective/ troll contrary to your
"pathetic" claim. In short, your behavior is incoherent and
irrational.
any code you produce for your employer is probably an over
engineered, prematurely optimized bag of shite; I pity your
employer.

LMAO ... I love moronic speculations that fall sooo faarr from
the mark. They always bring a huge grin to my face ;-)

KHD
 
R

Richard

[Please do not mail me a copy of your followup]

Leigh Johnston <[email protected]> spake the secret code
Actually whilst this builder pattern (which does not appear to be the
same as the builder pattern in GoF) solution does kind of look clean it
does smell of over engineering the simple problem of allocating a
collection of objects.

The only real problem with my initial solution of a simple list of
explic object allocations in a constructor is the repetition of code and
string literals; is this such a big deal? I think not. Ian pointed out
that this would be fine if the code was generated.

I really don't like duplication and in particular repeated duplication
of string constants is something I view as more smelly than just
duplication of code. So yeah, I probably would have introduced some
named constants (if you type the name wrong, its a compilation error,
but if you type the string literal wrong, its a much harder to find
run-time error).

I have done both builder and table-based initializations before. I've
done the table-based stuff when it was repeated blocks of identical
arguments to the same function, like a registration API. I've done
the builder stuff when most of the time you wanted to supply defaults
for most of the values in a structure and only wanted to explicitly
specify the differences. A blog post on the latter for Direct3D 11
resource descirption structures is here: <http://tinyurl.com/22jw3f2>.

In your particular case, I was likely to have done some sort of
refactoring to eliminate the duplication if I was writing the code.
However, if someone else had written the code I wouldn't have found
this so egregious as to warrant changing unless it had a bug. I don't
consider repetition to be readable, because too much repetition tricks
your brain into thinking they're all the same when in fact there's an
important difference hiding in all that repetition.
 
R

Richard

[Please do not mail me a copy of your followup]

Leigh Johnston <[email protected]> spake the secret code
The use of macros would amortize the problems of code and string literal
repetition of course and whilst I usualy eschew the use of macros
perhaps their use in this particular case is warrented? [...]

I use macros to eliminate duplication as well. For instance,
sometimes you need to do a bunch of template stuff with repeated
blocks of template related code. You can't get rid of that
duplication without macros. To emphasize that the macros are only
there for the purpose of eliminating this duplication, I'll #define
them right before they're used and then #undef them right afterwards.

Recently I contributed to an example of using Boost.Spirit with LLVM
and suggested emphasizing the duplication by eliminating it through
macros. You can see that in action here:
<https://github.com/scientific-coder/Computer-Languages/blob/master/lang_3-llvm.cxx>

By using the macro, it makes it explicit that the chunks of code are
the same with different text substituted inside. Prior to that, it
wasn't obvious if there were subtle differences between the repeated
blocks of text.
 
I

Ian Collins

[Please do not mail me a copy of your followup]

Leigh Johnston<[email protected]> spake the secret code
Actually whilst this builder pattern (which does not appear to be the
same as the builder pattern in GoF) solution does kind of look clean it
does smell of over engineering the simple problem of allocating a
collection of objects.

The only real problem with my initial solution of a simple list of
explic object allocations in a constructor is the repetition of code and
string literals; is this such a big deal? I think not. Ian pointed out
that this would be fine if the code was generated.

I really don't like duplication and in particular repeated duplication
of string constants is something I view as more smelly than just
duplication of code. So yeah, I probably would have introduced some
named constants (if you type the name wrong, its a compilation error,
but if you type the string literal wrong, its a much harder to find
run-time error).

I'd also remove the the duplicated insertion code, something I find
particularly irksome. Something like

template <typename Fn>
void addSymbol( const wchar_t* type )
{
// Note 'name' added as a static member of function class.
//
specific_namespace(type).symbol_table().insert(fn::name,
value(FunctionDefinition, function_ptr(new Fn())));
}

void addSystem()
{
const wchar_t* system = L"system";

add_namespace(scope::Namespace, L"system");

addSymbol<wait_1>( system );
addSymbol<wait_2>( system );
...
}

As fist cut.
 
M

Michael Doubez

On 09/12/2010 14:04, Michael Doubez wrote:
On 09/12/2010 12:18, Michael Doubez wrote:
On 08/12/2010 21:34, red floyd wrote:
On 08/12/2010 20:19, Keith H Duggar wrote:
On 08/12/2010 16:59, Yannick Tremblay wrote:
So for example, although I do not beleive that there exists a
number
of lines per functions that is the threshold between a bad and
a good
function, in some evironment, it can be worthwhile to place a
rule
that say that all "all functions must be less than XX lines
unless a
good explanation is provided".
Why provide a good explanation? Functions that contain switch
statements are often long and require no explanation. The
following
function of mine is over 100 lines long and requires no
explanation:
[snip unbelievably naive and primitive mess]
Wow ... just wow ... that is a prime(evil) example of the horrific
code that poorly trained fanboys write when they lose all (or
never
had any) rational perspective on code readability.
It's exactly the kind of stuff you see all over Micros$$t code so
I guess it's not so surprising in your specific case; but ... wow.
You are right about one thing though, no explanation should be
provided in this case. Instead the code should be instantaneously
rejected and the programmer sent to rehab.
There is nothing wrong with the constructor I posted. It
contains no
branches (is therefore very simple) and all it does is construct
objects
which is generally what constructors do. It is also perfectly
readable.
and it would be much clearer if it was table driven. All that nasty
inline stuff could be replaced by a loop and a table.
Just to show that I am not immune to constructive criticsm (and to
shut
the trolls up) I decided to rewrite the constructor so it uses a
table
and luckily the use of templates made sure it wasn't too tedious:
[snip]
Actually, I'd rather have a builder pattern:
[snip]
ByteCodeRepository repository = ByteCodeRepository::Builder()
.addNamespace(L"")
.addNamespace(L"system"),
.addNormalFunction<wait_1>( L"wait" )
.addNormalFunction<wait_2>( L"wait" )
[snip]
.addNamespace(L"text"),
.addNormalFunction<tokens> ( L"tokens" )
.addNormalFunction<to_utf8> ( L"to_utf8" )
.addNormalFunction<from_utf8> ( L"from_utf8" )
.addNamespace(L"math"),
// ...
;
};
Hereafter it is not too hard to make a loop for registration.
But I agree that if it doesn't make sense to keep it afterward, you
could put that in a function and it can exceed the XX lines limit.
I don't see how this is any better than the other two solutions.
I see the following advantages:
- the namespace string is not repeated, typing errors are reduced.
- the namespace.function tree becomes apparent which make reading
easier (you could also reorganize it into subinitialisation functions/
modules). In fact, syntactic sugar could be designed to make easier to
read.
- the init can be put into its own file, which separates the code
and the initialisation data.
- the structure can be reused/preprocessed/enhanced before
insertion: gives a base for future changes (in particular using more
than one insertion sequence).
And to preempt the vociferous Duggar yes it is obvious that using design
patterns generally do make things cleaner but I have to admit I have not
*knowingly* used this particular pattern before. I am not ignorant of
design patterns in general; I use the observer pattern a lot for
example. :)

Actually whilst this builder pattern (which does not appear to be the
same as the builder pattern in GoF) solution does kind of look clean it
does smell of over engineering the simple problem of allocating a
collection of objects.

True, it does seem a lot of effort for no real technical gain. But
IMHO, this is a one time effort for the whole lifetime of the project
(let say two years :) ) which may justify it in terms of ROI.

As for the pattern, IIRC the exact name is is "named parameter idiom"
but since it effectively constructs the data, I guess it becomes a
builder pattern.
The only real problem with my initial solution of a simple list of
explic object allocations in a constructor is the repetition of code and
string literals; is this such a big deal?  I think not. Ian pointed out
that this would be fine if the code was generated.

The intermediate table based solution probably sucked the most.

Perhaps the solution would not be to build a central data but using
the same pattern for directly calling the relevant functions.

In particular, you wouldn't have all this storage of functions of
different type. All the most since it is certainly already done
somewhere else (I guess).

Something along the line:

const std::wstring iCurentNamespace;

builder& add_namespace(const std::wstring& aNamespace)
{
if( /* namespace does not already exists */ )
{
add_namespace(scope::Namespace, aNamespace);
}
iCurentNamespace = aNamespace;
}

template <typename T>
builder& add_normal_function(const std::wstring& aFunction)
assert( !iCurrentNamespace.empty() );
specific_namespace(iCurrentNamespace).symbol_table()
.insert(aFucntion
, value(FunctionDefinition,
function_ptr(new T())));
return *this;
}

And then you put your build tree in a function.
 
P

Peter Remmers

Am 07.12.2010 16:52, schrieb James Kanze:
On 07/12/2010 00:55, Keith H Duggar wrote:
[...]
First random choice of a *real world* function of mine:
plugins::entry_list::iterator plugins::find(const plugin& aEntry)
{
lib::lock lock(*this);
for (entry_list::iterator i = iEntries.begin(); i != iEntries.end(); ++i)
if (i->path() == aEntry.path())
return i;
return iEntries.end();
}

The form I prefer.

Who says this is THE canonical form? Can there be a THE canonical form
at all?

I my opinion, with the "i=begin; i!=end; ++i" form it is far easier to
prove that the loop must eventually terminate, because every programmer
would translate this as "for each element", which obviously terminates
because the number of elements is finite.
Certainly. I use for loops myself a lot. In this case, I don't
see any real difference between my while and:

for ( ; i != iEntries.end()&& i->path() != aEntry.path(); ++ i) {
}

There is little difference, because this is only a refactoring of your
while loop, leaving the exit condition the same. See below.
Which ever seems more natural or more appropriate is purely a
matter of taste.


I don't have any irrational fear of if or return. I just prefer
to use them when appropriate. I do have a fear of code that I'm
not certain is correct. For a short bit of code like this, of
course, all of the posted forms are fairly readable: the form I
posted (with the while) has the advantage of being the canonical
form: the way linear search was first presented and analysed
(and proved) in literature. I would expect most programmers to
immediately recognize it as such.

You seem to have the assumption that everyone knows what is THE
canonical form...
Well, I don't. It must be because I'm not old enough to have had them
drummed into my head in the old days.
My opinion is based on looking at the different variants that are at
one's disposal and favoring one of them for reasons that I find logical,
and for which I can explain those reasons.
The issue of readability is arguable. I can understand your
point of view. The issue of verifiability is less arguable,
since the classical tools (logical or automatic) don't handle
multiple exits as well. And in this particular case, the fact
that it is a classical algorithm with a canonical form argues
strongly for using that canonical form, even for reasons of
readability.

What your "canonical" version does is tear apart the "for each element"
nature of the loop (which can be made even shorter and clearer with
instruments such as BOOST_FOREACH or other languages' built-in
constructs) by moving some of its components outside of the loop, and
unnecessarily marry it with the search criteria, which is something
different, by putting them side-by-side in your while condition.

To put it differently, "for each element" is at a higher level than
"take one, if there are more, take another". Your version breaks this
high-level construct into its low-level parts and scatters them around
your function and mingles them with the element inspection part.

If the "for each element" is obvious as a whole, it is immediately also
obvious that the loop must eventually terminate - whether a match is
found or not.

What your version also does is have the search criteria logic inverted,
which adds another element of unreadability.

The for-each version:

Look at each potato in the pile in succession.
If during your search you come across the potato you're looking for,
then you can stop searching.
If you have looked at the whole pile then the potato was not in the pile.

Your version:

Take the first potato from the pile.
While you have a potato in your hand AND it is NOT the one you're
looking for, throw it away and take another one.
Once you have stopped searching, the one you are holding now is the one
you're looking for... Which means your hand may also be empty in case
you haven't found it.


I find the first version much more natural.

Also note that the first version does not necessarily need the "empty
hand" to express the "not found" case.
Microsoft does not define the canonical forms. Agree.

The standard
literature where the algorithm was present *and* proved does.
Disagree.
No one does. Giving Microsoft's code as an example, however, was good
indicator that your canonical form is not the one single authoritative form.
And in small functions like these, it's not that important.
Agree. They are small enough to understand them anyway, even though they
may not use the reader's preferred way of expressing the algorithm. One
of the reasons to write small and understandable functions.


Peter
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,756
Messages
2,569,535
Members
45,008
Latest member
obedient dusk

Latest Threads

Top