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
Flobbster
Feb 17, 2005

"Cadet Kirk, after the way you cheated on the Kobayashi Maru test I oughta punch you in tha face!"
^^ Not before I make this post that I've already been typing :v:

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, but I would argue that forcing the user to put unrelated methods statically into some kind of "StringUtils" class or whatever is an even more egregious violation. There's no "object" there -- it's a workaround for an implementation detail and has nothing to do with the component design of the project. And as long as the language doesn't permit extension methods/categories to access private data in the class, then there's no violation of encapsulation either.

I use categories all the time when I do Cocoa programming and I can't imagine living without them. I wrote a method once that escaped XML entities (ampersand, quotes, greater/less-than signs) and returned the new string, and it makes a lot more sense to write (I'll use C#-style syntax here for those unfamiliar with Obj-C) x = the_string.escapeXMLEntities() than it is to write x = HurfDurfXMLEscaper.escapeXMLEntities(the_string). It's no loving contest.

Adbot
ADBOT LOVES YOU

Anonymous Name
Apr 25, 2006

by Fragmaster
Well, you could just write a class that derives from string, which includes your new methods.

Horse Cock Johnson
Feb 11, 2005

Speed has everything to do with it. You see, the speed of the bottom informs the top how much pressure he's supposed to apply. Speed's the name of the game.

Anonymous Name posted:

Well, you could just write a class that derives from string, which includes your new methods.

System.String is sealed in the .NET Framework.

trex eaterofcadrs
Jun 17, 2005
My lack of understanding is only exceeded by my lack of concern.

Mr. Herlihy posted:

System.String is sealed in the .NET Framework.

And java.lang.String is final. You'd have to facade it, and lose a bunch of syntatic sugar.

KaeseEs
Feb 23, 2007

by Fragmaster

Flobbster posted:

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

You've just nailed one of the biggest meta-horrors there is. Programmers* are superstitious fucks who care more about fidelity to the received wisdom of their teachers and blind adherence to dogma than actually mapping out a solution in terms that match the way they think about the problem (don't worry, though; after doing this long enough, you forget how to think about problems in any other terms than those that match your One True Model!). They will move mountains to shoehorn a [potentially simple] design into their [convoluted] methodology of choice (likely the only one they bothered learning), and berate without end their peers that do otherwise. They will argue at length without reason or sense about topics in which they hold no expertise.

There are a lot of issues that feed these pathologies; computer programming and software engineering are immature fields that have made vast gains in very few years, and no analysis of said gains has been sorted out as a clear winner yet. Often, when programmers are being taught, trite and contorted examples of 'bad' techniques are trotted trotted out as straw men for 'better' techniques to tear down (in some cases, bad and better are accurate, which is why it's really sad that they're demonstrated so poorly); related to this, programmers tend to know just enough about logic, the scientific method and statistics to be dangerous. Finally, the social aspects of programming can encourage the formation of primadonnas and other borderline personality types.

For some examples, talk to three C++ programmers: one taught in the early '80s (a more recent coder who is comfortable in C is an accaepable substitute), one taught in the early/mid '90s, and one in the last few years.




*vast overgeneralization for the sake of argument (physician heal thyself lol)

Plorkyeran
Mar 22, 2007

To Escape The Shackles Of The Old Forums, We Must Reject The Tribal Negativity He Endorsed

Anonymous Name posted:

Well, you could just write a class that derives from string, which includes your new methods.

Even if this was possible, it still wouldn't work cleanly on strings you didn't create.

Vanadium
Jan 8, 2005

Sounds like it should be easily possible to make foo == any_of(bar, baz, qux) work in C++, if some boost lib does not already.

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.
Does the runtime overhead of creating a list and copying elements to it count as a coding horror?

Volte
Oct 4, 2004

woosh woosh
No, because if the number of possibilities is small enough that you would otherwise list them in the code then the performance difference is negligible. If the choices are dynamic or enormous you'll probably (hopefully) be using a list operation anyway (albeit not likely an inline one). Only if you are doing many such checks in rapid succession would the difference manifest itself, in which case you would then optimize accordingly. Of course, you shouldn't be optimizing before you need to anyway. So any drawbacks are in most cases purely theoretical.

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.

Volte posted:

No, because if the number of possibilities is small enough that you would otherwise list them in the code then the performance difference is negligible.
Maybe, but it's an unnecessary source of potential overhead for a negligible readability improvement.

Flobbster
Feb 17, 2005

"Cadet Kirk, after the way you cheated on the Kobayashi Maru test I oughta punch you in tha face!"

Mustach posted:

Maybe, but it's an unnecessary source of potential overhead for a negligible readability improvement.

I haven't had an opportunity to play around with variadic templates yet in the upcoming C++0x, but I bet something like this could be thrown together:

code:
template <typename ValueToCompare, typename... PossibleValues>
bool is_one_of(const ValueToCompare& lhs, PossibleValues... rhs)
{
    // return (lhs == the first rhs value) || (is_one_of(lhs, the remaining rhs values));
}
The implementation would test the first value ORed with a recursive call that unpacks the remaining arguments and performs the test again. Assuming the compiler can aggressively inline this, it would probably expand to a simple sequence of || operations anyway. Anyone with a supporting compiler want to take a crack at it?

This is also CRAZY and going way out of one's way to implement what amounts to syntactic sugar for a sequence of OR comparisons :psyduck:

Vanadium
Jan 8, 2005

Flobbster posted:

This is also CRAZY and going way out of one's way to implement what amounts to syntactic sugar for a sequence of OR comparisons :psyduck:

So basically you are saying it is going to be in the next boost release?

Edit: Based on your example, seems to work with gcc 4.3.1:

code:
#include <iostream>

template <typename T, typename Other>
bool is_one_of(T lhs, Other rhs) {
  return lhs == rhs;
}

template <typename T, typename First, typename... Rest>
bool is_one_of(T lhs, First rh, Rest... rhs) {
  return lhs == rh || is_one_of(lhs, rhs...);
}

int main() {
  if (is_one_of(1, 3, 4, 1, 2, 5)) 
    std::cout << "yay" << std::endl;

  if (is_one_of<std::string>("foo", "bar", "baz", "foo")) 
    std::cout << "yay 2" << std::endl;
}
I would still prefer to have the 'a == any_of(b, c, d)" syntax because it is easier to read and probably makes it easy to overload other operators than == as well. I did not bother with the whole "taking template arguments by const reference" thing because you probably need to use boost.call_traits to do it correctly, and I have no idea how to apply that to variadic templates.

Vanadium fucked around with this message at 22:33 on Aug 27, 2008

Flobbster
Feb 17, 2005

"Cadet Kirk, after the way you cheated on the Kobayashi Maru test I oughta punch you in tha face!"

Vanadium posted:

I would still prefer to have the 'a == any_of(b, c, d)" syntax because it is easier to read and probably makes it easy to overload other operators than == as well. I did not bother with the whole "taking template arguments by const reference" thing because you probably need to use boost.call_traits to do it correctly, and I have no idea how to apply that to variadic templates.

After thinking about it, 'a == any_of(b, c, d)' might be easier than I first thought.

Instead of doing the comparison inside 'any_of' like above, just have it return an instance of a class, say, AnyOfComparator. Then define global operators, template <typename T> bool operator==(const T& lhs, const AnyOfComparator<???>& rhs) and template <typename T> bool operator==(const AnyOfComparator<???>& lhs, const T& rhs) (I can't visualize what the template args for this class would be without playing around with it). These operators would just delegate to a helper function in the comparator class to do the actual comparison. This way, you could extend it to other relops by just overloading them.

I may just have to download the latest gcc to play with this, just for my own curiosity. I really just want to see if code like this would get inlined into a similar sequence of comparison/branches that the raw conditional statement would.

Things like this is why I can't wait for C++0x to be official. I rarely do any serious C++ programming anymore, but this would be like a fun new Christmas toy for me.

vvv Except what we're talking about is syntax like: string s; s.myOwnExtensionFunction();, in which no conversion, implicit or otherwise, will downcast "s" from a string to some arbitrary subclass that I write. Nor should it.

Flobbster fucked around with this message at 22:48 on Aug 27, 2008

Anonymous Name
Apr 25, 2006

by Fragmaster

Plorkyeran posted:

Even if this was possible, it still wouldn't work cleanly on strings you didn't create.
It would if you have implicit conversion operators / constructors. Remember that we are only talking about new functions, not new members. Nothing is lost when "converting" from one to another.

Flobbster
Feb 17, 2005

"Cadet Kirk, after the way you cheated on the Kobayashi Maru test I oughta punch you in tha face!"
Holy poo poo, I made 'any_of' with variadic templates work. (g++ 4.3.0) I suppose the code below definitely qualifies as a "horror".

code:
// Forward declaration
template <typename... Values>
class any_of_comparator;

// Base case
template <typename First>
class any_of_comparator<First>
{
private:
	const First& first;
	
public:
	any_of_comparator(const First& _f) : first(_f) { }
	
	template <typename T>
	bool not_contains(const T& value) const
	{
		return value != first;
	}

	template <typename T>
	bool contains(const T& value) const
	{
		return value == first;
	}
};

// Recursive case
template <typename First, typename... Rest>
class any_of_comparator<First, Rest...> : private any_of_comparator<Rest...>
{
private:
	const First& first;

public:
	any_of_comparator(const First& _f, const Rest&... _r) :
		first(_f), any_of_comparator<Rest...>(_r...)
	{
	}

	template <typename T>
	bool not_contains(const T& value) const
	{
		return (value != first) && any_of_comparator<Rest...>::not_contains(value);
	}

	template <typename T>
	bool contains(const T& value) const
	{
		return (value == first) || any_of_comparator<Rest...>::contains(value);
	}
};

// The functional form is required so that the compiler will deduce the template types
// (which it won't do if we left this out and tried to use the constructor for the
// above class instead)
template <typename... Values>
any_of_comparator<Values...> any_of(const Values&... values)
{
	return any_of_comparator<Values...>(values...);
}

template <typename T, typename... Values>
bool operator==(const T& lhs, const any_of_comparator<Values...>& rhs)
{
	return rhs.contains(lhs);
}

template <typename T, typename... Values>
bool operator!=(const T& lhs, const any_of_comparator<Values...>& rhs)
{
	return rhs.not_contains(lhs);
}
The recursive inheritance trick on the comparator class is pretty cool, and I wouldn't have thought of it if I hadn't seen a similar declaration for tuples in the variadic templates proposal doc.

So the original question was, how efficient is this compared to a chain of if-statements? With -O3 enabled, the compiler does a phenomenal job of inlining this and it turns out it's exactly the same:

code:
// Try with constants. The following lines of code both generate the exact same assembly:
//     i == any_of(1, 2, 3, 4, 5)
//     (i == 1 || i == 2 || i == 3 || i == 4 || i == 5)
	movl	-28(%ebp), %eax
	cmpl	$1, %eax
	je	L4
	cmpl	$2, %eax
	je	L4
	cmpl	$3, %eax
	je	L4
	cmpl	$4, %eax
	je	L4
	cmpl	$5, %eax
	sete	%dl
	jmp	L5
	.align 4,0x90
L4:
	movl	$1, %edx

// Try with variables. The following lines of code both generate the exact same assembly:
//     i != any_of(j, k, l)
//     (i != j && i != k && i != l)
	cmpl	-32(%ebp), %eax
	je	L20
	cmpl	-36(%ebp), %eax
	je	L20
	cmpl	-40(%ebp), %eax
	setne	%al
	jmp	L21
	.align 4,0x90
L20:
	xorl	%eax, %eax
That's just loving incredible. Crazy poo poo like this is why I still love C++ after all these years.

EDIT: removed an extra not in the != operator

Flobbster fucked around with this message at 00:55 on Aug 28, 2008

Vanadium
Jan 8, 2005

I got pretty much as far, except I did the recursion by composition and not inheritance, but then I tried to wrap boost::call_traits<T>::param_type around everything to avoid needless copying and it all fell apart. :(

Edit: I guess they just gently caress with argument deduction. How does this perfect forwarding thing work again...

Any ideas how to make it require less copying?

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

template<typename... ArgsT>
struct any_impl;

template<typename FirstT>
struct any_impl<FirstT> {
  any_impl(FirstT first) : first(first) {}

  FirstT first;
};

template<typename FirstT, typename... OtherTs>
struct any_impl<FirstT, OtherTs...> {
  any_impl(FirstT first, OtherTs... others)
    : first(first), others(others...) {}

  FirstT first;
  any_impl<OtherTs...> others;
};

template<typename T, typename AnyT>
bool operator==(T obj, const any_impl<AnyT>& any) {
  return obj == any.first;
}

template<typename T, typename FirstT, typename... OtherTs>
bool operator==(T obj, const any_impl<FirstT, OtherTs...>& any) {
  return obj == any.first || obj == any.others;
}

template<typename T, typename AnyT>
bool operator==(const any_impl<AnyT>& any, T obj) {
  return obj == any.first;
}

template<typename T, typename FirstT, typename... OtherTs>
bool operator==(const any_impl<FirstT, OtherTs...>& any, T obj) {
  return any.first == obj || any.others == obj;
}

template<typename... ArgTs>
any_impl<ArgTs...> any_of(ArgTs... args) {
  return any_impl<ArgTs...>(args...);
}

// "trace" copying
template<typename T>
struct verbose {
  verbose(T val) : val(val) {
    std::cout << " verbose( " << val << " )" << std::endl;
  }

  verbose(const verbose& other) : val(other.val) {
    std::cout << " verbose([" << val << "])" << std::endl;
  }

  ~verbose() {
    std::cout << "~verbose( " << val << " )" << std::endl;
  }

  bool operator==(const verbose& other) const {
    std::cout
      << " verbose( " << val << " ) == verbose( "
      << other.val << " )" << std::endl;
    return val == other.val;
  }

  T val;
};

int main() {
  if (any_of(4, 3, 2, 1) == 1)
    std::cout << "yay" << std::endl;

  if (std::string("foo") == any_of("foo", "bar", "baz"))
    std::cout << "yay 2" << std::endl;

  verbose<int> v1(1), v2(2), v3(3), v4(4);
  if (any_of(v1, v2, v3, v4) == verbose<int>(5))
    std::cout << "yay 3" << std::endl;
}

Vanadium fucked around with this message at 00:44 on Aug 28, 2008

Arconom
Jun 27, 2006
Edouard Joseph Gilliath 1417 - 1460 Battle of Arkinholm risen again to protect
You guys code too much.

Scaevolus
Apr 16, 2007

Flobbster posted:

So the original question was, how efficient is this compared to a chain of if-statements? With -O3 enabled, the compiler does a phenomenal job of inlining this and it turns out it's exactly the same:
What about -O2?

That Turkey Story
Mar 30, 2003

Vanadium posted:

I got pretty much as far, except I did the recursion by composition and not inheritance, but then I tried to wrap boost::call_traits<T>::param_type around everything to avoid needless copying and it all fell apart. :(

It would be impossible to deduce T in an expression like that because you'd be trying to deduce an unknown metafunction's nested type. The purpose of call_traits is for times when T is already known, for instance if T is a template parameter of a class and you wish to use call_traits to determine the parameter type to be used for a member function which takes a T. std::forward in 0x actually uses this behavior to its advantage to make it so that you have to explicitly specify the template instantiation when using it (its parameter type is based on the evaluation of an identity metafunction of the specified type).

Flobbster
Feb 17, 2005

"Cadet Kirk, after the way you cheated on the Kobayashi Maru test I oughta punch you in tha face!"

Scaevolus posted:

What about -O2?

-O2 comes out the same as -O3, compiled into to an inlined sequence of cmp/branch instructions. Under -O/-O1 though, the class, instantiated object, and method calls remain.

POKEMAN SAM
Jul 8, 2004
At work someone wrote this:

code:
if (m_variable != null) {
    throw new ArgumentNullException("m_variable");
}
lol what a retard

vanjalolz
Oct 31, 2006

Ha Ha Ha HaHa Ha
Lets bring this thread back to easy to understand coding horrors :)

A few days ago I saw return ((x > 0) ? true : false); and there were like 10 of these in a line.

Scaevolus
Apr 16, 2007

Flobbster posted:

-O2 comes out the same as -O3, compiled into to an inlined sequence of cmp/branch instructions. Under -O/-O1 though, the class, instantiated object, and method calls remain.

I ask because -O3 can cause some weird bugs, so I tend to use -O2.

more falafel please
Feb 26, 2005

forums poster

vanjalolz posted:

Lets bring this thread back to easy to understand coding horrors :)

A few days ago I saw return ((x > 0) ? true : false); and there were like 10 of these in a line.

I've seen return(((some_bool) ? (true) : (false)));

Mikey-San
Nov 3, 2005

I'm Edith Head!

more falafel please posted:

I've seen return(((some_bool) ? (true) : (false)));

Sometimes you need to make absolutely sure you really mean true.

sarehu
Apr 20, 2007

(call/cc call/cc)
I saw

code:
for (int loop = 0; loop < 1; loop++) {
...
}
recently. It wasn't the kind of thing that should ever be a loop, too.

RegonaldPointdexter
Mar 13, 2006

Hey guys what's going on?
I saw this in some JavaScript yesterday:

code:
var change = true;
change = false;
while(change) {
  change = false;
No, I didn't remove any lines inbetween. It was exactly like this.

HIERARCHY OF WEEDZ
Aug 1, 2005

code:
DELETE FROM tblGoo WHERE SUBSTR(foo, 1, 3) <> '200'
-- TO MAKE SURE FOO IS A DATE
Uh-huh. That's fascinating.

Fenderbender
Oct 10, 2003

You have the right to remain silent.

RegonaldPointdexter posted:

I saw this in some JavaScript yesterday:

code:
var change = true;
change = false;
while(change) {
  change = false;
No, I didn't remove any lines inbetween. It was exactly like this.

Maybe the developer is a staunch republican?

:rimshot:

Mikey-San
Nov 3, 2005

I'm Edith Head!
Just spotted this in the source for a web performance analysis tool:

code:
  
if (pObj==NULL)
    return JS_TRUE;;

return JS_TRUE;

POKEMAN SAM
Jul 8, 2004

RegonaldPointdexter posted:

I saw this in some JavaScript yesterday:

code:
var change = true;
change = false;
while(change) {
  change = false;
No, I didn't remove any lines inbetween. It was exactly like this.

Just trying to be thread safe!

DaTroof
Nov 16, 2000

CC LIMERICK CONTEST GRAND CHAMPION
There once was a poster named Troof
Who was getting quite long in the toof

Ugg boots posted:

Just trying to be thread safe!

Hahahahaha. I had a coworker who used to pepper functions with sleep calls and identical database updates as a poor attempt to work around race conditions. His code looked like the guy from Memento wrote it.

Zhentar
Sep 28, 2003

Brilliant Master Genius
Searching for "if 1" in my code base here finds enough results that I'm not sure if it's in the tens of thousands or hundreds of thousands. :911:

JoeNotCharles
Mar 3, 2005

Yet beyond each tree there are only more trees.

Mikey-San posted:

code:
  
if (pObj==NULL)
    return JS_TRUE;;

return JS_TRUE;

Nothing wrong with that (except the doubled ; ). It's future-proofing. If you want to add more tests to that method, you put them between the two return statements. If you left out the first one, whoever extends it next might forget to check if pObj is set.

For most things this wouldn't be appropriate, but "if (pObj == NULL)" is an obvious guard and not part of the method's internal logic.

Flobbster
Feb 17, 2005

"Cadet Kirk, after the way you cheated on the Kobayashi Maru test I oughta punch you in tha face!"

JoeNotCharles posted:

Nothing wrong with that (except the doubled ; ). It's future-proofing. If you want to add more tests to that method, you put them between the two return statements. If you left out the first one, whoever extends it next might forget to check if pObj is set.

For most things this wouldn't be appropriate, but "if (pObj == NULL)" is an obvious guard and not part of the method's internal logic.

Then there should be a comment indicating exactly what you just said :colbert:

Mikey-San
Nov 3, 2005

I'm Edith Head!

Flobbster posted:

Then there should be a comment indicating exactly what you just said :colbert:

And when you do that, the code isn't necessary at all. Don't rely on code to convey intent, that's what comments are for. If you're worried about a future traveler not knowing to look for a potential situation and handle it differently, make a note in a comment.

Vanadium
Jan 8, 2005

RegonaldPointdexter posted:

I saw this in some JavaScript yesterday:

code:
var change = true;
change = false;
while(change) {
  change = false;
No, I didn't remove any lines inbetween. It was exactly like this.

Looks like the loop would potentially reset change to true if it turned out it did not actually want to exit, and the first "change = false" is just a quick hack to disable the loop entirely.

Dessert Rose
May 17, 2004

awoken in control of a lucid deep dream...

RegonaldPointdexter posted:

I saw this in some JavaScript yesterday:

code:
var change = true;
change = false;
while(change) {
  change = false;
No, I didn't remove any lines inbetween. It was exactly like this.

I actually did this in an early version of C#, to demonstrate a bug. I don't remember the exact circumstances leading up to this code, but I was having problems with string assignment, and this code actually looped forever:

code:
string s = "something";
s = "something else";
while (s != "something else") {
  s = "something else";
}
I was quite aggravated about this. No exceptions, nothing. I wish I could find the code again.

zootm
Aug 8, 2006

We used to be better friends.

Ryouga Inverse posted:

I was quite aggravated about this. No exceptions, nothing. I wish I could find the code again.
There is no guarantee that string literals will be interned, so surely this is an expected behaviour?

Adbot
ADBOT LOVES YOU

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.
== and != are overloaded to do value comparison for Strings in C#.

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