Sign in to follow this  
Kyall

Is C++ too complex?

Recommended Posts

SiCrane    11839
[quote name='Álvaro' timestamp='1355249382' post='5009481']
Not only is it syntactically legal to write code in the header files: Templated code [i]has[/i] to go there.
[/quote]
Template code usually doesn't need to go in header files. Even if you aren't using one of the semi-mythical compilers that support export, there's also explicit instantiation. It's just usually more practical to stick the definitions in headers.

Share this post


Link to post
Share on other sites
alvaro    21246
[quote name='SiCrane' timestamp='1355250509' post='5009489']
[quote name='Álvaro' timestamp='1355249382' post='5009481']
Not only is it syntactically legal to write code in the header files: Templated code [i]has[/i] to go there.
[/quote]
Template code usually doesn't need to go in header files. Even if you aren't using one of the semi-mythical compilers that support export, there's also explicit instantiation. It's just usually more practical to stick the definitions in headers.
[/quote]

Explicit instantiation works in some contexts, but it's a hack to get around the problem that we are pointing out: The problem is still there.

Share this post


Link to post
Share on other sites
SiCrane    11839
I'm not clear what your point is. I'm only pointing out that your statement that template code has to go into a header (with an italicized has) is not true.

Share this post


Link to post
Share on other sites
[quote name='Bubsy' timestamp='1355249217' post='5009479']
You misinterpreted ChaosEngine.

It's not about the C++ runtime model (on which the pure virtual class acts like an interface indeed), what he criticized was the source code allegedly separation between declaration (header files) and implementation (.cpp files), which IMO violates the DRY principle.[/quote]The C# interface-implementation combination seems to violate DRY exactly as much as a pure virtual class and an inheriting concrete class do in C++. Your point was...?
[quote]More so, AFAIK the compiler and the preprocessor don't enforce this source code separation, so it's sintatically legal to write code in the header files.
[/quote]Correct. But ChaosEngine said a C# interface is a much cleaner expression of intent than a C++ header file, and my counterpoint was that you [i]can[/i] write an equivalent expression in a C++ header file that is not appreciably "less clean". A class which contains nothing but public virtual functions is an interface; there's no way to confuse it for anything else.

Share this post


Link to post
Share on other sites
alvaro    21246
My statement that template code has to go into a header is basically true in practice (at least it has to go there in the place where I work, in the standard library implementation and in Boost).

Even if my statement is a bit of a simplification, the point was that not only does the C++ compilation model not enforce the separation of interface and implementation into header and module, but it actually makes it hard to do, even if you are trying to be a good little programmer and follow the convention. Edited by Álvaro

Share this post


Link to post
Share on other sites
Bruno Sofiato    407
[quote name='Stroppy Katamari' timestamp='1355255717' post='5009527']
[quote name='Bubsy' timestamp='1355249217' post='5009479']
You misinterpreted ChaosEngine.

It's not about the C++ runtime model (on which the pure virtual class acts like an interface indeed), what he criticized was the source code allegedly separation between declaration (header files) and implementation (.cpp files), which IMO violates the DRY principle.[/quote]The C# interface-implementation combination seems to violate DRY exactly as much as a pure virtual class and an inheriting concrete class do in C++. Your point was...?
[quote]More so, AFAIK the compiler and the preprocessor don't enforce this source code separation, so it's sintatically legal to write code in the header files.
[/quote]Correct. But ChaosEngine said a C# interface is a much cleaner expression of intent than a C++ header file, and my counterpoint was that you [i]can[/i] write an equivalent expression in a C++ header file that is not appreciably "less clean". A class which contains nothing but public virtual functions is an interface; there's no way to confuse it for anything else.
[/quote]

You misinterpreted, it's .h/.cpp source code schema that violates the DRY principle, not the pure virtual base class and its concrete implementation. It's the definition of a single/complete [i]entity [/i]into two or more files that is being criticized by me.

Share this post


Link to post
Share on other sites
SiCrane    11839
[quote name='Álvaro' timestamp='1355255959' post='5009528']
My statement that template code has to go into a header is basically true in practice (at least it has to go there in the place where I work, in the standard library implementation and in Boost).
[/quote]
There is no such thing as "the" standard library implementation. There are several standard library implementations that go with different compilers. A C++03 compiler with working export would be able to not put implementations in a header. It would be an extremely bad idea due to the practical issues found with actual export implementations, but again you are confusing practicality with necessity.

I don't disagree with your statement that C++ does not enforce separation of interface and implementation, but your supporting arguments are not one hundred percent correct and you are phrasing them in the form of absolutes. This may seem like nitpicking, but this is, after all, a thread about the complexity of C++.

However, just because there is no system of enforced separation of interface and implementation that does not mean you cannot create separate files for interface and implementation, if you want them, even for template classes. You can place the template interface in one header and the implementation in a file that is included separately. (Some people go a step further and have a third file that only contains forward declarations for the template classes.) The compiler won't see any practical difference from a single included file, but the perceived benefit that other people desire of having one file that has the clean interface without the function implementations is still there.

Share this post


Link to post
Share on other sites
ChaosEngine    5185
[quote name='Stroppy Katamari' timestamp='1355255717' post='5009527']
Correct. But ChaosEngine said a C# interface is a much cleaner expression of intent than a C++ header file, and my counterpoint was that you can write an equivalent expression in a C++ header file that is not appreciably "less clean". A class which contains nothing but public virtual functions is an interface; there's no way to confuse it for anything else.
[/quote]

Until someone decides to add an implementation to for one of those methods. Then it becomes an abstract base class. Hell, it can still be pure virtual and have an implementation.

Ultimately, you're missing the point. The C++ compilation model does not split interface and implementation into two separate files, it splits declaration and definition. They sometimes happen to coincide with interface and implementation, but not quite (see private methods, members etc). This is for the benefit of the compiler not the programmer.

The key point is that this is a legacy of the C compilation model that was built to cope with the hardware restrictions of the time. Most modern languages don't bother with this because it's simply not necessary.

Share this post


Link to post
Share on other sites
Hodgman    51234
[quote name='ChaosEngine' timestamp='1355084075' post='5008867']
You could argue that the separation between declaration and implementation is built into the language in C# and java using interfaces, as opposed to C++s frankly demented compilation model.[/quote]Yeah the real issue to me isn't the [font=courier new,courier,monospace].h/.cpp[/font] schism, but the actual way in which C++ code is compiled. #include just means copy&paste, whereas in other languages, including a module is a higher level construct. I've often seen CPP files that are 60k lines long, after all the #includes have been resolved... ([i]hence crap like [font=courier new,courier,monospace]WIN32_LEAN_AND_MEAN[/font] being invented[/i]). No matter what kind of [font=courier new,courier,monospace].h/.cpp[/font] organisation you use, you can't fix the compilation model ([i]nor the fact that so much of the ABI is implementation defined, which keeps C around for interop[/i]).

If you do want to write more C# style code in C++ though, I've worked on a code base that looked like:
[code]//foo.h
#pragma once
class IFoo
{
public:
static IFoo* New();
virtual ~IFoo() {}
virtual void Frobnicate() = 0;
};

//foo.cpp
class Foo : public IFoo
{
int member;
void Frobnicate()
{
member = 42;
printf("hello world");
}
};
IFoo* IFoo::New() { return new Foo; }[/code]p.s. it's not my cup of tea though. Edited by Hodgman

Share this post


Link to post
Share on other sites
kop0113    2453
[quote name='NightCreature83' timestamp='1354278416' post='5005667']

how would you replace the goto in this bit with an exception
[code]
for (int bar =0; bar < 100; ++bar)
{
for(int foo = 0; foo < 100; ++foo)
{
if (foo * bar == 100)
{
goto loopBreak;
}
}
}

loopBreak:
printf("%d", 100);
[/code]
[/quote]
Sorry, been away and a tad late to the party.

There was a great example in Bjarne Stroustrup's book demonstrating throwing an exception out of a deeply nested loop containing the result and then catching it after.
This was however a toy implementation and isn't recommended at all.

I have no problem using a goto in this way (and I do find myself doing similar). In my opinion, this [b]isnt[/b] misusing C.

An example of a misuse of a goto (In C++) would involve the classic case of jumping to the end of a function and returning an error code rather than use an exception, whereas in C, this is acceptable.

[quote name='snowmanZOMG' timestamp='1354529055' post='5006558']
Try writing your own parser for the language...

[/quote]

Try writing a parser in pure C#, you will run into exactly the same issues. It also happens that there are many more parsers available to C++ than there is C#. And those for C# are usually just bindings to a C++ library anyway.


[quote name='snowmanZOMG' timestamp='1354529055' post='5006558']
Almost everyone LOVES Java and hates C, C++,

[/quote]

Everyone loves tablets... doesnt mean it is possible to write good software on one. You would use a proper tool like a PC.

(I should stop defending C++, I usually lose too much reputation points ;). When it comes down to it, it is personal choice. I would be very interested in having an official language choice Poll on these forums though! I would like to know how close C# is to C++ in popularity of (Indie?) games developers. Edited by Karsten_

Share this post


Link to post
Share on other sites
alvaro    21246
[quote name='Karsten_' timestamp='1355407579' post='5010213']
[quote name='snowmanZOMG' timestamp='1354529055' post='5006558']
Almost everyone LOVES Java and hates C, C++,
[/quote]
[/quote]

Oh, I missed that one earlier. Almost everyone has bad taste, I see. [img]http://public.gamedev.net//public/style_emoticons/default/smile.png[/img]

I hate Java, I love C and I like enough things about C++ that I don't think I can go back to programming in C. Edited by Álvaro

Share this post


Link to post
Share on other sites
Telastyn    3777
[quote name='Karsten_' timestamp='1355407579' post='5010213']
Try writing a parser in pure C#, you will run into exactly the same issues. It also happens that there are many more parsers available to C++ than there is C#. And those for C# are usually just bindings to a C++ library anyway.
[/quote]

The original argument was that writing a parser [i]for[/i] C++ is a complete pain due to the complexity of the language, not that writing a parser [i]in[/i] C++ is a pain.

Writing a parser in C# and C++ are pretty similar in difficulty. Writing a parser [b]for[/b] C# is tons easier than C++. Edited by Telastyn

Share this post


Link to post
Share on other sites
Cornstalks    7030
[quote name='Karsten_' timestamp='1355407579' post='5010213']
[quote name='NightCreature83' timestamp='1354278416' post='5005667']
how would you replace the goto in this bit with an exception
[code]
for (int bar =0; bar < 100; ++bar)
{
for(int foo = 0; foo < 100; ++foo)
{
if (foo * bar == 100)
{
goto loopBreak;
}
}
}

loopBreak:
printf("%d", 100);
[/code]
[/quote]
Sorry, been away and a tad late to the party.

There was a great example in Bjarne Stroustrup's book demonstrating throwing an exception out of a deeply nested loop containing the result and then catching it after.
This was however a toy implementation and isn't recommended at all.

I have no problem using a goto in this way (and I do find myself doing similar). In my opinion, this [b]isnt[/b] misusing C.
[/quote]
Just thought I'd throw an alternative out here (it's kind of hard to give any kind of "proper" alternative, because the original will always print 100, no matter what...):
[code]
int findSomething()
{
for (int bar =0; bar < 100; ++bar)
{
for(int foo = 0; foo < 100; ++foo)
{
if (foo * bar == 100)
{
return 100;
}
}
}
return -1;
}


// Then in your code...
printf("%d", findSomething());
[/code]

I've found that most of the time, deeply nested stuff can be turned into useful, smaller functions. Not always, but a lot of the time. Edited by Cornstalks

Share this post


Link to post
Share on other sites
SiCrane    11839
[quote name='Bubsy' timestamp='1355412579' post='5010243']
Does anyone still write a parser by hand instead of using yacc, antlr or something ? [img]http://public.gamedev.net//public/style_emoticons/default/tongue.png[/img]
[/quote]
Actually yes, especially when dealing with C++. The parser for clang is a hand written recursive descent parser and IIRC, gcc switched to a handwritten parser sometime in 2004 or 2005. C++'s grammar is sufficiently unruly that most standard tools have a hard time with it, especially the LALR ones.

Share this post


Link to post
Share on other sites
alvaro    21246
[quote name='Cornstalks' timestamp='1355413577' post='5010250']
Just thought I'd throw an alternative out here (it's kind of hard to give any kind of "proper" alternative, because the original will always print 100, no matter what...):
[code]
int findSomething()
{
for (int bar =0; bar < 100; ++bar)
{
for(int foo = 0; foo < 100; ++foo)
{
if (foo * bar == 100)
{
return 100;
}
}
}
return -1;
}


// Then in your code...
printf("%d", findSomething());
[/code]

I've found that most of the time, deeply nested stuff can be turned into useful, smaller functions. Not always, but a lot of the time.
[/quote]

If you can find a good name and parameters that make sense for that function, indeed this is a good solution. But this has little to do with goto: Extracting code into functions with good names and sensible parameters should be done everywhere because it makes the code more clear.

I have seen people bending over backwards trying to avoid using goto, doing things like extricating that part of the code, but the function name ends up being some monstrosity with the word "helper" in it, and it ends up getting most of the local variables of the calling function as parameters, some of them by reference. In that case that piece of code has no business being a function, and the goto is preferable.

Share this post


Link to post
Share on other sites
[quote name='Álvaro' timestamp='1355416406' post='5010265']
I have seen people bending over backwards trying to avoid using goto, doing things like extricating that part of the code, but the function name ends up being some monstrosity with the word "helper" in it, and it ends up getting most of the local variables of the calling function as parameters, some of them by reference. In that case that piece of code has no business being a function, and the goto is preferable.
[/quote]I recognize multi-level break goto is not a terrible construct, and it's probably necessary in some high performance code, but most of the time you can do this:
[code][&](){ /* may return from inner loop here */ }();[/code]
Same natural code structure as with the goto solution, but no goto, no contrived names or messy argument lists.

Share this post


Link to post
Share on other sites
alvaro    21246
[quote name='Stroppy Katamari' timestamp='1355422105' post='5010294']
[code][&](){ /* may return from inner loop here */ }();[/code]
[/quote]

I am not familiar enough with lambda expressions to know if this is cool or horrible. :)

[quote]Same natural code structure as with the goto solution, but no goto, no contrived names or messy argument lists.[/quote]
The goto solution has the same natural code as with the lambda-expression solution, but no lambda expression and no returns that don't actually return from the function.

Share this post


Link to post
Share on other sites
Cornstalks    7030
FWIW, I wasn't necessarily saying "never use goto" (I have issues with blanket statements). I was just showing another alternative (which I have found to usually be preferable (though as I said is not always the case)).

Share this post


Link to post
Share on other sites
[quote name='Álvaro' timestamp='1355424620' post='5010313']
[quote name='Stroppy Katamari' timestamp='1355422105' post='5010294']
[code][&](){ /* may return from inner loop here */ }();[/code]
[/quote]

I am not familiar enough with lambda expressions to know if this is cool or horrible. [img]http://public.gamedev.net//public/style_emoticons/default/smile.png[/img][/quote]It's Cornstalks' function suggestion, just replacing the function with a lambda in order to fix the (potential) issues you pointed out. Those issues are exactly the kind lambdas are intended to deal with, and thus this piece of code is totally mundane, not any sort of trickery. I'd argue it is not horrible because it is straightforward and not a hack, and it is a little bit cool because it is straightforward and not a hack. [img]http://public.gamedev.net//public/style_emoticons/default/smile.png[/img]
[quote][quote]Same natural code structure as with the goto solution, but no goto, no contrived names or messy argument lists.[/quote]
The goto solution has the same natural code as with the lambda-expression solution, but no lambda expression and no returns that don't actually return from the function.
[/quote]I'm not claiming it is massively better than the goto (if at all better), but it's obviously about as convenient, and also works for people who don't want to use goto or are prohibited from doing so.

The returns [i]do[/i] return from the function. You are just thinking about the wrong function.[img]http://public.gamedev.net//public/style_emoticons/default/smile.png[/img]

Share this post


Link to post
Share on other sites
Vortez    2714
I never understood this hated toward goto... it's not like using 1 or 2 goto in a program gona make the code unreadable or spagetified like it was back in the assembly days (when every branching was coded using gotos), from wich i believe that fear/hate come from. It's like not wanting to use a tool just because someone told you to :)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this