• (nodebb)

    He forgot the call to Frenk.Terminate()

  • Prime Mover (unregistered)

    Frenk and Grenk.

    I confess this calls to mind Bloop, Floop and Gloop.

  • LCrawford (unregistered)

    I'm not a fan of the run-on code as in the end solution. It's too much reminiscent of the old BASIC days, in which you'd jam as many statements as would fit on a line to minimize use of GOTO statements.

    As Frenk would say "Frist", except I'd be as wrong as his unholy solutions.

  • Foo AKA Fooo (unregistered)

    I must admit, as a C++ programmer I find this funny, since often C++ is derided as too complex and abstract, but here the idiomatic modern C++ solution feels really down to earth and readable compared to either of those versions:

    std::vector <int> r (daysInMonth(monthAndYear));
    std::iota (begin (r), end (r), 1);
    return r;
    

    (hope that gets formatted properly)

    As a side benefit it avoids unnecessary allocations since it knows the final size from the start, though in this particular case (max. 31 items) it may not matter much.

  • 516052 (unregistered)

    Same here. It might look like a neat and clever solution at first. But it's difficult to read and understand if you don't know the thought process behind why it was written. It's impossible to reasonably comment. And if Java is anything like the C# equivalent of LINQ it's impossible to debug as well.

    It's the same reason why I dislike LINQ when it's overused. There is a place and time for it and a place and time for a for loop.

  • (nodebb)

    A LinkedHashSet does keep order: It works like a HashSet, but it keeps separate previous/next pointers to iterate over the elements in insertion order. When the data is copied back into the list, it is already sorted.

  • Collector (unregistered)

    I would have expected something even more simple, e.g. like

    return IntStream.rangeClosed(1, DateUtils.daysInMonth(monthAndYear)).collect(Collectors.toList());

  • I dunno LOL ¯\(°_o)/¯ (unregistered)

    "but it feels like a code smell"

    Or does it smell like a code feel?

  • Lothar (unregistered)

    The date-handling is all taken care of by daysInMonth, which means this is the rare date-handling code where the date-handling isn't the WTF

    Well there is a bit of WTF because the helper method returns the wrapper object Integer and not the primitive int and therefore could in theory return null (e.g. if the passed date - which is a String - can't be parsed to an actual date).

  • 516052 (unregistered) in reply to I dunno LOL ¯\(°_o)/¯

    I don't know about you but if my monitor starts giving off a smell I tend to loose sight of the code and reach for the fire extinguisher.

  • FFLoucks (unregistered) in reply to Foo AKA Fooo

    not a C++ programmer, but shouldn't std::iota (begin (r), end (r), 1); be instead: std::iota (begin (1), end (r), 1);

  • Brian (unregistered) in reply to Foo AKA Fooo

    Heh, "modern C++". In my experience, if you're working in C++ at all, there's some kind of restriction on using the newer language features due to legacy support or whatnot. (I had one project that couldn't even use the STL because it was stuck on an ancient compiler that didn't support templates.) Otherwise you're on C# or Javascript or whatever it is the cool kids are doing these days.

  • Tom (unregistered)

    a stream one-liner which wasn't a disaster

    That's debatable... but I guess Java is to blame here, because the Streams API is so much more verbose than it needs to be.

    The equivalent in C# would be:

    return Enumerable.Range(1, DateUtils.daysInMonth(monthAndYear)).ToList();
    
  • Cidolfas (unregistered)

    Going to agree, the last solution is way harder to read than a more correct version of the loop. It relies on knowing how several more methods work and doesn't self-document.

  • Kduncan (unregistered)

    One could create a static array of ints containing 1 to 31, then use Arrays.copy(r) to get a quick copy of the appropriate size.

  • Foo AKA Fooo (unregistered) in reply to FFLoucks

    The first two parameters give the range to fill, the 3rd one the starting value, so begin(r) is correct. (In fact, begin(1) would make no sense, since 1 is a number, not a container. -- Yes, unless you define an begin(int) overload, but that would we weird. ;)

  • Foo AKA Fooo (unregistered) in reply to Brian

    There are such organizations, but not all. In my work, we can use all new features as soon as gcc/clang support them in a stable release. What we ban are actually some legacy features, enforced (where possible) with appropriate warning options and -Werror.

  • good times create bad code (unregistered)

    And here I sit, wondering why this windows update takes over an hour. It's probably populating, clearing, unsorting, resorting, etc. And nobody knows what's going on anymore, because everything has a 100 layers of abstraction and 3rd party libraries underneath...

  • Prime Mover (unregistered) in reply to good times create bad code

    It's analysed your system to determine it's more than 1 year old, and so is linking in several timewasting routines that do nothing but slow your response down so as t encourage you to get a new machine.

  • (nodebb) in reply to good times create bad code

    "Look, that code was written three years ago. Everyone on that team has since jumped to a new job. We just maintain the code. And by 'maintain', I mean desperately block any task that involves touching that code."

  • guest (unregistered) in reply to Foo AKA Fooo

    Don't forget C++ would have simply offered the ordered_set and unordered_set classes. Good luck telling this person why a LinkedHashSet does not preserve order while a TreeSet does.

    Ah, the beauty of Java. All the claims of modernization and best practices with the worst possible implementation.

  • Best Of 2021 (unregistered)

    LinkedHashSet does preserve order. That's what the 'linked' part is about.

    This code is still ridiculous of course, but not in that way.

    TRWTF here is really why Java managed to make such a mess of lambdas and streams. They had C# to look at as an example before they did it - ok, Linq syntax has its lovers and its haters, but the extension methods and the way lambdas work are nice. But, like generics, Java looked at that and thought 'nope, we want a less good, more verbose, easier to mess up version'.

    Of course the real winner here is APL where the iota primitive gives you the list without any need to write boilerplate nonsense at all.

  • (nodebb) in reply to Foo AKA Fooo

    I must admit that as a Swift programmer I find the "modern" C++ solution funny. In Swift you'd write

    return Array(1 ... daysInMonth)
    

    That's shorter than the C++ and Java versions and, I'd submit, more readable.

    I am sure there are people lining up behind me to laugh at Swift's verbosity.

  • Sole Purpose Of Visit (unregistered) in reply to Jeremy Pereira

    Not much use if you want an array/list/vector of things that don't submit to the axioms of Peano, though, is it?

  • Melnorme (unregistered) in reply to ggeens

    Yeah, this post is wrong I think.

  • Grumpy Gus (unregistered) in reply to Sole Purpose Of Visit

    APL had this beat fifty years ago:

    $IO daysInMonth

    Where in this character set $IO is a stand in for the index operator “I”

  • ooOOooGa (unregistered) in reply to Jeremy Pereira

    There is the python version, which has to be corrected for a 1-based list.

    daysInMonth = monthrange(2004, 3)[1] return range(1, daysInMonth + 1)

  • Chris (unregistered)

    You just know that somewhere, the calling code is looping over the returned list instead of just looping from 1 to daysInMonth itself.

    +1 to the comments about LINQ and streams making clean code more difficult to read just to provide shorter code that may or may not be smarter, depending on how it's used.

  • 516052 (unregistered)

    Like all things the problem isn't with the hammer but with the dimwitted programmers who see every new thing as the solution to everything and apply it everywhere. If I had a year back for every time I saw someone completely replace all loops in their program with LINQ I'd be 30 again.

  • (nodebb)

    The real WTF is not using Collectors.toList():

    return IntStream.rangeClosed(1, DateUtils.daysInMonth(monthAndYear)).collect(Collectors.toList());
    

    Which can be shortened to this (with appropriate static imports elsewhere):

    return rangeClosed(1, daysInMonth(monthAndYear)).collect(toList());
    
  • Sole Purpose Of Visit (unregistered) in reply to 516052

    Ignoring ForEach, which spits out side-effects like nobody's business, I fail to see your problem here.

    Linq (or -- I assume -- a properly implemented Java Streams equivalent -- does exactly what you want when you traverse a collection.

    Get used to it. You have an input collection. You have an output collection. This is the nearest you are going to get to FP in C#.

    You want to debug it? Fine. Separate the lambda out into a local function. You can debug the local function, if you're not up to reasoning about why the output collection isn't what you expected.

    You have a desperate need for side-effects? No problem. Just don't work anywhere near me, or in fact anywhere near the sort of architect/designer/developer who actively hates side-effects.

    What I'm saying here, I think, is that you should actively try to regress back to your 30-year-old self and ask this simple question: "Can I understand what the fuck is going on here?"

  • Sole Purpose Of Visit (unregistered) in reply to Chris

    And how exactly would "what you just know" make a difference?

    The OP code is borked. It is a WTF. It's a simple loop in base Java. It might be an iterator in C++. It might be a list comprehension in Python. But actually, nobody cares. It's borked because it's borked.

    Anybody complaining about chaining Linq statements together ("Unreadable!") or -- we haven't seen this yet, but -- objecting to Fluent Programming (basically, return a this), is, IMHO, completely out of their tiny little minds

    I don't insist on these design patterns. I do think they are worth considering, and are not at all verbose.

    But hey. Sometimes you are employed to do the same old crap over and over and over again. Sometimes it's easier to give in and accept that you are just not very good at learning stuff.

    I'm fine with that. I suggest that you should not be fine with it.

  • Chris (unregistered)

    Or try migrating that code to Kotlin — much simpler than any of the Java versions:

    // Add `.toList()` if you _really_ do want a `List<String>` rather than a nice `IntRange` type
    fun daysRange(yearMonth: String) = 1..daysInMonth(monthAndYear))
    
  • 516052 (unregistered)

    I think the people defending LINQ here don't get what we are complaining about. Nobody is saying that you shouldn't use it to query data structures. You absolutely should. What we, or at least I am complaining about is:

    1. Using LINQ to replace loops when there is no benifit to doing so or when it just does not make sense. LINQ is great if you want to have an SQL like query over a data structure that is not a database. But it's not the magic coding tool people use it as. It's a query tool and not a replacement for all loops. So only use it when it makes sense to do so.

    2. Long complex multi stage queries that chain one after the other. Example: MyList.Select(something...).Where(something else...).Select(third condition...).Select(yet more query...)... ad infinitum.

    Each of those is fine on its own. But chained together like that they make the process of refactoring or debugging basically impossible because you can't get to the individual steps. And of course they make for an idiotically huge cludge of code that you have to slowly parse to get what's going on.

    Far too many times have I run into something like this where I've had to make a small change to the query details, but because the detail I need to change is somewhere in the middle and it's all chained together I had to rewrite the whole thing. Where as with loops I would just have moved an IF around or moved the order of nested loops.

    You wouldn't write something like that in SQL either and for the same reasons.


    Again, it's not LINQ that's the problem. It's stupid developers that think it's the second coming of goto and use it as diligently.

  • Ruts (unregistered) in reply to 516052

    if my monitor starts giving off a smell I tend to loose sight of the code and reach for the fire extinguisher.

    If my monitor starts giving off a smell, I think I'd reach for the plug first

Leave a comment on “Revenge of the Stream”

Log In or post as a guest

Replying to comment #:

« Return to Article