Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
zootm
Aug 8, 2006

We used to be better friends.

Mustach posted:

== and != are overloaded to do value comparison for Strings in C#.
Ah, fair enough. For some reason I thought it was just switch that was magic.

Adbot
ADBOT LOVES YOU

JoeNotCharles
Mar 3, 2005

Yet beyond each tree there are only more trees.
Duplicate code is terrible, but common enough that it's not really worth posting in this thread - usually.

However, I just found an absolutely ridiculous amount of it:

code:
// mFileName is a member variable of SomeClass.
// All names were made up by me, so ignore them; the real ones aren't [i]too[/i] crappy.

bool SomeClass::saveAs()
{
  if (filetype == FILE_TYPE_1)
  {
    mFileName = getFileNameFromAFileDialog();

    // about 50 lines of code involved in saving the file

    if (loggedIn)
      sendFileUpdatedMessageToAnotherApp(loginName,
                                         about 20 other parameters,
                                         one per line);
    else
      sendFileUpdatedMessageToAnotherApp("",
                                         about 20 other parameters,
                                         one per line);
  }
  else if (filetype == FILE_TYPE_2)
  {
    mFileName = getFileNameFromAFileDialog();

    // about 50 lines of code involved in saving the file, which are
    // EXACTLY THE SAME as for FILE_TYPE_1

    if (loggedIn)
      sendFileUpdatedMessageToAnotherApp(loginName,
                                         about 20 other parameters,
                                         one per line);
    else
      sendFileUpdatedMessageToAnotherApp("",
                                         about 20 other parameters,
                                         one per line);  
  }
  else if (filetype == FILE_TYPE_3)
  {
    mFileName = getFileNameFromAFileDialog();

    // about 50 lines of code involved in saving the file, with a
    // ONE LINE DIFFERENCE from the code in FILE_TYPE_1 and FILE_TYPE_2

    if (loggedIn)
      sendFileUpdatedMessageToAnotherApp(loginName,
                                         about 20 other parameters,
                                         one per line);
    else
      sendFileUpdatedMessageToAnotherApp("",
                                         about 20 other parameters,
                                         one per line);
  }
}

bool SomeClass::save()
{
  if (filetype == FILE_TYPE_1) {
    if (neverBeenSaved) {
      // ALL the code from saveAs for FILE_TYPE_1
    } else {
      // the same code again, just missing the mFileName = because it's already set
    }
  } else if (filetype == FILE_TYPE_2) {
    if (neverBeenSaved) {
      // ALL the code from saveAs for FILE_TYPE_2
    } else {
      // the same code again, just missing the mFileName = because it's already set
    }
  } else if (filetype == FILE_TYPE_3) {
    if (neverBeenSaved) {
      // ALL the code from saveAs for FILE_TYPE_3
    } else {
      // for FUCKS SAKE what were you THINKING?
    }
  }
}
That's NINE copies of the core "save" code, and EIGHTEEN of the sendFileUpdatedMessage call. And yes, there was one change in one of the copies which I can't account for.

But wait! There's more!

code:
bool SomeClass2::save()
{
  // it's exactly like SomeClass1::save, with 1 additional line in the 50-line 
  // core save code because this class has 1 extra data member!
}

bool SomeClass2::saveAs()
{
  // yeah, again!
}

BigRedDot
Mar 6, 2008

JoeNotCharles posted:

That's NINE copies of the core "save" code, and EIGHTEEN of the sendFileUpdatedMessage call. And yes, there was one change in one of the copies which I can't account for.

From the other end of the spectrum (bigger code block, but repeated few times) I recall some code from a physicist office mate once that had one 3000 line block of code repeated five times in a row—just with what amounted to a loop iteration variable changing everywhere in each block.

return0
Apr 11, 2007

BigRedDot posted:

From the other end of the spectrum (bigger code block, but repeated few times) I recall some code from a physicist office mate once that had one 3000 line block of code repeated five times in a row—just with what amounted to a loop iteration variable changing everywhere in each block.


It was a savage optimisation.

Lexical Unit
Sep 16, 2003

I was trying to fix a compile issue due to an upgrade to a newer version of a vendor provided library. The code was C++. The writer of this library was sitting behind me and I was at the keyboard. I opened up one of my files that had a compile error and was fixing it when the guy behind me says:

Guy: What's that syntax there?
Me: Eh?
Guy puts finger on screen to point at a &
Guy: That.
Me: Oh, I don't want to copy that object so I passed it by reference.
Guy: What's that?
Me: Um. It's a reference.
Guy: I don't get it. Is that like a pointer or something? I usually use that to mean address-of.
Me: Well... it's kinda like a pointer... but it's a reference.
Guy: I don't know about that, I'd take it out to be safe.
Me: Uh huh. Well. I'll take my chances.

For fucks sake this guy wrote nearly 300 kloc of C++ and he doesn't know what a reference is? gently caress me.

JoeNotCharles
Mar 3, 2005

Yet beyond each tree there are only more trees.

Lexical Unit posted:

For fucks sake this guy wrote nearly 300 kloc of C++ and he doesn't know what a reference is? gently caress me.

I'd MUCH rather have someone who doesn't know about a C++ feature and sticks to C than someone who thinks they understand exceptions or templates or whatever and gets them wrong.

Mustach
Mar 2, 2003

In this long line, there's been some real strange genes. You've got 'em all, with some extras thrown in.
You say that like references are one of C++'s harder-to-understand constructs.

Lexical Unit posted:

For fucks sake this guy wrote nearly 300 kloc of C++ and he doesn't know what a reference is? gently caress me.
More evidence against putting much meaning behind line counts. When you code like the guy in BigRedDot's story, it's pretty easy to hit the high numbers.

JawnV6
Jul 4, 2004

So hot ...

Flobbster posted:

Objective-C has had this so-called "monkeypatching"/extension methods for about 100 years now in the form of categories, and it's about time other languages like C# have decided that it's a feature worth having.

I often hear self-proclaimed "OO purists" complain that attaching methods to a class you didn't write is a violation of OO design

I thought the whole deal with "monkeypatching" was overriding existing methods. So for example, if I want to change String.length() to always return 42 or rand() or something I can do it and make it a horrible mess to debug whenever that library is included.

I work in a language with the constructs "is also" and "is only". So if you've declared a structure and I want to add to it, it's as easy as saying "your_struct is also {...};" If I want to blow it out entirely and replace it, it's "your_struct is only {...};" Same with functions, objects, anything. I can just attach another file and go change everything.

The runtime debugger builds up all the code and figures out the also's/only's, it's one of the only ways to see what the hell is actually included and running.

edit: I forgot "is first". "is also" adds to the end of whatever was there before, "is first" adds to the top.

JawnV6 fucked around with this message at 12:55 on Aug 31, 2008

JoeNotCharles
Mar 3, 2005

Yet beyond each tree there are only more trees.

Lexical Unit posted:

I was trying to fix a compile issue due to an upgrade to a newer version of a vendor provided library. The code was C++.

...

For fucks sake this guy wrote nearly 300 kloc of C++ and he doesn't know what a reference is? gently caress me.

Actually, let me ask a question - when you say "the code was C++" do you mean the library was definitely written in C++, or it had a C++ interface? Cause it could well have all be C on the inside.

Lexical Unit
Sep 16, 2003

The library is the C++ implementation for a CORBA client using TAO. It is most assuredly C++ in every conceivable way. The guy billed himself as "The C++ Guy," not "The C Guy Who Just Happens To Use A C++ Compiler." His job description could have literally been "The Guy Who Implemented This Library In C++."

JediGandalf
Sep 3, 2004

I have just the top prospect YOU are looking for. Whaddya say, boss? What will it take for ME to get YOU to give up your outfielders?

whiskas posted:

If any of you have ever used infragistics this is all too common:


We use Infragistics @ work and I haven't come across this. How does this happen?

Anonymous Name
Apr 25, 2006

by Fragmaster

Lexical Unit posted:

Me: Well... it's kinda like a pointer... but it's a reference.
It's exactly like a pointer in implementation, of course. Actually I see references overused pretty often -- they're best for optimization so you're not copying an object, like in your example, but I also see them used for output often, which is bad. For a hypothetical example, there could be a call:

code:
GetWordwrapLines( str, str_len, column_width, lines, count );
And the first three parameters are input while the last two are output, but it looks like they're all input. There's no indication, from the above code, which are input and which are output. Using pointers for output (&lines, &output) makes it more obvious. Plus it allows you to pass NULL if you don't care about a certain value, rather than creating a local variable just so you can call the function.

Vanadium
Jan 8, 2005

Anonymous Name posted:

It's exactly like a pointer in implementation, of course.

Pointers behave nowhere near exactly like this:

code:
#include <string>
#include <iostream>

std::string f() { return "yay"; }

int main() {
  const std::string& s = f();

  std::cout << s.size() << " - " << s;
}

Lexical Unit
Sep 16, 2003

Anonymous Name posted:

unclear code
So long as you practice good const correctness, this issue should be made pretty clear from the function signature. And really, if you're using a function, I'd expect you'd be familiar with that much at the very least.
code:
int foo(const object& input, object& output);
Also sometimes it's not just optimization that a reference is used for, but some objects simply don't have value semantics and shouldn't ever be copied. When dealing with some opaque object from some vendor's library, it's best just to be safe and not assume things will just work. It'd be nice if they actually documented their library so I would know exactly how their objects can be used... but that's just a pipe dream.

floWenoL
Oct 23, 2002

Lexical Unit posted:

So long as you practice good const correctness, this issue should be made pretty clear from the function signature. And really, if you're using a function, I'd expect you'd be familiar with that much at the very least.

The person who wrote the code may be completely familiar with the function, but maybe not the person reading the code later.

BigRedDot
Mar 6, 2008

floWenoL posted:

The person who wrote the code may be completely familiar with the function, but maybe not the person reading the code later.
I pretty fastidiously avoid using reference arguments as return parameters, for exactly this reason. Unfortunately I seem to see them alot at work, both from coworkers and from some of our libraries, for instance:
code:
ProjectDegrees( double northing, double easting, double & lat double & lon );
UnprojectDegrees( double lat, double lon, double & northing, double & easting );
Athough, I hate this pair even more for their names, since I can never remember if, for instance, ProjectDegrees is supposed to signify Project_TO_Degrees or Project_FROM_Degrees and I invariably have to go look which is which. There were lots of function names with this problem at a previous job, grrr. But I digress. . .

Anyway I did just recently finally concede a situation where reference return parameters were more useful than not (to me anyway), so I can't make a blanket admonition. I got tired of writing the the little snippets of code to read values out of text entry widgets all over the place, and having a stable of separate GetFloat, GetUnsigned, GetDouble, GetChar, GetInt, GetWhatever, ... functions annoys the hell out of me (other people at work do this in other situations, and that's also a coding horror to me). So I use:
code:
template <typename T>
bool ScrapValueFromWidget( Widget * w 
                           T &      val ) { ... }
If only return types were part of function signatures in C++ I could make the return type T and just leak the exception from boost::lexical_cast if it fails, but we go to work with the compiler standard we have, not the compiler standard we might want. In any case, I think the function name makes it pretty clear, and it's documented as a return parameter in the doxygen docs for anyone that cares.

Lexical Unit
Sep 16, 2003

floWenoL posted:

The person who wrote the code may be completely familiar with the function, but maybe not the person reading the code later.
So what is the person who's reading the code going to get out of reading it if they don't know what any of the functions do? :raise:

floWenoL
Oct 23, 2002

Lexical Unit posted:

So what is the person who's reading the code going to get out of reading it if they don't know what any of the functions do? :raise:

Whatever can be gleaned from the function name, comments, and parameter names. If pointers for output params were used consistently, a simple search suffices to find out where a variable can be modified in a called function. If they're not, one has to look up each function where said variable is used as a parameter. Lame.

floWenoL
Oct 23, 2002

BigRedDot posted:

code:
template <typename T>
bool ScrapValueFromWidget( Widget * w 
                           T &      val ) { ... }

I don't get why you can't use T *val here.

Mustach
Mar 2, 2003

In this long line, there's been some real strange genes. You've got 'em all, with some extras thrown in.

Anonymous Name posted:

Using pointers for output (&lines, &output) makes it more obvious. Plus it allows you to pass NULL if you don't care about a certain value,
code:
f(&p, NULL, &r);
Argh my program crashed because the function tried to dereference and write to NULL. Also which of those are output params; I think this function takes at least one pointer-to-const.

floWenol posted:

If they're not, one has to look up each function where said variable is used as a parameter. Lame.
Yeah that's real tough.

floWenoL
Oct 23, 2002

Mustach posted:

code:
f(&p, NULL, &r);
Argh my program crashed because the function tried to dereference and write to NULL. Also which of those are output params; I think this function takes at least one pointer-to-const.

I don't know if you're being intentionally obtuse, but the idea is to use pointers (and not references) only for output parameters. Not to mention that you really shouldn't be passing in NULL to a function without checking that it does handle it. Note that this is a burden only on the code writer and not the code reader.

quote:

Yeah that's real tough.

Oh, how cute, someone who has never done maintenance on a large code base.

more falafel please
Feb 26, 2005

forums poster

floWenoL posted:

I don't know if you're being intentionally obtuse, but the idea is to use pointers (and not references) only for output parameters.

So you never use pointers for other parameters?

floWenoL
Oct 23, 2002

more falafel please posted:

So you never use pointers for other parameters?

One can never say never in C++, eh?

Mustach
Mar 2, 2003

In this long line, there's been some real strange genes. You've got 'em all, with some extras thrown in.

floWenoL posted:

I don't know if you're being intentionally obtuse, but the idea is to use pointers (and not references) only for output parameters.
There are plenty of currently-existing functions in the world that take pointers as input parameters, and Anonymous Name already mentioned passing in NULL as a valid argument.

quote:

Oh, how cute, someone who has never done maintenance on a large code base.
Being able to search for "&v" over "v" is not the huge timesave you're making it out to be. Java has no "const"; any method can modify any object that's passed to it if the object's class has mutators. That hasn't stopped the creation of huge and functioning Java codebases, probably because they aren't structured so that "I don't know where this variable is being modified, time to search every source file" becomes possible.

StickGuy
Dec 9, 2000

We are on an expedicion. Find the moon is our mission.

floWenoL posted:

If pointers for output params were used consistently, a simple search suffices to find out where a variable can be modified in a called function. If they're not, one has to look up each function where said variable is used as a parameter. Lame.

floWenoL posted:

Not to mention that you really shouldn't be passing in NULL to a function without checking that it does handle it.
:psyduck:
So... you should always have to check whether functions can handle NULL pointers, but you should never have to check whether or not a pointer is being used for input or output?

floWenoL
Oct 23, 2002

StickGuy posted:

:psyduck:
So... you should always have to check whether functions can handle NULL pointers, but you should never have to check whether or not a pointer is being used for input or output?

Hint: one has to be done only by the code writer, and the other may potentially have to be done by code readers/maintainers.

floWenoL
Oct 23, 2002

Mustach posted:

There are plenty of currently-existing functions in the world that take pointers as input parameters, and Anonymous Name already mentioned passing in NULL as a valid argument.

There are plenty of currently-existing functions in the world that take {pointers,references} as {input,output} parameters; so what? If you're in a position where you (as a company) can apply a consistent coding standard and you're working more with your own code than third party code, standardizing on pointers as output parameters is a feasible thing to do.

I don't really see what Anonymous Name said has anything to do with what I said, but whatever.

quote:

Being able to search for "&v" over "v" is not the huge timesave you're making it out to be. Java has no "const"; any method can modify any object that's passed to it if the object's class has mutators. That hasn't stopped the creation of huge and functioning Java codebases, probably because they aren't structured so that "I don't know where this variable is being modified, time to search every source file" becomes possible.

It's not going to save you gigantic amounts of time, but if you're working with a large codebase with many contributors every little bit helps. Also, there are huge and functioning {assembly,COBOL,MUMPS} codebases that do not have "const" either; I don't see what *that* has to do with this discussion, either.

JoeNotCharles
Mar 3, 2005

Yet beyond each tree there are only more trees.

floWenoL posted:

Oh, how cute, someone who has never done maintenance on a large code base.

And yet you keep saying you the writer of functions should be checking for NULL and things like that... Why would you trust the writers of functions in a large code base? Guaranteed at least 50% of the people who worked on them are blithering idiots.

Vanadium
Jan 8, 2005

I am not really willing to give up the convinience of using references for "out" parameters just so you guys do not have to look up the function, sorry guys :shobon:

floWenoL
Oct 23, 2002

JoeNotCharles posted:

And yet you keep saying you the writer of functions should be checking for NULL and things like that... Why would you trust the writers of functions in a large code base? Guaranteed at least 50% of the people who worked on them are blithering idiots.

Wrong-o. I'm saying that the writer of functions should be documenting whether their functions handle NULL or not. And if the writer of the function is indeed an idiot and didn't specify the behavior, well, then you (the maintainer) can assume it doesn't; the result will be no worse than that in the reference case (since a "NULL" reference is undefined).

floWenoL
Oct 23, 2002

Vanadium posted:

I am not really willing to give up the convinience of using references for "out" parameters just so you guys do not have to look up the function, sorry guys :shobon:

Don't you have physics homework that needs doing, Vanadium? :v:

That Turkey Story
Mar 30, 2003

floWenoL posted:

Wrong-o. I'm saying that the writer of functions should be documenting whether their functions handle NULL or not. And if the writer of the function is indeed an idiot and didn't specify the behavior, well, then you (the maintainer) can assume it doesn't; the result will be no worse than that in the reference case (since a "NULL" reference is undefined).

So in other words you get exactly the same behavior when using a pointer except that with a reference you know that an object must be passed based simply based on the parameter type whereas with a pointer you only know if you read further documentation.

floWenoL
Oct 23, 2002

That Turkey Story posted:

So in other words you get exactly the same behavior when using a pointer except that with a reference you know that an object must be passed based simply based on the parameter type whereas with a pointer you only know if you read further documentation.

You get behavior that is *no worse* than using a reference and potentially more readable. :P

I kind of regret bringing this up because it always turns into a shitfest. Honestly, if it's for your own personal project or whatever it doesn't really matter. Didn't we come to an agreement the last time? You mentioned some sort of syntax like "Foo(bar, out(baz))" and I think something like that would be fine if it were applied to the standard libraries (which is a pipe dream, I guess).

BigRedDot
Mar 6, 2008

floWenoL posted:

I don't get why you can't use T *val here.
There's absolutely never a case where NULL should be passed in, but allowing T * would mean the function now has to check that in every single case. That's just silly, and I don't want to do it.

floWenoL
Oct 23, 2002

BigRedDot posted:

There's absolutely never a case where NULL should be passed in, but allowing T * would mean the function now has to check that in every single case. That's just silly, and I don't want to do it.

No it doesn't. That's silly.

That Turkey Story
Mar 30, 2003

floWenoL posted:

You get behavior that is *no worse* than using a reference and potentially more readable. :P

I kind of regret bringing this up because it always turns into a shitfest. Honestly, if it's for your own personal project or whatever it doesn't really matter. Didn't we come to an agreement the last time? You mentioned some sort of syntax like "Foo(bar, out(baz))" and I think something like that would be fine if it were applied to the standard libraries (which is a pipe dream, I guess).

Yeah. I think in the very least we did agree that it would be nice if in certain cases you explicitly label the out parameter when you pass an argument, such as by using something like a boost-style reference wrapper. My stance aside from that, and the reason I prefer references in the absence of a reference wrapper, is that I believe the parameter type should as closely match the purpose of the parameter as possible and tell as much information as possible about its use. A reference has more strict requirements than a pointer, so at least for me, it is more clear of the intent of that parameter if it uses a reference than if it uses a pointer. In either case with a pointer type, you at least wonder if a null pointer is valid (that case doesn't even have to pop into your head with a reference). In the end, I'd much rather see a more specific type than a pass by pointer just for a convention to show an out-parameter and I think that's where we disagree.

floWenoL posted:

No it doesn't. That's silly.

I would at least assert it just like you might do with any function's simple preconditions.

That Turkey Story fucked around with this message at 01:21 on Sep 2, 2008

Mustach
Mar 2, 2003

In this long line, there's been some real strange genes. You've got 'em all, with some extras thrown in.

floWenoL posted:

Wrong-o. I'm saying that the writer of functions should be documenting whether their functions handle NULL or not.
You liar:

floWenol posted:

Lexical Unit posted:

So what is the person who's reading the code going to get out of reading it if they don't know what any of the functions do? :raise:
Whatever can be gleaned from the function name, comments, and parameter names. If pointers for output params were used consistently, a simple search suffices to find out where a variable can be modified in a called function. If they're not, one has to look up each function where said variable is used as a parameter. Lame.

The person who wrote the code may be completely familiar with the function, but maybe not the person reading the code later.
If that's what you really meant, then I'm going to drop it, too. My biggest problem was with the idea that pointer-as-out was some kind of replacement for reading function documentation/asking a coworker; the rest just spun off of that and is apparently well-beaten horse.

BigRedDot
Mar 6, 2008

floWenoL posted:

No it doesn't. That's silly.

Look, I'd love to have explicitly labeled output parameters too. And in the absence of such, I almost always think it's better to not use reference parameters as output parameters. But I'm not going to uphold a convention "just because" in the cases where it doesn't make sense.

If I allow T* then what are the cases. I can 1) never check for NULL, and fail ungraciously if someone happens to pass it in, and I try to write to it. That just won't fly, at least not on the product I develop. So I am left with 2) checking for NULL every single time. Apart from just being irksome in the "why do I have to do this completely unnecessary thing" sense, it's also not so good in that although I can return failure, the real reason for the failure (a NULL pointer that should have never been passed in, as opposed to a failure of lexical_cast) is not immediately evident.

Or, in a trivial function with a blatantly obvious name and explicit supporting documentation I can allow a reference output parameter and not have to worry about any of the above because it's not even possible in the first place.

Flobbster
Feb 17, 2005

"Cadet Kirk, after the way you cheated on the Kobayashi Maru test I oughta punch you in tha face!"
Everyone in this thread right now should shut up and use C#, since it has an explicit distinction between ref and out parameters.

Problem solved.

Adbot
ADBOT LOVES YOU

more falafel please
Feb 26, 2005

forums poster

floWenoL posted:

No it doesn't. That's silly.

Have fun with that.

mustDeref() owns you

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply