You should not learn specific languages at a CS study, you should learn several paradigms, at least:
Imperative (C, Pascal,...)
Object Oriented (C++, Java, Beta, Smalltalk,...)
Functional (ML, lisp, scheme,...)
And perhaps predicate programming (Prolog,...) and the related; constraint programming (Mozart,...)
When you get your degree, you should be able to use a new language after 1-3 weeks, use it comfortably -- knowing most of the constructs by heart after 2-5 weeks, and after a month or two, you should be an expert, mastering almost every technique the language has to offer.
when I first started at CS, I was taught a specially designed imperative language, not quite unlike C, but without the hassels of a real-world programming language.
The language implemented only some simple types: int, real, char and string. More advanced type could be constucted as tuples of other types (struct) or choice of other types (union, with tags).
The language prevented accessing a union without branching on the type-tag (a bit like functional style: case e of X(x) => f(x) | Y(y) => g(y).
Funther more, pointers, and recursive types could be created for any of the above types.
The language had only one kind of branching: if, one kind of looping: while.
The language had nested scope of variables and
functions, and type-polymorhic code using a construction not wholly unlike C++ templates.
We were taught the sematics of the language in terms of transition theory between states in the computer (well suited for the imperative paradigm).
Fast execution type was not a goal for the language, cleanness of semantics of the availible
constructs was.
We were the taught (and given exercises) to implement various programs, and other language constructs, such as: for, switch, recursive types using pointers and other nice stuff, and charged with proving the correct semantics of our solutions (including, of course, loop-induction).
This has given a clean, well defined understanding of programming, which we can "adjust" to any given imperative paradigm we encounter, somewhat like: Oh, the for construct of C is a way to structure loops, their invariants and progression
We were given a lecture in, how the world would have looked if all was nice and pretty, and the means to understand the more "polluted" (i.e. post-increment; i++) semantics and "real-world" languages in terms of well-defined simple building blocks.
This approach has given a very flexible way to understand the exact semantics of other languages, as opposed to knowing, partly how i++ works in C++ and not understanding the full implications of that semantics
Morale: Learn the "pretty-stuff" in the beginning, you want code anything that's work anything the pair of years anyway (that's true, don't kid yourself, you'll do everything much better, cleaner, more efficient a couple of years from now;)
Postulate: Adultery is a symmetric relation? (not transetive;)
Consequence: (I lust for neighbor wife
=> I commit adultery (with neighbor wide)
=> Neighbor wife should be put to death.)
I'm not sure she would like the fact that she has
no influence on that;)
Morale: Definitions and implication rules must be carefully thought through, otherwise someone will find a way to misuse them;)
First of all, this will be my last reply to this (and other) threads (sipposedly) about debugging MT code. We are way off topic here.
About compile-time type refinement (templates in C++)
What you get from compile-time type-refinement is a valuable tool to detect and diagnose common errors that are made in OO-programming: putting the wrong type of object into an instance of structure. i.e. inserting real's into a list of (conceptually, when you dont have parametrised types) integers.
On dynamicly loaded code
It does not matter that you can later (i.e. at runtime) specialize the methods of a type-instantiated class or algorithm, since it must nessesarily accept the same types as it's parents. Types have a natural partial ordering, which is commonly refered to as specialization, this ensures that stuff that gets put into a method has at least the structure that the method requires. Therefore you will not have problems with later loaded dynamic code.
On the other hand, you cannot further refine the types of arguments to methods of a type-parametrised method, since that would break the inheritance invariant: I must accept what my parents accept. This is why you need generic programming and parametrised types in the first place
Unless I've overridden the == operator for the foo* type this operation will compare pointers not the values of the foo objects. No compile time check will catch this
Neither should it be able to. You may wish to compare references (in this case pointers), or you may wish to compare values. It is not the business of the find() algorithm to select. One way is not better than the other. Actually, the find_if() allows you to specify another predicate than the default operator== to use for comparison.
BTW: I did not say that compile-time type refinement made every error on collections compile-time analyzable.
A properly constructed B will prevent me from altering its internals
The problem is, that you wish to distinguish between those that should have a protected (kind of read-only) reference, and those that should not. The best example is a datastructure fullfilling the Monitor pattern, it may have either several readers or one writer at the time (very handy for collections). For the readers, you wish to return constant references to the contents of the monitor protected data, for the writer you wish to pass a reference that allows to change the data. The references are to the same class, and refer to the same value,but should allow different operations, therefore they should have seperate types, derived from the type: reference-to-value-of-class-X. Actually, I am starting work on my thesis where I aim to establish and implement other type-decorations, such as parametrised authentication (auth, encrypted, and others) to allow deduction of proofs of program security
If I were to "provide accessors to the relevant data memebers", I would have to make a class hieraki to implement constant references, and I'm not even sure that could be done.
You quote comparison of OO and GP to say that C++ support only a subset of generic programming, which is absolutely true, and which is the reason of many woes over inheritance from type-parametrised classes (deriving from templates).
Then you state: Java Collections looks and behaves a hell of a lot like STL., to which I must diagree:
The STL collections are programmed using generic programming, which means, that they operate on any compile-time refined type. Java collections are programmed using Object Orientation, which means that the operate on any type deriving from the type specified in the interface/class description (Object).
There is a big difference here, You cannot specify a JAVA collection which can only hold i.e. integers, and have a compile-time type-check verify that invariant. You will get to rely on runtime checking of the types.
The implementation differences are mainly syntactic
No, it is ideological, generic vs. OO-ideology.
These last are a result of the implemtation language not a fundamental property
JAVA does not support the generic programming paradigm, therefore it implements collections in the OO-paradigm. The differences in implementation are definatly due to fundamental differences in which programming paradigm you choose to implement collections.
BTW: In C++ it would be hard to implement collections in the OO paradigm, since classes do not inherit from a common base class.
Just because Microsoft "invented" it, it's not nessesarily bad. It's bad if Microsoft can use it to control a market which they already dominate completely.
One thing we should learn from Microsoft is: embrace and extend.
I can very easily override the insertion routeines for collections with, something that calls the instanceof operator... and
return if it returns false. This gives me the sort of typesafety you're talking about.
The whole point was to have type-safety, and get compile-time errors, instead of runtime error's which may occur after you shipped the product.
Java does have final, so you can pass parameters can prevent thier alteration.
Java has value constants, not reference constants. Please try to think a bit about the difference:
class A {
B bInstance;
const b getbInstance() { return bInstance; }
}
Now, if someone was to call A.getInstance(), they will have a READ-ONLY reference, and will not be able to change A's bInstance through it. There is NO WAY to do this in JAVA. It prevents lot's of errors where programmer change data that was supposed to be constant seen from the outside.
As for the part about generic programming. You obviosly have not understood generic programming and parametrised types. The trick is, that you wish to specify the concrete type that an algorithm work on (specializing the interface if you will, some call this compile-time type refinement), so that you will get compile-time type-errors if the (type-instantiated) algorithm is applied to data of the wrong type.
A good example of Generic Programming is a collection, putting stuff into and iterating over a collection requires no specific knowledge of the types of the elements of the collection (which is why the JAVA collections can accept Object), but when you actually use the Collection, you want a typed collection, which you can specify to hold only class X objects. Therefore you need to specify the return types and argument types for the methods og the collection down to some type T, so just like you normally pass other stuff as parameters, you parametrise the collection with the type T.
One OO-language which has compile-time type-refinement (another kind of parametrised types, which is more general than templates) is BETA (which has it's own -- mainly idiological -- problems with multiple inheritance)
When I say that collections can't be type safe, I mean: "No general class or interface can be written such that you can later specify the exact type of the arguments passed and returned".
Example (C++, you could also use i.e. BETA, ML and whatnot..)
std::vector long_list;
long_list.push_back(10L);// OK
long_list.push_back("10");// COMPILE-TIME ERROR!
JAVA
Collection c = new SomeImplementerOfCollection();
c.insert("10");// OK
c.insert(new File());// OK, no warning!
String s = (String) c.SomeMethodForGettingStuff();// RUNTIME ERROR!
If you actually want the JAVA behaviour in C++ (you can store anything in the collection) you do:
But you miss out on the oppotunity to get a compile-time error if you try to push stuff of the wrong type into a collection.
Const
In JAVA, a constant is a value, in C++ "const" (usually;) refers to a reference, with the sematics that, using this reference, you cannot change the referenced object. This is very different from the JAVA "final" stuff.
You may wan't to read The common JAVA chant where I list some other problems with JAVA, C++ and concludes that basicly no good OO-languages exist (that I know of).
No pointer errors: They are called runtime-exceptions in JAVA;), You are better off handling them in JAVA, but if you don't do pointer arithmetic, and keep your casting to a minimum, you will have no more C or C++ errors with pointers than with JAVA references.
No malloc errors: Well, not simple ones anyway (as you state), but you wan't to make sure you understand, that GC does not exclude memleak (through unused but referenced data!). On the other hand, I can't believe that GC for C and C++ subsets which doesn't do pointer arithmetic (and somekind of "decent" arrays) is not yet an ANSI standard.
Exception handling: C++ has quite OK exception handling. there are just 2 points that are really missing:
Exceptions are passed by value, and thus they will be "sliced" to the type that you catch, this requires you to have an "ObjectException" which has a pointer to the object you wish to throw.
The possibility to declare exceptions that must be caught, I like the JAVA way of having runtime and "compile-time" exceptions.
Java has other serious problems:
Lack of parametrised types: Kill generic programming, prevents type-safe containers. There is no way the impact of this can be overestimates. Types are your friend, they catch many error, especially with inexpirienced/unskilled programmers
Well defined destruction semantics: You are not guaranteed that objects are GC'ed -- Which means that you can't do clever stuff to auto-release of locks on data-structures when references go out of scope.
"wrong" kind of multiple inheritance: The JAVA "interface" is too weak, you really want to be able to write code in an interface, using only the declared interface methods.
No references to simple types: and the Object versions of simple types are immutable!
No standardized preprocessor:(or other facility). the "__FILE__" "__LINE__" and hopefully "__CLASS__", "__METHOD__", macros in C and C++ are GOOD, they allow you to extract information about the program, without explicitly writing it. Also I HATE it when the JAVA compiler says: "Error: Code unreacable" -- I usually know that, how about just warning instead!
Lack of type decoration: "const" keeps you from having to rely on programmer practice not to change objects that are "read-only". It also allow a lot of optimization. "mutable" is also nice...
Basically, JAVA lack many of the advances in OO-technolgy that it should have embraced. The JAVA language is a very BAD OO-language, it just has a lot of nice standard libraries, and an emulator for the JVM is available for may machines.
This just goes to show, that there are NO really good OO-languages out there (that I have had my hands on anyway)
I realize that, but I simply could not resist commenting on the change of devel tools after the sentece:
We're looking for better tools, and if that means changing languages or going to another UN*X, we're ready to do it
In my mind, this statement shows a common flaw in reasoning of IT project: changing tools based on a single premise (in this case, MT-debug support, normally the premise would be something like "easier GUI", "faster filesystem", "prettier icons",...), instead of making decisions based on the entire needs of the entire project.
It seems to me, that you may actually share this wiew with me:
you're gonna start thinking that a language that does memory management for you probably wouldn't be such a bad idea
I agree with that phrasing. I would like to see a subset of C++, that allows real garbage-collection (not the ad-hoc analysis in currently availible gabage-collectors). Even though that would mean dumping C compatability.
A story I hear particularly often is: you should use Java, it's better to debug than C++, and it's got Garbage Collection.
Well, that are definatly pro's for Java, but what about the con's:
Java has NO! parametrised types This means that generic programming is impossible. One specific consequence of that is, that collections cannot be type-safe, and you loose a lot of the help that type-errors can buy you.
Java doesn't have "const" (and friends) which means that when you give someone an object reference you have no control over what they do with that. When returning read-only object, the only solution is to clone() them. Very expensive!
Java cannot reference simple types In Java, you can only reference Object's not the simple types. Even the integerObject (and friends) are immutable, so that doesn't help you pass reference parameters which have simple types (I realize, that this is normally a sign of OO-design flaw, but I really want that flexibility, especially for JNI code!)
There are more, but these should make my point.
So, before switching some project to Java, do a cost-benefit analysis.
Last but not least, I would like to second your statement, which gives me a chance to repeat something very wise you said:
Support the developers, first, and everything else will follow.
Are you really changing Language and OS for better multi-thread debug?
This is one of the symptomathics of IT today. You start out analyzing the problem, then you choose an aproprite tool. Some month's later you hit trouble and you consider moving to new language, OS, architecture, whatever, totally discarding the initial analysis that led to the choises you made!
On topic: You should not expect multi-threaded code to be easily debugged, afterall it is hard to write!
You should instead put effort into the really core components that are multi-threading sensitive (synchronization when referencing datastructures and stuff like that, btw. C++ is excellent for that, using Monitors), and make all other code REQUIRE to use the methodology you develop in these components.
Try to collect the multi-thread sensitivity in small, well-defined areas of your program, and try to prove, or at least reason, about the correctness of the code there. One thing you may wan't to do is define (in C++) Locking Iterators, which Lock datastructures they work on, and (using reference counts) automatically unlocks the structure when Iterators fall out of scope.
You may also have some luck in using some of the design patterns that deal with multi-threading.
Morale:You cannot debug away every race-condition, that's bad practice you HAVE to think.
This scares the shit out of me, it took the help of major climatic chages and violent ecological damage to get rid of the dinosaurs. The last thing we wan't is to have to fight them "mano-et-mano";)
Most bacteria caused deseases, that does not exists anymore, are "extinct" because the bearers of the bactiria were KILLED! by it. We really don't need more bacteria species to battle when penicilin (the only weapon we have against bacteria, apart from letting people die in isolation) is proving less and less effective
I have just now submitted the following to Microsoft as feedback via their feedback option on their website, let's see if I get a reply;)
After reading your page: http://www.microsoft.com/oem/nakedPC.htm, I would like to known the answer to the following questions:
1) Why is Microsoft, really, opposed to letting the customer of computer-hardware decide what affiliation he wishes to have with any OS vendor.
> Your customers depend on you. Trouble is, if you act on your
> customers' willingness to buy Naked PCs-knowing full well they
> are at risk of acquiring pirated operating systems elsewhere-you
> expose them to legal risks, viruses, and frustrating technical troubles.
2) Why should PC-resellers's take the decision for customers who are perfectly able to choose themselves?
2.1) What places Microsoft in a situation where it is nessesary, or desireable to give advice regarding the business strategy of companies not affiliated with Microsoft?
2.2) I fail to see why users are extraordinary vulnerable to virus, or run any more of a risk of installing piracy software, because the PC is bundled with an operating system, could Microsoft please elaborate on how that could happen.
3) How can OEM's get additional tech-support problems when they have actually sold only hardware, since software (such as Microsoft Windows, or Microsoft Word) generate by far the greatest support burden for support departments?
>And even if your customer manages to illegally acquire and install
>operating systems elsewhere, it still costs them far more time and
>money than they bargained for
4) In the spirit of competition, is it not in the buyers interest to be able to buy a certain commodity where it is cheapest, not in bundles?
5) Operating systems may still be purchased seperatly, or licensed without payment, such as several free operating systems that are available gratis. Is Microsoft unaware of that?
If yes, why does Microsoft see every other operating system than Microsoft Windows as a pirate OS yields no credit to Microsoft as a fair, competitive company? ("if your customer manages to illegally acquire and
install operating systems")
6) How is selling a computer without an OS more like selling a house without a roof, than like selling a flashlight without batteries?
7) Assuming Microsoft really means that "Naked PC's" are that bad for the business of OEM, how does Microsoft explain the large sales of these.
8) In my home country, Denmark, the bundling of products, as proposed by Microsoft is illegal, if the product cannot be purchased seperatly from the same vendor for an amount not deviating to much from the bundled price, would Microsoft back a proposal to remove this law?
9) Microsofts suggested course of action hardly seems to benefit the customer, or the hardware-reseller since: the customer is unable to get what he want's from the hardware-reseller, and thus is forced take his shopping elsewhere. Would Microsoft argue that this is bad practice from the customer? Does Microsoft really believe that the customers buying "Naked PC's" will buy Microsoft Windows from resellers following the advice on the page?
I have heard just about enough of the "JAVA rul3z" and "JAVA SUXX", It's time to get some facts on the table: Let's first of all get a little thing done with: Sun claims, that JVM code is portable, Well... that is true in the same sense as Commodore 64-code is -- There is an emulator for many platforms. People hardly ever talk about the JAVA language being portable, although it should be (with M$-JAVA as a possible exception;). Now that that's out of the way, we can get to the real problems:
JAVA lacks parametrised types
Parametrised types are the building stones of type-safe generic programming. The lack of parametrised types is the reason why every time you use a JAVA container, you must cast to the correct type.
C++ solves some of these problems, but you still can't use types as first order values.
JAVA cannot specialize return types
virtual functions must have the exact same return-type for both super and derived classes. This makes it really hard to write general interfaces which are specialized to typesafe implementations
JAVA has disfunctional multiple inheritance
JAVA implements virtual inheritance through interface'es. This is a really wierd thing to do for a language that does not have object variables (it only has object reference variables!)
That no stack-space objects can be created exactly allows JAVA to sidestep many of the C++ problems with multiple inheritance (i.e. allocation and copying).
That there are several conventions that one could use for "real" multiple inheritance, does not mean that you have to select the weakest one....
It's horrible to write the same code behind 5,6,7 or more implementations of an interface, just because JAVA-designers chose the easy to implement option.
JAVA lacks a preprocessor
Althoug the C-preprocessor allows for some of the ugliest code, it also allows for some utterly elegant hacks for assertions, unique ID's, and conditional compilation which are really handy, and which are not feasible to do using just JAVA constructions, not to mention the __FILE__, __LINE__, macro's for doing tracelogging.
I (myself) can live with this, there's nothing like a makefile saying:
%.java: %.javacpp $(CPP) $< -o $@
But what about the poor IDE-developers, stuck without a preprocessor?
JAVA is not a good language, but it has a large array of good libraries
Don't confuse a good language for a bad language with a lot of standard-libraries.
JAVA has wierd behaviour for functions whose access has not been specified
if you dont specify "public", "protected" or "private" as method access modifier, you get a 4th behaviour: public inside the same package, private outside... now first of all, it's stupid to make an access modifier without having a keyword for it, but even worse.... package developers and testers won't catch a missing modifier until some poor soul uses their package "from the outside" (another package).
Well, and there's just one thing that's both good and bad:
JAVA does not have operator overloading
this is both good and bad... Using operator overloading in the right places leads to much more readable code, but in the wrong places (i.e. where ^x is overloaded to do something like roof(x)) can make code utterly unreadable.
+,*,/,%,&,<,<=,=,... are general functions on many structures (rings, fields, groups, orders, lattices,...), it's kind'a sad that one can't overload them when implementing a Complex, FiniteField or TypeLattice class (think crypto, and compilers!)
But it's not all bad, you know:
JAVA has only object references, and a garbage collector
Having only object references save lots of trouble when doing copying, think how much trouble it is to store a C++ exception for later throwing!
A garbage-collector is a good-thing (TM), I just dont know, why C++ does not have an optional garbage-collector, which could be turned on or off on compile time. If you really want to free your memory yourself (and this is a good idea!) just assing NULL to the object reference...
JAVA has a large standard library
All those nice networking functions, and abstractions, that really nice.
That some work has gone into designing these libraries, and that they function (relatively) well with each other is a seldom sight in the world of "real-world" oriented languages (as if ML and other functional (and contraint for that matter) languages, is not real-world;)
I really think it's a shame, that all the nice compile-time type-safety is lost in JAVA, all those nice abstrations, and you can't get a descent type-warning.
Then we know what to do, convince the pr0n business to use Ogg...
It's worked before, and it's working for DivX ;)
You should not learn specific languages at a CS study, you should learn several paradigms, at least:
And perhaps predicate programming (Prolog,...) and the related; constraint programming (Mozart,...)
When you get your degree, you should be able to use a new language after 1-3 weeks, use it comfortably -- knowing most of the constructs by heart after 2-5 weeks, and after a month or two, you should be an expert, mastering almost every technique the language has to offer.
when I first started at CS, I was taught a specially designed imperative language, not quite unlike C, but without the hassels of a real-world programming language.
The language implemented only some simple types: int, real, char and string. More advanced type could be constucted as tuples of other types (struct) or choice of other types (union, with tags).
The language prevented accessing a union without branching on the type-tag (a bit like functional style: case e of X(x) => f(x) | Y(y) => g(y).
Funther more, pointers, and recursive types could be created for any of the above types.
The language had only one kind of branching: if, one kind of looping: while.
The language had nested scope of variables and functions, and type-polymorhic code using a construction not wholly unlike C++ templates.
We were taught the sematics of the language in terms of transition theory between states in the computer (well suited for the imperative paradigm).
Fast execution type was not a goal for the language, cleanness of semantics of the availible constructs was.
We were the taught (and given exercises) to implement various programs, and other language constructs, such as: for, switch, recursive types using pointers and other nice stuff, and charged with proving the correct semantics of our solutions (including, of course, loop-induction).
This has given a clean, well defined understanding of programming, which we can "adjust" to any given imperative paradigm we encounter, somewhat like: Oh, the for construct of C is a way to structure loops, their invariants and progression
We were given a lecture in, how the world would have looked if all was nice and pretty, and the means to understand the more "polluted" (i.e. post-increment; i++) semantics and "real-world" languages in terms of well-defined simple building blocks.
This approach has given a very flexible way to understand the exact semantics of other languages, as opposed to knowing, partly how i++ works in C++ and not understanding the full implications of that semantics
Morale: Learn the "pretty-stuff" in the beginning, you want code anything that's work anything the pair of years anyway (that's true, don't kid yourself, you'll do everything much better, cleaner, more efficient a couple of years from now ;)
Postulate: Adultery is a symmetric relation? (not transetive ;)
;)
;)
Consequence: (I lust for neighbor wife
=> I commit adultery (with neighbor wide)
=> Neighbor wife should be put to death.)
I'm not sure she would like the fact that she has
no influence on that
Morale: Definitions and implication rules must be carefully thought through, otherwise someone will find a way to misuse them
First of all, this will be my last reply to this (and other) threads (sipposedly) about debugging MT code. We are way off topic here.
About compile-time type refinement (templates in C++)
What you get from compile-time type-refinement is a valuable tool to detect and diagnose common errors that are made in OO-programming: putting the wrong type of object into an instance of structure. i.e. inserting real's into a list of (conceptually, when you dont have parametrised types) integers.
On dynamicly loaded code
It does not matter that you can later (i.e. at runtime) specialize the methods of a type-instantiated class or algorithm, since it must nessesarily accept the same types as it's parents. Types have a natural partial ordering, which is commonly refered to as specialization, this ensures that stuff that gets put into a method has at least the structure that the method requires. Therefore you will not have problems with later loaded dynamic code.
On the other hand, you cannot further refine the types of arguments to methods of a type-parametrised method, since that would break the inheritance invariant: I must accept what my parents accept. This is why you need generic programming and parametrised types in the first place
Unless I've overridden the == operator for the foo* type this operation will compare pointers not the values of the foo objects. No compile time check will catch this
Neither should it be able to. You may wish to compare references (in this case pointers), or you may wish to compare values. It is not the business of the find() algorithm to select. One way is not better than the other. Actually, the find_if() allows you to specify another predicate than the default operator== to use for comparison.
BTW: I did not say that compile-time type refinement made every error on collections compile-time analyzable.
A properly constructed B will prevent me from altering its internals
The problem is, that you wish to distinguish between those that should have a protected (kind of read-only) reference, and those that should not. The best example is a datastructure fullfilling the Monitor pattern, it may have either several readers or one writer at the time (very handy for collections). For the readers, you wish to return constant references to the contents of the monitor protected data, for the writer you wish to pass a reference that allows to change the data. The references are to the same class, and refer to the same value,but should allow different operations, therefore they should have seperate types, derived from the type: reference-to-value-of-class-X. Actually, I am starting work on my thesis where I aim to establish and implement other type-decorations, such as parametrised authentication (auth, encrypted, and others) to allow deduction of proofs of program security
If I were to "provide accessors to the relevant data memebers", I would have to make a class hieraki to implement constant references, and I'm not even sure that could be done.
You quote comparison of OO and GP to say that C++ support only a subset of generic programming, which is absolutely true, and which is the reason of many woes over inheritance from type-parametrised classes (deriving from templates).
Then you state: Java Collections looks and behaves a hell of a lot like STL., to which I must diagree:
The STL collections are programmed using generic programming, which means, that they operate on any compile-time refined type. Java collections are programmed using Object Orientation, which means that the operate on any type deriving from the type specified in the interface/class description (Object).
There is a big difference here, You cannot specify a JAVA collection which can only hold i.e. integers, and have a compile-time type-check verify that invariant. You will get to rely on runtime checking of the types.
The implementation differences are mainly syntactic
No, it is ideological, generic vs. OO-ideology.
These last are a result of the implemtation language not a fundamental property
JAVA does not support the generic programming paradigm, therefore it implements collections in the OO-paradigm. The differences in implementation are definatly due to fundamental differences in which programming paradigm you choose to implement collections.
BTW: In C++ it would be hard to implement collections in the OO paradigm, since classes do not inherit from a common base class.
Just because Microsoft "invented" it, it's not nessesarily bad. It's bad if Microsoft can use it to control a market which they already dominate completely.
One thing we should learn from Microsoft is: embrace and extend.
The whole point was to have type-safety, and get compile-time errors, instead of runtime error's which may occur after you shipped the product.
Java does have final, so you can pass parameters can prevent thier alteration.
Java has value constants, not reference constants. Please try to think a bit about the difference:
class A {
B bInstance;
const b getbInstance() { return bInstance; }
}
Now, if someone was to call A.getInstance(), they will have a READ-ONLY reference, and will not be able to change A's bInstance through it. There is NO WAY to do this in JAVA. It prevents lot's of errors where programmer change data that was supposed to be constant seen from the outside.
As for the part about generic programming. You obviosly have not understood generic programming and parametrised types. The trick is, that you wish to specify the concrete type that an algorithm work on (specializing the interface if you will, some call this compile-time type refinement), so that you will get compile-time type-errors if the (type-instantiated) algorithm is applied to data of the wrong type.
A good example of Generic Programming is a collection, putting stuff into and iterating over a collection requires no specific knowledge of the types of the elements of the collection (which is why the JAVA collections can accept Object), but when you actually use the Collection, you want a typed collection, which you can specify to hold only class X objects. Therefore you need to specify the return types and argument types for the methods og the collection down to some type T, so just like you normally pass other stuff as parameters, you parametrise the collection with the type T.
For the parametrised type stuff, look at Re:Poor multi-thread debug support on Linux. Parametrised types are (weakly) implemented in C++ via templates.
One OO-language which has compile-time type-refinement (another kind of parametrised types, which is more general than templates) is BETA (which has it's own -- mainly idiological -- problems with multiple inheritance)
When I say that collections can't be type safe, I mean: "No general class or interface can be written such that you can later specify the exact type of the arguments passed and returned".
Example (C++, you could also use i.e. BETA, ML and whatnot..)
JAVA
If you actually want the JAVA behaviour in C++ (you can store anything in the collection) you do:
But you miss out on the oppotunity to get a compile-time error if you try to push stuff of the wrong type into a collection.Const
In JAVA, a constant is a value, in C++ "const" (usually ;) refers to a reference, with the sematics that, using this reference, you cannot change the referenced object. This is very different from the JAVA "final" stuff.
You may wan't to read The common JAVA chant where I list some other problems with JAVA, C++ and concludes that basicly no good OO-languages exist (that I know of).
JAVA has (according to you)
Java has other serious problems:
Basically, JAVA lack many of the advances in OO-technolgy that it should have embraced. The JAVA language is a very BAD OO-language, it just has a lot of nice standard libraries, and an emulator for the JVM is available for may machines.
This just goes to show, that there are NO really good OO-languages out there (that I have had my hands on anyway)
What you say is true, but it's not the issue.
I realize that, but I simply could not resist commenting on the change of devel tools after the sentece:
We're looking for better tools, and if that means changing languages or going to another UN*X, we're ready to do it
In my mind, this statement shows a common flaw in reasoning of IT project: changing tools based on a single premise (in this case, MT-debug support, normally the premise would be something like "easier GUI", "faster filesystem", "prettier icons",...), instead of making decisions based on the entire needs of the entire project.
It seems to me, that you may actually share this wiew with me:
you're gonna start thinking that a language that does memory management for you probably wouldn't be such a bad idea
I agree with that phrasing. I would like to see a subset of C++, that allows real garbage-collection (not the ad-hoc analysis in currently availible gabage-collectors). Even though that would mean dumping C compatability.
A story I hear particularly often is: you should use Java, it's better to debug than C++, and it's got Garbage Collection.
Well, that are definatly pro's for Java, but what about the con's:
- Java has NO! parametrised types This means that generic programming is impossible. One specific consequence of that is, that collections cannot be type-safe, and you loose a lot of the help that type-errors can buy you.
- Java doesn't have "const" (and friends) which means that when you give someone an object reference you have no control over what they do with that. When returning read-only object, the only solution is to clone() them. Very expensive!
- Java cannot reference simple types In Java, you can only reference Object's not the simple types. Even the integerObject (and friends) are immutable, so that doesn't help you pass reference parameters which have simple types (I realize, that this is normally a sign of OO-design flaw, but I really want that flexibility, especially for JNI code!)
- There are more, but these should make my point.
So, before switching some project to Java, do a cost-benefit analysis.Last but not least, I would like to second your statement, which gives me a chance to repeat something very wise you said:
Support the developers, first, and everything else will follow.
Are you really changing Language and OS for better multi-thread debug?
This is one of the symptomathics of IT today. You start out analyzing the problem, then you choose an aproprite tool. Some month's later you hit trouble and you consider moving to new language, OS, architecture, whatever, totally discarding the initial analysis that led to the choises you made!
On topic: You should not expect multi-threaded code to be easily debugged, afterall it is hard to write!
You should instead put effort into the really core components that are multi-threading sensitive (synchronization when referencing datastructures and stuff like that, btw. C++ is excellent for that, using Monitors), and make all other code REQUIRE to use the methodology you develop in these components.
Try to collect the multi-thread sensitivity in small, well-defined areas of your program, and try to prove, or at least reason, about the correctness of the code there. One thing you may wan't to do is define (in C++) Locking Iterators, which Lock datastructures they work on, and (using reference counts) automatically unlocks the structure when Iterators fall out of scope.
You may also have some luck in using some of the design patterns that deal with multi-threading.
Morale:You cannot debug away every race-condition, that's bad practice you HAVE to think.
No, you would need 2 stacks (or equivalently a queue) to implement a tape.
If you only have a stack, you can only decide ContextFree grammers, which is a subset of what a touring machine can decide.
So, you can decide, if a string is of the form a^nb^n, but not if it's a^nb^na^n, which you need a touring machine for.
--
Helge Jensen
How did they implement the infinite tape?
Just wondering B*)
This scares the shit out of me, it took the help of major climatic chages and violent ecological damage to get rid of the dinosaurs. The last thing we wan't is to have to fight them "mano-et-mano" ;)
Most bacteria caused deseases, that does not exists anymore, are "extinct" because the bearers of the bactiria were KILLED! by it. We really don't need more bacteria species to battle when penicilin (the only weapon we have against bacteria, apart from letting people die in isolation) is proving less and less effective
I have just now submitted the following to Microsoft as feedback via their feedback option on their website, let's see if I get a reply ;)
After reading your page: http://www.microsoft.com/oem/nakedPC.htm, I would like to known the answer to the following questions:
1) Why is Microsoft, really, opposed to letting the customer of computer-hardware decide what affiliation he wishes to have with any OS vendor.
> Your customers depend on you. Trouble is, if you act on your
> customers' willingness to buy Naked PCs-knowing full well they
> are at risk of acquiring pirated operating systems elsewhere-you
> expose them to legal risks, viruses, and frustrating technical troubles.
2) Why should PC-resellers's take the decision for customers who are perfectly able to choose themselves?
2.1) What places Microsoft in a situation where it is nessesary, or desireable to give advice regarding the business strategy of companies not affiliated with Microsoft?
2.2) I fail to see why users are extraordinary vulnerable to virus, or run any more of a risk of installing piracy software, because the PC is bundled with an operating system, could Microsoft please elaborate on how that could happen.
3) How can OEM's get additional tech-support problems when they have actually sold only hardware, since software (such as Microsoft Windows, or Microsoft Word) generate by far the greatest support burden for support departments?
>And even if your customer manages to illegally acquire and install
>operating systems elsewhere, it still costs them far more time and
>money than they bargained for
4) In the spirit of competition, is it not in the buyers interest to be able to buy a certain commodity where it is cheapest, not in bundles?
5) Operating systems may still be purchased seperatly, or licensed without payment, such as several free operating systems that are available gratis. Is Microsoft unaware of that?
If yes, why does Microsoft see every other operating system than Microsoft Windows as a pirate OS yields no credit to Microsoft as a fair, competitive company? ("if your customer manages to illegally acquire and
install operating systems")
6) How is selling a computer without an OS more like selling a house without a roof, than like selling a flashlight without batteries?
7) Assuming Microsoft really means that "Naked PC's" are that bad for the business of OEM, how does Microsoft explain the large sales of these.
8) In my home country, Denmark, the bundling of products, as proposed by Microsoft is illegal, if the product cannot be purchased seperatly from the same vendor for an amount not deviating to much from the bundled price, would Microsoft back a proposal to remove this law?
9) Microsofts suggested course of action hardly seems to benefit the customer, or the hardware-reseller since: the customer is unable to get what he want's from the hardware-reseller, and thus is forced take his shopping elsewhere. Would Microsoft argue that this is bad practice from the customer? Does Microsoft really believe that the customers buying "Naked PC's" will buy Microsoft Windows from resellers following the advice on the page?
- JAVA lacks parametrised types
- JAVA cannot specialize return types
- JAVA has disfunctional multiple inheritance
- JAVA lacks a preprocessor
- JAVA is not a good language, but it has a large array of good libraries
- JAVA has wierd behaviour for functions whose access has not been specified
Well, and there's just one thing that's both good and bad:Parametrised types are the building stones of type-safe generic programming. The lack of parametrised types is the reason why every time you use a JAVA container, you must cast to the correct type.
C++ solves some of these problems, but you still can't use types as first order values.
virtual functions must have the exact same return-type for both super and derived classes. This makes it really hard to write general interfaces which are specialized to typesafe implementations
JAVA implements virtual inheritance through interface'es. This is a really wierd thing to do for a language that does not have object variables (it only has object reference variables!)
That no stack-space objects can be created exactly allows JAVA to sidestep many of the C++ problems with multiple inheritance (i.e. allocation and copying).
That there are several conventions that one could use for "real" multiple inheritance, does not mean that you have to select the weakest one....
It's horrible to write the same code behind 5,6,7 or more implementations of an interface, just because JAVA-designers chose the easy to implement option.
Althoug the C-preprocessor allows for some of the ugliest code, it also allows for some utterly elegant hacks for assertions, unique ID's, and conditional compilation which are really handy, and which are not feasible to do using just JAVA constructions, not to mention the __FILE__, __LINE__, macro's for doing tracelogging.
I (myself) can live with this, there's nothing like a makefile saying:
%.java: %.javacpp
$(CPP) $< -o $@
But what about the poor IDE-developers, stuck without a preprocessor?
Don't confuse a good language for a bad language with a lot of standard-libraries.
if you dont specify "public", "protected" or "private" as method access modifier, you get a 4th behaviour: public inside the same package, private outside... now first of all, it's stupid to make an access modifier without having a keyword for it, but even worse.... package developers and testers won't catch a missing modifier until some poor soul uses their package "from the outside" (another package).
- JAVA does not have operator overloading
But it's not all bad, you know:this is both good and bad... Using operator overloading in the right places leads to much more readable code, but in the wrong places (i.e. where ^x is overloaded to do something like roof(x)) can make code utterly unreadable.
+,*,/,%,&,<,<=,=,... are general functions on many structures (rings, fields, groups, orders, lattices,...), it's kind'a sad that one can't overload them when implementing a Complex, FiniteField or TypeLattice class (think crypto, and compilers!)
- JAVA has only object references, and a garbage collector
- JAVA has a large standard library
I really think it's a shame, that all the nice compile-time type-safety is lost in JAVA, all those nice abstrations, and you can't get a descent type-warning.Having only object references save lots of trouble when doing copying, think how much trouble it is to store a C++ exception for later throwing!
A garbage-collector is a good-thing (TM), I just dont know, why C++ does not have an optional garbage-collector, which could be turned on or off on compile time. If you really want to free your memory yourself (and this is a good idea!) just assing NULL to the object reference...
All those nice networking functions, and abstractions, that really nice.
That some work has gone into designing these libraries, and that they function (relatively) well with each other is a seldom sight in the world of "real-world" oriented languages (as if ML and other functional (and contraint for that matter) languages, is not real-world ;)