Friday, May 29, 2009

The Horror Returns

I last complained about C++ back in September (on the 20th and 21st). I thought I had seen all the horrors that the new template error checking could produce.

I was wrong.

Check out the new spewage from g++:

main.cpp: In member function `void Test<t>::test()':
main.cpp:11: error: expected `;' before "i"
main.cpp:11: error: `i' undeclared (first use this function)
main.cpp:11: error: (Each undeclared identifier is reported only once for each function it appears in.)
main.cpp: In member function `void Test<t>::test() [with T = int]':
main.cpp:20: instantiated from here
main.cpp:11: error: dependent-name ` std::vector<t,std::allocator<_chart> >::const_iterator' is parsed as a non-type, but instantiation yields a type
main.cpp:11: note: say `typename std::vector<t,std::allocator<_chart> >::const_iterator' if a type is meant


Not bad, 8 lines (some very long) for a 24 line program! Oh, and can I say how much I "love" the <> syntax for templates when it comes time to post into HTML (of course, C++ predates the web, so I can't blame Bjarne too much :)

Here is "teh codz"

#include <vector>
#include <cstdio>

template<typename T>
class Test
{
public:
void test(void)
{
std::vector<T> v;
for(std::vector<T>::const_iterator i = v.begin(); i != v.end(); ++i)
printf("%p\n", &*i);
}
};

int main(int argc, char **argv)
{
Test<int> t;

t.test();

return 0;
}


Line 11 is the 'for' loop. g++ is complaining about the declaration for 'i', which is the standard (ugly) iterator. The note must of been added after lots of people complained.

The core of the error is "parsed as a non-type, but instantiation yields a type". It means that because it uses <T> somewhere, it must be parsed as a non type (that is, g++ has no idea what the type could be at this time). However, it is being used to declare a variable - which must have a type. So, g++ is confused.

The note tells us how to fix it:

$ diff main.bad.cpp main.cpp
11c11
< for(std::vector<T>::const_iterator i = v.begin(); i != v.end(); ++i)
---
> for(typename std::vector<T>::const_iterator i = v.begin(); i != v.end(); ++i)

Thanks diff for more < and >! (also predates HTML, so maybe HTML is to blame...)

Of course, if the compiler knows what the problem is well enough to emit the note, and the fix is so easy, makes you wonder why the compiler can't just fix it for you...

Thursday, May 28, 2009

Lua

I have been hearing a lot about Lua. Apparently it is very popular in game development circles. I love to read about the history of things, and Lua has a nice page for that.

They say:
"The main contenders were Tcl and, far behind, Forth and Perl."
That's pretty interesting to see. What made them not use Tcl?
"In 1993, Tcl and Perl ran only on Unix platforms."
That's a real shame. I was introduced to Tcl in 1999, when there was already a Windows version. I'm not sure when the code was first ported to Windows, I found a Usenet post from comp.lang.tcl called "New Release of TkWin -- Tk for Windows" discussing version 0.2, from Jul 18 1994. Incredible to think there may not have been a Lua by so slim a margin...

So, could Lua be a replacement for Tcl for me?

Lua feels like "everything is a table". This causes the problem that tables are not a primitive type, so there are also types for numbers and strings (as well as boolean). The syntax is vaguely C (actually more Pascal).

The use of tables seems to give easy access to object oriented programming. That is something Tcl is weaker on (mostly from the "too many choices" problem). I'm not too concerned about OO in my scripting. Scripting is for fast development, OO is for structure and maintenance.

I think I will pass on Lua for now.

Wednesday, May 27, 2009

Iterators::end

The greatest benefit of moving vectors and maps into the base language is an improvement in the syntax for iterators.

For example, C++:

std::vector<MyCoolType*> myVec;
myVec.push_back(new MyCoolType);
for(std::vector<MyCoolType*>::const_iterator i = myVec.begin(); i != myVec.end(); ++i)
(**i).print();


Versus D:

MyCoolType[] myVec;
myVec ~= new MyCoolType
foreach(i; myVec)
i.print();


First, the differences:
  1. Every class reference is automatically a pointer (MyCoolType[], not MyCoolType*[])
  2. Binary operator~ is used for vector concatenation (an object is promoted to a vector of size 1)
  3. Pointers to structures can use '.' It's obvious that the pointer needs to be dereferenced.
  4. "foreach" allows automatic const iteration. There is "foreach(ref i; myVec)" for non-const.
The advantages should be clear. Iteration in C++ is an abomination. Typedef's can clean things up some, but they also obscure what is really happening (error messages will likely come back as the underlying types).

I have become inoculated to these problems, partly because the Visual C++ IDE makes it easier (with auto complete). D makes it possible to be productive in Vi again... (not every machine has VStudio)