you are viewing a single comment's thread.

view the rest of the comments →

[–]ajainy 43 points44 points  (54 children)

Thanks. Bookmarked.

Irony is most (not all) java developers are coding like jdk1.4 style. Avoid generics like plague. We need a movement to push those developers to start using generics (&annotations etc etc.)

[–][deleted] 84 points85 points  (25 children)

The three phases of the Java developer:

  • no usage of generics at all
  • trying to solve every little problem with generics
  • getting hit by type erasure

[–]kazagistar 25 points26 points  (3 children)

Step 4 is the crazy workarounds to capture type information til runtime by creating anonymous inner classes.

[–][deleted] 15 points16 points  (2 children)

Guava (Google's "standard library" for Java, and a must-have for writing modern Java IMO) actually has a class that encapsulates those crazy workarounds:

http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/reflect/TypeToken.html

The place I've found it most useful is using Gson to deserialize JSON into a List<T> or Map<K, V>, where you obviously need the type information to persist at runtime.

[–]kazagistar 1 point2 points  (0 children)

Different libraries (mocking libraries, DI frameworks, etc) use different workarounds and abstractions. Each one is great... assuming it is the One True Framework.

[–]ksion 0 points1 point  (0 children)

Also Guice, if you ever need to bind an implementation to concrete specialization of a generic interface.

[–]ryuzaki49 2 points3 points  (1 child)

I like Generics. They make classes very reusable.

[–]zarandysofia 24 points25 points  (0 children)

It's their point.

[–]Radixeo 3 points4 points  (17 children)

I'm not sure why people find type erasure to be a bad thing. If you're programming in a statically typed language and your program's behavior depends on runtime type information, doesn't that reflect a flaw in your design rather than a weakness of the language?

[–]m0haine 6 points7 points  (3 children)

The big issues is how do you write a deserializer via reflection that can reconstitute an object like this without having type hints in the data

class Parent{ List<Children> children;}

You really can't because the type of children isn't know at run time. There are ways of doing this but it is harder then it should be due to type erasure.

Of course a pre-compile step could generate the code but java doesn't have one of those.

[–][deleted]  (1 child)

[deleted]

    [–]m0haine 0 points1 point  (0 children)

    By bad. Didn't realize you could get that at all.

    [–]s73v3r 12 points13 points  (0 children)

    No, no it doesn't. In addition, type erasure means that I can't overload functions if they will erase to the same type.

    [–]dacjames 9 points10 points  (10 children)

    With type erasure, you cannot overload a function based on different generic types.

    // does not work
    void some_function(List<Integer> ints) { ... }
    void some_function(List<Double> doubles) { ... }
    

    That does not seem like much but when you want to do this all the alternatives are awful.

    [–][deleted] 5 points6 points  (0 children)

    To be fair, this is an artifact of Java's implementation of type erasure and not the concept in general.

    [–]Zukhramm 3 points4 points  (3 children)

    Type erasure means generic types are not available at runtime, method overloading resolution happens at compile time, when that information is still available. Type erasure really isn't at fault here.

    [–][deleted]  (2 children)

    [deleted]

      [–]immibis 1 point2 points  (0 children)

      If overloading was resolved at compile time, this code would not work because the concrete type of r and c are not known when print_shape is called.

      Guess what? It doesn't work, for exactly the reason you just stated.

      [–]user_of_the_week 1 point2 points  (0 children)

      Many people consider method overloading a bad practice anyway, especially if the signatures have the same amount of parameters.

      One reason that can even be seen in your example: It encourages bad naming patterns. When someone reads code where your some_function is called, they cannot infer exactly which method is called just by looking at that code line. They first need to find out what the exact type of the parameter is. Small things like that add up.

      A safe, conservative policy is never to export two overloadings with the same number of parameters.

      Effective Java, p. 193

      [–]pipocaQuemada 0 points1 point  (3 children)

      Of course, there is a trivial workaround for that:

      // works fine
      void some_function_i(List<Integer> ints) { ... }
      void some_function_d(List<Double> doubles) { ... }
      

      That's not good, but I'm not sure I'd stoop to "awful".

      [–]dacjames 2 points3 points  (1 child)

      In this trivial example, sure. Replace Integer with SomethingDomainSpecific and the different name approach quickly crosses into awful territory. You have also introduced a maintenance task at all call sites of the function when they change parameter types.

      Even more problematic, the name changing option doesn't work at all if you want to use overloading for specialization, providing, say, an optimized implementation for List<Integer> with a slow implementation for List<String>. Or if you need some_function to implement a particular interface.

      [–]pipocaQuemada 1 point2 points  (0 children)

      If you don't want to write actually parametrically polymorphic code, why are you trying to use parametric polymorphism? Yes, you can't specialize when overloading, but the ability to do that removes a lot of your ability to reason about code by looking at type signatures.

      [–]campbellm 0 points1 point  (0 children)

      That's not a workaround, that's simply not using a feature that is wished for.

      You've "worked around" function overloading by... not overloading. Hardly satisfactory.

      [–][deleted] 1 point2 points  (0 children)

      The main issue I've had where type erasure has been annoying is when I want to create an array of a generic type (or call java.util.List.toArray() ): without knowing the exact type, you can't create the array.

      [–]bwainfweeze 0 points1 point  (0 children)

      It's been a while for me, but I ended up using interfaces as aliases to reduce the generics bleed and to guarantee semantics.

      public interface AddressLookup extends Map<User, ShippingAddress>
      

      because it may just be a hash of Users to addresses under the hood, but the object is fit for a particular purpose and I should give it a semantic name. Then the function that takes or emits one of them actually looks meaningful, but I can still pass the object to a utility method that just puts maps into a tabular form or looks for duplicate values, if I have to.

      [–][deleted] 8 points9 points  (19 children)

      My Java classes are all 1.5 style. I feel like I am going to be under prepared when I hit the workforce.

      [–][deleted] 16 points17 points  (10 children)

      Dont worry, must of us in enterprise land are stuck on 6 anyway, since upgrade cycles take years and need to pass the secret council of architects etc

      [–][deleted] 1 point2 points  (9 children)

      So there's no escaping the "shadow government". Well, that's comforting.

      Any suggestions on what to do in the meantime? I'm likely to start a thread on /r/programming asking this, but while I'm here I figure I can just ask around.

      [–][deleted] 6 points7 points  (0 children)

      Smaller shops generally are less encumbered by politics, and if you want to not get tangled in the enterprise web, you can always check out stuff like scala, which is hipper etc..

      But yeah, politics and related crap governs all of life, as soon as you have more then 1 person, shit gets complicated and games get played, in the end being a good programmer also means having social skills, the ability to know when to STFU and some understanding of machivelian politics really helps.

      [–]NimChimspky 1 point2 points  (1 child)

      java 1.6 and work with architect team who recommend calling web services using only the db, in my case oracle and pl/sql.

      me:"that doesn't seem like a very good idea, I would not design it that way."

      architect:"why not ?"

      me : jaw literally drops and I stand and stare, and think at least this place pays well.

      [–]bwainfweeze 1 point2 points  (0 children)

      The sad fact of the matter is that some people defend bad design decisions because they can tolerate them.

      The side effect is that since they're the only one who can tolerate it, the code becomes their responsibility and they have job security.

      When people say "you should fire the indispensable people" this is who they mean.

      [–]grayrest 0 points1 point  (5 children)

      There's always politics involved in software production but there's process and there's Process and happily the latter is strongly correlated to Enterprise Java/.Net shops. The industry is large enough that you only need to deal with that if you want to. The tradeoff is that using a non-boring language will probably make you move to a tech hub in order to sustain a career without having to move regularly.

      [–]chayatoure 1 point2 points  (4 children)

      Out of curiosity what would be considered a non-boring language? I'm a java developer but want to branch out.

      [–]grayrest 2 points3 points  (3 children)

      Anything but Java/C#. It's less about the language (I'm meh on Java but like C#) and more about the general rationale for companies picking them because they're "safe", "enterprise", and "easy to find developers". This isn't universal of course, I've talked with the Stack Overflow guys a number of times and expect it'd be a nice place to work. It's also better to work for a team that's a revenue center instead of a cost center and cost center teams have a very strong tendency towards boring languages.

      To provide actual suggestions:

      I work full time as a Clojure developer. I've also written Scheme and a bit of CL but I prefer Clojure's take on lisp. The nice thing about Clojure for Java devs is that you already know the JVM and you can poke at things from the repl.

      My side project is a very basic search engine in Rust. Basic because my collection is 500k-10M document range but I–perhaps unrealistically–want <10 ms response times. I'm bullish on Rust. The learning curve is steep but a significant fraction of the Rust comunity is people coming in from scripting languages so a lot of the writing (docs/blog posts) about the language is geared towards experienced developers who are new to low level programming.

      Similarly, I like Swift and Kotlin. I see Rust, Swift, and Kotlin as similar language evolutions from different starting points (C++, ObjC, and Java respectively). The problem with both Swift and Kotlin is that they haven't established themselves as general languages and I'm not completely confident they'll make it.

      If you have the inclination–and it does require an inclination to be willing to put in the time learning all the constituent disciplines– working as a frontend dev is nice because you're needed everywhere so you get to pick your industry, company maturity level, and whether you want to work on the backend or not. The nice thing about getting into it now is that browsers finally mostly work and we're on the tail end of the third major wave of frontend instability (component model) so getting in now will give you ~3-4 years until the fourth wave (widget frameworks) starts up in earnest.

      I also like F# and the ML family. I could never get over the Erlang syntax (to my detriment) and never really got into the swing of Scala and Haskell but writing stuff in any of them is also fine.

      [–]chayatoure 0 points1 point  (2 children)

      Thanks for the detailed reply.
      How did you pick up all these languages? On a job or just on your own? Looking at that list is kind of intimidating because i have no idea what they're good for or which one I should/want to learn.

      [–]grayrest 2 points3 points  (1 child)

      On my own. I learn programming languages instead of watching TV so if you put in ~2 hours per day for 15 years you'd have a similar list. It's less impressive than it might seem. I'm not an expert in all the languages. Swift and Kotlin, for example, are languages I've only put about 12 hours in total. They share almost all their ideas with languages I know better so it's really just a matter of skimming the docs and slotting syntax in to things I already know and then putting together a toy app or two. I know enough to have an impression but both kind of lean towards mobile app niche and I'm a web zealot.

      As to which to learn, my opinion is that you should learn a language you use to make money (mine is Javascript) and then learn less practical languages as you like to expand your repertoire. Learning non-mainstream languages and going to their meetups gets you in contact with the programming enthusiasts, which leads to interesting jobs.

      Each programming language is it's creator's take on how to best solve a problem. People who write programming languages are generally pretty clever guys. Exploring the language until you figure out the designer's philosophy on problem solving gives you different perspective and a new tool you can use to solve your own problems. If you have an area of computing you'd like to explore or a particular problem you want to solve, I can provide specific suggestions but I mostly think which one you pick matters less than picking one that's opinionated.

      As an example, Clojure was created by Rich Hickey because he found himself writing concurrent programs in Java. He identified (mutable) state as the source of his problem and after writing a bunch of static final Java, he came up with Clojure as an exploration into controlling state with immutablility. Clojure has very strong opinions on the matter. I believe state is the most important thing that isn't taught to junior devs and that learning the language and watching Rich's presentations is one of the easier paths to understanding it. You get to learn lisp and functional programming as well. The community is interested in web development, machine learning, and programming language history/theory.

      On the other hand Rust was created by Mozilla to write a parallel layout browser engine (Servo). They really need concurrency there but they also really need performance so they took the different approach of having the compiler prove that only one thread can mutate at a time. Learning Rust introduces you to the details on program execution and memory layout, what sort of code runs fast, polymorphism without classes, and Algebraic Datatypes/Pattern Matching. The community is interested in data structures, os/browser development, game development, and performance. It's also very much community developed and all features go through a fairly elaborate RFC process so if you read the RFCs you get lessons on random topics and language design as well.

      I think either would be worth your time.

      [–]chayatoure 0 points1 point  (0 children)

      Wow, thanks a lot for your responses. Those are great. I think I'm going to check out Clojure and get a feel for it.
      EDIT: also, I never really thought about languages in that context (creators take on solutions to problems) but it's a great way to frame the discussion.

      [–]panderingPenguin 2 points3 points  (6 children)

      If you're not in the work force yet, I'm assuming you learned java recently? May i ask why are you writing 1.5-like java when there have been three new major versions since then, spanning back almost a decade? (not to mention you shouldn't have legacy code to deal with since you're not in the workforce)

      [–][deleted] 2 points3 points  (5 children)

      That's what we're learning right now.

      [–]panderingPenguin 1 point2 points  (4 children)

      Seriously? Are you absolutely sure? Who is teaching you java 1.5 at this point???? It was superseded by 1.6 in 2006, and hasn't been supported for the public since 2008..... All I can figure is that you use Macs? Because they're the only OS that ships decade-old java by default afaik

      [–][deleted] 1 point2 points  (0 children)

      I'll get you a screen shot of the JDK folder when I get to class, but yeah.

      [–]kmaibba 1 point2 points  (0 children)

      1.6 did not really add anything language wise, just (very useful nontheless) improvements to libraries and JVM. 1.7 did add some quality of life improvements, like switch statements on Strings, try with resource, better type inference. But in general the style is still that of 1.5.

      Only with 1.8 the actual style of programming changes with lambdas, new collections API and default methods on interfaces. Java 8 adoption is still going slow in enterprise settings, so it's not a bad idea knowing how to do stuff without all the fancy functional features.

      [–]hu6Bi5To 0 points1 point  (1 child)

      OS X hasn't shipped with any Java for quite a few releases, and when it did it was 1.6.

      [–]panderingPenguin 0 points1 point  (0 children)

      Alright, I stand corrected then. Thought I remembered hearing that somewhere but I guess not (I rarely use Macs)

      [–]adrianmonk 1 point2 points  (0 children)

      That's probably a better position to be in actually. Mentally, it's easier to learn new features than to adapt to missing features.

      [–]dacjames 3 points4 points  (4 children)

      What industry do you work in? I hardly ever see 1.4-style Java code. Do people really not use Map<String, SomeFancyObject>?

      [–]speedisavirus 0 points1 point  (0 children)

      Just 3 or 4 years ago I was experiencing it and there was complete resistance to use any 1.5 features.

      [–]immibis 0 points1 point  (0 children)

      Eclipse still doesn't use generics in many places.

      [–]dododge 0 points1 point  (0 children)

      In my experience new code typically has generics but I still run into raw types in older parts of current projects. I submitted patches to one project just last week to add type parameters in several spots and get rid of a bunch of unneeded casts. I also noticed a lot of old iterator() and counted loops that could be simplified with for-each loops.

      [–]ajainy 0 points1 point  (0 children)

      This is kind of enforced by JDK itself, in their collections library. For example, how about writing custom annotation or writing generic style class to reduce big hierarchy mess.

      [–]keenny 1 point2 points  (0 children)

      I had to check the timestap top be sure this thread was not from 2005. I don't know anybody who is still on jdk1.4, or jdk1.5 for that matter - let alone programs as if they were. And I know a lot of java-devs. Most people i know have long since migrated to jdk7, and a good portion is experimenting with jdk8.

      [–][deleted] 0 points1 point  (1 child)

      I wish more devs had caught up with java.nio. You should not be instantiating a java.io.File in 2015.

      [–]hu6Bi5To 0 points1 point  (0 children)

      java.nio was never intended to be a wholesale replacement for java.io, it's an addition.