Allegro.cc - Online Community

Allegro.cc Forums » Off-Topic Ordeals » Which language is best?

This thread is locked; no one can reply to it. rss feed Print
Which language is best?
Thomas Fjellstrom
Member #476
June 2000
avatar

Thats nice, I'd rather not develop some possible commercial software on illicit software ;)

That and Vista really isn't good enough to convince me to switch back.

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

nonnus29
Member #2,606
August 2002
avatar

Has anyone else read this guy? Do his ideas have merit? Or are we doomed to eternally debate the merits of general purpose language X vs language Y? Personally, I hope there's a better way....

Thomas Fjellstrom
Member #476
June 2000
avatar

That dude used the word Paradigm, therefor I shall ignore any thing he has to say. Since its all likely repetitive "Think outside the box" crap.

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

Steve++
Member #1,816
January 2002

This is the idea behind LOP: Write each module in a domain-specific language. If you don't know that language, spend time learning it. If a good-enough domain-specific language doesn't exist, spend time creating one. This is supposed to save time. Riiight...

axilmar
Member #1,204
April 2001

Shawn Hargreaves said:

The point is not that it is impossible, but that it is much harder to get right.

So in the real world (the world of tools I can actually download and use today, rather than theoretical ones that haven't been written yet) it turns out that there are far more refactoring tools for Java and C# than there are for C++, and these have much richer features and are more robust.

The reason Java as more refactoring tools is that Java uses inheritance of classes and interfaces much more than in C++, and not because it is more difficult to do it in C++.

Quote:

It depends on the feature. Some things are fine in libraries, but others can benefit from dedicated language support for many possible reasons:

  • Better error reporting.

  • More efficient code generation.

  • Nicer syntax.

It certainly depends on the feature...but if it covers those qualities you mention as a library implementation, then it is much preferrable than in the language.

Quote:

Not a huge difference, but the C# version is slightly more concise, and more importantly, less error prone because the braces are enforced as part of the construct, rather than just relying on scoping rules to release the lock at the right place.

The C++ is not error prone at all...it is just as bulletproof as the C# version. The positioning of braces has nothing to do with correctness, as the two implementations are equal.

I will dare say that the C++ version is better, because it allows for much less indentation levels. It is common in C# and Java to write code beyond 4 identation levels, and it gets stupid after a while.

Plus the C++ idiom works for many things like mutex release, file close, handle destruction, so as that the programmer does not have to learn 2 idioms...where as in Java and C# one has to learn synchronization using 'lock' or 'synchronize' (that's idiom #1) and releases resources in 'finally' clauses or at the end of the function (that's idiom #2).

Quote:

Another example is lambda functions. boost::lambda does an amazing job of implementing them in a library, but has lots of corner cases that can be very confusing in practice. Nowhere near as clean and easy to understand as the C# delegate syntax.

Lambdas and delegates are two completely different things. Lambda functions are anonymous functions that are created at the point of their declaration and used as objects, whereas delegates are containers of methods. You should have compared C# delegates to libsig++ or Qt signals. To put it with code:

//fictional C++ lambdas
template <class T, class F> void map(container<T> &con, const F &fun);
list<int> list1;
map(list1, void (list<int>::iterator &t) { cout << *t; }

//delegates ala libsig++
signal<int, float> += slot(foo, &Foo::action1);

With operator overloading, C++ can have delegates just as C#. You are right though that lambdas need support from the language, because in C++ code can not be treated as data.

Quote:

You are mistaken about how C# generics work, and are describing the Java implementation here. C# generics do not cause any unneccessary boxing

Sorry, my bad. According to this, the JIT compiler creates a different instance of a template according to its data type...much like in C++, but in C# the template instance will not actually be created until needed. For me, they are equal, and C++ 'bloat' is not something that affects the applications I write. Of course, the situation could be better, but it's not that critical, considering all the other benefits of C++.

Quote:

But also, the C++ template system makes it hard to give good error messages, as witnessed by the fact that no C++ compiler which actually exists today can come anywhere near the clarity of the errors you get from misusing generics in C# or Java.

The reason that you get clearer error messages in C#/Java is because of constraints: if your template argument does not implement the constraint, then the compiler says that 'foo does not implement bar' or something similar...whereas in C++ there is an error message that points inside the template class, which is difficult to trace (especially if there are many typedefs of template types etc). But, again, this is something not critical, in my opinion. Personally (I must emphasize it because other people may not have a similar experience) I never had any serious problem with the C++ error messages for templates, even in MSVC 6.0.

Quote:

But I'm also aware that they have a lot of issues, high on the list being that a lot of people just don't understand them (which is not aided by generally poor error reporting). So if I'm writing a library that I intend to be used by a wide audience, heavy reliance on templates is probably not a great idea. Generics do much better in that regard. The typical idiot Visual Basic programmer who barely knows enough to string together a couple of forms for his business would be totally lost if you handed him a template API, but can generally get on ok with using generic container types.

I do not see how the type of programmer you mention can not get lost with generic container types while he will get lost with C++ templates. A List<T> and std::list<T> is almost the same thing...the programmer you mention will probably choke on both. The typical idiot Visual Basic programmer most probably should not touch generics/templates in either language.

Personally I do not see why C++ template error reporting shall be so bad. An error message for a template should be reported at the place of instantation, not at the place of declaration, if the error concerns a template parameter. For example, if I write the following code:

template <class T> class Map {
    ...
    if (x < y)
    ...
};

class Foo {
};

Map<Foo> map1;

then I expect the compiler to tell me that "Foo does not define operator < at declaration of 'map1'", for example, and it is dead easy to do (why it is not done, it is beyond me; most probably those C++ compiler writers have much higher decryption capabilities).

Zaphos said:

That feature just calls "make" whenever you save, and isn't recommended. The Eclipse CDT manual, right in the "before you begin" section, states: "For C/C++ projects this feature should be turned off, otherwise builds will be performed whenever a file is saved, including makefiles and header files."

I do not know the exact implementation, but I have hapilly used autocompile with the Eclipse C++ plugin...albeit for small projects, using gcc and precompiled headers. And from what I remember, it compiles the file you save, but not other files.

But again, it is not a language issue per se, but more of an environment issue. You can have an interpreted C++, if you like interactive development (disclaimer: haven't tried it).

You can also try an online C++ compiler here which can emit bytecode if you like.

Zaphos
Member #1,468
August 2001

Quote:

Of course refactoring is technically doable in C++: you can always write a program to programmatically manipulate code written in any well defined language.

Hmm, really? Seems refactoring can get confusing when you allow for complex macros on top of the a language, since we need to consider how the code would expand for any possible set of inputs to those macros, not just those inputs the compiler will see on the current build system. I would worry that those macros might have the ability to take what looks like a clean refactor &, for some input, make the refactor unclean. After all, we have a lot of trouble automatically proving anything at all about programs ... given a well defined but powerful macro language, I imagine the same difficulties would arise. Essentially: how can you refactor if you can have arbitrary-sized blocks of code which may essentially expand to anything at all, as far as you know?
As a more practical concern, here: In a portable, complex C/C++ project we can easily get many different possible code paths pending the macro settings -- are we in debug mode? which compiler are we using? which version of that compiler? which platform are we on?
These code paths may interlace freely, and some will be mutually exclusive, and some won't. At any given time we need to ensure that ALL valid code paths (not just the current one!) remain valid, but we may ignore invalid code paths (these need not compile). Can we really say that will never confuse a refactoring tool? I think the best it could do is to try going through each possible code path, assuming each is valid, and coming back crying if any of them don't make sense. (it's not even clear this is possible, if we can generate code paths based on possible future compiler settings ... going further toward the 'worst case' nightmare fantasy, could we have infinite possible code paths?)

And for a very specific example (not necessarily exhibiting the same problems): if you have something like

#define makevar(N) int var##N
...
makevar(A);
cout << varA;

then you rename "varA" to "foo" ... what is the refactorer supposed to do? Probably 'makevar' was intended to be extensible with more serious initialization in the future -- it would be rather harsh to just replace the macro call to "makevar(A)" with "int foo". And if we changed the behavior of the makevar macro, that's almost certainly a side effect the code author did not expect or intend, and will lead to confusing when they try to make a different variable with makevar (and end up just getting foo back!). So it seems like all the refactorer safely do is fail to refactor.

edit:

Quote:

The reason Java as more refactoring tools is that Java uses inheritance of classes and interfaces much more than in C++, and not because it is more difficult to do it in C++.

This seems incredibly unlikely, especially when presented as the (sole, absolute) reason.

axilmar
Member #1,204
April 2001

Zaphos said:

Hmm, really? Seems refactoring can get confusing when you allow for complex macros on top of the a language, since we need to consider how the code would expand for any possible set of inputs to those macros, not just those inputs the compiler will see on the current build system.

I am not denying that the preprocessor does not make refactoring difficult. My claim is that refactoring is not a commonly used operation in the C++ world because there aren't so many occasions that it is needed. It is very common in the Java world to change the class hierrachy, interfaces, etc, whereas in C++ it is not that common (not so common that the text replacement does not cover).

nonnus29
Member #2,606
August 2002
avatar

Quote:

This is the idea behind LOP: Write each module in a domain-specific language. If you don't know that language, spend time learning it. If a good-enough domain-specific language doesn't exist, spend time creating one. This is supposed to save time. Riiight...

SQL is a domain specific language, so that doesn't save time? Riiight... ;)

For a suitably large domain dsl's make perfect sense. I guess the thing that holds them back is there aren't that many large domains. Or the fact developers are too wrapped up in debating meaningless minutia and can't pull back and see the big picture ie look for the domain?

Steve++
Member #1,816
January 2002

The thing is that domain specific languages are exploding all over the place. Look at Java EE. It's covers a domain - a well defined one, but look at how many DSLs it uses.

Shawn Hargreaves
The Progenitor
April 2000
avatar

Quote:

Quote:

Another example is lambda functions. boost::lambda does an amazing job of implementing them in a library, but has lots of corner cases that can be very confusing in practice. Nowhere near as clean and easy to understand as the C# delegate syntax.

Lambdas and delegates are two completely different things. Lambda functions are anonymous functions that are created at the point of their declaration and used as objects, whereas delegates are containers of methods.

You're describing what delegates used to be in .NET 1.0.

Modern C# 2.0 delegates are in fact full lambda functions, including lexical scoping.

Quote:

The reason that you get clearer error messages in C#/Java is because of constraints

Exactly! The language has been designed specifically to enable good error messages and make things less confusing.

Quote:

I do not see how the type of programmer you mention can not get lost with generic container types while he will get lost with C++ templates. A List<T> and std::list<T> is almost the same thing...the programmer you mention will probably choke on both. The typical idiot Visual Basic programmer most probably should not touch generics/templates in either language.

Tell that to the literally millions of idiot Visual Basic programmers who are happily churning out code using "List(of String)" or "Dictionary(of String, Wibble)"...

They don't write new generic types (in fact they tend not to write new classes much at all), but there are an awful lot of people who are gainfully employed writing simple procedural code to string together those generic library types.

An STL list is equally simple to declare, but the problem with templates comes when you do something wrong. For a skilled programmer this tends not to be obvious, because top class programmers learn by understanding how the entire system works so they can predict how it will behave, but an awful lot of people don't learn like that. They just try things out, and rely heavily on their IDE and compiler error messages to tell them what they are doing wrong. For someone like this, STL is unusable because when you make a typo using a std::list<>, you get incomprehensible gibberish back. It really does make a huge difference when the compiler is able to tell them exactly what and where the problem is.

Quote:

Personally I do not see why C++ template error reporting shall be so bad.
...
and it is dead easy to do (why it is not done, it is beyond me; most probably those C++ compiler writers have much higher decryption capabilities).

If it's really that easy, why not go write a compiler that does it right? :-)

Fact: all existing C++ compilers give terrible error messages for mistakes involving templates.

From this you conclude that all existing C++ compiler writers must somehow be stupid, or not trying hard enough, or have failed to notice the problem.

Doesn't it seem even slightly possible that the compiler writers are actually very smart people, and have been working hard on this for over a decade now, but that it it turns out to be an incredibly hard problem?

When presented with a problem hard enough to not have been solved in over a decade, my personal inclination would be to stop throwing myself at the vertical cliff face and try to find an alternative route :-)

axilmar
Member #1,204
April 2001

Quote:

You're describing what delegates used to be in .NET 1.0.
Modern C# 2.0 delegates are in fact full lambda functions, including lexical scoping.

Indeed, but the term 'delegate' is not very appropriate for lambda functions.

Quote:

Exactly! The language has been designed specifically to enable good error messages and make things less confusing.

But constraints are not the desicive factor for good error reporting. I believe that error reporting in C++ templates could be much better, as I already have said.

Quote:

An STL list is equally simple to declare, but the problem with templates comes when you do something wrong. For a skilled programmer this tends not to be obvious, because top class programmers learn by understanding how the entire system works so they can predict how it will behave, but an awful lot of people don't learn like that. They just try things out, and rely heavily on their IDE and compiler error messages to tell them what they are doing wrong. For someone like this, STL is unusable because when you make a typo using a std::list<>, you get incomprehensible gibberish back. It really does make a huge difference when the compiler is able to tell them exactly what and where the problem is.

I think you are overstating the problem. The first time you deal with error messages from C++ templates the report might seem cryptic. But any person deserving the title of programmer should be able to easily comprehend the error message after a while.

Quote:

Fact: all existing C++ compilers give terrible error messages for mistakes involving templates.

Here is a little situation that usually produces an error message:

1#include <map>
2using namespace std;
3 
4class Foo {
5public:
6};
7 
8class Bar {
9public:
10};
11 
12int _tmain(int argc, _TCHAR* argv[])
13{
14 map<Foo, Bar> map1;
15 map1[Foo()] = Bar();
16 return 0;
17}

The error message is:

c:\program files\microsoft visual studio 8\vc\include\functional(143) : error C2784: 'bool std::operator <(const std::reverse_iterator<_RanIt> &,const std::reverse_iterator<_RanIt2> &)' : could not deduce template argument for 'const std::reverse_iterator<_RanIt> &' from 'const Foo'
        c:\program files\microsoft visual studio 8\vc\include\xutility(1842) : see declaration of 'std::operator <'

It is not a difficult to comprehend message is it? I have not written "operator <" for type Foo.

Quote:

From this you conclude that all existing C++ compiler writers must somehow be stupid, or not trying hard enough, or have failed to notice the problem.

I never said they are stupid. What I said is that they haven't addressed the problem because they do not have the problem. It is the same like garbage collection: they can easily code large programs without GC, where the rest of the people are not that capable. Propably because these compiler writers are too smart.

Quote:

Doesn't it seem even slightly possible that the compiler writers are actually very smart people, and have been working hard on this for over a decade now, but that it it turns out to be an incredibly hard problem?

When presented with a problem hard enough to not have been solved in over a decade, my personal inclination would be to stop throwing myself at the vertical cliff face and try to find an alternative route :-)

Really, I do not see how hard it is to infer that a template argument does not implement a particular interface.

Microsoft has already done it, but they prefer to report the details before the actual error. I have just noticed that the last line of the error output is:

c:\program files\microsoft visual studio 8\vc\include\functional(143) : error C2676: binary '<' : 'const Foo' does not define this operator or a conversion to a type acceptable to the predefined operator

...which says exactly what the problem is.

Shawn Hargreaves
The Progenitor
April 2000
avatar

Quote:

I believe that error reporting in C++ templates could be much better, as I already have said.

I'm sure it will continue to get better. But today it is pretty bad. And you are mistaken in thinking that the compiler writers are not spending time on this problem: it is actually being taken very seriously and a lot of work is going into how to improve things. It just happens to be a really hard problem.

I can't tell you exactly what the hard bits are, having never written a C++ compiler myself, but I'm inclined to believe those who have when they tell me this turns out to be extraordinarily difficult!

Quote:

I think you are overstating the problem. The first time you deal with error messages from C++ templates the report might seem cryptic. But any person deserving the title of programmer should be able to easily comprehend the error message after a while.

Ah yes, the "programming is hard, so programmers need to be clever" argument. Yes, it's true, after a while a clever person can comprehend all sorts of stuff. But does that mean we should just give up and settle for what we have today? I think not. In an ideal world people shouldn't have to spend time getting used to things that seem cryptic, and I think we should strive toward that ideal world.

There are two possible ways to improve cryptic error messages: improve the compiler, or improve the language.

You seem convinced that a better compiler could make the whole problem go away, but I just don't see that. Smart people have tried to write this compiler, and failed. Maybe they will figure it out next year, but maybe not. I'm not betting on it. From a practical perspective, that better compiler certainly does not exist today.

Wheras better languages do exist today. Several of them. You can download them and use them for free.

I'm a practical guy, and from a practical perspective, it seems a lot less risky to go with the solution that has been proven to work, rather than one that you think might be possible in the future (especially when the people who actually write the compilers disagree).

Quote:

The error message is:

c:\program files\microsoft visual studio 8\vc\include\functional(143) : error C2784: 'bool std::operator <(const std::reverse_iterator<_RanIt> &,const std::reverse_iterator<_RanIt2> &)' : could not deduce template argument for 'const std::reverse_iterator<_RanIt> &' from 'const Foo'
        c:\program files\microsoft visual studio 8\vc\include\xutility(1842) : see declaration of 'std::operator <'

It is not a difficult to comprehend message is it?

Are you kidding?

That's a TERRIBLE error message!

What is xutility?
What is functional?
What is a reverse_iterator?
What is std:: operator <?

I'm not using any of those in my code! Stupid compiler is giving me random errors from some code that I'm not even calling. Must be a compiler bug.

What does that even mean "could not deduce template argument"?

What, you mean I have to write a less than operator before I can use a type in a map? Nobody told me that!

So where does std:: operator< come in? How is that related to the < operator I normally use in my code?

You have to know a lot about both C++ and the STL implementation to decode this stuff.

A good error message would be:

"Cannot store Foo in a map because Foo does not implement operator <"

But no existing C++ compiler can come within a million miles of telling me that.

C#, on the other hand, can tell me exactly what the mistake is:

using System;

class Container<Key, Value> where Key : IComparable<Key> { }

class Foo { }

class Test
{
    public Test()
    {
        Container<Foo, string> container;
    }
}

t.cs(15,9): error CS0309: The type 'Foo' must be convertible to 'System.IComparable<Foo>' in order to use it as parameter 'Key' in the generic type or method 'Container<Key,Value>'

GullRaDriel
Member #3,861
September 2003
avatar

What a debate !

"Code is like shit - it only smells if it is not yours"
Allegro Wiki, full of examples and articles !!

23yrold3yrold
Member #1,134
March 2001
avatar

Quote:

Fact: all existing C++ compilers give terrible error messages for mistakes involving templates.

"Fact" is right.

Quote:

That's a TERRIBLE error message!

And I've seen much, much worse. :) I've always wondered why the C++ compiler can't speak plain English for errors like that ...

--
Software Development == Church Development
Step 1. Build it.
Step 2. Pray.

Goalie Ca
Member #2,579
July 2002
avatar

Trying to understand error strings in a library as complicated and as templated as itk [1] is impossible. Luckily you can generally figure it out by looking at the line number and thinking.

[1]http://www.itk.org/

C# is quite a fine language for programming everyday desktop applications. Memory management needs a little help and for speed reasons it should almost always link with a native library but other than that, its quite fine.

C++ is the only real general purpose language here. C++ is good at most things and excels at the rest. C++ needs a bit of work and a whole bunch of libraries (but c# needs a whole bunch of libraries).

-------------
Bah weep granah weep nini bong!

Marcello
Member #1,860
January 2002
avatar

I think template errors are best when you're not even using templates, but just something normal, like strings.

Marcello

axilmar
Member #1,204
April 2001

Quote:

I'm sure it will continue to get better. But today it is pretty bad. And you are mistaken in thinking that the compiler writers are not spending time on this problem: it is actually being taken very seriously and a lot of work is going into how to improve things. It just happens to be a really hard problem.

I have to disagree about 'pretty bad'. It is not as good as it is supposed to be, but it is nowhere near as 'bad'.

Quote:

I can't tell you exactly what the hard bits are, having never written a C++ compiler myself, but I'm inclined to believe those who have when they tell me this turns out to be extraordinarily difficult!

The reason I believe the problem is not as difficult as we are being told is because I tried to solve it with a test compiler I wrote explicitely for that some moons ago.

The problem can be described like this:

"If I find that a type does not implement an operation, within a template class, what do I do? is it the template erroneously implemented or the template instantiation is wrong?".

The solution is pretty easy: the compiler knows the exact type of the operand, and it also knows where the template instantiation is. That is the reason all the compilers can finally say that the problem arises at the specific line the template class is instantiated.

Even in the case that the template class instantiates other template classes with the same parameters, even if the type is passed through a typedef, it is still possible to say where the error is, and this is demonstratable from the 'map' example I gave you earlier: all compilers will show the line of the map instantiation as the line the error comes from.

To put it with symbols: suppose you have a type K[T] which uses types K1[T], K2[T] etc where Ks are the template classes and T is the template type. At any position within a template class, the template instantiation forms a tree where root is the first class that T is passed to: K[T] -> K1[T] -> K2[T] etc. Therefore, in order to show a comprehensible error report is to start the error report from the root of the tree and not from its edges.

I hope you understand after this analysis that the problem of template error reporting is very much an implementation issue rather than a language issue.

Quote:

Ah yes, the "programming is hard, so programmers need to be clever" argument. Yes, it's true, after a while a clever person can comprehend all sorts of stuff. But does that mean we should just give up and settle for what we have today? I think not. In an ideal world people shouldn't have to spend time getting used to things that seem cryptic, and I think we should strive toward that ideal world.

I agree with you, but in the quest to find the ideal we should not give up what we have today, if it is possible. I prefer to fix C++ (because it is doable) rather than to give up its goodies for a dumbed down version called C#.

Quote:

Are you kidding?

That's a TERRIBLE error message!

What is xutility?
What is functional?
What is a reverse_iterator?
What is std:: operator <?

Ok, I admit it is not a perfect message, but the reason it is not a perfect message is because the compiler writers preferred connecting the operators provided by STL to the user-defined types, which is totally silly. If an operator is not specified for a type, and a conversion to another type is not possible, then the user should not see that the compiler failed to identify a conversion.

But the message above is not the last line. The last line of the error message is much better:

c:\program files\microsoft visual studio 8\vc\include\functional(143) : error C2676: binary '<' : 'const Foo' does not define this operator or a conversion to a type acceptable to the predefined operator

Again, it is not a perfect message, but as you can see the compiler prints the desired information. At another line, the compiler prints the error line:

test1.cpp(18) : see reference to class template instantiation 'std::map<_Kty,_Ty>' being compiled

Which means that:

1) the compiler knows the real source of error.
2) the compiler knows the exact problem.

Therefore the compiler could easily have said:

test1.cpp, line 18: operator < not defined for class Foo

So template error reporting is an implementation issue after all.

Quote:

C#, on the other hand, can tell me exactly what the mistake is:

using System;

class Container<Key, Value> where Key : IComparable<Key> { }

class Foo { }

class Test
{
public Test()
{
Container<Foo, string> container;
}
}

t.cs(15,9): error CS0309: The type 'Foo' must be convertible to 'System.IComparable<Foo>' in order to use it as parameter 'Key' in the generic type or method 'Container<Key,Value>'

There is also lots of information that one needs to know:

1) what does it mean to 'be convertible to'?
2) what is System?
3) what is 'I' in front of the comparable?
4) what is 'Comparable'?
5) how is 'Comparable' handled?
6) why Container<Key,Value> may be a method?

At least with C++, it is common knowledge of how "operator <" works: it takes two arguments and returns a bool.

With C#, I have to do a lot more:

1) I have to lookup the documentation of IComparable.
2) I have to modify my class to implement IComparable.
3) if I do not have the source, I have to make a wrapper class for 'Foo' which contains/extends Foo and implements IComparable, and load the runtime with extra objects.

What if I want my key to be a primitive? the Container class becomes complicated then. Does C# support template specialization? if it does not, then primitive keys would have to be boxed in order to be used as keys, and thus the advantage of using primitives is lost. If C# does support specialization, then one has to write a two implementations of comparison, one for primitives and one for IComparables.

Shawn Hargreaves
The Progenitor
April 2000
avatar

Quote:

The solution is pretty easy: the compiler knows the exact type of the operand, and it also knows where the template instantiation is. That is the reason all the compilers can finally say that the problem arises at the specific line the template class is instantiated.

That logic works fine until you have templates of templates. It can only find the outermost point of the instantiation which failed, not the specific point where a type that was ok transitions to a type that violates a constraint. Templates of templates aren't that uncommon, especially in code that uses smart pointers, strings, and the pair type.

Also, this only tells you where the problem happened, not what went wrong, which is really where the errors fall down. Determining what went wrong is not as simple as just reporting what method or operator call wasn't implemented, because STL (or any modern C++ library) uses a lot of partial specialization tricks that obscure this. Type traits, iterator traits, etc, make it impossible to figure out what's going on when you do things like try to instantiate a random iterator container on a type that only provides input iterators.

Quote:

There is also lots of information that one needs to know:

1) what does it mean to 'be convertible to'?
2) what is System?
3) what is 'I' in front of the comparable?
4) what is 'Comparable'?
5) how is 'Comparable' handled?
6) why Container<Key,Value> may be a method?

At least with C++, it is common knowledge of how "operator <" works: it takes two arguments and returns a bool.

Now that's not fair! If you're allowed to say it is common knowledge how operator < works in C++, then you have to grant me that it is also common knowledge how IComparable works in C#.

But there is actually a big difference between the required knowledge to understand the C# error message versus the C++ one. All the terms in the C# error directly relate either to the container type, the type I tried to store in the container, or the interface which I should have implemented to make this work. In other words every one of these terms is something that I need to know, or if I don't know, I need to go look up.

Whereas in the C++ error message, there are too many terms which have nothing to do with my code. It is leaking STL implementation details which I ought not to have to know about. I wanted to store a Foo in a std:: map, and this failed because Foo has no operator <, but the error message refers to reverse_iterator, xutility, functional, and std:: operator <. I actually do happen to know what those are because I've been using STL for years, but I shouldn't need that knowledge just to construct a basic map.

Quote:

With C#, I have to do a lot more:

1) I have to lookup the documentation of IComparable.
2) I have to modify my class to implement IComparable.

And in what way is this different to the C++ guy who has to look up the documentation for operator <, and modify their class to implement it?

Quote:

What if I want my key to be a primitive?

All the primitive types already implement IComparable: they wouldn't be comparable, otherwise!

Thomas Fjellstrom
Member #476
June 2000
avatar

Quote:

At least with C++, it is common knowledge of how "operator <" works: it takes two arguments and returns a bool.

It sure as hell isn't common knowledge. I haven't yet found ONE good resource that lists all of the standard operator overload formats, and explains how and why to use them. NOT ONE.

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

Matt Smith
Member #783
November 2000

Everyone has only mentioned text-based languages.

I think the class-hierarchy diagramming part of UML is the way forward.

And operator overloading will only make sense when the full Unicode set is allowed ;)

nonnus29
Member #2,606
August 2002
avatar

Quote:

I think the class-hierarchy diagramming part of UML is the way forward.

I read a book were the guy was talking about specifying lexers and parsers using uml style diagrams and made the case that visually specifying languages was the way of the future. Damn if he didn't have text embedded in the diagrams describing the abstract syntax though.

The big problem with uml and all other design and documentation tools is that they're separate from the actual implementation so when developers change a bad or poorly thought out design when they're coding theres no change in the documentation unless they go back and change it. And we all know how programmers love to maintain documentation.

Another factor is that visual languages can always be reduced to a text representation. There's an abundance of tools for manipulating string of characters, but not so many for manipulating graphical diagrams.

Matt Smith
Member #783
November 2000

Quote:

abundance of tools

That's the only problem. UML tools are generally free & crap or uberexpensive and untested (by me)

The same goes for programmable diagramming tools which can be coerced into doing UML e.g. Dia (free and crap), and Visio or Flash MX (expensive)

I'm writing my own. It has only cost me 6 years (on and off) so far.

Goalie Ca
Member #2,579
July 2002
avatar

Quote:

I think the class-hierarchy diagramming part of UML is the way forward.

Hells no! This is why i hate those people who study software engineering in grad school. They have no idea what all the other programmers who don't write databases/information systems do for a living. These other systems aren't perfect and could use some love and attention (esp since far more everyday people need to write code to do their thing than exist software engineers with a CS degree).

Ironically the people who have it figured out the best are the systems engineers. PLC ladder logic. So simple you can have any electrician draw a diagram that controls 1000's of inputs and 1000's of outputs with super rediculous reliability and no race conditions or deadlocks. There's a reason why its used everywhere including power plants, factories, and even buildings (lighting and security).

For scientific computing while matlab is nice for ease of use, fortran is nicer because it can actually be used to process data. New standards like f95 now support > and < keywords :D Most numerical/scientific libraries are still written in fortran. UML is useless for scientific people.

Then for the embedded systems designer you have VHDL/Verilog and C/asm/c++. VHDL and Verilog are crazy complex. C and ASM can become tedious and could use some love but we need something low level with a similar paradigm in mind to replace it. Even the java micro environment is a pain in the ass to work with. Compile once my ass and its a resource hog. I wouldn't use it for anything real time ever ever ever.

Business and psych use SPSS stats packages. There's a nice gui application but it can never just do everything people want. i know that you can script it with python. I'd assume that all the numerical stuff though is written in fortran.

In my experience CS researchers seem to focus on OOP and there are a few "old-farts" who look at functional programming and maybe a nut ball that looks at something completely different (like category theory). Like i said, OOP and those tools are fine for writting information systems and maybe even desktop applications and such but there's sooooo much programming which goes on outside of that rather small realm.

-------------
Bah weep granah weep nini bong!

axilmar
Member #1,204
April 2001

Quote:

That logic works fine until you have templates of templates. It can only find the outermost point of the instantiation which failed, not the specific point where a type that was ok transitions to a type that violates a constraint. Templates of templates aren't that uncommon, especially in code that uses smart pointers, strings, and the pair type.

No, it is not a problem. As I have shown in the example that uses 'std::map', which uses 'std::pair' and a host of other classes, the compiler knows exactly the outtermost error position and the exact type of error.

Quote:

Also, this only tells you where the problem happened, not what went wrong, which is really where the errors fall down. Determining what went wrong is not as simple as just reporting what method or operator call wasn't implemented, because STL (or any modern C++ library) uses a lot of partial specialization tricks that obscure this. Type traits, iterator traits, etc, make it impossible to figure out what's going on when you do things like try to instantiate a random iterator container on a type that only provides input iterators.

Again, the compiler knows the exact position of error and the types involved.

Quote:

Now that's not fair! If you're allowed to say it is common knowledge how operator < works in C++, then you have to grant me that it is also common knowledge how IComparable works in C#.

Not really. Operator < works the same across all languages (except Lisp and its variants): it is an infix operator that accepts two arguments and returns true/false. Whereas IComparable could be coded in many different ways, with many different function names and maybe different return types.

Quote:

But there is actually a big difference between the required knowledge to understand the C# error message versus the C++ one. All the terms in the C# error directly relate either to the container type, the type I tried to store in the container, or the interface which I should have implemented to make this work. In other words every one of these terms is something that I need to know, or if I don't know, I need to go look up.

Whereas in the C++ error message, there are too many terms which have nothing to do with my code. It is leaking STL implementation details which I ought not to have to know about. I wanted to store a Foo in a std:: map, and this failed because Foo has no operator <, but the error message refers to reverse_iterator, xutility, functional, and std:: operator <. I actually do happen to know what those are because I've been using STL for years, but I shouldn't need that knowledge just to construct a basic map.

I agree with your point, but I disagree on the part that says it is the language's fault. I think it is an implementation issue, not the language's fault.

Quote:

And in what way is this different to the C++ guy who has to look up the documentation for operator <, and modify their class to implement it?

First of all, you do not need to look up the documentation for operator <, because it is common knowledge. When you get to the point of using a map, you already have used operator < in an if statement at least once in your life.

Secondly, you do not need to modify the class; you can provide the operator function externally. That's very handy when you do not have the source.

Quote:

All the primitive types already implement IComparable: they wouldn't be comparable, otherwise!

I do not understand how primitives can implement an interface; primitives are not objects, they do not have a vtable, so how is it possible to implement IComparable?? It is either that a) the compiler cheats and provides an intrinsic implementation of IComparable or b) primitive values are boxed into objects, thus loosing the advantage of using primitives in generics.

Furthermore, if you do a 'x < 3', is the IComparable interface invoked or not?

nonnus29
Member #2,606
August 2002
avatar

Quote:

That's the only problem. UML tools are generally free & crap or uberexpensive and untested (by me)

The same goes for programmable diagramming tools which can be coerced into doing UML e.g. Dia (free and crap), and Visio or Flash MX (expensive)

I'm writing my own. It has only cost me 6 years (on and off) so far.

In my opinion, a programming language can't be entirely graphically, or you'd end up with insanely complex flowchart (lego mindstorms has a graphically language, I've never seen it though) for any nontrivial application. Plus using uml is bad idea because it's to ambiguous to generate actual programs from. Sure you can generate skeleton classes, but that's about 1% of the problem.

My idea is to combine a visual model of a finite state machine and attach code to the nodes to perform actions and code to the edges to specify the conditions for transitions between states. The language used for the code part could be any language that the tool would massage into shape when the 'generate source code' button is pushed (hey, I didn't say it was a good idea...).

Quote:

Hells no! This is why i hate those people who study software engineering in grad school. They have no idea what all the other programmers who don't write databases/information systems do for a living.

I hate those guys too, there's nothing like someone who's never worked as a professional programmer telling you about a new pattern he just 'discovered'. But the truth is, there are ALOT of database driven applications around (the internet) and thats were alot of money's at (financial services).



Go to: