6 ms·
Ever since the JDK 1.0 days, I didn’t get why there was this C/C++ carry-over inconsistency of manually-boxed types and non-Objects primitive types separated fr
by himom 8y ago
Ever since the JDK 1.0 days, I didn’t get why there was this C/C++ carry-over inconsistency of manually-boxed types and non-Objects primitive types separated from Objects. A type hierarchy, patterned similar to Ruby’s as an example, makes the most sense:
- Object contains a Class that it derrives from (no BaseObject or Modules)
- Class is an Object
- String is an Object
- Boolean is a two-value singleton of true and false
- Number is an abstract subclass of Object
- Decimal and Integer are abstract subclasses of Number
- Float, Double,
LongDouble, BigDecimal are concrete subclasses of Decimal
- SignedByte, Byte, Short, UnsignedShort, Int, Unsigned, Long, UnsignedLong, Char, BigInt are concrete subclasses of Integer (or U/I/F## types reminiscent of Rust instead of C type names)
and so on.
Then there is no boxing/unboxing of simple types or literals because they are one-and-the-same, and no there’s no confusion about how to interact with any truly generic type of value.
- gamegoblin 8y agoThere is a huge performance and memory difference between boxed and unboxed types.
- makecheck 8y agoJava has been around a long time now and machines were a lot slower in the JDK 1.0 days so they were probably considering the poor performance of requiring a minimum Object overhead. And the distinction has worked elsewhere. Objective-C for instance has an NSObject in Cocoa but the language is a proper superset of C and has no problem with plain types. (Granted if you use low-level objcruntime functions, it will be more complex to pass in C data types that are not objects but they still work.) Despite not requiring Object everywhere, early Java had a frustrating tendency to use Object for many basic things, seemingly requiring boxing and casting more than it should. (At least with Objective-C++ you had the option of some std:: container of plain data, if you didn’t want to wrap in some NS<container> type.) Both Java and Objective-C ultimately changed the syntax to allow type specifications in containers to compensate.
- bluejekyll 8y ago> early Java had a frustrating tendency to use Object for many basic things, seemingly requiring boxing and casting more than it should. Early Java didn’t have Generics. With Generics, using Object instead of genericizing the type would be an anti-pattern in modern Java. A lot of warts in Java are being removed.
- pjmlp 8y agoAlmost correct, except that Sun ignored the prior work with languages like Eiffel, Sather, Modula-3, Oberon variants. In Eiffel for example, you can declare what is the default behavior (reference or value type), and then any user of the type is able to still override it at declaration site.
- AnimalMuppet 8y agoPerhaps not "ignored". Perhaps just "didn't follow". Even if it would be your preferred way for a language to do things, not doing so isn't necessarily wrong.
- pjmlp 8y agoMaybe, but the fact that they feel the market pressure to add them to stay competitive on modern hardware vs what .NET did a few years later, means it wasn't properly right as well.
- antonvs 8y agoJava was released in Jan 1996, .NET in Feb 2002. A lot changed in those six years. .NET built on the shoulders of the giant that was Java, as well as the lessons from the globally accelerating development enabled by the internet. Those early decisions may not have been technically right in some sense, but technical considerations are not the only factor.
- pjmlp 8y ago
- MaxBarraclough 8y agoI've heard theorists say exactly this a number of times before. The reason Java isn't a 'pure' object-oriented language is simply performance. Suppose everything - even every int - is heap-allocated. You now need a very sophisticated JIT compiler (as in, better than any we have today), or it's going to run dog slow. Having a huge number of needless allocations happening at every step is going to: 1. Slow things down by doing vastly more heap allocations that you otherwise would (even with Java's ultra-fast allocations) 2. Slow things down by doing violence to your code's locality and cache behaviour, because your ints no longer live in the stack 3. Slow things down by doing violence to your code's locality and cache behaviour, because Java objects are bloated compare to raw ints 4. Slow things down by hugely increasing garbage-collection pressure If Gosling had taken that route, we wouldn't be talking about Java today.
- pjmlp 8y agoAgreed, but they could have had a bit more value types love and AOT on 1.0 days, given the ongoing research of GC enabled languages for systems programming all the way back to CLU and Mesa/Cedar. Oh well, at least in couple of years we will have them.
- MaxBarraclough 8y agoAgree. This is something .Net does well.
- marcosdumay 8y agoLanguages do not need a 1 to 1 relationship between the storage medium of a value and the interface it exposes to a programmer. Java's situation is even worse because it's a compiled language that does not need a JIT or even much sophistication from a compiler to keep a single hierarchy on its type system. I suspect the reason Java did it was to not surprise C++ programmers. Solely dictated by marketing, not by technical reasons.
- MaxBarraclough 8y ago> Languages do not need a 1 to 1 relationship between the storage medium of a value and the interface it exposes to a programmer. Sure, but that doesn't excuse the well-documented 'sufficiently-smart-compiler fallacy'. The performance improvements that can be had by the escape-analysis/object-inlining family of JIT compiler optimisations, are considerable, but even today, production JVMs don't do a very good job. It's not an easy problem to solve well. > I suspect the reason Java did it was to not surprise C++ programmers. Solely dictated by marketing, not by technical reasons. I sincerely doubt it. You're wrong to dismiss the performance question.
- cityhomesteader 8y ago> Then there is no boxing/unboxing of simple types or literals because they are one-and-the-same, and no there’s no confusion about how to interact with any truly generic type of value. It's simply performance/space. It's why value types still exist in Java, C#, etc. > A type hierarchy, patterned similar to Ruby’s as an example, makes the most sense: The type hierarchy doesn't matter. That's what C# does. It has one unified type system where even int, double, etc all ultimately derived from Object and it still have value types. It's a language/compiler design issue. > Then there is no boxing/unboxing of simple types or literals because they are one-and-the-same, and no there’s no confusion about how to interact with any truly generic type of value. In ruby there is no unboxing, but you could argue that all simple types are "lightly boxed" because they are objects by default.
- cup-of-tea 8y agoCommon Lisp has exactly this and it's a damn sight faster than Ruby and Java. Java is the way it is because it was designed to be marketed from the start. And that marketing is the only reason it is popular.
- de_watcher 8y ago> this C/C++ carry-over inconsistency of manually-boxed types and non-Objects primitive types separated from Objects C++ allows user-defined value types that will behave like fundamental types. And it has raw pointers/references to them. Among all, there was a user-defined value type invented: the shared pointer (which works kinda like a GC, or exactly like a GC if you implement it and throw RAII out of the window). Java took only the fundamental types and a shared pointer. No wonder that there are some parts missing.