In C# I can create a dictionary that has ints as keys and strings as the values. I can then look up the value of any string using the int key. Dead simple. If I want an array I can use something like myDictionary.Values.ToArray() and I get all of the values in a string[], because it knows what type everything is. That's what generics are _for_.
Providing I am using Java correctly, I'm creating a HashMap<long,string> (and it has to be a Long, because you can't use primitive types, for some bizarre reason), and then the "put" method does, indeed, mandate that I'm using a Long and a String, but the "get" takes an object, and the toArray returns an array of _objects_. What the fuck? What is the point of specifying types if the compiler is going to just ignore them?
I feel terribly spoiled by working with a language which does what you bloody well tell it to, rather than being a half-assed job to give you the appearance of doing something useful without finishing the job.
Providing I am using Java correctly, I'm creating a HashMap<long,string> (and it has to be a Long, because you can't use primitive types, for some bizarre reason), and then the "put" method does, indeed, mandate that I'm using a Long and a String, but the "get" takes an object, and the toArray returns an array of _objects_. What the fuck? What is the point of specifying types if the compiler is going to just ignore them?
I feel terribly spoiled by working with a language which does what you bloody well tell it to, rather than being a half-assed job to give you the appearance of doing something useful without finishing the job.
no subject
Date: 2012-01-30 02:11 am (UTC)That is pretty silly. I'm sure it has something to do with backwards compatibility as that was a feature that didn't even exist until 1.5, but yeah.
Now I am really curious why it was done that way.
no subject
Date: 2012-01-30 05:44 am (UTC)I know you're going to hate this - but if you implemented a small class that does what you want, it'll get Java more C# like, and you wont need to write it again - but I know the answer would be "I shouldn't have to!" =)
no subject
Date: 2012-01-30 08:28 am (UTC)I could write something better, but I think I'll just get my coding done for now. If I'm forced into doing more Java work then I can think about it later.
no subject
Date: 2012-01-30 07:28 am (UTC)Surely you can use HashMap
Surely you can use HashMap<Integer,String> instead of <HashMap int,String>?
And don't you need to be using getKey() and getValue()?
I would have expected that array of objects to be set entries where you could get the values by going andysArray[0].getValue() -> Returns string.
Depends what you're trying to do on the array side, but if you wanted the values of the Hashmap in an array I guess it would be something like andysHashMap.getValues().toArray(); I would *hope* that would give you an array of Strings.
no subject
Date: 2012-01-30 08:25 am (UTC)And the method I was looking at is:
http://docs.oracle.com/javase/7/docs/api/java/util/HashMap.html#get%28java.lang.Object%29
which isn't typed for its parameter.
And no, if you call values() then you get a Collection<V>, which has two overrides for toArray - and neither of them automatically know the type, one of them returns an array of objects, and the other requires you to pass in an array of the type you want.
no subject
Date: 2012-01-30 09:24 am (UTC)The primitives not being objects is... a quirk. And I agree, it's pretty freaking dumb.
/J
no subject
Date: 2012-01-30 12:17 pm (UTC)no subject
Date: 2012-01-30 12:24 pm (UTC)The problem with the Java ones is that they didn't change the JVM to support Generics, so there's all sorts of jiggery-pokery to make them work well. I assume they didn't want to lose backwards compatibility at the time.
no subject
Date: 2012-01-30 02:08 pm (UTC)But ... how on earth did they manage to set things up so that the virtual machine had to have specific support for this sort of detail in the high-level language's type system?
I can see that the JVM has to be at least a little higher-level than anything looking like a real CPU architecture, since it has to implement bounds checking and garbage collection and so on and hence has to retain at least some semantic information about what is and isn't a pointer and what size objects are and so forth. And I'm prepared to accept that there might be some other constraint along the same sort of lines that requires the JVM to know about and collude in details of the language(s) being compiled to it.
But even so ... surely any feature of a type system to make it implement parametrised types could be completely desugared at compile time, by converting every referred-to instance of such a type (e.g. HashMap<thistype,thattype>) into a separate concrete type (say, __AutoGeneratedHashMapType312), and likewise for methods taking an incompletely specified type argument? More or less the same way C++ compilers do it. I don't see why the JVM should need to know that a bunch of __AutoGeneratedTypeX things all originally stemmed from the same twenty lines of the source code; as long as it can execute it, that's surely enough?
no subject
Date: 2012-01-30 02:15 pm (UTC)However, having it in the underlying bytecode/IL means that when you are calling things written in one language from something written in another language, they both understand. If you call a List<String>.Add() from any .Net language they all know that it only takes a String, because they all understand generics. In Java they use type erasure, so to any non-Java language it looks like a standard List, and will take anything you like.
Also, generics are _not_ templates. C# does not generate a separate class for List<String>, List<int> and List<Doggie> - they are all the same class, with a type annotation.
no subject
Date: 2012-01-30 02:22 pm (UTC)Ah, I see. It wasn't obvious to me from your original post that you were trying to use multiple JVM-targeted languages, so that might be what I missed.
(Though if you enshrine your type system in the VM, that may improve interoperability between languages targeting the VM, but I'm guessing it also limits the languages that can target that VM? Particularly excitingly cutting-edge functional languages with really advanced and weird type systems...)
C# does not generate a separate class for List<String>, List<int> and List<Doggie> - they are all the same class, with a type annotation.
This probably is where I should go and read up more carefully, but ... is there a visible consequence within C# itself of drawing that distinction, or is it only relevant when you're looking at the compiled bytecode?
no subject
Date: 2012-01-30 02:26 pm (UTC)And yes, the choice of JVM/IL/etc definitely limits you. If you want to call a method that uses generics then you need to support generics. The other way around, of course, you can just make everything an object and do it dynamically :->
no subject
Date: 2012-01-30 02:31 pm (UTC)The distinction between Foo<bar> and Foo<quux> being different classes and the same class with an annotation. Surely even in the latter case I'd want my language to ensure they were assignment-incompatible, for instance.
(Or is there some exciting case involving asymmetric type compatibility, such as being able to assign only one way between Foo<SomeBaseClass> and Foo<SomeSubclass>?)
no subject
Date: 2012-01-30 02:41 pm (UTC)Also, what with code being compiled from IL on the fly, it means you only have to compile one set of code rather than compiling (and storing in memory) every kind of List that's in use.
There's a good starting point here:
http://msdn.microsoft.com/en-us/library/c6cyy67b%28v=vs.80%29.aspx
As to your last point, I think this ties into some of the work in C#4 on covariance and contravariance:
http://blogs.msdn.com/b/csharpfaq/archive/2010/02/16/covariance-and-contravariance-faq.aspx
no subject
Date: 2012-01-30 07:41 pm (UTC)Not sure what you mean here. If you instantiate a std::vector templated on the same type, it's the same type in both libraries.
There is no automatic way of assigning a vector of one type to a vector of a different type.
no subject
Date: 2012-01-30 07:45 pm (UTC)no subject
Date: 2012-01-30 07:54 pm (UTC)no subject
Date: 2012-01-30 08:04 pm (UTC)If I was a C++ developer then I'd be tempted to play around with what happened if I had multiple versions of libraries and tried to make them work together. But I'm not, so I shan't!
no subject
Date: 2012-01-31 08:44 am (UTC)I like being a C++ programmer, but I certainly don't recommend it. :)
no subject
Date: 2012-01-31 11:25 am (UTC)I program in C++, but I'm still distressingly ignorant of this sort of compiler stuff. I think we may, here, have hit the inter-cultural misunderstanding...
I'm not sure you can automatically do that in C++. Trying to think it through, it seems like, if you want Library A and Library B to make function calls to each other then they need to be the same in all sorts of little binary things like "when you make a function call, what order do things go on the stack" and "how many bytes is an int" and "what name does the compiler use internally for this user function" let alone "how a vector of ints is normally stored in memory" etc, etc. And in Java and .NET this just automatically works, because all of those things are specified in the standard (or not even needed because everything is bytecode). But in C and C++, the language makes no guarantees whatsoever about those things, it's all agreed (or not) by conventions between compiler vendors, but it's not part of the language standard. And I don't know how wide those agreements are, though it's the sort of thing you need to know if you write libraries.
If so, the advantage of java is that you CAN use a library produced by someone else and it will Just Work. But the advantage of C++ is that if you DO manage to get it to compile, you have a higher chance that the vector of ints will produce no code whatsoever -- it will be compiler optimised to a pointer and an array offset used directly by each place that accesses it. However, this only works when everything is compiled by the same compiler (and often not even then, because it's hard to do that sort of optimisation across lots of different files), so there IS a need standards between different libraries -- they're just not universal, or easy...
no subject
Date: 2012-01-30 01:00 pm (UTC)I have no idea what arrays are like in C# but I honestly can't recall ever using one directly in Java. Always an ArrayList, Vector, Set or whatever instead.
Maybe that's just me.
no subject
Date: 2012-01-30 01:09 pm (UTC)In c# I'd do that with myDictionary.Values[0] - and I figured that there'd be an equivalent in Java. How would you recommend doing that?
And what should I use - a HashMap, Hashtable, or something else, as a dictionary?
no subject
Date: 2012-01-30 01:36 pm (UTC)List vals = new ArrayList(myDictionary.getValues());
value = vals.get(0);
I guess. Or maybe:
value = myDictionary.getValues().Iterator().next() ?
The problem is that the getValues() returns a Collection which is just a bunch of stuff that you can iterate through rather than a List.
That's just off the top of my head though: sorry if any of it's no right.
no subject
Date: 2012-01-30 01:41 pm (UTC)http://code.google.com/p/guava-libraries/wiki/GuavaExplained?tm=6
no subject
Date: 2012-01-30 07:37 pm (UTC)I don't really see that this is a problem. The returned collection is unordered (and is probably a reference to the map's internal data structures, the docs say the returned collection changes if the map does), so there is no 'first element' to access.
You might find it inconvenient, but it's conceptually correct and more efficient than turning into a list/array automatically.
no subject
Date: 2012-01-30 09:52 pm (UTC)Mind you, I'm not convinced that this is a good example of "conservative in what you do, liberal in what you expect from others", and one of the posters claims.
no subject
Date: 2012-01-31 09:07 pm (UTC)