• snoofle (cs) in reply to Volmarias
    Volmarias:
    Ciaran McCreesh:
    Ah yes. No-one will ever need typedef, so let's remove it from the language! Also, operator overloading is clearly always evil, there are no legitimate uses of multiple inheritance, programmer-controllable memory management is pointless, stack allocation is a waste of time, const is silly, scope-controlled destruction doesn't help anyone, a common base class for everything is good and treating programmers like idiots is the best idea ever.

    Sounds like your "brillant" code was scrapped in favor of something written with Java, and you're Not At All Bitter Not Even A Little Bit.

    Frankly, I don't see why you're happy with the wastefulness of C++. Why aren't you writing in assembly? I mean, have you SEEN the overhead that compilers create? And I don't see why we need to be told that we can't use a floating point number JUST AS IT IS as a pointer! Damnit, I know exactly what I'm doing, just let me do it!

    Methinks you want a language called "C"

  • ais523 (unregistered) in reply to webrunner
    webrunner:
    I actually had to do some hashmaps of vectors in C++ and discovered if you just go std::map<std::string, std::vector<std::string>> it gives you an error for nesting <'s
    At least in part, that's because you've ended the line with >> (which is a bitshift operator, and also overloaded for streaming for some reason). If you write it as > > (with a space), you'll avoid that particular lexing problem. I can't remember enough C++ to know whether there's anything else wrong with that code, though.
  • SomeCoder (unregistered) in reply to webrunner
    webrunner:
    I actually had to do some hashmaps of vectors in C++ and discovered if you just go std::map<std::string, std::vector<std::string>> it gives you an error for nesting <'s

    That's because you're not writing it correctly.

    You have to say:

    std::map<std::string, std::vector<std::string> >
    

    Notice the space between the two > at the end. That is because >> is an operator in C++. One of those oddities of the language but a useful one to know.

    This WTF is NOT that much of a WTF. As someone else said, if you ever use the STL in C++ much (or write anything non-trivial in C#) you will encounter something like this.

    I've never nested generics/templates that deep before but it's not a huge WTF. We need more context before we can say how bad it really is.

  • real_aardvark (cs) in reply to brazzy
    brazzy:
    Ritchie:
    Have to say that the real WTF is the Java language itself. You can't typedef this, so you're stuck between writing out a long generic definition, getting RSI writing out a whole load of class definitions which makes the calling code smaller but the called code ten times more complicated and error prone, or creating a derived class which might look like the generic version some of the time, but will bite you in the ass when you discover it isn't.

    On your left, a rock. On your right, a hard place.

    In front of you: the correct ways to do it, which are either:

    1. If you just want to search for entries that match a specific Long, Timestamp and String: collate them into a single class with appropriate equals() and hashCode() methods so that instances can be used straightforwardly as a key in a simple HashMap.

    2. If you want to do flexible partial-match searches: use a friggin' DBMS.

    With your wonderful typedef, you'd still be writing WTF code, it just wouldn't be as obvious.

    This seems to be the sanest comment so far (by quite a long way).

    (a) A typedef isn't going to help clients of the code, although I'm damn sure it would help maintainers of the code, so Java should have it anyway. I can't think of a good use-case outside of generics, and I suspect they just skipped over the idea when adding the latter. (b) There is nothing wrong with the code in the OP. Absolutely nothing. As other, sane, posts have pointed out, this is exactly the sort of the thing that the STL does internally. (c) The key word here is "internally." (d) I don't care whether the snippet in question is wrapped in a class, or an adapter, or groovy (shudder), or even candy-floss for that matter. As long as the user has a decent, workable API, it may well be the best way of expressing the concept internally.

    It isn't a question of Java vs C++; it's a question of design. And, since, we can't see the design ...

    ... this is not a WTF.

  • kl (unregistered)

    And who said you can't program LISP in Java? :)

  • snoofle (cs) in reply to foo
    foo:
    What ever problem it is that really, truly, honestly, _needs_ a solution like this... that needs to distinguish between objects created in the same thread and the same name inside the same millisecond... SHOULD NOT be solved with Java.
    I respectfully disagree. I have used Java for about 11 years now (and C++ for years before that), mostly for real time high performance transaction systems (think making trades in your 401(k)'s securities account). We routinely get 10,000 transactions/second in a given system within any given second. Keys are typically made up of more than just the timestamp. Java can handle it if you know how to program it correctly.

    Same as with any tool: don't blame the hammer, blame the carpenter.

    The developer of this nested structure seems like he knew what he needed to solve the problem; he just didn't encapsulate it enough for it to be easily readable by the next person (possibly through lazyness, or a push to meet a deadline?)

  • livid (cs)

    That's still better than the "mystery" HashMap. I recently refactored an XML parser that created a HashMap from an XML document. The map key was always a String (the element name), but the value could be an Element, could be a List, or it might be another Map. The parser code was an ugly tangle of if-else if-...-else instanceof conditionals, and although there were plenty of comments describing the XML document structure, the actual code itself was spaghetti.

    The "obvious" solution, per a couple of co-workers, was to just use a Map<String,Object>. shudder

  • noah (unregistered)

    The real WTF is that he didn't see that this might be a good time to declare his own class encapsulating that super generic definition. SuperHashMap superHashMap = new SuperHashMap(); is a bit more readable. Oh, and the variable type should be just Map, not HashMap. Always code to the interface.

  • DW (unregistered)

    Geez thats not a WTF.

    A WTF would be the rest of the app using generics with a comment above a "Map superHashMap = new HashMap();" line with a two page description explaining all the things on that line, alluding to a two day exploration of the code, along with the super important text "most of the time".

  • DW (unregistered) in reply to webrunner
    webrunner:
    I actually had to do some hashmaps of vectors in C++ and discovered if you just go std::map<std::string, std::vector<std::string>> it gives you an error for nesting <'s

    As other people I'm sure pointed out, its because two <<'s or two >>'s in C++ today parse as a different token and are required to fail. In C++0x, it will be 'fixed'.

  • PhilipD (unregistered)

    TRWTF is that he used the implementation classes in the variable declaration instead of interfaces: Vector instead of List HashMap instead of Map etc.

  • grumpy (unregistered) in reply to yuumei

    Not sure I see the big deal here. Assuming he actually needed a datastructure like this, I'd rather have it with generics than without.

    Of course, imagining a case where you need a hashmap where the value type is another hashmap where the value type is a vector of hashmaps is a bit hard, but the problem seems to be that he required a really weird data structure, not that he used generics to implement it.

  • SomeCoder (unregistered) in reply to real_aardvark
    real_aardvark:
    This seems to be the sanest comment so far (by quite a long way)... ...

    And this seems to be the new sanest comment of the day. I agree 100%.

  • sarge (unregistered)

    The real WTF was calling the variable superHashMap, there's not much super about it.

  • ClaudeSuck.de (unregistered) in reply to ParkinT
    ParkinT:
    What a HASH mess!!

    I like the 'superHashMap'. Does he wear a mask or a red cape?

    No he smokes the supeerHash in a pipe.

  • Edward Royce (unregistered) in reply to Claxon
    Claxon:
    Volmarias:
    I'm being VERY explicit about what's going on, and it shuts the compiler up.
    /**
     * Warning! This class contains VERY explicit language, 
     * due to all of the compiler warnings I was getting...
     * Sheesh!
     */
    

    /*

    • Especially when the compiler used a webservice to report my ass to TDWTF! */
  • ericpearson (cs)

    Wow, reminds me of some of the public APIs in a recent Microsoft Biztalk beta.. their public functions would return and take stuff like that.

  • Generics'R'Us (unregistered) in reply to yuumei

    Some people just don't get it.

  • b (unregistered)

    I'm guessing this would've been better off as HashMap<OrderedTriple<Long, Timestamp, String>, Object>. Sometimes you need nested hashes, but this doesn't look like one of those times.

  • The Hermit (cs)

    This guy must've been a Perl coder. Coz this definitely looks like a Perl answer to a Java problem.

  • KG (unregistered)

    I wouldn't use generics for this sort of data structure - not even with typedefs. The best thing would be to refactor it out into a set of classes.

  • mitchless (unregistered)

    Of course the real WTF here is that Java doesn't provide a clean way to typedef.

  • real_aardvark (cs) in reply to KG
    KG:
    I wouldn't use generics for this sort of data structure - not even with typedefs. The best thing would be to refactor it out into a set of classes.
    *Ahem*.

    Read upwards to Brazzy, please.

    Otherwise, you carry on. I'm sure that programming by piece-work is far more satisfying than actually producing a maintainable product. Lines of code are so important these days.

    Or then again, this could be the most sophisticated sarcasm yet seen on this site.

  • smxlong (cs)

    That looks like a perfectly reasonable data structure to me. However, I'd wrap it in a class which makes the interface a little less verbose.

    Not seeing the WTF. Unless you consider complex data structures a WTF.

  • Jake (unregistered)

    Of course, the REAL WTF is that the coder didn't use the Map/List interfaces for his superMap type. :P

  • Chris (unregistered)

    Um, considering the alternative is doing a ton of casting when you access the elements out of this, I'd rather have the generics.

    Nesting four data structures though, that's a different story. I don't think anyone wants that!

  • deathkrush (unregistered) in reply to yuumei

    Looks like the programmer is infected with Perl.

    Captcha: augue (indeed)

  • Jay (unregistered) in reply to Ciaran McCreesh
    Ciaran McCreesh:
    Ah yes. No-one will ever need typedef, so let's remove it from the language! Also, operator overloading is clearly always evil, there are no legitimate uses of multiple inheritance, programmer-controllable memory management is pointless, stack allocation is a waste of time, const is silly, scope-controlled destruction doesn't help anyone, a common base class for everything is good and treating programmers like idiots is the best idea ever.

    Hmm. I've programmed in vanilla C, C++, and Java. I certainly don't think Java is the most perfect programming language imaginable, and I don't want to get into a flame war about it, but just my thoughts on your complaints:

    typedef: I've never missed it. It's much cleaner to create a class to implement what you're trying to do. Like someone mentioned "typedef Map<String,String> Phonebook". I'd rather:

    class Phonebook
    {
      Map<String,String> data;
    
      public String getPhone(String name)
      {
        return data.get(name);
      }
      ... etc ...
    }
    

    Then you can create exactly the set of functions you need with meaningful names. If your reply is that that's too much trouble because you just want to do Map functions directly, then why not just say "Map<String,String> phonebook". That's all you need.

    operator overloading: Amusing and I've had a few cases where it would have been handy. But hardly a big deal. You can always declare a "plus" function and write "c=a.plus(b)" whereever you would like to have written "c=a+b". Unless you're defining a new number type -- complex numbers or fractions or something -- it's likely that operator overloading would subtract from readability rather than add to it.

    multiple inheritance: There are occassions where this is useful. Frankly I rarely used it in C++. I've had a few times that I've groaned about having to use "implements" as a poor alternative and write a slew of pass-thru functions. But only a few. The early Java advertising didn't claim that multiple inheritance was illegitimate, just that it was very hard to implement unambiguously.

    progammer-controlled memory management: Wow, I thought the lack of this was the biggest plus in Java! It dramatically simplified programming. In C++, not only is keeping track of everything you allocated and making sure you release it a tedious chore, but the fact that you have to do it forces you to write more complex programs. Like, in Java I routinely create an object within a function, return it, and the caller just pulls out the value it needs and forgets the object, like "x=myFunction(z).someValue". You can't do that in C++ because you'd have to save the function reference and explicitly destroy the object. There are all sorts of little conveniences like this in Java, where the fact that you DON'T CARE about de-allocation let's you shorten and simplify your code.

    If you really do need to force-free an object, fine, just set the handle to null. If you really care, call gc().

    stack allocation: Not sure what you mean there. You can create stacks in Java. Do you mean the the stack that holds your local variables? Why would you want to manage this yourself? It's a trivial operation that the compiler handles just fine.

    const: Java calls it "final". A dumb name, but it's the same concept.

    scope-controlled destruction: How does it help anyone? If you're not really tight on memory space, it doesn't matter, and if you are, the gc will fire up and free the space when needed.

    common base class: If you don't want to use Object, don't use it. How does it hurt to have a feature available that you don't happen to need in this particular program?

    I have a number of complaints about Java, but they apparently don't overlap your complaints at all.

    My complaints include:

    1. It seems to me that the most obvious protection levels would be "public" and "available to this class and any child classes, but no one else". Indeed I think the latter should be the default. But it's not only not the default, it doesn't even exist. Instead there's the stupid "package" level protection, which makes no sense to me at all. If another class in a package needs access to my ... semi-private ... data, it should have to explicitly say so, not just magically get it.

    2. No convenient way to pass a primitive by reference or to pass a handle to a handle, like a C++ "&". If a function has to return more than one value, the only way to do this is to create an object to encapsulate the values. Sure, I can do this, but it's tedious. If I need to return, say, name and phone number, why can't I just do it, instead of having to create a new object to contain them.

  • James (unregistered) in reply to Jon B
    Jon B:
    public void DoNothing<T>(T eyewear) where T : goggles {}

    ^^^^^ Wins.

  • ounos (cs) in reply to James

    Great! Now with generics, we don't have to create lousy classes any more! Yay!

  • java.lang.Chris; (cs)

    To all those harping on about how wonderful typedefs are in C++, take a look at the compiler messages when you use the STL but get something a little wrong. Suddenly all those typedefs will be expanded out into their equivalents of the Java example shown (only worse, because all STL implementations are a maze of twisty inheritance passages). Typedef usage in C++ is often little better than the preprocessor abuse that a lot of C programmers get upto.

    For those who really are deluded enough to believe that C++ has any value whatsoever, please check out the FQA:

    http://yosefk.com/c++fqa/

  • CynicalTyler (unregistered)

    Sorting an array of objects by comparison with O(n) in a non-parallelized environment?! This looks like a job for... SUPERHASHMAP!

  • asdf (unregistered)

    It's only a wtf if you're used to java. In most of the scripting languages nested hashmaps are fairly tradditional.

  • One Guy (unregistered)

    The RWTF is using Hashmap and Vector as types

  • noname (unregistered) in reply to Jay

    I'm going to skip the rest since I don't feel like a slug-fest, but...

    Jay:
    const: Java calls it "final". A dumb name, but it's the same concept.

    Unless it's changed since 1.4, these aren't remotely the same.

  • EvanED (cs) in reply to Jay
    Jay:
    scope-controlled destruction: How does it help anyone? If you're not really tight on memory space, it doesn't matter, and if you are, the gc will fire up and free the space when needed.
    Because there are far more resources than memory which you may want to release. Do you always ensure that your files will be closed? Contrast what you have to do in Java when you use a file:
    File file(...);
    try {
       doStuff();
    }
    catch(Throwable t) {
       file.close();
       throw t;
    }
    to what you have to do in C++:
    fstream file(...);
    doStuff();

    This is a common error that the RAII idiom can all but eliminate in most cases.

    And the sorts of things that you want to do like this is vast. Want to temporarily change the value of a variable? In C++, make a restorer class that will restore the old value when destructed. (You only have to do it once, and such a class will come in handy quite a bit.) Want to change the cursor to an hourglass while doing a long operation? Make the destructor turn it back to a pointer.

  • TheSak (unregistered)

    Looks like a good way to index a very large hashtable when you have to search against multiple properties.

  • meir (unregistered)

    I found myself writing some similar code, and was kind of suprised to see the result. But I have a very logical explaniation how my code came to be.

    I needed to write a program which manipulates context-free grammers. So I defined a class: GrammerSymbol which could represent a Token type or a Grammer Variabel. Now I could define a class representing a product of a given grammer variable, but I prefered using: List<GrammerSymbol> To list all the product I obviously use: Set<List<GrammerSymbol> Then the grammer would obviusly come out: Map<GrammerVariable,Set<List<GrammerSymbol>> and a predictive parsing table would be: Map<GrammerVariable,Map<TokenType,List<GrammerSymbol>>>

    and thus your code grows.

  • Edward Capriolo (unregistered)

    Yes, if you take generics to far you start losing the benefits of a class based programming language.

  • Some (unregistered)
    2. No convenient way to pass a primitive by reference or to pass a handle to a handle, like a C++ "&". If a function has to return more than one value, the only way to do this is to create an object to encapsulate the values. Sure, I can do this, but it's tedious. If I need to return, say, name and phone number, why can't I just do it, instead of having to create a new object to contain them.
    Totaly disagree. Don't forget that your system is designed object-oriented. Also ALL data should be represented a object's that can handle them self. Also when you need to return some data it SOULD be an object.
  • sf (unregistered) in reply to SomeCoder
    SomeCoder:
    real_aardvark:
    This seems to be the sanest comment so far (by quite a long way)... ...

    And this seems to be the new sanest comment of the day. I agree 100%.

    Well I think your comment is even more sane still. Bravo! ;-)

  • DKO (unregistered) in reply to java.lang.Chris;
    Comment held for moderation.
  • Cronus (cs) in reply to Smash
    Smash:
    TraumaPony:
    Wow, how witty.
    Great! Let the Flame Wars begin. And since it's my turn, I guess I'll throw an infamous yo'mama joke now.

    Captcha: valetudo. That's a fighting style. Oh the irony...

    Here we go again...

  • baps (unregistered)

    Why is this wtf again? This exact line is from my code (c++ stl):

    map<int, map<time_t, map<string, some_struct> > >

    This data structure is part of a distributed server app., some_struct is indexed by the tuple (server_id, timestamp, struct_uniq_id) for fast searching. Perfectly reasonable. Also, c++ map is a red-black tree (usually), so index is ordered - you get nice time ordering for timestamp.

  • Yazeran (unregistered) in reply to foo
    foo:
    What ever problem it is that really, truly, honestly, _needs_ a solution like this... that needs to distinguish between objects created in the same thread and the same name inside the same millisecond... SHOULD NOT be solved with Java. The programming language to succinctly solve this problem does not exist... and is not intended for mortals. That would be a nightmare problem even for Haskel... or any language. Hell, I think staring into the face of Chluthlu for an hour would be easier. Defining the data structure is simple enough... working with it would drive a mortal to madness.
    Which proves it is a work of Cthulhu

    Yazeran

  • CornedBee (unregistered)

    The only thing wrong with that is that the language in question (could be C# or Java, but I'm guessing Java) doesn't have typedefs.

    Oh, and Vector instead of ArrayList. That's wrong, too.

  • alegr (cs) in reply to java.lang.Chris;
    java.lang.Chris;:

    For those who really are deluded enough to believe that C++ has any value whatsoever, please check out the FQA:

    http://yosefk.com/c++fqa/

    That reminds me about "Expelled: No Intelligence Allowed" movie.

  • xokas (unregistered)

    What else can you expect from a "superHashMap"?

  • Andy (unregistered) in reply to Tim Ward
    Tim Ward:
    Is this another way of saying:

    "Why hasn't Java got typedef?"

    It does, but in a different form.

    Java doesn't have a C style typedef because it would not fit with the implmentation of the Java technology.

    In C, a typedef is a source level shortcut for a type that may be too complex to key in many times. Nice, but not really usefull unless you happen to define it exactly the same in several different source files. Of course, most programmers use an include file to increase the probabilty that it will be defined the same in each source file. The compiler doesn't care, it takes your word for it that each source file was compiled with exsctly the same typedef.

    In Java, the compiler validates types by opening the actual compiled object code for every other module that is used by this source code. (Yes, it knows how to take care of circular references when compiling more that one source file at a time.) Include files are also not used, since any source level information must come from and be used by only one source file. In this way, the true types are verified at compile time. Also, the types are verified at link and run time. (The same time in Java)

    In C, once the typedef is evaluated at compile time, it is assumed to be correct. It is not checked at link or run time. The compiled object files don't have enough information to check the types. I have gone through the debugging process when two modules thought the type was slightly different and just wrote into memory what they thought it should look like.

    In Java, types are actual classes. In C, typedef is a source level shorthand.

    Both have their places. But they are designed for different uses.

  • Michael (unregistered)

    How is it even WTF? Please provide cleaner implementation of multi-dimensional map (by long time and string) with fewer lines of code... All I see is bunch of people who complain about things they can't comprehend.

Leave a comment on “Very Specific Generics”

Log In or post as a guest

Replying to comment #:

« Return to Article