Kuro5hin.org: technology and culture, from the trenches
create account | help/FAQ | contact | links | search | IRC | site news
[ Everything | Diaries | Technology | Science | Culture | Politics | Media | News | Internet | Op-Ed | Fiction | Meta | MLP ]
We need your support: buy an ad | premium membership

[P]
How Java Should Be

By hardburn in Technology
Mon Mar 12, 2001 at 02:12:19 PM EST
Tags: Software (all tags)
Software

Java is a great language. Not because it's cross platform or other such over-hyped nonsense. No, Java is arguably a better design then C++ because of its garbage collection, built-in multi-threading, and cleaner code layout. However, there are a few areas of Java that I feel make it less-then-perfect for use in programming. I will focus on things that especialy matter to a Free Software programmer like myself, but will touch on issues that would also apply to non-Free Software.


First, I should qualify my statement above about the uselessness of cross platform. Some may recall that there was a cross platform language long before Java; it's called "C". At a time when you were considered insane for closing your source, C was a great cross platform language. However, Bill Gates and others of his ilk didn't see it that way.

With the recent surge of interest in Free Software, C can once again be the cross platform language it was meant to be. Sure, it means putting a few ugly #ifdef's in your code, but the result will be code which is actually better at being cross platform then the "write once, debug everywhere" of Java. Also, recompiling isn't as big a deal in Free Software as it is in closed-source. In any case, we don't need it, and anything in the language specification for having this functionality outside what is in normal C/C++ should be viewed as language bloat.

In short, Free Software only cares about the source being cross platform, not the binaries.

This brings me to my first point: #ifdef. It makes sense in theory to not have something like an #ifdef in Java, given Sun's goals for the language. However, real life isn't so kind, and our goals are somewhat different from Sun's, right? There are some Java compilers (especially machine-code compilers; more on that later) that have problems with certain code tricks, libraries, etc. Using something similar to an #ifdef could often fix this problem, but Java has been neutered of this ability (some have suggested patching the code during the 'make' process if a specific compiler was used, which is very kludgey, to say the least). Besides, adding this doesn't really make it any worse then C/C++, it's just adding functionality they already have.

An #ifdef may help non-Free Software, but not as much, since non-Free Software has the advantage that it probably knows what compiler will be used ahead of time and can thus not use tricks that that specific compiler can't handle. Note that this differs from coding your program specifically for a compiler (which is bad programming practice, except in rare circumstances) in that we are not programming it to optimize for that compiler, just working around its bugs. Free Software usually doesn't have that luxury, and could thus benefit more from an #ifdef-alike.

The second point, is various deficiencies in keywords, although these are certainly not specific to Free Software. Inline could help a lot in speeding up programs, as could macros. Several times I find myself wanting to use a macro (another thing I'd like to see added) or inline function but must put up with using a function call. Java does do some automatic inlineing for you, but frankly, I prefer to have more control over what the compiler does.

I really want to see an unsigned keyword, so much so that I wrote GPL'd UnsignInt and UnsignShort libraries myself (and kludgy ones at that!). I'd still like to see this become a keyword, though.

A const keyword would also be nice, as it adds to self-documenting code, as this post brings out.

Thirdly, there's various issues with libraries in Java, but again, these are hardly specific to Free Software. Those who have programmed in Java know just how ugly the various file I/O libraries are. To read a file, you want to use java.io.BufferedReader (just as an example). But wait! The constructor for BufferedReader takes in a java.io.Reader object. Actually, you probably don't want to use Reader directly, but rather a class that extends it, probably java.io.FileInputStream. Phew! To summarize this into code:

// "filename" is a String declared elsewhere
BufferedReader in = new BufferedReader(new FileInputStream(filename));

OTOH, this process does allow a lot of flexibility, but I'd really like to see a library that wraps this whole process into one class. In Java's defense, it would be quite easy to write this wrapper yourself.

String manipulation is also severely lacking. The library java.lang.StringBuffer and java.util.StringTokenizer are about all you get. StringBuffer allows you to append or prepend a String, or put data in an arbitrary location into the String. StringTokenizer lets you break a String into smaller Strings at a certain delimiter character. We might not need it to be as great as perl, but could we have something a little heftier, please?

There has been a lot of talk of licensing issues. Depending on how strictly you interpret the GPL, it may be illegal to use a GPL'd program on a non-Free VM, unless you say that the VM is an OS of sorts. This can be solved by either using a Free VM (like Kaffe), using a machine code compiler (see bellow), or by appending your program's licensing statement with something like this:

This program is distributed under the terms of the GNU General Public License, with the extension that it may be used on a non-Free Java Virtual Machine.

Of course, IANAL, so much will have to be done to make sure this statement is legally binding.

Lastly, Java byte code. Like the lack of #ifdef, using interpreted byte code makes theoretical sense given Sun's commitment to making Java cross platform. It also makes sense on embedded devices. However, for desktops, byte code is just a resource pig. While JIT compilers help this a lot, it would be better just to go straight into machine code. Fortunately, the GNU project is creating just such a compiler that is part of the GCC suite. It's called GCJ, but it is extremely buggy right now.

There are other machine code compilers, such as Visual J++, but none that are Free Software. Getting your program to compile on GCJ is somewhat like eating steak with a spoon. This is unfortunate, given the speed and memory use you can see over plain old byte code, even with a JIT compiler (which incurs some overhead in converting the byte code to machine code on the fly). Given time, GCJ will fix it's bugs and can become widely accepted throughout the Free Software community, but until then, a resource-hogging byte code compiler (preferably JIT) is generally the most sensible alternative.

In summary, my suggestions are to add something similar to an #ifdef, additions of inline, unsigned, and const keywords, clean up the libraries while leaving the current flexibility intact, and greater use of machine code compilers. These recommendations, I feel, will make Java far more suitable for use in Free Software.

Sponsors

Voxel dot net
o Managed Hosting
o VoxCAST Content Delivery
o Raw Infrastructure

Login

Poll
What needs to be fixed most in Java?
o #ifdef 2%
o keyword deficiencies 4%
o library deficiencies 6%
o machine code compilers 20%
o add a 31337-speak generator 17%
o Java is for Quiche Eaters 25%
o C 10%
o other 13%

Votes: 120
Results | Other Polls

Related Links
o UnsignInt and UnsignShort
o this post
o Kaffe
o GCC suite
o GCJ
o Also by hardburn


Display: Sort:
How Java Should Be | 70 comments (64 topical, 6 editorial, 0 hidden)
Your suggestions (3.00 / 5) (#2)
by scorbett on Thu Mar 08, 2001 at 02:46:42 PM EST

In summary, my suggestions are to add something similar to an #ifdef, additions of inline, unsigned, and const keywords, clean up the libraries while leaving the current flexibility intact, and greater use of machine code compilers.

In other words, turn it into C++, eh? Where's the benefit of that? If you want the speed of machine code compilers, use C++. If you want the advantage of cross-platform (without all the ugliness brought about by #ifdefs), use Java.

However, I agree with you on the "const" keyword - Java could really use that.



No (3.00 / 1) (#4)
by hardburn on Thu Mar 08, 2001 at 02:55:27 PM EST

It's still Java, for reasons which will come to me :)


----
while($story = K5::Story->new()) { $story->vote(-1) if($story->section() == $POLITICS); }


[ Parent ]
Hardly C++ (4.40 / 5) (#5)
by Mendax Veritas on Thu Mar 08, 2001 at 02:59:27 PM EST

Even with all of his suggestions, it still won't have pointers (and therefore the rampant abuse of them), multiple inheritance, or true genericity, and it will still have garbage collection. Those differences alone will keep it quite distinct from C++.

Of the recommendations put forth in this article, I like "const" best -- the lack of it was one of the first things that bothered me when I started learning Java. It's particularly annoying since objects are always passed by reference; it basically means that any method you pass an object to can do whatever it wants to the object. There's no way to enforce a restriction against that, as there is in C++ with "const".

[ Parent ]

Yes there is (3.33 / 3) (#10)
by hardburn on Thu Mar 08, 2001 at 03:37:55 PM EST

Use 'static final', which gets you most of what you want. The addition of 'const' was suggested because it makes the code look better. See the comment linked to in the submission about the use of 'const' for more detail.


----
while($story = K5::Story->new()) { $story->vote(-1) if($story->section() == $POLITICS); }


[ Parent ]
Uh, no (4.83 / 6) (#14)
by 0xdeadbeef on Thu Mar 08, 2001 at 04:43:43 PM EST

What most people want is the ability to declare a method 'const', so that one may guarantee that it will not change the state of its object, and to have const parameters, so that that one may guarantee that a method does not alter its parameters (such as by calling their non-const methods).

You can try to kludge the latter by declaring parameters 'final', but all that does is prevent you from reassinging the local reference. For the most part, it is useless, and used mainly to tell the compiler it can make some assumptions that allow inner classes to access those parameters. It's a bit like the difference between const T* (can reassign pointer, but not change data) and T* const (can change data, but not reassign pointer).



[ Parent ]
As I pointed out in my comment (2.60 / 5) (#16)
by weirdling on Thu Mar 08, 2001 at 04:50:05 PM EST

final is practically the same thing as const. Witness:
const int aConst = 4;
final int aFinal = 4;
Both can't be changed. Of course, the keyword final also means that something cannot be derived from, a woeful deficiency in C++:
public final class Widget { }
creates a class that cannot be derived from, or, in Java-speak, extended:
public class Other extends Widget { }
will fail in the compiler.
When final is used in a method declaration:
public final doSomething() { }
it is almost always inlined if it does not extend a previous method and it is short enough.

I'm not doing this again; last time no one believed it.
[ Parent ]
C++ "const" does something that Java can (4.83 / 6) (#19)
by Mendax Veritas on Thu Mar 08, 2001 at 05:20:42 PM EST

The issue is not objects that can never be changed, but methods that guarantee not to alter the objects passed to them. Consider this C++ example:

Y f(const X& x) { ... }

void g() {
    X x;
    Y y = f(x);
}

The function g can do anything it wants to x, but the function f is not allowed to alter x (it can call only const methods of x, which in turn are not allowed to alter data members), because x is passed by const reference. This is an important property of const. As far as I know, there is no equivalent capability in Java.

Now, C++ being what it is, there is an escape route by which you can modify an object even when you have only a const reference to it. But you have to go out of your way to do it; it is very unlikely to happen by accident. You do it like this:

void f(const X& x) {
    const_cast<X&>(x).method_that_is_not_const();
}

This, which explicitly uses a typecast to get rid of the "const" property of the reference, will compile successfully and do exactly what it looks like it's doing. But the typecast is required, so the fact that you're cheating is explicit in the code. One typical use of this technique is to implement lazy updates within an object for performance reasons.

--mv

[ Parent ]

ARGH! K5 SCREWED UP MY SUBJECT LINE! (4.00 / 2) (#20)
by Mendax Veritas on Thu Mar 08, 2001 at 05:22:38 PM EST

That was supposed to read "C++ const does something that Java cannot do"... sorry.

--mv

[ Parent ]

I was curious (2.33 / 3) (#22)
by weirdling on Thu Mar 08, 2001 at 06:20:18 PM EST

I tried creating the following method on a random class I've got in VisualAge:
public void trysomething(final String whatever) {
   whatever = "Hi";
}
and the compiler complained that I couldn't assign whatever to anything.
Of course, I can execute a method on that object that modifes the object. I guess to me this isn't a huge deal. I hardly ever used const as a C programmer, due to the fact that the entire function tree *must* be constant with respect to that variable, or it is pointless.
To me, object orientivity removes this problem, as the final keyword keeps one from assigning any values to the object one shouldn't, and the object itself should maintain internal consistency. This is easy enough to do with the synchronized keyword in Java.
I guess it really is a matter of paradigm.

I'm not doing this again; last time no one believed it.
[ Parent ]
synchronized keyword???? (5.00 / 1) (#35)
by Carnage4Life on Sat Mar 10, 2001 at 04:51:13 PM EST

To me, object orientivity removes this problem, as the final keyword keeps one from assigning any values to the object one shouldn't,

The final keyword only works on the local variable, it is completely useless since even without it you still couldn't change what the original reference points at. What does this have to do with OO anyway?

and the object itself should maintain internal consistency. This is easy enough to do with the synchronized keyword in Java.

What the does the synchronized keyword have to do with the fact that you can pass an object to a function and the function can alter the state of the object? The synchronized keyword deals with making sure that multiple threads cannot access synchronized functions in an object concurrently.


[ Parent ]
In Java (none / 0) (#39)
by weirdling on Mon Mar 12, 2001 at 01:54:27 PM EST

If you force access through get and set methods and make the data members private, another function that isn't part of the object can't access them, period. You can't cast it to another type and then access it like in C. This is true OO, and is why I don't really think the const keyword is so important.
As to the synchronized keyword, in my experience, having threading issues cause problems with data corruption is much more common than having a function widdle on a const. The synchronized keyword essentially eliminates threading problems.

I'm not doing this again; last time no one believed it.
[ Parent ]
get and set methods??? (none / 0) (#41)
by Carnage4Life on Mon Mar 12, 2001 at 03:31:22 PM EST

If you force access through get and set methods and make the data members private, another function that isn't part of the object can't access them, period. You can't cast it to another type and then access it like in C. This is true OO, and is why I don't really think the const keyword is so important.

Your examples are more and more divorced from the issue at hand. If a class has public get and set methods, then it's data members are effectively public with the added liability of a function call being needed to access them.

The point that the C++ programmers, including myself, are trying to make is that you cannot specify that a function should not modify the state of an object passed to it. If you pass an object to one of my methods in Java, there's nothing stopping me from setting all the fields in the object to NULL either on purpose or by accident. C++ uses const to prevent that behavior, Java has no similar construct. This is particularly annoying when one is trying to create abstract classes or interfaces for which you don't want objects passed to their subclasses to modify.

Secondly with const one can specify that certain methods in a class should not be able to modify the state of the class (e.g. your beloved get() functions).


[ Parent ]
Why get and set methods are secure (none / 0) (#45)
by weirdling on Mon Mar 12, 2001 at 06:39:17 PM EST

In true OO design, the class itself is responsible to make sure that it does not get into a incoherent state. So, classes that need to make sure that things are handled correctly need to have get and set methods that will check to make sure that it is ok to change the data elements. Any changes to one part may or may not trigger other changes.
Oh, and yeah, in Java, the security can be rather tightly checked, as in security measures are built into the JVM.
So, now in C/C++, where data is *not* actually encapsultated, but, rather, is a part of a structure, as are all the virtual methods and so on. That makes it rather easy to gain access to any data element in a class, as you have said. This is one of the components of the pointer-safe idea.
Actually, in proper OO design, you want to avoid accessing data members directly as much as possible. I'm not a radical OO designer, but I do believe that only objects in the same package should ever access each other, and then, only in a parent-child relationship, or a peer relationship.

I'm not doing this again; last time no one believed it.
[ Parent ]
Pointless OO Theory (none / 0) (#48)
by Carnage4Life on Mon Mar 12, 2001 at 09:48:06 PM EST

You keep bringing up irrelevant aspects of OO theory. It is all well and good to claim that an object's get and set methods should make sure the changes are coherent but 99 per cent of the time the Object does not have enough information to make that call. A simple example is a linked list node with getNext(), setNext(), setData() and getData() methods. There is nothing the Node can do to verify whether certain changes to it's next pointer or its data are valid or not since it depends on context.

In the above example I can set the next pointer to null or not depending on whether the node is at the tail of a list or not. There's no way to code that into the get and set methods. The same goes for code that sets what the data the Node refers to or even better changes the state of the data pointed at by the Node via getData().modifyState(). With const in C and C++ you can specify these semantics on a per function level of granularity.

This is just one of several deficiencies of Java. A lack of enumerated types is also another oversight that is quite considerable. That said Java does fix a lot of the issues that were sticking points in C++ and made developing certain kinds of applications a lot more than the crapshot it had been with C and C++.


[ Parent ]
Of course (none / 0) (#54)
by weirdling on Wed Mar 14, 2001 at 01:18:09 PM EST

In true OO design, the linked list would be managed entirely by the elements of the linked list themselves, not by an external function, so no external function has any business accessing what should be private data members. So, one simply wouldn't have getNext and setNext as public methods. One would have addElement and removeElement as the public methods.
My point in bringing up 'irrelevent OO theory' is that many of the complaints I hear so often about Java from C/C++ people is precisely because they do not understand the 'irrelevent OO theory'. C/C++ people still think of a class as a fancy structure and that some function might be able to modify it, rather than thinking of a class as an entity unto itself, which is capable of handling its own security, which is what the 'irrelevent OO theory' teaches. No, it's not relevent to C/C++, because C/C++ can't *enforce* private data members any more than it can *enforce* the const keyword, but in Java, which is a lot more object-oriented, it can and does enforce private data members. Classes in Java are true classes rather than converted structs, and once one learns the OOD method, the need for a const keyword, in my opinion, goes away.

I'm not doing this again; last time no one believed it.
[ Parent ]
hmm (5.00 / 1) (#56)
by jacob on Wed Mar 14, 2001 at 10:32:36 PM EST

Const is a way of making a promise that's additional to what the object itself can enforce -- it has nothing to do, per se, with keeping an object in a consistent state.

Consider a program that has a gui that presents the user with some number of choices, and relates the choice the user makes with a model that then does something useful. We'll implement it as follows:

class GUI
{
GUI(Iterator choices, Model m)
{
// make a button for each choice that calls a method on m when clicked
}

// ... other stuff
}

class Model
{
Model(Iterator choices)
{
// do something appropriate with each choice
}

// ... other stuff
}

class Controller
{
Model model;
GUI gui;

Controller()
{
// make a list of choices
LinkedList choices = new LinkedList();
choices.append("choice a");
choices.append("choice b");

// pass the list to model
model = new Model(choices.iterator());

// pass the same list to gui
gui = new GUI(choices.iterator());
}

// ... other stuff
}

Looks fine, right? Well, maybe ... but what if Model's constructor modifies the list by calling Iterator.remove()? Then the invariant that the controller expects to be true (that the list is the same when passed to model and gui) no longer holds, and when you expect an invariant to be true and it isn't, bad things always find a way of happening. The controller actually wants to only hand the iterator over as a constant that can be inspected but not modified, even though the datum can (and should) be modified at other stages of the program.

In C++, we could solve that problem very easily:

Model(const Iterator & choices)

does the trick (is my syntax right, people who have actually used C++ this year?). In essence, Model is promising anyone who uses it that although it could change choices, it isn't going to. If the compiler can't prove that Model's constructor isn't going to modify the iterator, it won't compile the program, which is a pretty darned good way of keeping your promise.

In Java, you can't do that. What you can do is have every mutable object have a GetImmutable() method or something similar that returns another object that can access the same data but that will never change it (which is what providing an Iterator rather than the list itself would accomplish). That has two problems: first, it's phenomenally more verbose compared to the const solution, because it requires that every object that can be modified implement this function (and there's no way that it can be taken care of by inheritance -- the fields that can or can't be updated are specific to every subclass). Second, an ImmutableBlah object is only as "immutable" by convention: nothing could stop me from having my "immutable" subclass of an iterator actually wreak havoc all over the list if I wanted to. Put more politely, nobody is actually proving that the methods on the "immutable" object don't modify the object, they're only claiming that they don't. That claim might be false, and then you have the potential for bugs.

There is nothing about OOP that makes it redundant to declare a datum as constant in a particular context. It's not because C++ programmers view objects as structs that they think that; it's because they program in a language that lets them think about what should be constant and what needs to change in a given method.

--
"it's not rocket science" right right insofar as rocket science is boring

--Iced_Up

[ Parent ]
Inexperience (4.00 / 1) (#58)
by Carnage4Life on Thu Mar 15, 2001 at 02:58:36 AM EST

In true OO design, the linked list would be managed entirely by the elements of the linked list themselves, not by an external function, so no external function has any business accessing what should be private data members

Wow. You completely misunderstood my post. OK let's try again. Let's say you have a Node class which can be used by any class that implements the ListType interface which contains amongst others a method insert(Node newNode). Now in Java it is impossible to enforce that anybody who implements your interface makes sure that the inserted Node is not modified by the insert operation. This means that someone can implement your interface but create lists where the insert operation calls newNode.setData(null) or newNode.setNext(null) to its heart's content which isn't what the original designer of the interface had in mind.

The above example is contrived but is not far removed from real world scenarios I have heard or seen. Basically const specifies that the same object that goes into a method leaves the method unchanged, Java does not have a feature that enables one to make that guarantee.

I had initially planned to write a post flaming you for your inability to see something right in front of your face but after rereading your post it is clear that you are simply inexperienced. You simply are unable to grasp what I am talking about because the problems you have had to deal with were relatively simple.

Write a few thousand line programs in both Java and C++ (throw in C and Smalltalk as well) that will have to be robust enough to deal with being mishandled by other programmers yet are also flexible enough to be extended in ways you did not imagine without requiring major rewrites, then come back and rant about how final is no different from const.

[ Parent ]
I am happy you did not flame (none / 0) (#60)
by weirdling on Thu Mar 15, 2001 at 01:58:30 PM EST

Truth is that we actually have quite different programming styles. OOD, as I have learned it, being that I did very little programming other than OOP, would have a Node class that managed *everything*. You would never have a ListType interface. Of course, this brings us to what I dislike most about Java: lack of multiple inheritance. But that's another argument for another day.
The fact is that in my many years of programming, working on many projects in both C++ and Java, I have never once had to use the const keyword and never suffered for it. The fact that it is not in Java primarily bothers C++ people, which was the point of my original post.
There, see, I managed not to flame you for being so pompous...

I'm not doing this again; last time no one believed it.
[ Parent ]
Wrong application of OOD. (5.00 / 1) (#62)
by Carnage4Life on Thu Mar 15, 2001 at 04:02:52 PM EST

Truth is that we actually have quite different programming styles. OOD, as I have learned it, being that I did very little programming other than OOP, would have a Node class that managed *everything*. You would never have a ListType interface.

Really? What if I write a Node class that will be used by many different developers in building Queues, Stacks, Vectors, LinkedLists, etc but want each of these classes to be able to be used by anyone who simply needs a ListType? This problem is more common than you think and is the principal idea behind Java's Collection framework and a number of interfaces including Collection, List, Set, Iterator and Enumeration. Like I said this a simple and contrived example, the real world examples I am describing are more subtle and complex.

If you are building classes that have so much knowledge about what classes will use them and in what context then you are building very rigid and inextensible software.

[ Parent ]
different techniques in Java (5.00 / 2) (#51)
by zzzeek on Tue Mar 13, 2001 at 02:44:09 PM EST

I am not saying the const keyword would not perhaps be handy in Java....but one thing I notice in these discussions is that everyone always wants to do this 1->1 comparison of C++ and Java programming techniques. The Java language lends itself to different ways to get from point A to point B, meaning its not just a "substitution of keywords" issue, but you would make usage of Java's unique contructs to design your code differently, to achieve a similar end result as in a C++ program. Often, these alternative techniques are more verbose and "more trouble" than they would be in C++, but that is part of the philosophy in Java, its more verbose overall, and to a C++ programmer, more effort in that sense (but then, as a result of this extra formality imposed in design, its not at all uncommon that it runs perfectly the first time after compile and never crashes, so, you make the call).

As far as this const discussion goes, if I have a mutable object in Java, and I want to pass it around to other classes but I dont want them to change the object, I have to go through more effort, usually creating a separate "view" object or interface:



public interface IntegerView {
   public int getValue();
}

public class MutableInteger implements IntegerView {
   private int value;

   public void setValue(int value ) {this.value = value;}

   public int getValue() {return value;}
}

public class IntegerPeeker {
   public void lookAtInt(IntegerView view) {
   // ...
   }
}

Another example is the way the java collections classes such as Set and Map return a view-only Iterator object for other classes to peruse their contents. Yes this is a lot more effort, but it forces the developer to create classes and interfaces whose roles are very clearly defined, instead of sprinkling keywords here and there to redefine class behaviors in an arbitrary and potentially inconsistent way. Again, not that const is evil, but just that using it is less in the original "spirit" of java development.

Also, as far as creating abstract classes that have data members which you dont want messed up by subclasses, you declare the member variables of the abstract class as private and force the subclasses to use accessor methods to view them. I do this all the time and its a standard design.



[ Parent ]
We're thinking along the same lines! (none / 0) (#59)
by jacob on Thu Mar 15, 2001 at 11:15:47 AM EST

I actually made just such a suggestion in a previous comment elsewhere in this thread. However, as I said there, const actually does buy you an additional bonus over the "immutable view" approach: if I declare a parameter as const, the C++ compiler will only let my program compile if it can prove that the datum never gets modified by my function, even indirectly through calls to other functions. In the view approach, I'm merely asserting that I don't modify anything; if I do, nothing will stop me. Consider:


interface ImmutableA
{
safelyGetA();
}

class A
{
private int a;
public getA() { return a; }
public setA(int a) { this.a = a; }

// an inner class to implement a const interface
class ConstantMe implements ImmutableA
{
private A a;
ConstantMe(A a) { this.a = a; }
public int safelyGetA() { return a.getA(); }
}

public GetImmutable() { return new ConstantMe(this); }
}


Looks fine, right? Well, it's not: what if I subclass A in the following way:


class B extends A
{
// increment a with each call
public int getA()
{
setA(super.getA() + 1);
return super.getA();
}
}


Now if I have an A it might be a B, and thus my ImmutableA might actually be pointing to a B, and when I safelyGetA, I might actually be updating the local variable a. What's worse, the programmer who implements B doesn't even have to be malicious to make that happen: nowhere is it stated that getA must not modify A, but the implementor of safelyGetA relies on that being true. And if you're going to be adorning every function that's constant with a comment that says so, why not say "const" in the declaration instead and let the compiler see for itself? I don't see why that would be un-object-oriented.

--
"it's not rocket science" right right insofar as rocket science is boring

--Iced_Up

[ Parent ]
Minor historical note (3.22 / 9) (#7)
by Signal 11 on Thu Mar 08, 2001 at 03:03:22 PM EST

I'm not qualified to comment on the content of the article or evaluate the additions and modifications to Java that the author is suggesting, but I would like to simply remind readers of this story that Sun Microsystems is the judge, jury, and executioner for any/all modifications to the Java language as Microsoft found out the hard way in court and later had to create C-sharp as a response to Java after their modifications were rejected.

Be careful with the wording of "How Java Should Be" because if Sun Microsystems doesn't approve the change
1. It isn't Java,
2. You'll need to create an entire new language to add the aforementioned features and
3. you won't be able to claim it's "java compatible".

I believe the author is implicitly suggesting the creation of a java-like language with these extra features and to have it backwards compatible with existing java VMs, but I'm not sure.


--
Society needs therapy. It's having
trouble accepting itself.

Discussion and jwz (4.50 / 2) (#8)
by Aquarius on Thu Mar 08, 2001 at 03:19:52 PM EST

I've not used Java a great deal, mainly because I do pretty much everything in scripting languages these days. Even to me, though, this looks well-written (although I'm not sure why there necessarily needs to be the Free Software angle -- it doesn't seem to add a lot), and it's nicely complimented by jwz's thoughts on Java.

Aq.


"The grand plan that is Aquarius proceeds apace" -- Ronin, Frank Miller
For once I agree with jwz (4.33 / 3) (#17)
by Mendax Veritas on Thu Mar 08, 2001 at 05:02:17 PM EST

I often react to jwz's pronouncements with something less than approval, despite the fact that he used to have a quote from me in his sig, but I agree with just about all of these comments on Java.

--mv

[ Parent ]

Sorry, but you're a loony and a troll. (3.72 / 11) (#11)
by General_Corto on Thu Mar 08, 2001 at 04:04:43 PM EST

To quote your last paragraph:
In summary, my suggestions are to add something similar to an #ifdef, additions of inline, unsigned, and const keywords, clean up the libraries while leaving the current flexibility intact, and greater use of machine code compilers. These recommendations, I feel, will make Java far more suitable for use in Free Software.
How exactly does the alteration of the language spec make Java "far more suitable for Free Software"??? You may as well have said "Helping little old ladies across the street, I feel, will make stock options far more suitable for use in Chicken McNuggets." It makes about as much sense.

I'm sorry, but it seems to me that you're attempting to do a namedrop to tug on people's heartstrings. And that's called trolling.

P.S. I still don't agree on your points, for the same reasons as before.


I'm spying on... you!
Java I/O (4.20 / 5) (#12)
by traphicone on Thu Mar 08, 2001 at 04:08:43 PM EST

Okay, granted

BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
String s = System.in.readLine();
int i = Integer.parseInt(System.in.readLine());

is not

string s;
int i;
cin >> s >> i;

Fine.

BufferedReader in = new BufferedReader(new FileReader(filename));
String s = in.readLine();
int i = Integer.parseInt(in.readLine());

is not

ifstream stream;
stream.open(filename);
string s;
int i;
stream >> s >> i;

either, but which code blocks look more object oriented, and which look more like they do what they do?

It would actually be terribly unfair to pass judgement on either language based solely on the examples above. What it does do, however, is give an inkling of the consistency and power of file I/O in Java. In Java the particular source of your input and output is abstracted away from the programmer. It doesn't matter any longer if your data is going to or coming from the console, a file, a socket, or anything else for that matter. This can seem like a bit of a hassle and some extra work at first, but I feel that the payoff in modularity and API consistency is well worth it.

Another thing to note is that file I/O in Java more or less breaks the mechanism of performing the input and output away from the mechanisms which interpret the data. Here the Java platform really shines. For example, instead of forcing string formatting into the mechanism for I/O, it's broken off into it's own library. Take a look at the java.text package to get an idea of how much you can do with string formatting. Who needs printf()?

"Generally it's a bad idea to try to correct someone's worldview if you want to remain on good terms with them, no matter how skewed it may be." --Delirium

Correction... (3.00 / 1) (#21)
by traphicone on Thu Mar 08, 2001 at 06:01:39 PM EST

Wooha! I love catching my mistakes before someone else does.

The first block of code should have looked like this. Otherwise, my point didn't really get made, did it?

BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
String s = in.readLine();
int i = Integer.parseInt(in.readLine());


"Generally it's a bad idea to try to correct someone's worldview if you want to remain on good terms with them, no matter how skewed it may be." --Delirium
[ Parent ]

How about (none / 0) (#29)
by weirdling on Fri Mar 09, 2001 at 12:38:37 PM EST

FileInputStream fis = new FileInputStream("whatever");
ObjectInputStream ois = new ObjectInputStream(fis);
int i = ((Integer)ois.readObject()).intValue();

Of course, it is far easier to just store the whole darn object and everything it references and reload it next time:

public class foo implements serializable {
.
.
.
public static foo getClass(String fname) {
   FileInputStream fis = new FileInputStream(fname);
   ObjectInputStream ois = new ObjectInputStream(fis);
   foo out = (foo)ois.readObject();
   fis.close();
   return out;
}
.
.
.
} // end of foo...

Now, to get really clever, here is a bit of code that doesn't even have to be linked to the foo class:
Class class = Class.forName("foo");
Class[] args = new Class[1];
args[0] = String.class;
Method getClass = class.getMethod("getClass", args);
Object[] values = new Object[1];
values[0] = "whatever";
Object fooClass = getClass.invoke(null, values);
// Now, if fooClass implements runnable:
(new Thread(fooClass)).start();

This is the Java.lang.reflect stuff, and it still checks all the access restrictions, etc.

I'm not doing this again; last time no one believed it.
[ Parent ]
Java I/O (none / 0) (#47)
by bertok on Mon Mar 12, 2001 at 09:32:30 PM EST

You say "the consistency and power of file I/O in Java" as if C++ doesn't have the same features!

C++ is in some ways even more powerful because it combines OO and Generic programming in it's I/O library. It's also much more efficient because it uses pointers. For example, if you override std::streambuf correctly, you can stream data directly to and from the destination, avoiding one or more of the memory allocations and redundant copies that Java performs during IO. I use this kind of thing to stream directly from memory-mapped files. The performance is stunning.


--
"If you would be a real seeker after truth, it is necessary that at least
once in your life you doubt, as far as possible, all things."

[ Parent ]

I'm a Java developer (4.36 / 19) (#15)
by weirdling on Thu Mar 08, 2001 at 04:46:18 PM EST

Your complaints boil down to these few things:
Need an ifdef to deal with compilers
Need inline, const keywords
Need unsigned types
Need machine-code compilers.

Fine, this looks like a laundry list of complaints that many people have with Java at first. Note I said *at first*. I will take them one by one.

#ifdef
You say this is necessary to deal with vagaries of compilers. Well, if a compiler fails to deal with something that is in the Java spec, it is the compiler's problem, not the programmers. If this is the case, the compiler will end up with egg-on-face and reduced sales. The fact is that any major Java compiler, almost all of which are free, are pretty much complete. They may not deal with certain tricks, but if you are using tricks to program with, you have terribly missed the point of Java.

Inline and Const keywords
The keyword you are looking for is final. If a function is declared final, it is inlinable if it is not an extension of a previous function. If that is the case, and it is short enough, it will almost always be inlined. You do know that the keyword inline is a suggestion to a C/C++ compiler, too...
As to const, final means almost exactly the same thing. const char * in C is static final String in Java. However, just as in C, if you change the *content* of the String object, you will get away with it. The final keyword only refers to the reference made.

Unsigned data types
The reason these aren't in Java is that Java is natively a 64-bit CPU. True, its ints are only 32 bits, but the thing was intended to run on a 64-bit architecture using longs, and, while you can easily run out of 2 billion ints, longs are another story entirely. The odds of actually needing an unsigned data type for long are pretty low. However, I do sort of agree with you that an unsigned 32-bit type would be nice due to the fact that so much of the available OS mechanics are in unsigned 32-bit values.

Now, as to greater use of machine code. There are quite a few compilers that do this already, and many JVMs do just in time compiling. The problem with a machine-code compiler is that the object code is not easily transferable. What this means in real life is that I develop Java on Win2K, and deploy on Solaris. I don't want to do anything other than ftp my jar file to Solaris. I don't want to recompile it there. There isn't any point. Machine-code compilers for the Solaris target aren't that much faster than JIT JVMs. On x86, they are moderately faster; certainly not enough to offset how much of a pain they are.

C/C++ is used by default by the free/open source movement. Java is beginning to be the language of choice in commercial development, and the reason is simple: one man-hour of Java is equal to around ten of C/C++ in real-world output, so with the costs of engineers being what they are, it is far cheaper to purchase fast enough machines to deal with the inefficiencies than to have a developer tied up for ten times as long. The free/open source movement donates its time, so tends to use tools that are themselves free/open source, because there isn't a compelling economic reason to do otherwise. Often, the target is outdated hardware that is itself quite cheap/free. That's the real reason for the difference in use.

I'm not doing this again; last time no one believed it.
Not quite (4.00 / 2) (#23)
by hardburn on Thu Mar 08, 2001 at 06:40:06 PM EST

Inline and const keywords are still needed because they don't always do the same thing as the Java "equivenents". See the post I linked to and some discussion in other threads to this story.

What you bring out about use of machine code is very true . . . for non-Free Software! My article was focused on Free Software, where the benfits of going directly to machine code outweigh the use of byte code, IMHO.

Not having unsigned is still anoying.


----
while($story = K5::Story->new()) { $story->vote(-1) if($story->section() == $POLITICS); }


[ Parent ]
Java Mantra (4.60 / 5) (#24)
by mvw on Thu Mar 08, 2001 at 08:41:01 PM EST

one man-hour of Java is equal to around ten of C/C++ in real-world output, so with the costs of engineers being what they are, it is far cheaper to purchase fast enough machines to deal with the inefficiencies than to have a developer tied up for ten times as long.

I see this argument repeated again and again, but actually never saw proof. I mean a 1:10 or even 1:2 diference in productivity is a strong claim, isn't it?

And don't tell me it is because C/C++ programmers waste 90% of their time fixing memory leaks.

The only reason I can think of, might be the enormous size of the Java library. Getting similiar C++ code typically involves searching for external libs. On the other hand, all these libraries, be it the Java standard ones, or some external C++ ones, tend to help only so far and need a lot of time to get accustomed with (like every complex library does).

No, I don't buy that Java mantra.


Regards, Marc
[ Parent ]

Ok, I'll bite (4.00 / 1) (#28)
by weirdling on Fri Mar 09, 2001 at 12:13:31 PM EST

I do Java programming for a living. Before that, I was a C++ bigot. Most of my programming, indeed, most commercial programming is in the business of GUIs or pushing around strings. C/C++ is very bad at pushing around strings, and most GUIs are complex and hard to program in C/C++, being as how they are native.
The AWT and Swing stuff does have its problems, AWT being excessively primitive and Swing hardly ever working right, but they are both vastly easier to program than any other GUI platform I've worked on.
Strings in C/C++ are a pain. Java String objects are extremely efficient and do most of what you'd ever want to do.
And, that's one of the things: the library in Java is very complete and it all works. It doesn't vary from platform to platform, it isn't modified significantly once put in place, and there are very few vagaries due to platforms to worry about. C/C++, the standard library varies from compiler to compiler, let alone platform. The standard library in C/C++ is not easy to use. File IO in Java is vastly more reliable, particularly if you wish to move to another platform. Sockets are a dream. Threading is a piece of cake, requiring no locks or any other mechanism other than the keyword synchronized used judiciously. Most of the Java libraries are threadsafe to the point that they will not get into a damaged state by two threads accessing them simultaneously.
Java is superior for deployment and testing, as well, but that is mostly the JVM and the debugging environment. I can make a change to a live system that is actually serving, save the change, and have it read in the next time the thread passes there. The VisualAge environment is by far the best I've ever used. It is so good I bought my own liscence to program in at work rather than continue with Visual Cafe. The VisualAge environment is the first debugger I've ever seen that handles multiple threads well. Right now, Java commercial tools are far ahead of C/C++ commercial tools.
I think the strongest argument I have, though, is that every single C/C++ programmer I know who has ever switched to Java and subsequently done an extensive project in Java simply won't go back.

I'm not doing this again; last time no one believed it.
[ Parent ]
Bingo! (5.00 / 1) (#40)
by kostya on Mon Mar 12, 2001 at 03:17:07 PM EST

The only reason I can think of, might be the enormous size of the Java library. Getting similiar C++ code typically involves searching for external libs.

There you go. That's EXACTLY why.

As someone who has worked in both, I believe it is getting better with C++ (can't speak for C). The STL, or standard library as it is now, is getting more and more complete. This was missing initially. Then everyone starting using different libraries from different vendors, yadda, yadda. You couldn't take your code that was built on MSVC++ and switch to Rogue Wave's libraries. There were libraries, but they weren't standard. Java had it all standard from the beginning.

That being said, the Java library is friggin' huge--which isn't always a good thing. If it came standard with the OS, that might be one thing. But it doesn't. The rt.jar and minimum executables (java.exe, etc.) is something like 5 megs in size!

The other thing that makes Java more "productive" is GC. No, C++ programmers don't spend 90% of their time looking for memory errors. Heck, I have spent a good bit of Java time trying to find what is generating the NullPointerException. It's just that GC allows simpler code creation--you don't have to think as hard because there isn't as much to keep track of.

Of course, this is why Java will never fill the systems programming slot, but it does make it easy to crank out code in. It will come back to haunt you in a lot of cases, but then that's true in every language for some feature. Knowing how to get past that is what seprates the good programmers from the bad ones in every language ;-)



----
Veritas otium parit. --Terence
[ Parent ]
const in C (4.50 / 2) (#27)
by Per Abrahamsen on Fri Mar 09, 2001 at 09:05:06 AM EST

As to const, final means almost exactly the same thing. const char * in C is static final String in Java. However, just as in C, if you change the *content* of the String object, you will get away with it. The final keyword only refers to the reference made.

This is not true for C. const char * mean pointer to a character constant (read C declarations from right to left). This means that the *pointer* is not constant, but the object it points to is constant, or rather, it cannot be changed through this pointer. If you want a constant pointer to mutable content, use char *const. If you want both the pointer, and the content, to be read-only, use const char *const.

Java might be unable to declare references to constant objects (I don't know Java), but that is a limitation not shared by C or C++.

[ Parent ]
const (4.00 / 1) (#46)
by crazycanuck on Mon Mar 12, 2001 at 08:41:27 PM EST

forget C, this is about C++.

const string s = "hello"; is const and cannot be modified.

[ Parent ]
#ifdef is evil (4.27 / 11) (#18)
by Dacta on Thu Mar 08, 2001 at 05:14:28 PM EST

It makes for unmaintanable code. That is why most C/C++ free software projects are trying to minimise it's use.

The proper way to get similar functionality in Java is to take advantage of its late binding features, and load a different class depending on on what is needed.



#ifdef is evil - "me too!" (none / 0) (#37)
by khallow on Sun Mar 11, 2001 at 11:13:50 PM EST

I agree with Dacta. The key point here is whether you need to do code restructuring (which the precompiler does) right before a compile. Why would using the precompiler be more efficient than dealing with the issues in your program? Guess it's a matter of view point.

This might be an abuse of ettiquette (promotion alert), but I'm familiar with an open source project called "Open Tibet" that dealt with similar issues. Hmmm, there isn't that much information there. Here's a better link.Basically, they're in the process of rewriting javascript so that it has a number of interesting features (Smalltalk object model, browser-based IDE, blah blah blah). A user can have any browser and we all know IE 5.0 is a lot different from Netscape 3.0.

The usual solution is to run certain code in an if/then statement conditional on the browser. The Open Tibet people wanted to get away from inserting browser specific code. Instead, a number of classes are solely meant for a particular browser.

When the javascript is downloaded to the user's browser, the server-side queries for the browser type (and some other browser specific data) and downloads javascript libraries meant for that particular browser environment. And the developer doesn't have to put in a lot of browser specific code.

IMHO, C and C++ projects should treat their environment specific code in a similar way.

As an aside, there's another issue where Java has some strength. It has a large number of published specifications on API's and other things. It's a great time saver to be able to implement wholely or partially an existing interface. For example, Java has published API's for commit/rollback transactions, threading and distributed computing, arbitrary precision arithmetic, a modem API, and so on.

Some of this can be pretty useless - the telephony interface or "JTAPI" didn't have an interface for fax/modems. Instead, I used HylaFAX, a C++-based faxing service that runs on Unix systems.


Stating the obvious since 1969.
[ Parent ]

#ifdef as a compiler directive (4.60 / 5) (#26)
by jesterzog on Fri Mar 09, 2001 at 07:35:55 AM EST

I don't really agree with you about the need for an #ifdef. You've mentioned some of my argument anyway, but I guess I set some of your points at different priorities.

In C and C++, #ifdef is really a compiler directive. When you compile the code, the compiler reads the compiler directives and uses them to figure out how it should be interpreting the code that you've written, whether it should be ignoring one bit or another bit, and so on.

This goes dead against Java's main marketing point of cross platform ability.

If you compile some Java code for an x86 running Windows using #ifdef's, what happens as soon as someone wants to take your compiled bytecode module and dump it on a sparc running Solaris? As I'm sure you're aware, there's a good chance that necessary chunks of code will be missing, because the #ifdef blocked it out at compile time.

Java doesn't do it's cross-platform thing incredibly well in the first place, but something like this would be abandoning its most hyped up goal. Worst of all, having it there would encourage inexperienced programmers (ie. most programmers) to use it whether they absolutely need it or not, without realising the implications. This would be bad. Imagine all the uninformed managers and businesses wanting to use the shortcuts all the time to get it to run in Windows only (marketable enough). The collection of Java apps in the world would be flooded with non-portable code.

Java is more of a runtime language, and what you might prefer over #ifdef is a more dynamic runtime type of #ifdef - so all the code is included, and the bytecode module will run quite happily on either an x86 or a sparc. The problem with this, though, is that your module might still not run on an alpha, or an x86 running Net-BSD, or whatever else someone comes up with in the next few years. Again, it goes completely against the Java write-once, run anywhere philosophy.

Java's good for some things, but you're always going to be restricted within the walls of the virtual machine runtime environment for anything to have a hope of being reliable. If you need to stray outside of it to get something done in a platform specific way, you might be using the wrong language for the job and should perhaps reconsider your design. Of course Java could be changed to allow for platform-specific code (and technically it already does if you start calling external modules), but the results of even having that available in the specs would be disastrous.

On a side note, I'm surprised you didn't mention overloading operators. Being someone who wrote quite a lot of C++ before I tried Java, operator overloading is something I really would have enjoyed.


jesterzog Fight the light


Your implied use of #ifdef is wrong (none / 0) (#30)
by GusherJizmac on Fri Mar 09, 2001 at 02:18:23 PM EST

I really really want to be able to compile out bits of code for production. Doing logging messages and assertions can be creat speedups for efficiency through the use of pre-processor directives. #ifdef isn't just for writing cross-platform code. And anyway, you can't be totally cross platform in Java when doing certain things like spawning external processes or file manipulation. Java gives you a "lowest common denominator" interface to the underlying system. I know that Java isn't designed for system programming, but why not make it as powerful as it can be?
<sig> G u s h e r J i z m a c </sig>
[ Parent ]
Good point (none / 0) (#38)
by khallow on Sun Mar 11, 2001 at 11:52:02 PM EST

I really really want to be able to compile out bits of code for production. Doing logging messages and assertions can be creat speedups for efficiency through the use of pre-processor directives. #ifdef isn't just for writing cross-platform code. And anyway, you can't be totally cross platform in Java when doing certain things like spawning external processes or file manipulation. Java gives you a "lowest common denominator" interface to the underlying system. I know that Java isn't designed for system programming, but why not make it as powerful as it can be?

This is an effective use of #ifdef. I've experienced code (not mine! :-) that ran significantly slower because of string comparisons in the logging code (e.g., "if (debugFlag.equals('true'))"). For intelligent code, the performance issue is somewhat questionable. IMHO, removing logging at compiler time is a convenience. I.e., I'd rather deal with a small performance hit from logging than figure out why a murky bit of someone's C code isn't running on my machine.

In the long run, I'm pragmatic. I'd rather have code that works. If that means that it's written cryptically in C, then that's too bad. After all, the price is always right for open source. OTOH, if I have to write or maintain code, then I won't mess around with the precompiler stuff.


Stating the obvious since 1969.
[ Parent ]

A baby can't eat meat neither should grown men (3.00 / 1) (#31)
by hardburn on Fri Mar 09, 2001 at 02:48:46 PM EST

So because a few newbies abuse it, those of us who know what we're doing are to be deprived of it?


----
while($story = K5::Story->new()) { $story->vote(-1) if($story->section() == $POLITICS); }


[ Parent ]
Yes you should be deprived of it (5.00 / 1) (#34)
by jesterzog on Sat Mar 10, 2001 at 01:09:13 AM EST

If you weren't deprived of that particular feature, Java would just turn into yet another "98% of people and businesses only care about Microsoft Virtual Machine and x86's" language.... which sort of defeats the purpose of having a multi platform bytecode-compiled language that's supposed to be cross platform.

Java should aim to be as forced cross platform as possible, because that's what it is. This is for the same reason that C enforces type checking and XHTML enforces end tags on elements. Otherwise what's the point of having a Java runtime interpreter that won't run 98% of Java programs?

If you want to change the language like that then go ahead, but please give it a different name so 98% of people businesses who don't know what they're doing don't get mixed up. It's just the way I feel, anyway.


jesterzog Fight the light


[ Parent ]
Language Advocacy (2.80 / 5) (#32)
by armag0n on Fri Mar 09, 2001 at 07:07:48 PM EST

I'm sick of all these stories being posted that deal with language advocacy and/or programmer language angst.

What is wrong with you people?

There are many languages out there, each is suited to different tasks. Find the one that does what you need and use it. Stop trying to turn one language into a panacea.

I would agree . . . (none / 0) (#52)
by hardburn on Tue Mar 13, 2001 at 02:47:44 PM EST

. . . except that no language I've seen does everything I want. Java is the closest I've seen yet. However, as jwz said, Java is only really better compared to the dreck languages we've been seeing today.

I've been looking for the language that screams out "Hey, I'm better then everyone else! Use me!!!" When I was first learning Java, I thought it might be it. It wasn't. I wrote this story hoping to help make it into my dream language.


----
while($story = K5::Story->new()) { $story->vote(-1) if($story->section() == $POLITICS); }


[ Parent ]
C is hardly cross platform for modern development (4.90 / 10) (#33)
by Carnage4Life on Fri Mar 09, 2001 at 09:58:09 PM EST

No, Java is arguably a better design then C++ because of its garbage collection, built-in multi-threading, and cleaner code layout

Bad intro. Garbage collection and a threading library don't have anything to with whether Java is a better designed language or not. It simply means Java has more extras than C++. The ease with which one can express and solve typical programming problems is usually the hallmark of a well designed language.

First, I should qualify my statement above about the uselessness of cross platform. Some may recall that there was a cross platform language long before Java; it's called "C". At a time when you were considered insane for closing your source, C was a great cross platform language.

C is not a cross platform language once you decide to do anything outside the ANSI standard. Manipulating directories, making GUIs, using sockets and multithreaded programming are four examples of things that most modern programs do that is not cross platform in standard C. On the other hand, all of these are cross platform in Java. What seems like hype to you is reality to thousands of developers working in hundreds of companies that are spending billions of dollars on software. My last job was at i2 Technologies and Java was a boon to them because they develop software on 6 different platforms (4 UNIX and 2 Windows) and not having to create seperate code bases for all 6 platforms has saved them millions of dollars. I just got back from an intervies with UBS Warburg in Chicago and they said the exact same thing.

An #ifdef may help non-Free Software, but not as much, since non-Free Software has the advantage that it probably knows what compiler will be used ahead of time and can thus not use tricks that that specific compiler can't handle.

Shitty compilers and/or library implementations is not a reason to kludge up the language with a construct like #ifdef. Anyway most Java compilers/JVMs are up to snuff on most platforms unless you restrict yourself to only using GNU software. I personally use IBM's.

String manipulation is also severely lacking. The library java.lang.StringBuffer and java.util.StringTokenizer are about all you get. StringBuffer allows you to append or prepend a String, or put data in an arbitrary location into the String. StringTokenizer lets you break a String into smaller Strings at a certain delimiter character. We might not need it to be as great as perl, but could we have something a little heftier, please?

There are lots of Free and non-Free libraries that add lots of text manipulation power to Java including OROMatcher, pat, and GNU RegExp. No language has all your needs in its standard library and expecting such is foolhardy. As long as third party libraries exist that can do what you want, why complain?


Java a low level better structured C++ (none / 0) (#36)
by arturo on Sat Mar 10, 2001 at 10:06:04 PM EST

Java is not a great language. If you want to play with a really *BIG* one see OCaml. Believe me!
Arturo Borquez
[ Parent ]
It's not so simple (5.00 / 1) (#66)
by Nelson on Mon Mar 19, 2001 at 11:27:51 AM EST

Bad intro. Garbage collection and a threading library don't have anything to with whether Java is a better designed language or not. It simply means Java has more extras than C++. The ease with which one can express and solve typical programming problems is usually the hallmark of a well designed language.

I agree that garbage collection should be implemented as an extra that the developer or end user can control but to implement a fully modern garbage collector you need to have it designed in to the language.

Tell me how to implement a concurrent generational garbage collector in C++? How about a mark and sweep with compression? It's possible if you write all your code in a limited way, but then you're restricting the language. I think it's probably possible to replace all the assignment operators and write your own allocation/deallocation functions and do it, but not easy and something that you application needs to have in its design. With C++, garbage collection is pushed in to the application design which essentially makes it intelligent allocation and deallocation and not garbage collection anymore. You can't garbage collection arbitrary C++ code. You need to design the language with that in mind if you wish to have it and that's where the benefit is with some of the newest and best garbage collectors that are nearly impossible to implement effieciently without being designed in from the start.

With threading the argument is a little different. With Java and Ada, the language has threading semantics defined. To implement those languages with the proper semantics you have to follow their threading semantics regardless of the system. With C++ the threading semantics are defined by the system that the compiler is being implemented on. What happens on the system when one process issues a yield() can be defined. Implicite semaphors (monitors) can be defined. Can this stuff be duplicated in C++? Sure, but you have to do tricks and they may be different from system to system. What about the language model and stack behavior with threads? User threads vs. system threads? Garbage collection and concurrency are to some extent extras but to have portability and any level of consistency from system to system they need to be defined in the language.

[ Parent ]

Show me the code (2.00 / 1) (#42)
by mickedata on Mon Mar 12, 2001 at 04:09:59 PM EST

When do I need #ifdef in Java? Show me the code.

If you like #ifdef, use #ifdef (4.50 / 2) (#43)
by ianb on Mon Mar 12, 2001 at 05:16:16 PM EST

If you really want to use #ifdef and company, then do so. Is there any reason why cpp doesn't work just as well on Java source as C source? It would help solve some of the problems people have with the lack of typedefs as well.

The cpp run isn't built into compilers, but all you have to do to fix that is make a wrapper script. Empower yourself!

Or try m4 (3.00 / 2) (#49)
by srichman on Tue Mar 13, 2001 at 12:21:05 AM EST

Which doesn't claim to be language specific at all.

[ Parent ]
if you want $ifdef... (4.50 / 2) (#44)
by Bridge Troll on Mon Mar 12, 2001 at 06:15:09 PM EST

This is a point that many make about Java. No one ever seems to mention that you can run "cpp" on ANY file. It just ignores any lines that don't start with the "#". WindowMaker (AfterStep maybe?) uses it in it's config files, for example. What is so hard about typing "cpp foo.java > outfile" before compiling anyway?


And besides, pounding your meat with a club is a very satisfying thing to do :) -- Sleepy
confirmation (4.00 / 1) (#50)
by hany on Tue Mar 13, 2001 at 07:38:02 AM EST

I can confirm "interoperability" of cpp with .java sources. All it takes to use #ifdef and alikes in .java sources is just little tinkering with Makefile :) .

I'm using "Makefile + cpp + javac" for about 2 years without much problems (only line numbering in stack dumps is sometimes not "exact").

And I'm looking forward to use "Makefile + cpp + gcc-java" to produce binary code from java sources.


hany


[ Parent ]
not exactly (none / 0) (#53)
by mikpos on Wed Mar 14, 2001 at 11:06:40 AM EST

This is a common misconception. cpp does not just ignore lines that don't start with '#'. Everything in a file processed with a C pre-processor, yes, even stuff in an '#if 0', must be comprised of valid C tokens. Otherwise it is a syntax error.

I'm not exactly sure if this would cause any problems with Java or not, seeing as Java decided to stick fairly close to the C language in terms of syntax style. I'm thinking there might be problems with punctuators, but it's been a while since I've used Java.

Anyway, there is a project on Freshmeat (whose name escapes me) which is a generic "C" pre-processor. It recognises all C pre-processor directives, but does not require valid C tokens otherwise. If you have troubles, you could do that, or preferably use a real macro language like M4 instead.

[ Parent ]

Limited method overloading (none / 0) (#55)
by swr on Wed Mar 14, 2001 at 07:13:36 PM EST

I realize I'm entering the discussion a bit late, but I've just encountered a little annoyance that seems relevant...

Suppose you want to implement something similar in form to java.util.Properties (which will be my example for this post). There are some little things that would be convenient to do, but the Java language won't let you.

One of the things I would like to do is have two methods of the same name (for consistency) but one declared static (a convenience, for operating on an intelligently chosen default), the other non-static. Look at java.util.Properties, there is a static method called getDefaultProperties(). Wouldn't it be nice to have a static Properties.get("foobar") that you could call when you want to access the default properties, instead of having to do the Properties.getDefaultProperties().get("foobar") thing? But that is impossible in Java because you can't have a static and non-static method of the same name.

Also, wouldn't it be nice to have methods returning values of different types, depending on what type the caller wants? Going back to the java.util.Properties example, suppose you want to get a property that is always an integer, as an int. The get() method returns a String, which you must then turn into an int with Integer.parseInt(). If you were implementing a class of similar form to Properties you could have a method called getInt() that calls get() and does the conversion for you, but it's another method name for the devloper to remember, and another name for what really is the same function.

So in the end, we have to do int foobar = Integer.parseInt( Properties.getDefaultProperties().get("foobar") ); instead of simply int foobar = Properties.get("foobar"); even though the latter is completely unambiguous.

The problem of course, is that Java only looks at the number and types of the arguments passed to a method, ignoring the other information available to it.



ambiguity (none / 0) (#64)
by Puchitao on Sat Mar 17, 2001 at 03:01:02 PM EST

The reason you can't have overloaded functions that differ only in the type they return is that the compiler doesn't always have enough information to figure out which one you meant. Your example,

int foobar = Properties.get("foobar");

is unambiguous, but say, for example, that "Properties.set()" (or whatever they call it) takes first the name of the property and then either an integer or a string, which it assigns to said property. Something like:

Properties.set("foo", Properties.get("bar"));

is thus ambiguous; the compiler won't know which versions of "get()" and "set()" to choose. Now, in this example, there's not much of an error condition if the compiler chooses integer over string, or vice versa, but consider:

Properties.set("foo", Properties.get("bar") + Properties.get("baz"));

Here, "+" could be interpreted as either addition or string concatenation; thus if bar = "123" and baz = "456", foo will either be "579" or "123456", based on which functions the compiler chooses.

I suppose you could introduce (and require) some keyword like "default", so that the programmer could specify which version is chosen in ambiguous situations, but I don't think it would be worth the confusion (and possibly, library rewriting) it would entail.

Perhaps we can do *snappy fun* with you everytime! -- Orz
[ Parent ]
Explicit casts are already required (none / 0) (#69)
by swr on Tue Mar 27, 2001 at 02:13:57 AM EST

Something like:
Properties.set("foo", Properties.get("bar"));
is thus ambiguous; the compiler won't know which versions of "get()" and "set()" to choose.

But such ambiguity already exists!

Looking again at java.util.Properties, there are two list() methods accepting a single argument: one accepting a PrintStream, the other accepting a PrintWriter. Now suppose you have something like this:

Properties.getDefaultProperties().list( someHashtable.get("thePrintStreamObjectIPutHereEarlier") );

That is abiguous. Hashtable.get() returns an Object. How is the compiler to know that you want the PrintStream version of Properties.list() instead of the PrintWriter version? It doesn't. The above will not compile. You need to make an explicit cast:

Properties.getDefaultProperties().list( (PrintStream) someHashtable.get("thePrintStreamObjectIPutHereEarlier") );

The above will compile fine. If the Object returned by the Hashtable.get() method is not of the PrintStream type, a ClassCastException will be thrown at run time. Sure it would be nice if the type checking could be done at compile time, but that just isn't possible in some cases.

In your example, the ambiguity can be solved in exactly the same way:

Properties.set("foo", (String)Properties.get("bar"));



[ Parent ]
re: explicit casts (none / 0) (#70)
by Puchitao on Wed Apr 04, 2001 at 03:19:36 AM EST

Such an ambiguity does not already exist; the compiler knows exactly what version of Hashtable.get() to choose. There is only one function that it can choose from: the one of type String -> Object. Whether you choose to downcast this Object to a PrintStream or a PrintWriter doesn't make it a different function; the same code is executed either way.

This is a much different situation than having two functions, one of type String -> PrintStream and the other of String -> PrintWriter. Casting won't help in this situation; the compiler will know which version of Properties.getDefaultProperties.list() to use, but as to Hashtable.get(), there are still two choices.

Your solution,

Properties.get("foo", (String) Properties.get("bar"));

does not solve the problem I specified. Had I said that Properties.get() were a function from Strings to some (if any) common ancestor of Int and String, then you could solve the problem by casting. But that is not the case I outlined. If multiple functions could have the same name and argument types but different return types, then a new language construct (different from casting) would need to be added to the language.

A much better solution to your hashtable problem, of course, would be the introduction of generic types. Hopefully, GJ or some equivalent is worked into the next major Java release. Parameterized types would render this problem moot; the Hashtable type would become rather Hashtable<PrintStream> (provided of course you're only stowing PrintStreams in there), and the compiler wouldn't need any hints to figure out that get() was a function from Hashtable<PrintStream> to PrintStream. The lack of proper support for generics is the big reason such ugly hacks (like casting to and from Objects in order to use container classes) were necessary. Now, if only "generics" had buzzword potential, maybe Sun would put it into Java... ;)

Perhaps we can do *snappy fun* with you everytime! -- Orz
[ Parent ]

Operator overloading (none / 0) (#57)
by salkin on Thu Mar 15, 2001 at 12:41:32 AM EST

The single feature I miss most from C++ is operator overloading. I cannot understand why this simple feature was overlooked. Yes, it places a burden on the library writer. The payoff for this is the far simpler code that can be written using the library. I think that simpler and easier to read code is the largest element of lowering maintenance costs for software.

The real trouble with Java (4.00 / 1) (#61)
by tchaika on Thu Mar 15, 2001 at 03:59:17 PM EST

On a more abstract level, the key problem with Java is that it uses the syntax from an obsolete/niche (at least it -should- be) structured assembler - C, that just isn't suited to modern programming (outside of writing kernels, drivers, and other things it was originally designed for).

It ignores developments in programming language design of the last 30 years, as well as matters of convenience.

More specific:

For example, let's pick string handling. Java has the most limited String class that I've seen in years. A 'pragmatic' programming language should include regular expressions and compentent special-case syntax for string manipulation. The String class would get a C+ if a second year undergrad handed it in as their C++ programming assignment, as would a lot of the Java libraries.

Lets add to this list - natural, simple syntax for mathematical functions (esp. complex numbers), file processing, construction of new data types, manipulation and traversal of compound data types and collections, generic programming (templates or some other mechanism).

Gripes:

Data type system with no clear rationale (primitives vs. native types). Think of the convenience if everything was an object [discounting nebulous claims of improved performance with primitives here - it's not worth the penalty].

The heinous, broken, packaging and classpath system (a.k.a. You Never Know Quite What You're Going to Get).

No design-by-contract (if you don't believe the value of this, try it on production code sometime).

Unbelievably lame collection/container classes.

Unbelievably lame date/time manipulation, which ties into the miserable history of many of the library classes, of subtle changes in meaning and working, bugs cleaned up and new ones introduced, depending on what JVM is being used.

Broken and random exception heirarchy, with bugs in the specification.

Broken and random threading library. Yes - synchronized() is broken.

Utterly broken floating point - don't use it for any serious numerics, it's worse than Excel.

Incomplete documentation. Microsoft's APIs may traditionally be heinous but at least all the subtleties of their behaviour are usually documented. Javadoc contains stupidities like "this function adds a day to today's date". Great - what happens on the last day of the month, does it wrap around to the next month? Who knows. [Granted, documentation of the date/time stuff has improved in recent versions].

Bad, bad, horrid performing GUI libraries. Why does resizing my JBuilder window make my Pentium 3 PC respond slower than Borland C++ did on a 486DX/33 with no graphics accelerator?

Invaliditiy of bytecode. Why on earth write a JIT compiler? Instead, concentrate on the option to compile to binary. If you can support Java on platform XYZ, obviously you're capable of compiling to XYZ's native architecture. Bytecode caters for the 5% of cases where true, dynamic porting to an unknown platform (i.e. some random web browser) is needed. Most Java code runs on the same server and never gets ported anywhere, except maybe from NT dev workstations to production UNIX boxes.

So why the popularity of Java? It bundles basic threading and networking functionality, and support for distributed computing, and web standards, into an easy to use, cheap, and familiar package. It has no inherent compelling architectural advantage.

But you can say at least - C++ makes it damn near impossible to not make a mistake (who would claim their code is absolutely perfect about memory leaks etc if it combines operator overloading, exceptions, and a few other goodies). If you've got it all straight, you've wasted time. Java OTOH makes you have to work hard to actually make a mistake (e.g. memory leak, out of bounds array reference).

D'o (none / 0) (#63)
by tchaika on Thu Mar 15, 2001 at 04:03:09 PM EST

OK so misspelling 'competent' doesn't do my argument any favors - apologies.

[ Parent ]
Gripes (none / 0) (#68)
by hardburn on Fri Mar 23, 2001 at 11:15:12 AM EST

For example, let's pick string handling. Java has the most limited String class that I've seen in years.

The standered libs are, yes. Check out the gstring library.

Think of the convenience if everything was an object [discounting nebulous claims of improved performance with primitives here - it's not worth the penalty].

This is annoying at times, but I think it's still worth it.

Broken and random threading library. Yes - synchronized() is broken.

Could you elabroate? I've found Java threads to be much nicer then a lot of the crap I've seen.

Incomplete documentation. Microsoft's APIs may traditionally be heinous but at least all the subtleties of their behaviour are usually documented.

Getting better, as you mentioned. Still, I like the fact that Javadoc is a standered part of any Java SDK. There are C/C++ equivelients which do the same thing, but nothing standered.

Invaliditiy of bytecode. Why on earth write a JIT compiler?

Exactly. Whats the big deal recompiling stuff every once and a while? Byte code has it's use, but normaly, just put it in machine code. This is why I like GCJ.


----
while($story = K5::Story->new()) { $story->vote(-1) if($story->section() == $POLITICS); }


[ Parent ]
C Constructs in Java (none / 0) (#65)
by depsypher on Sat Mar 17, 2001 at 04:54:33 PM EST

If you ever wondered how to typedef, implement a union or enum (with type safety) in Java, check out audioinfusion.com/cConstructsInJava.txt

Personally I especially miss having an easy way to do enums in Java. This article describes a pretty good hack to get it into the language.

And to think we could have had Self... (none / 0) (#67)
by zak on Mon Mar 19, 2001 at 04:25:11 PM EST

Check out Sun's "other" research language, which they killed at 1995 (probably after deciding to go for Java, the "let's make it look like C++, and oh let's break pure object orientation while we're at it" option).

http://www.sun.com/research/self.

The research papers are particularly interesting - the JIT and dynamic profiling/recompilation tricks have supposedly only been re-introduced in HotSpot (some 4/5 years after the Self implementation). Maybe it's time for a revival :).



How Java Should Be | 70 comments (64 topical, 6 editorial, 0 hidden)
Display: Sort:

kuro5hin.org

[XML]
All trademarks and copyrights on this page are owned by their respective companies. The Rest 2000 - Present Kuro5hin.org Inc.
See our legalese page for copyright policies. Please also read our Privacy Policy.
Kuro5hin.org is powered by Free Software, including Apache, Perl, and Linux, The Scoop Engine that runs this site is freely available, under the terms of the GPL.
Need some help? Email help@kuro5hin.org.
My heart's the long stairs.

Powered by Scoop create account | help/FAQ | mission | links | search | IRC | YOU choose the stories!