• (disco)

    .... deja vu... i've seen that code before....

  • (disco)

    Sometimes this kind of code exists because of functors. But most of the time...

  • (disco)

    When you want another line in the Call Stack list I guess...

  • (disco) in reply to Tsaukpaetra

    It's kind of like when you were in school and you had page or word counts to meet for your term papers? Enterprise software has stack trace size requirements that must be met.

  • (disco)

    Don't really see the issue here. The function name is descriptive of what it does, the code is easy to read and works exactly as designed.

    That's more than you can say for most enterprise software.

  • (disco) in reply to LB_
    LB_:
    Sometimes this kind of code exists because of functors. But most of the time...

    Yeah, x => x is a thing that occassionally pops up in my codebase too. How else would you OrderBy<T>(Func<T, TResult>) a list of integers?

  • (disco)

    Some silly some maybe not so silly reasons for this function.

    • Place holder for future expansion -- then it will become a RWTF because the function name will no longer be descriptive.
    • Programmer paid by the line.
    • Perceived compiler problem that was really an obscure bounds/stack-smash error that got pushed somewhere else by adding this function (RWTF)
    • Attempt to defeat optimizer.
    • Provides a hook for debugging (e.g. add a line to output the variable prior to returning - sorry this is almost reasonable).
    • Provides a hook to support threading if this variable will be shared across threads (e.g. lock fetch unlock return).
  • (disco)

    @PaulaBean seems to have forgotten to list this topic now that the article is live. @Remy @PJH (not sure who to summon)

  • (disco)

    I saw something like in our code base (I probably wrote it, forgot that I did and don't want to look at the blame annotations :blush: ) but it's in a Template pattern and meant to be overridden. Not sure what kind of fuckery that is.

  • (disco)

    Hey, when you use this it stops all that infernal register optimization. :innocent:

  • (disco)

    I don't know about Ruby, but I've used an exact analogue of this method in PHP, where there is a valid use case for it;

    function with($value) {
        return $value;
    }
    
    with(clone $myObject)->method();
    // necessary because `(clone $myObject)->method();`
    // would error because of PHP syntax parsing limitations
    
  • (disco)
  • (disco)

    I've used something like this before to provide a point for method interception with AOP for debugging. Not the hugest WTF I've seen.

  • (disco)

    Reminds me of a function I found in my codebase:

    public bool ValidateObject(object _oObject)
    {
        bool _bRetVal = false;
        if (_oObject != null)
       {
            _bRetVal = true;
        }
        return _bRetVal;
    }
    

    The xdoc comment says it's to validate whether the object is "still instantiated"

  • (disco) in reply to Jaloopa

    Well, it does... something. Something potentially useful, too (I have pretty much the same logic in one of my custom validation attributes).

    The way of writing it, though... ew. What's wrong with a simple

    public bool ValidateObject(object _oObject)
    {
        return _oObject != null;
    }
    

    Filed under: also, hungarian, eww

  • (disco) in reply to Maciejasjmj

    Coding standards, because this is by people who learned their early C lessons in full. All variables to be defined at the start of each method, no early returns, must return a defined variable.

    The Hungarian is of the worst type. Don't want to think of a suitable prefix? Use _o, because it's an object.

  • (disco)

    One additional tiny bit of WTFery: in Ruby, return is optional. So, the body of this becomes a one-liner, just the name of the argument passed in.

    Also, it's unlikely this method was used as a callback, in the way usually seen in things like JavaScript. The usual way to do that in Ruby is to pass a block of code. On the other hand, such a block may have called this method... but on the third hand, it could have just had the argument, not bothering to call the method.

  • (disco) in reply to Jaloopa
    Jaloopa:
    no early returns

    I have yet to find a proper explanation for this. Because no one can convince me that tracking a state of a variable is easier than just looking for returns.

  • (disco) in reply to Jaloopa
    Jaloopa:
    because this is by people who learned their early C lessons in full.
    Jaloopa:
    object _oObject

    So you're writing C# as though it was C? Aw Jesus, you're so fucked.

  • (disco) in reply to Onyx
    Onyx:
    I have yet to find a proper explanation for

    Apparently it's confusing. Personally, I think it's a lot more readable than 10 nested if statements with a big tail of else at the far end. They have relented as far as allowing an early return right at the start after basic sanity checks.

    Maciejasjmj:
    I have pretty much the same logic in one of my custom validation attributes
    Usual use is something along the lines of
    thing myThing = new thing();
    ...
    if (ValidateObject(myThing) && someCondition)
    {
        myThing.doThings();
    }
    

    If I'm refactoring in the area I tend to swap it out for a != null

    Maciejasjmj:
    So you're writing C# as though it was C? Aw Jesus, you're so fucked.
    Offer letter came through for my new job today. `_iFuckedLevel--`
  • (disco) in reply to Onyx
    Onyx:
    I have yet to find a proper explanation for this.

    It's only useful in languages without RAII and exception handling.

  • (disco)
    One must wonder what that experience was.
    Pumping up LOC, I suppose?
  • (disco)

    This is normal in certain kinds of meta coding. You can't tell without the context. It is very rarely that anyone needs to do that however.

  • (disco)

    As someone who loved combinator calculus, I'd use this sort of thing. But I'd call it I instead of return_value

  • (disco)

    That code is perfectly valid. It also works fine, as long as it's the last line of your function or block.

  • (disco) in reply to Jaloopa
    Jaloopa:
    Use _o, because it's an object.
    [image]

    (also, that image made me LOL in its own right.)

  • (disco) in reply to RFoxmich

    Another not-so-silly potential reason: So return values can be easily messed with using an automated testing framework and mocking library.

  • (disco)
    No, there's no cornify on this one.

    I am disappoint, @remy.

  • (disco) in reply to Onyx

    I worked for a "no early returns" believer for a year. He didn't really have a good reason for it, though. When he left, I re-did some of his stuff with early returns. Doing so cut the line count nearly in half - admittedly, many of those lines were either "{" or "}", because this was a C-based language using Allman brace style.

  • (disco)

    That's an identity function. It's useful for callbacks, as some people have already pointed out. Also, this being Ruby, it's possible it's used for some things that you wouldn't intuitively think of if you're used to sane languages; in Ruby, return has very special semantics that vary depending on context.

  • (disco) in reply to EatenByAGrue
    EatenByAGrue:
    I worked for a "no early returns" believer for a year.

    Was he also a member of the school of “thought” that bans break and continue?

  • (disco) in reply to dkf

    Not quite a ban, but he definitely tried to avoid them.

  • (disco) in reply to Tsaukpaetra

    My guess would be someone coming from some other language, where functions need to explicitly define a return value even if they do not have an early return. When I first started playing (before attempting any work) in Ruby it was kind of uncomfortable to not put that return statement in.

    It was probably the case that the IDE or static code analyzer was bitching about unnecessary return statements. This little wrapper function was probably a workaround that let the author write their 'return statement' without generating so many warnings.

  • (disco) in reply to EatenByAGrue
    EatenByAGrue:
    Allman brace style

    The One True Style™, may it live forever. :trolleybus: :)

  • (disco) in reply to Jaloopa
    Jaloopa:
    `(++(_iFuckedLevel--))++`
    WTFTFY
  • (disco) in reply to LB_

    Or I don't know Ruby at all well, but might it actually be doing something useful, like doing some copying of the value? Or lazy-evaluation? Or being a convenient place of bombing out if the incoming value isn't assignable? Dunno.

  • (disco)

    My first thought here is that this is a transformation function that does nothing. There are other transformation functions that actually do something.

  • (disco)

    This reminds me of a guy who used to work here, whose typical function was:

    int add(struct foo *a, struct foo *b)
    {
       int foo1;
       int foo2;
       int footmp;
    
       if( a == NULL ) {
            return 0;
        }
    
        if( b == NULL ) {
            return 0;
        }
    
        foo1 = a->foo;
        foo2 = b->foo;
    
        footmp = foo1 + foo2;
    
        return footmp;
    }
    

    If he'd gotten the chance he'd have done it with a 1-character indent too. And naturally, this is in a context where the caller already makes sure never to pass NULL pointers into the function.

  • (disco) in reply to PleegWat
    PleegWat:
    ```c if( a == NULL ) { ```

    Sure, can't complain about defensive programming. No problem here.

    PleegWat:
    ```c return 0; ```

    Um, oookay. I guess if you want to have a system where NULL + 100 is 0, go right ahead. Maybe a and b can't ever have values that add to 0? Not how I would do it, but whatever.

    PleegWat:
    ```c foo1 = a->foo; foo2 = b->foo;
    footmp = foo1 + foo2;
    
    return footmp;
    
    </div></BLOCKQUOTE>
    
    Argh, why? I mean, sure, I prefer verbose code over short code that's more difficult to read, but I don't think `return a->foo + b->foo` is overly complicated.
    
  • (disco) in reply to Dragnslcr

    He did it with longer functions as well. And defensive coding is nice in theory, but I'm a fan of compact code. If the function isn't supposed to ever receive a NULL argument, and it receives one anyway, let it segfault, then at least I know where the problem is.

  • (disco) in reply to PleegWat
    PleegWat:
    let it segfault

    :doing_it_wrong:!

    https://imgs.xkcd.com/comics/compiler_complaint.png

  • (disco) in reply to boomzilla
    boomzilla:
    It's kind of like when you were in school and you had page or word counts to meet for your term papers? Enterprise software has stack trace size requirements that must be met.

    I do work in JavaEE. I don't need to add anything for the stack trace to meet the minimum size requirement. ;)

    Filed under: Bonus points if at least half the stack trace is from the app server

  • (disco) in reply to Onyx

    I'm mostly a "no early returns guy", though I do to bail on searches early and when the alternative would be absurd. I'm not going to add 4 checks, a counter, and noop my way through the rest of a collection just to get "returnVal" to my one return statement, but as a matter of general practice I dislike multiple returns.

    The basic reasoning is because early returns are spaghetti-code-ish half-return-half-gotos. Where as with one final return you enter at the top of the function and exit at the bottom, always.

    It's not like you dont have to track the "state of variables" if you're trying to figure out a function with multiple returns, just one fewer, with the exception that it can now bail on lines 20, 27, or 45. It's one fewer "mystery" to worry about, especially the lines add up. Also, since each return can now have some "returnVal" variable of their own, now you've just multiplied the thing you don't like by 3 instead of solving anything.

    Of course both issues can be alleviated greatly by just not having giant functions doing too many things in the first place.

  • (disco) in reply to Dragnslcr
    Dragnslcr:
    Argh, why?

    If you don't exercise as much stack space as possible, the bits get all flabby. YOU DON'T WANT FLABBY BITS DO YOU?!

    You have a pile of flabby bits, the next thing you know you've got a @flabdablet on your hands, and then you've got trouble.

  • (disco) in reply to vita10gy
    vita10gy:
    just one fewer

    One fewer, which, in even mildly complex functions, could potentially change in one or more different ways before it finally gets returned. If it reaches a point where it doesn't change anymore, that's much easier to figure out with an early return than by having to dig through the entire rest of the function just to double-check that it's not changing anymore.

  • (disco) in reply to vita10gy
    vita10gy:
    It's not like you dont have to track the "state of variables" if you're trying to figure out a function with multiple returns, just one fewer, with the exception that it can now bail on lines 20, 27, or 45. It's one fewer "mystery" to worry about, especially the lines add up.

    But then there's a different problem of "ok, this is false now, does it change later?".

    With a return at least you're safe from that.

  • (disco) in reply to Onyx
    Onyx:
    But then there's a different problem of "ok, this is false now, does it change later?".

    With a return at least you're safe from that.

    Fox:
    One fewer, which, in even mildly complex functions, could potentially change in one or more different ways before it finally gets returned. If it reaches a point where it doesn't change anymore, that's much easier to figure out with an early return than by having to dig through the entire rest of the function just to double-check that it's not changing anymore.

    Well, again, I don't think any coding standards should be adopted in a "no matter how hard it is to do this, do this" fashion. However I think in most cases if you're "tracking" too many changes in one function, it shouldn't be one function in the first place.

    With a few exceptions this usually strikes me as a "well, sure, it's superficially a little cleaner that way, but only because you've backed yourself into this corner" type deal. You shouldn't have a 200 line function you're "tracking" anything which "could change based on the code below it" (as if what's there is just some mystery on what it does or if it does it) in any terribly meaningful way in the first place.

    The main overarching objection stems from this: You wouldn't add a goto, or something equivalent, to just skip over a chunk of code and avoid the implications of "I know I have what I want now, what if the code below this changes it?!" literally anywhere else outside of a function (at least I hope not :)). I don't particularly see why that modus operandi changes inside a function. Code starts at the top, and runs to the bottom literally everywhere else, why do functions differently as a matter of policy?

  • (disco) in reply to FrostCat
    FrostCat:
    flabby bits

    :giggity:

  • (disco) in reply to vita10gy
    vita10gy:
    I'm mostly a "no early returns guy"

    I broke my mouse clicking the little heart too hard.

  • (disco) in reply to Fox
    Fox:
    double-check that it's not changing anymore.

    Use more final. In fact, final all the things. The vast majority of variables shouldn't vary.

Leave a comment on “The Returned Value”

Log In or post as a guest

Replying to comment #460480:

« Return to Article