Jump to content

  • Log In with Google      Sign In   
  • Create Account


Is C++ too complex?


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
122 replies to this topic

#101 SiCrane   Moderators   -  Reputation: 9541

Like
2Likes
Like

Posted 11 December 2012 - 12:28 PM

Not only is it syntactically legal to write code in the header files: Templated code has to go there.

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.

Sponsor:

#102 Álvaro   Crossbones+   -  Reputation: 12903

Like
1Likes
Like

Posted 11 December 2012 - 12:46 PM


Not only is it syntactically legal to write code in the header files: Templated code has to go there.

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.


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.

#103 SiCrane   Moderators   -  Reputation: 9541

Like
1Likes
Like

Posted 11 December 2012 - 01:36 PM

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.

#104 Yrjö P.   Crossbones+   -  Reputation: 1412

Like
0Likes
Like

Posted 11 December 2012 - 01:55 PM

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.

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...?

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.

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.

#105 Álvaro   Crossbones+   -  Reputation: 12903

Like
2Likes
Like

Posted 11 December 2012 - 01:59 PM

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, 11 December 2012 - 02:00 PM.


#106 Bubsy   Members   -  Reputation: 407

Like
2Likes
Like

Posted 11 December 2012 - 02:16 PM


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.

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...?

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.

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.


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 entity into two or more files that is being criticized by me.

#107 SiCrane   Moderators   -  Reputation: 9541

Like
0Likes
Like

Posted 11 December 2012 - 02:46 PM

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).

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.

#108 ChaosEngine   Crossbones+   -  Reputation: 2289

Like
2Likes
Like

Posted 11 December 2012 - 03:41 PM

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.


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.
if you think programming is like sex, you probably haven't done much of either.-------------- - capn_midnight

#109 Hodgman   Moderators   -  Reputation: 29383

Like
2Likes
Like

Posted 11 December 2012 - 05:49 PM

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.

Yeah the real issue to me isn't the .h/.cpp 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... (hence crap like WIN32_LEAN_AND_MEAN being invented). No matter what kind of .h/.cpp organisation you use, you can't fix the compilation model (nor the fact that so much of the ABI is implementation defined, which keeps C around for interop).

If you do want to write more C# style code in C++ though, I've worked on a code base that looked like:
//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; }
p.s. it's not my cup of tea though.

Edited by Hodgman, 11 December 2012 - 05:51 PM.


#110 Karsten_   Members   -  Reputation: 1574

Like
0Likes
Like

Posted 13 December 2012 - 08:06 AM

how would you replace the goto in this bit with an exception

for (int bar =0; bar < 100; ++bar)
{
	 for(int foo = 0; foo < 100; ++foo)
	 {
	 	 if (foo * bar == 100)
	 	 {
	 	 	 goto loopBreak;
	 	 }
	 }
}

loopBreak:
	 printf("%d", 100);

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 isnt 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.

Try writing your own parser for the language...


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.


Almost everyone LOVES Java and hates C, C++,


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_, 13 December 2012 - 08:15 AM.

Mutiny - Open-source C++ Unity re-implementation.
Defile of Eden 2 - FreeBSD and OpenBSD binaries of our latest game.


#111 Álvaro   Crossbones+   -  Reputation: 12903

Like
0Likes
Like

Posted 13 December 2012 - 08:20 AM


Almost everyone LOVES Java and hates C, C++,


Oh, I missed that one earlier. Almost everyone has bad taste, I see. Posted Image

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, 13 December 2012 - 08:21 AM.


#112 Telastyn   Crossbones+   -  Reputation: 3726

Like
0Likes
Like

Posted 13 December 2012 - 08:24 AM

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.


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

Writing a parser in C# and C++ are pretty similar in difficulty. Writing a parser for C# is tons easier than C++.

Edited by Telastyn, 13 December 2012 - 08:26 AM.


#113 Bubsy   Members   -  Reputation: 407

Like
0Likes
Like

Posted 13 December 2012 - 09:29 AM

Does anyone still write a parser by hand instead of using yacc, antlr or something ? Posted Image

#114 Cornstalks   Crossbones+   -  Reputation: 6974

Like
0Likes
Like

Posted 13 December 2012 - 09:46 AM


how would you replace the goto in this bit with an exception

for (int bar =0; bar < 100; ++bar)
{
     for(int foo = 0; foo < 100; ++foo)
     {
         if (foo * bar == 100)
         {
             goto loopBreak;
         }
     }
}

loopBreak:
     printf("%d", 100);

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 isnt misusing C.

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...):
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());

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, 13 December 2012 - 09:55 AM.

[ I was ninja'd 71 times before I stopped counting a long time ago ] [ f.k.a. MikeTacular ] [ My Blog ] [ SWFer: Gaplessly looped MP3s in your Flash games ]

#115 SiCrane   Moderators   -  Reputation: 9541

Like
2Likes
Like

Posted 13 December 2012 - 09:50 AM

Does anyone still write a parser by hand instead of using yacc, antlr or something ? Posted Image

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.

#116 Bubsy   Members   -  Reputation: 407

Like
0Likes
Like

Posted 13 December 2012 - 09:54 AM

Cool, didn't know that !!! thanks for sharing ;)

#117 Álvaro   Crossbones+   -  Reputation: 12903

Like
0Likes
Like

Posted 13 December 2012 - 10:33 AM

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...):

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());

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.


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.

#118 Yrjö P.   Crossbones+   -  Reputation: 1412

Like
1Likes
Like

Posted 13 December 2012 - 12:08 PM

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.

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:
[&](){ /* may return from inner loop here */ }();
Same natural code structure as with the goto solution, but no goto, no contrived names or messy argument lists.

#119 Álvaro   Crossbones+   -  Reputation: 12903

Like
0Likes
Like

Posted 13 December 2012 - 12:50 PM

[&](){ /* may return from inner loop here */ }();


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

Same natural code structure as with the goto solution, but no goto, no contrived names or messy argument lists.

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.

#120 Cornstalks   Crossbones+   -  Reputation: 6974

Like
0Likes
Like

Posted 13 December 2012 - 02:31 PM

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)).
[ I was ninja'd 71 times before I stopped counting a long time ago ] [ f.k.a. MikeTacular ] [ My Blog ] [ SWFer: Gaplessly looped MP3s in your Flash games ]




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS