@Riven (Reply #111) - That is extremely disappointing. Taking that particular course of action is like replacing the head of a hammer with an extra claw because someone was trying to remove nails using the wrong side of the hammer. Like I said, the copy constructor and intern() method are there for a reason. It must have been an intentional design decision. I had faith that whoever had the authority to make that decision would understand the tool they were attempting to modify a little better than that. I almost wrote a long rant about developers thinking they can add new features in a vacuum without thinking about their side effects or incompatibility with stronger features of a language. It’s even worse that they would disregard backwards compatibility for something as dumb as that. (It’s not considered a memory leak if you set a StringBuilder or Collection’s capacity too large after all; you’re supposed to copy and trim them too if you’re going to store them long term and need to conserve space) but not sacrifice backwards compatibility for serious annoyances like type erasure or lack of unboxed primitive parameter types in Generics.) I imagine there are less controversial and more practical changes you could make if backwards compatibility could be ignored everywhere.
@Princec (Reply #141)
- That’s nice, but would it be necessary if the default visibility of fields and methods were better?
- That would be pretty scary to encounter in the tall grass without any pokeballs. Up casting seems to be relatively rare with Generics in my experience of reading and writing code. It’s also a symptom of other problems with class designs. Maybe not worth losing the ability to catch certain errors or read the programmer’s intent from only the source code (vs code + comments).
- I don’t know what that is, but I already said some of the proposals scare me.
- Thought that was already the case. It definitely should be if it’s not though…
- I don’t know what you mean, but it reminded me of an idea I once had. I think I gave up the idea because it looked too much like multiple inheritance. What about a mustoverride keyword or annotation for non-abstract class functions? Occasionally I’ve wanted to force a sub class to explicitly override a method (even if it only called the super function) but couldn’t use abstract because I wanted a default function and a non-abstract class. This would have been useful for me in things like initialize(), reset(), dispose() methods in some game engines.
- That’s been near the top of my wish list ever since I started doing A-star searching and complicated vector calculations. I thought about hacking together a translating compiler that added them using groups of primitives for assignments and function calls and ByteBuffers or parallel arrays for struct arrays, but I don’t know how you could return multiple values from a function. I’d rather that be supported in the JVM for performance reasons and to avoid another source of type erasure in addition to Generics.
- Don’t know if that’s good or unhelpful. Does that require 5?
- I can’t envision what features would be needed or what syntax could be used, but it’s probably worth standardizing.
@Princec (Reply #146)
That’s because C++ uses special constructors overloaded assignment operators (?) to handle conversions like that. It makes less sense in Java’s (reference centric) type system than in C++'s (value centric) type system. It’s a different style of coding. C++'s type conversions make code much more complicated without providing much benefit. Plus, your example would not work in C++ either. You have to call the c_str or copy functions, although you could say str = char_array;
instead of string = new String(charArray);
if the assignment types were swapped.
@delt0r (Reply #147)
Not exactly. It’s much worse. Calls to virtual functions on C++ object pointers behave nearly the same to calls on Java references to Java objects. (String)obj
does not change obj, it just asserts that it is the type String
. Primitive casts in both languages work the same way. Casting a double to a long truncates the number in both cases. You have to do something else to reinterpret the bits in the double type as a long type. Primitives in C++ can be turned into any other primitive using implicit casting. (Groan.) Other conversions can also be made implicit, but you have to create an overloaded assignment operator function for each type. C++ complicates things by allowing you to do both and hiding the meaning of type conversions. There’s something called slicing, where passing a type by value will give you a different version of the data and different virtual functions than passing the sub class to a function as a reference.
Speaking of casts as operations. I would actually like to see things like (int), (short), (long), etc replaced with int(x), short(x), long(x), etc. And conversion from floating points to integers be done by global floor(y), ceil(y), and truncate(y) functions. Primitive casts are basically functions anyway, and sometimes it would save two keystrokes. :persecutioncomplex: But what about getting rid of casts entirely? Maybe you could find alternatives to up casting or eliminate the need to do that. No class cast exceptions, no instanceof, and you could pass a reference to a ReadOnlyType and know it could never be cast to a ReadWriteType. I’m not sure about that, though.
@Spasi (Reply #151)
I’ve programmed in languages with and without semicolons. It’s not a deal breaker either way. When it’s habitual it doesn’t waste time and can be used as a sanity check and a hint to help your editor format your code as you type. Line continuation characters and writing multiple statements on one lines was a little distracting without having that habit, but it was a long time ago for me.
You’re right about right hand type declarations. The main example I can think of is separating function modifier from return type modifiers (like const), but not many languages need that. Things like fun or var could be dropped in some languages, but the syntax highlighting probably helps.
Any language addressing null “safety” is a mistake. It only means something bad in C and C++, and the billion dollar mistake in those languages were letting people treat pointers like ints. C++'s is one of very few languages that define objects by there value instead of their identity. Most variables have an empty/default value… I guess the rational behind saying null is a bad thing is because it has different semantics as a “default” pointer than the standard default values. Getting rid of “null” doesn’t get rid of the possibility of 0x0 being invalid memory, or 0x01 being equally invalid, or unaligned addresses being incorrect, or having dangling pointers, or having dead pointers, or pointers to incorrect variables, or pointers that accidentally get assigned an int value. It’s one of those things I’ve thought over a lot but still can’t see a convincing argument from other points of view. When you have a language which does NOT mix value and pointer semantics and uses exact references, you don’t have a problem. You tend to have an entirely different set of problems in those languages. In that case it’s normally related to using uninitialized values or not obeying the preconditions of a function.
NullPointerExceptions are the type of thing that annoys you when you’re a total noob to a language. Then you realize that using meaningless dummy objects, breaking preconditions of a function, and forgetting to assign a value to a variable are a bad thing no matter what language you’re using.
@princec (Reply #153)
Can you explain why checked exceptions are a problem? I’ve heard it a lot, and everyone seems to gloss over the fact that runtime exceptions (which are the only ones which are actually controllable and preventable by the programmer) don’t need to be checked. I’ve seen it in every anti-Java rant, but the argument that the programmer is a big boy seems to be a straw man… given that they pretend all exception types are checked. We’re grown ups. It’s not like connections ever get dropped or other programs modify the file system while my own program is running.
Also glossed over is the fact that it’s easy to say “throws IOException” for functions that actually do have a chance of doing that. Just attached the appropriate throws clause to all your help methods and put your try catch block in your one entry method that in turn calls IO related helper functions. Plus there’s the fact that you can do try-finally. Also never mentioned. It’s not in C# or C++ or anything else, so let’s ignore that it’s in Java. The problem is that most places where you have to handle a checked exception in Java you also have to handle in any language. It’s actually shorter to do using throws or try-finally than it is to do with a ton of if statements or lots of try-catch-rethrow’s.
Wow that’s long. And I still haven’t posted my own wish list / annoyance list.