Because in order to build a successful business it is necessary to do something different to what everyone else is doing. As many web site "entrepreneurs" learned in the last few years, playing "me too" rarely gets you anywhere.
I've found test driven development very useful on my most recent project, and intend to practise it in future too.
On this occasion, I did what you suggest: I built unit tests during development and threw them away when they were costing more time to maintain than they were saving in bugs that would not have been found another way. Once it was possible, I developed tests from the user's API level (its a middleware product), and these will be maintained for the life of the project. These API level tests include regression tests for specific bugs.
The XP folks seem to suggest maitaining unit tests at a level I consider excessive. I think they suggest one test per non-trivial method on all classes. This just seems too much, and very hard to achieve, since even in the best designed projects, individual methods are hard to test without also testing a bunch of other stuff.
It sounds like your project was suffering mainly from a lack of design skills. Spending a lot of time maintaining tests implies too much coupling between components: the only way that can come about is if changing one component affects many others, so there tests need updating too.
Java's bytecode has limitations that make implementing some languages efficiently difficult. In particular:
1. The only mechanism you can use to implement closures is a class. For functional languages, which make intense use of closures, this is not good enough. The Scheme and Lisp implementations on the JVM, for instance, are substantially less performant than those based on more appropriate VMs.
2. There is no way to optimise tail recursion. Again, functional languages use tail recursion a lot.
... but it is not the whole story. The rule against premature optimisation exists for a good reason: most programmers have terrible intuition about performance. The one thing you should do up-front is get the architecture - the distribution of code over machines, processes and loosely-coupled modules - right, so that it does not contain performance bottlenecks that will be impossible to get rid of later. Prototypes work well for this, as do small applications that are structurally similar to the one you want.
After that, all performance optimisation should be left until you can profile the application. Bits of the result will undoubtedly suck and need to be rewritten, but I'll put money on most of them not being the ones you expected.
This is where abstraction comes is. Abstractions are a very important aid to clarity, because they allow parts of the system to be considered in isolation from one another. To give a slightly practical example, a product I recently worked on used a variant of the banker's algorithm to avoid deadlocks. An odd choice, I know, but it was absolutely imperative that the system shouldn't dealock, and killing or restarting threads was unacceptable. The algorithm is complicated, and the original implementation took the simplest possible approach. When we profiled it, this turned out to be too slow, so I rewrote it, but because it was reasonably isolated from the rest of the system, I could do this without touching any other code.
Good abstraction is not the enemy of performance. It is its friend. In good abstractions, the data and code that need to work together, live together, and are shaped to one another. Oddly enough, this is what you need for performant software, too. On top of that, good abstractions make code easier to change.
What is the enemy of performance is bad abstraction. Which means too little or the right amount in the wrong place, just as much as too much. Aspects of Mozilla's design show signs of bad abstraction. In particular, it is hard to develop good abstractions for cross-platform UIs, and Mozilla's attempt is no exception. Using the HTML/XML renderer and JavaScript to implement the UI is a clear example of Bad Architecture, see paragraph 1, even if it is convenient. Similarly, the need for the elaborate modular design is debatable.
The design of the Linux kernel, is in many ways an example of Good Abstraction. Although it isn't written in a language that particularly facilitates abstraction (it is an OS kernel, after all), the different components are reasonable separated out. There don't appear to be direct dependencies between the IDE driver and the memory allocator, for example.
... machine code itself is an abstraction in the first place. This is especially true for modern processors that reorder instructions, execute them in parallel, and in extreme cases convert them into an entirely different instruction set.
The complexity of Really Big Systems is such that no one person could understand all the business logic, let alone the systems code. The stories I could tell, if men with large sticks wouldn't come and kill me...
The reason they end up with J2EE is it is *relatively* cheap and reliable, standard and easy to find developers for, while allowing for distributed transactions that ensure their databases don't become corrupt. That tends to be what really matters to them: if the system fails, which it will, regardless of what it was written in, and we bring it back up, will it Just Work ?
I think I see what you mean now. You could get rid of the packages entirely and rely on the classes scope hierachy to do the same thing. Aside from the difficulty with separating source files, that might be interesting.
- why are packages and classes treated differently? They are both just namespaces.
Because classes define the behaviour of instances, whereas packages are just namespaces ? The only reason packages exist at all is to break up the class namespace.
- Why can't I 'Object i = 5;'? There should be a 'void*' type.,
No there bloody well shouldn't, but there certainly should be type that is a sypertype of both the primitive and the reference types. I would personally prefer something between the "everything is an object" model of Smalltalk, and the automated boxing and unboxing of the.NET languages. The current system is pretty nasty.
- Why can't I 'Method m = Object.toString;'
I don't know. It would be a lot nicer, wouldn't it ? Probably because reflection only appeared in 1.1, and changing the way the class namespace worked to allow this would have broken existing code.
- Why can't I [stuff]
and get the right method called!?
Because Java doesn't do multiple dispatch. It only does static method overloading. The example you give (and multi-dispatch in general) conflicts rather with being statically typed. There are, of course, well known cases where multiple dispatch is useful, but they're not *that* common, and one of the design goals of Java was not to scare C++ programmers.
- Why can't I 'import java.util.*String*;' or 'import java.*.*;' ?
Ewww.
- Why do we have 'new' instead of alloc and init?
Given that instantiation is not polymorphic, I don't see what the benefit would be. Having said that, it would be nice for instantiation to be polymorphic, but it is hard to do without metaclasses, and once again static typing might get in the way
- Why aren't static methods inherited?
They are. If f() is static and visible on X, and Y extends X, you can call Y.f(). It isn't very useful, though, because they aren't polymorphic. A method in X that called f() would always call X.f(), rather than Y.f() even if it was actually invoked on an instance of Y, and Y had another method f() that hid it.
If that is what bothers you, you really need metaclasses. In languages with metaclasses the class of an object is represented by an instance of a unique class (the metaclass), specific to that class. The metaclass can define methods and data that the class will possess. f() above would be a method on the metaclass of X and Y, so Y could polymorphically override it.
The fact most readers of this comment will already have given up, have their toungues lolling out, or be preparing to flame me for suggesting anything so obviously stupid and useless (ie. not in C++), should given you a clue as to why the designers of Java did not do this.
Although it isn't the most useful standard (for several reasons), JMS does more than you imply. The container infrastructure takes care of resource sharing issues for you, but even that isn't the main benefit. The main benefit is that JMS messages can be enlisted in distributed transactions, and support limited reliable delivery. This makes them usable in really serious system where failure costs $1m a second.
One of the best criticisms of J2EE is in fact just this: EJB, JMS and so on allow blue-collar engineers to build really serious enterprise scale systems, but in fact most systems do not need anything like the firepower J2EE provides, and most engineers don't even know what XA *is*. It therefore gets used in lots of cases where it is analagous to using an Apache helicopter gunship to crack a nut. The average website just doesn't need most of J2EE.
This is what MS were playing on, whether they realise it or not, when they rewrote the pet-store application using ADO alone a claimed some incredible speedup. J2EE is just not needed, even some something like Amazon. Certainly not for Slashdot. Banks and airlines do need it, but not everyone works for a bank or an airline.
Small projects, and most software projects are small, do not really need, and cannot afford, "proper infrastructure". Small projects will usually end up with code fairly on in the process and a selection of incomplete documents that describe the design. The documentation is often - either deliberately or by default - not maintained. This situation makes version control and coding standards the highest priority.
Many people buy Weblogic. Many people who buy it also ignore it and then develop and deploy on JBoss because it is less painful. Just like many companies that have an official policy to use WebSphere find many of their applications being deployed on Weblogic.
There was a whole hell of a fuss about this when the WTD came in. The British government in particular insisted that employees be allowed to voluntarily choose to work more than 48 hours per week.
I'm not sure it can be part of your contract of employment, because you're not allowed to hire or fire based on willingness to work overtime. However, in practice, such hiring and firing does actually take place.
Bleugh ! I can't believe I said that. However, we work in an industry where 2 smart people can be worth a great deal more than any number of grunts, even if the grunts work 20 hour days.
Most software projects are actually overstaffed with programmers, and that the same amount of work could be done by substantially fewer people. Calls to work long hours often come about not because the amount of work to be done is large, but because the project is being constantly rewritten to accomodate changing requirements, or because there are fundamental technical flaws that there "isn't time" to fix.
Ultimately, the hard part of programming is not writing code, it is thinking, and thinking is better done by a small number of smart people who've had enough sleep, decent food, and some time with their families.
I sometimes give training courses in OO design and analysis as a part of my job (described at http://isocra.com/training/). In our case, all the trainers do it part time, spending the rest of their time developing our products or working on consulting jobs. Having professional software developers giving courses in software development techniques seems to make sense, and it means we can discuss our experience and those of the trainess in a serious way (actually that usually comprises a fair bit of the course time).
Unfortunately, this seems far from the usual case. Courses from the big training companies are sold on a franchise basis, and many of those giving them are not experienced in the subject matter themselves. The exercises tend to be very prescriptive, and therefore don't really help the trainees with using the information in their jobs. Often, the trainers are unable to discuss the material in any depth. Courses in specific technologies (as opposed to general techniques, like the ones we give), seem of very limited usefulness anyway. The same information is invariably available in books, or even in the online help for the product.
... in Java, because it is statically typed. Where code is not polymorphic, and manipulates the primitive types directly, it would be possible to use full-precision numbers, as supported by the hardware, just as Java does now. Something like C#'s automated boxing and unboxing could be used when the primitives were assigned between a polymorphic and a non-polymorphic context. That would answer the performance concerns with needing to distinguish fixnums from reference types, and still give fully OO primitives.
That would be why the JCP is working on a standard for them ? and why there is an implementation mechanism (type erasure) which requires only a small change to the VM ? and why 1.5 is slated to include them ?
Generics are well on their way. They keep getting held back from actualy inclusion in the VM, since in practice their absence is just an irritation, but the standard is already signed off. C++ templates are a pretty poor example of generics anyway. It has been done much better elsewhere.
You don't really explain why you think the primitive types are necessary, so it is hard to answer you, but the fact there is no common supertype of the primitives + Object is a complete PITA if you do anything complex in Java. Just look at the JDBC interfaces for an example. The need to promote and demote primitives to get them into collections is a major source of inefficiencies in Java programs.
Just to avoid any misunderstandings: the point is to give the primitives object-like semantics, not to store them in the same form as other objects, or to require people to use object-like syntax. The technology to treat primitives as objects has existed for Lisp and Smalltalk for years. The only reason it hasn't made it into Java is NIH syndrome.
Noone (or noone significant anyway) thinks the primitive types should be layed out in memory the same way as object types. The argument is that they should be semantically the same, but implemented differently. Thus, if I want to take the sine of a number, I can write:
(6.0).sin()
Rather than:
Math.sin(6.0)
Which involves the nasty, irrelevant class "Math". You should also be able to subclass the primitive types. Furthermore you can remove the length and precision limits on the various types. Integers should be stored as 32-bit ints where possible, and then gracefully degrade into big ints when they exceed 32 bits.
The technology to do this already exists. Lisp and Smalltalk VMs have done it for years. Unfortunately, the developers of Java got confused in just the same way as you're doing.
OK, well this post is much too late, but possibly the author might find it and read it.
You say you're the "de facto software project team leader". Who is the "de jure" team leader ? Who is meant to be doing the work you're doing ? If you have someone who's meant to be managing the project or providing technical leadership, and they're not doing their job, you need to make sure their boss knows about it. Have a few words with them first about your concerns, and if they don't act, go to their boss. I know it sounds harsh, but I've been in your situation, and it is a hiding to nothing. Noone gives you any credit for doing a job if they don't know about it.
If your place of work is relatively unstructured (as mine now is - I prefer it that way), and noone has an official leadership role, make sure your ultimate boss knows what you are doing. Once again, you don't get any credit for doing a job if noone knows about it. You're an employee (I assume), and ultimately the success or failure of the enterprise isn't your responsibility, although, of course, your job is.
If you're pretty confident that you have the responsibility of sorting out your project, then you really do need to sort out the problems you are having with your cow-orkers. It sounds to me as if they're either lacking in motivation, or not very good coders.
There's a judgement call to be made here as to whether these people are redeemable. They might not be. Some people just aren't up to programming, others require so much effort to train up that it is not worth the investment, others are unmotivated, due to personal problems, in such a way that you can't help. The only answer is to let such people go. This is why you need to be in a position of authority acknowledged by your boss. I don't necessarily mean that they need to be hurled bodily from the doors, but they need to be moved to work that they're capable of doing. When it comes to hiring new people, make sure you're involved in the process.
However, the only way you're going to find out whether your cow-orkers are redeemable, is by trying to help. If at the end of that process you,ve acheived nothing, then proceed as above. In order to help, I'd suggest some or all of the following:
1. Make sure people are motivated. They need to know what your project does for the company. They need to know what they, personally, can expect to gain from success. If - as is common is technical organisations - there's not real career progression opem, you might want to try to fix that.
2. Make sure they know what is required. That is: what must be delivered and when. They should feel that it is a team goal, and that it is acheivable. They should feel personally responsible for their bits.
3. Track what people are doing, on a day-to-day basis. Go from desk to desk and ask. Help with problems. If people have gaps in their knowledge or misunderstandings, talk them through it, rather than just telling them answers. If there are problesm with the rest of the organisation, try to sort them out.
4. Institute code reviews or pair programming. Make sure you are involved, but encourage them to critique one another's work and improve on it.
5. Change the way you're scheduling work to make tracking easier. Expect people to deliver demostrable units of functionality every at least week or so.
6. Never lose your temper or act in a condescending manner.
Because they're an afterthought. Java was originally designed without the primitive equivalent reference types and they were tacked on later to solve some problems which emerged. Basically, the problem was that there was no type that included both Object and the primitive types, which made reflection and collections hard to deal with.
The original decision not to make the primitives objects is one of the Great Mysteries of All Time. Sun say its for "efficiency reasons", but Java's antecedent languages (Smalltalk, Lisp, etc) solved the same problem using type tags, so primtives look like objects even though they are implemented differently, and indeed the best VMs actually do this internally for other reasons.
Essentially, its a mistake, IMHO.
Several times I got caught on the fact that there is no way to pass an int by reference. And I don't like Integer (see aboive)...
Java's basically an OO language. You can use it in non-OO ways, but you tend to run into problems like this. Basically, if you want to return more than one value from a method, you should probably group them together in their own class. If you want to use the return value to return an error code, you should learn about exception.
I program in Java every day, and the inability to return multiple values is not a problem for me in practice.
One (public) class per file.
.class files act as header files as well as binaries. In order to preserve the sanity of programmers, the compiler builds any unbuilt sources. To do that it has to find them. Hence the "file must have the name of the public class" rule.
By population, yes. If you cover the SE, Manchester, Merseyside, Birgmingham and the central belt of Scotland, you have more than a majority of the population.
And the soma ritual may also go back to Indus times. The matter is far from closed, but the best evidence comes from the language: people have mapped Indus valley script onto something like Dravidian quite convincingly. Attempts to map it onto a Sanscrit like language are much less convincing.
My bet would be that modern Hindu culture includes aspects of the ancient Indus culture, and aspects of the Aryan invader's culture.
Because in order to build a successful business it is necessary to do something different to what everyone else is doing. As many web site "entrepreneurs" learned in the last few years, playing "me too" rarely gets you anywhere.
I've found test driven development very useful on my most recent project, and intend to practise it in future too.
On this occasion, I did what you suggest: I built unit tests during development and threw them away when they were costing more time to maintain than they were saving in bugs that would not have been found another way. Once it was possible, I developed tests from the user's API level (its a middleware product), and these will be maintained for the life of the project. These API level tests include regression tests for specific bugs.
The XP folks seem to suggest maitaining unit tests at a level I consider excessive. I think they suggest one test per non-trivial method on all classes. This just seems too much, and very hard to achieve, since even in the best designed projects, individual methods are hard to test without also testing a bunch of other stuff.
It sounds like your project was suffering mainly from a lack of design skills. Spending a lot of time maintaining tests implies too much coupling between components: the only way that can come about is if changing one component affects many others, so there tests need updating too.
Java's bytecode has limitations that make implementing some languages efficiently difficult. In particular:
1. The only mechanism you can use to implement closures is a class. For functional languages, which make intense use of closures, this is not good enough. The Scheme and Lisp implementations on the JVM, for instance, are substantially less performant than those based on more appropriate VMs.
2. There is no way to optimise tail recursion. Again, functional languages use tail recursion a lot.
... but it is not the whole story. The rule against premature optimisation exists for a good reason: most programmers have terrible intuition about performance. The one thing you should do up-front is get the architecture - the distribution of code over machines, processes and loosely-coupled modules - right, so that it does not contain performance bottlenecks that will be impossible to get rid of later. Prototypes work well for this, as do small applications that are structurally similar to the one you want.
After that, all performance optimisation should be left until you can profile the application. Bits of the result will undoubtedly suck and need to be rewritten, but I'll put money on most of them not being the ones you expected.
This is where abstraction comes is. Abstractions are a very important aid to clarity, because they allow parts of the system to be considered in isolation from one another. To give a slightly practical example, a product I recently worked on used a variant of the banker's algorithm to avoid deadlocks. An odd choice, I know, but it was absolutely imperative that the system shouldn't dealock, and killing or restarting threads was unacceptable. The algorithm is complicated, and the original implementation took the simplest possible approach. When we profiled it, this turned out to be too slow, so I rewrote it, but because it was reasonably isolated from the rest of the system, I could do this without touching any other code.
Good abstraction is not the enemy of performance. It is its friend. In good abstractions, the data and code that need to work together, live together, and are shaped to one another. Oddly enough, this is what you need for performant software, too. On top of that, good abstractions make code easier to change.
What is the enemy of performance is bad abstraction. Which means too little or the right amount in the wrong place, just as much as too much. Aspects of Mozilla's design show signs of bad abstraction. In particular, it is hard to develop good abstractions for cross-platform UIs, and Mozilla's attempt is no exception. Using the HTML/XML renderer and JavaScript to implement the UI is a clear example of Bad Architecture, see paragraph 1, even if it is convenient. Similarly, the need for the elaborate modular design is debatable.
The design of the Linux kernel, is in many ways an example of Good Abstraction. Although it isn't written in a language that particularly facilitates abstraction (it is an OS kernel, after all), the different components are reasonable separated out. There don't appear to be direct dependencies between the IDE driver and the memory allocator, for example.
... machine code itself is an abstraction in the first place. This is especially true for modern processors that reorder instructions, execute them in parallel, and in extreme cases convert them into an entirely different instruction set.
The complexity of Really Big Systems is such that no one person could understand all the business logic, let alone the systems code. The stories I could tell, if men with large sticks wouldn't come and kill me ...
The reason they end up with J2EE is it is *relatively* cheap and reliable, standard and easy to find developers for, while allowing for distributed transactions that ensure their databases don't become corrupt. That tends to be what really matters to them: if the system fails, which it will, regardless of what it was written in, and we bring it back up, will it Just Work ?
I think I see what you mean now. You could get rid of the packages entirely and rely on the classes scope hierachy to do the same thing. Aside from the difficulty with separating source files, that might be interesting.
- why are packages and classes treated differently? They are both just namespaces.
Because classes define the behaviour of instances, whereas packages are just namespaces ? The only reason packages exist at all is to break up the class namespace.
- Why can't I 'Object i = 5;'? There should be a 'void*' type.,
No there bloody well shouldn't, but there certainly should be type that is a sypertype of both the primitive and the reference types. I would personally prefer something between the "everything is an object" model of Smalltalk, and the automated boxing and unboxing of the .NET languages. The current system is pretty nasty.
- Why can't I 'Method m = Object.toString;'
I don't know. It would be a lot nicer, wouldn't it ? Probably because reflection only appeared in 1.1, and changing the way the class namespace worked to allow this would have broken existing code.
- Why can't I [stuff] and get the right method called!?
Because Java doesn't do multiple dispatch. It only does static method overloading. The example you give (and multi-dispatch in general) conflicts rather with being statically typed. There are, of course, well known cases where multiple dispatch is useful, but they're not *that* common, and one of the design goals of Java was not to scare C++ programmers.
- Why can't I 'import java.util.*String*;' or 'import java.*.*;' ?
Ewww.
- Why do we have 'new' instead of alloc and init?
Given that instantiation is not polymorphic, I don't see what the benefit would be. Having said that, it would be nice for instantiation to be polymorphic, but it is hard to do without metaclasses, and once again static typing might get in the way
- Why aren't static methods inherited?
They are. If f() is static and visible on X, and Y extends X, you can call Y.f(). It isn't very useful, though, because they aren't polymorphic. A method in X that called f() would always call X.f(), rather than Y.f() even if it was actually invoked on an instance of Y, and Y had another method f() that hid it.
If that is what bothers you, you really need metaclasses. In languages with metaclasses the class of an object is represented by an instance of a unique class (the metaclass), specific to that class. The metaclass can define methods and data that the class will possess. f() above would be a method on the metaclass of X and Y, so Y could polymorphically override it.
The fact most readers of this comment will already have given up, have their toungues lolling out, or be preparing to flame me for suggesting anything so obviously stupid and useless (ie. not in C++), should given you a clue as to why the designers of Java did not do this.
Although it isn't the most useful standard (for several reasons), JMS does more than you imply. The container infrastructure takes care of resource sharing issues for you, but even that isn't the main benefit. The main benefit is that JMS messages can be enlisted in distributed transactions, and support limited reliable delivery. This makes them usable in really serious system where failure costs $1m a second.
One of the best criticisms of J2EE is in fact just this: EJB, JMS and so on allow blue-collar engineers to build really serious enterprise scale systems, but in fact most systems do not need anything like the firepower J2EE provides, and most engineers don't even know what XA *is*. It therefore gets used in lots of cases where it is analagous to using an Apache helicopter gunship to crack a nut. The average website just doesn't need most of J2EE.
This is what MS were playing on, whether they realise it or not, when they rewrote the pet-store application using ADO alone a claimed some incredible speedup. J2EE is just not needed, even some something like Amazon. Certainly not for Slashdot. Banks and airlines do need it, but not everyone works for a bank or an airline.
Small projects, and most software projects are small, do not really need, and cannot afford, "proper infrastructure". Small projects will usually end up with code fairly on in the process and a selection of incomplete documents that describe the design. The documentation is often - either deliberately or by default - not maintained. This situation makes version control and coding standards the highest priority.
Many people buy Weblogic. Many people who buy it also ignore it and then develop and deploy on JBoss because it is less painful. Just like many companies that have an official policy to use WebSphere find many of their applications being deployed on Weblogic.
I've spent many unhappy hours trying to get the IDE cables from the interfaces on the motherboard to the disk 18.1 inches away :(
They're OK as long as the manufacturers build them with keys. Without keys they are a veritable PITA.
There was a whole hell of a fuss about this when the WTD came in. The British government in particular insisted that employees be allowed to voluntarily choose to work more than 48 hours per week.
I'm not sure it can be part of your contract of employment, because you're not allowed to hire or fire based on willingness to work overtime. However, in practice, such hiring and firing does actually take place.
Bleugh ! I can't believe I said that. However, we work in an industry where 2 smart people can be worth a great deal more than any number of grunts, even if the grunts work 20 hour days.
Most software projects are actually overstaffed with programmers, and that the same amount of work could be done by substantially fewer people. Calls to work long hours often come about not because the amount of work to be done is large, but because the project is being constantly rewritten to accomodate changing requirements, or because there are fundamental technical flaws that there "isn't time" to fix.
Ultimately, the hard part of programming is not writing code, it is thinking, and thinking is better done by a small number of smart people who've had enough sleep, decent food, and some time with their families.
I sometimes give training courses in OO design and analysis as a part of my job (described at http://isocra.com/training/). In our case, all the trainers do it part time, spending the rest of their time developing our products or working on consulting jobs. Having professional software developers giving courses in software development techniques seems to make sense, and it means we can discuss our experience and those of the trainess in a serious way (actually that usually comprises a fair bit of the course time).
Unfortunately, this seems far from the usual case. Courses from the big training companies are sold on a franchise basis, and many of those giving them are not experienced in the subject matter themselves. The exercises tend to be very prescriptive, and therefore don't really help the trainees with using the information in their jobs. Often, the trainers are unable to discuss the material in any depth. Courses in specific technologies (as opposed to general techniques, like the ones we give), seem of very limited usefulness anyway. The same information is invariably available in books, or even in the online help for the product.
... in Java, because it is statically typed. Where code is not polymorphic, and manipulates the primitive types directly, it would be possible to use full-precision numbers, as supported by the hardware, just as Java does now. Something like C#'s automated boxing and unboxing could be used when the primitives were assigned between a polymorphic and a non-polymorphic context. That would answer the performance concerns with needing to distinguish fixnums from reference types, and still give fully OO primitives.
That would be why the JCP is working on a standard for them ? and why there is an implementation mechanism (type erasure) which requires only a small change to the VM ? and why 1.5 is slated to include them ?
...
Hmm
Generics are well on their way. They keep getting held back from actualy inclusion in the VM, since in practice their absence is just an irritation, but the standard is already signed off. C++ templates are a pretty poor example of generics anyway. It has been done much better elsewhere.
You don't really explain why you think the primitive types are necessary, so it is hard to answer you, but the fact there is no common supertype of the primitives + Object is a complete PITA if you do anything complex in Java. Just look at the JDBC interfaces for an example. The need to promote and demote primitives to get them into collections is a major source of inefficiencies in Java programs.
Just to avoid any misunderstandings: the point is to give the primitives object-like semantics, not to store them in the same form as other objects, or to require people to use object-like syntax. The technology to treat primitives as objects has existed for Lisp and Smalltalk for years. The only reason it hasn't made it into Java is NIH syndrome.
Another thing he missed: metaclasses
Noone (or noone significant anyway) thinks the
primitive types should be layed out in memory
the same way as object types. The argument is
that they should be semantically the same,
but implemented differently. Thus, if I
want to take the sine of a number, I can
write:
(6.0).sin()
Rather than:
Math.sin(6.0)
Which involves the nasty, irrelevant class "Math". You should also be able to subclass the primitive types. Furthermore you can remove the length and precision limits on the various types. Integers should be stored as 32-bit ints where possible, and then gracefully degrade into big ints when they exceed 32 bits.
The technology to do this already exists. Lisp and Smalltalk VMs have done it for years. Unfortunately, the developers of Java got confused in just the same way as you're doing.
OK, well this post is much too late, but possibly the author might find it and read it.
You say you're the "de facto software project team leader". Who is the "de jure" team leader ? Who is meant to be doing the work you're doing ? If you have someone who's meant to be managing the project or providing technical leadership, and they're not doing their job, you need to make sure their boss knows about it. Have a few words with them first about your concerns, and if they don't act, go to their boss. I know it sounds harsh, but I've been in your situation, and it is a hiding to nothing. Noone gives you any credit for doing a job if they don't know about it.
If your place of work is relatively unstructured (as mine now is - I prefer it that way), and noone has an official leadership role, make sure your ultimate boss knows what you are doing. Once again, you don't get any credit for doing a job if noone knows about it. You're an employee (I assume), and ultimately the success or failure of the enterprise isn't your responsibility, although, of course, your job is.
If you're pretty confident that you have the responsibility of sorting out your project, then you really do need to sort out the problems you are having with your cow-orkers. It sounds to me as if they're either lacking in motivation, or not very good coders.
There's a judgement call to be made here as to whether these people are redeemable. They might not be. Some people just aren't up to programming, others require so much effort to train up that it is not worth the investment, others are unmotivated, due to personal problems, in such a way that you can't help. The only answer is to let such people go. This is why you need to be in a position of authority acknowledged by your boss. I don't necessarily mean that they need to be hurled bodily from the doors, but they need to be moved to work that they're capable of doing. When it comes to hiring new people, make sure you're involved in the process.
However, the only way you're going to find out whether your cow-orkers are redeemable, is by trying to help. If at the end of that process you,ve acheived nothing, then proceed as above. In order to help, I'd suggest some or all of the following:
1. Make sure people are motivated. They need to know what your project does for the company. They need to know what they, personally, can expect to gain from success. If - as is common is technical organisations - there's not real career progression opem, you might want to try to fix that.
2. Make sure they know what is required. That is: what must be delivered and when. They should feel that it is a team goal, and that it is acheivable. They should feel personally responsible for their bits.
3. Track what people are doing, on a day-to-day basis. Go from desk to desk and ask. Help with problems. If people have gaps in their knowledge or misunderstandings, talk them through it, rather than just telling them answers. If there are problesm with the rest of the organisation, try to sort them out.
4. Institute code reviews or pair programming. Make sure you are involved, but encourage them to critique one another's work and improve on it.
5. Change the way you're scheduling work to make tracking easier. Expect people to deliver demostrable units of functionality every at least week or so.
6. Never lose your temper or act in a condescending manner.
Why are classes like Integer so weird?
Because they're an afterthought. Java was originally designed without the primitive equivalent reference types and they were tacked on later to solve some problems which emerged. Basically, the problem was that there was no type that included both Object and the primitive types, which made reflection and collections hard to deal with.
The original decision not to make the primitives objects is one of the Great Mysteries of All Time. Sun say its for "efficiency reasons", but Java's antecedent languages (Smalltalk, Lisp, etc) solved the same problem using type tags, so primtives look like objects even though they are implemented differently, and indeed the best VMs actually do this internally for other reasons.
Essentially, its a mistake, IMHO.
Several times I got caught on the fact that there is no way to pass an int by reference. And I don't like Integer (see aboive)...
Java's basically an OO language. You can use it in non-OO ways, but you tend to run into problems like this. Basically, if you want to return more than one value from a method, you should probably group them together in their own class. If you want to use the return value to return an error code, you should learn about exception.
I program in Java every day, and the inability to return multiple values is not a problem for me in practice.
One (public) class per file.
.class files act as header files as well as binaries. In order to preserve the sanity of programmers, the compiler builds any unbuilt sources. To do that it has to find them. Hence the "file must have the name of the public class" rule.
By population, yes. If you cover the SE, Manchester, Merseyside, Birgmingham and the central belt of Scotland, you have more than a majority of the population.
And the soma ritual may also go back to Indus times. The matter is far from closed, but the best evidence comes from the language: people have mapped Indus valley script onto something like Dravidian quite convincingly. Attempts to map it onto a Sanscrit like language are much less convincing.
My bet would be that modern Hindu culture includes aspects of the ancient Indus culture, and aspects of the Aryan invader's culture.
Ah, OK. My mistake. I didn't realise how far south it was. I just immediately thought "ancient India - Indus valley".
Nonetheless, that makes it even less likely that the city will have had any aspects of Hindu or Aryan culture in its makeup.