Welcome, Guest. Please login or register.

Login with username, password and session length

 
Advanced search

1411507 Posts in 69374 Topics- by 58429 Members - Latest Member: Alternalo

April 26, 2024, 12:57:51 AM

Need hosting? Check out Digital Ocean
(more details in this thread)
TIGSource ForumsDeveloperTechnical (Moderator: ThemsAllTook)What's your favorite programming language?
Pages: 1 ... 9 10 [11] 12
Print
Author Topic: What's your favorite programming language?  (Read 21338 times)
Boreal
Level 6
*


Reinventing the wheel


View Profile
« Reply #200 on: October 23, 2014, 08:41:48 AM »

@Boreal - perhaps more readable? certainly terser Wink

Code:
result = (!mode && test(a,b) || mode == 1) ? foo(a,b) : bar(a,b);

This is the original piece of code where the concept was taken from:

http://pigeonsnest.co.uk/stuff/pigeons-device.html

You could argue for splitting that code up into functions but this is very old code (from before C99) so inline functions were not standard and this was done instead as an optimization.  It's similar to Duff's Device in that it uses a switch statement to jump into the middle of a flow control expression.
Logged

"In software, the only numbers of significance are 0, 1, and N." - Josh Barczak

magma - Reconstructed Mantle API
Layl
Level 3
***

professional jerkface


View Profile WWW
« Reply #201 on: October 23, 2014, 04:25:52 PM »

This is why I love C.

Code:
switch(mode)
{
    case(0): if(test(a, b))
             {
    case(1):     result = foo(a, b);
                 break;
             }
             else
             {
    case(2):     result = bar(a, b);
                 break;
             }
}

Just let that sink in for a bit.

I have no idea what's going on in that code and I'm very scared.
Logged
Geti
Level 10
*****



View Profile WWW
« Reply #202 on: October 23, 2014, 05:27:50 PM »

Today I learned. I wonder how (badly) this kind of thing interacts with modern CPUs. The gruesome hack is certainly unfortunate.
Logged

Boreal
Level 6
*


Reinventing the wheel


View Profile
« Reply #203 on: October 23, 2014, 05:46:33 PM »

Today I learned. I wonder how (badly) this kind of thing interacts with modern CPUs. The gruesome hack is certainly unfortunate.

I doubt that it's an issue, but I don't think it's useful enough for any production-level code to have it.  It's hardly gruesome, just convenient at the time.  Same as the Duff's Device.

If you look at it from the perspective of C89, it's quite safe.
Logged

"In software, the only numbers of significance are 0, 1, and N." - Josh Barczak

magma - Reconstructed Mantle API
Geti
Level 10
*****



View Profile WWW
« Reply #204 on: October 23, 2014, 06:01:04 PM »

Of course, but it's a shame to have to write that kind of code with extra wrappers to set static variables in your search function. I used the word gruesome because the author did, not to be hyperbolic - I'm talking about the mode setting code at the start of the function that relies on NULL signalling to set or get a static variable storing the mode, not the switch itself. I hope that was clear.
Logged

Boreal
Level 6
*


Reinventing the wheel


View Profile
« Reply #205 on: October 23, 2014, 07:20:56 PM »

Of course, but it's a shame to have to write that kind of code with extra wrappers to set static variables in your search function. I used the word gruesome because the author did, not to be hyperbolic - I'm talking about the mode setting code at the start of the function that relies on NULL signalling to set or get a static variable storing the mode, not the switch itself. I hope that was clear.

Oh, yeah, that was some nasty stuff.
Logged

"In software, the only numbers of significance are 0, 1, and N." - Josh Barczak

magma - Reconstructed Mantle API
tjcbs
Level 1
*


View Profile WWW
« Reply #206 on: October 23, 2014, 11:00:39 PM »

Today I learned. I wonder how (badly) this kind of thing interacts with modern CPUs. The gruesome hack is certainly unfortunate.
[/quote]

It's just an indirect branch, right? The Gruesome Hack seemed like a consequence of anti global variable ideology, or maybe the author just wanting to be different, hardly something he had to do.
Logged

Geti
Level 10
*****



View Profile WWW
« Reply #207 on: October 23, 2014, 11:53:40 PM »

But it creates a global anyway! Doesn't polute the namespace I guess but it's not concurrency safe, invokes overhead each time the function is called and isn't a usable pattern for anywhere you may need to compare nulls - the last one not an issue for qsort etc but prevents it from being a general-use comparator. It's certainly an interesting way of doing it while getting around the interface requirement, but I'm not sold on it Smiley As you said, could be accomplished in other ways.
« Last Edit: October 23, 2014, 11:58:56 PM by Geti » Logged

Sik
Level 10
*****


View Profile WWW
« Reply #208 on: October 24, 2014, 02:09:20 AM »

Honestly it seems more of waiting to avoid repeating code. I mean, the more usual (and much more readable) way to do it would be:

Code:
switch (mode) {
   case 0:
      if (test(a, b)) {
         result = foo(a, b);
      } else {
         result = bar(a, b);
      }
      break;
  
   case 1:
      result = foo(a, b);
      break;
  
   case 2:
      result = bar(a, b);
      break;
}

If one wants to avoid repeating code there's always the possibility of doing this instead, assuming the original value of mode doesn't need to be retained (or that specific value of mode can be altered to mean what the test says, which is very likely the case and would simplify any code after it):

Code:
if (mode == 0) {
   if (test(a, b)) {
      mode = 1;
   } else {
      mode = 2;
   }
}

switch (mode) {
   case 1:
      result = foo(a, b);
      break;
  
   case 2:
      result = bar(a, b);
      break;
}

(leaving the switch there for the sake of example, e.g. you could have a default clause as well, or also more modes)
Logged
tjcbs
Level 1
*


View Profile WWW
« Reply #209 on: October 24, 2014, 02:46:51 AM »

I think geti got that logic to almost its tersest form, but if you reeeallly want to avoid duplication:

Code:
result = (((test(a,b) | mode) == 1) ? foo : bar)(a,b);
« Last Edit: October 24, 2014, 03:05:51 AM by tjcbs » Logged

Geti
Level 10
*****



View Profile WWW
« Reply #210 on: October 24, 2014, 03:15:31 AM »

Hahaha, I actually considered going that route but I'm not sure the functions can be inlined there if necessary. If someone knows concrete details for any compiler let me know but as far as I can see semantically you're treating them as function pointers there, albeit deterministically. Certainly very terse though, the OR is a nice (if fragile) touch.
Logged

Sik
Level 10
*****


View Profile WWW
« Reply #211 on: October 24, 2014, 04:57:21 AM »

Compilers will inline when given the chance or make a normal function call if they can't (as long as the code produces the same result they can do whatever they want). In fact the inline keyword is kind of a no-op in practice, the only thing it does is tell the compiler that you can't take a pointer to that function (inlining will be always up to the compiler, keyword or not).
Logged
oahda
Level 10
*****



View Profile
« Reply #212 on: October 24, 2014, 06:33:52 AM »

Aw. Guess I should remove the inline modifiers from my maths header then.
Logged

Cheesegrater
Level 1
*



View Profile
« Reply #213 on: October 24, 2014, 07:57:34 AM »

It can still be worth doing.

inline mandates that the linker merge multiple definitions of the function (if it does not actually inline), so even if you include the header in multiple places you'll end up with only one compiled version of the function in your final exe. Also it keeps you from getting errors about the symbol being defined multiple times.
Logged
oahda
Level 10
*****



View Profile
« Reply #214 on: October 24, 2014, 08:22:21 AM »

Well, there's a header guard so that shouldn't happen anyway, right?
Logged

Cheesegrater
Level 1
*



View Profile
« Reply #215 on: October 24, 2014, 08:28:29 AM »

Header guards only protect you from multiple copies in one file/translation unit.

At link time. If you put a function + function body in a header and #include the header in multiple files, you end up with one copy per .cpp file you had the #include in. Then the linker will note the multiple definitions and throw an error.

You have three options, then:

1) Split the function body and the prototype, like most people usually do.
2) Mark the function inline, which will merge the copies from multiple files into one.
3) Mark the function static, which will maintain a separate copy for each file (you only want to do this in certain special sorts of circumstances I won't go into).

Logged
oahda
Level 10
*****



View Profile
« Reply #216 on: October 24, 2014, 10:50:26 AM »

Ah, right. I've been splitting things up for so many years that I haven't really remembered that, and now I've been using inline functions and so it has been working out anyway.
Logged

Sik
Level 10
*****


View Profile WWW
« Reply #217 on: October 24, 2014, 01:58:28 PM »

Also it keeps you from getting errors about the symbol being defined multiple times.

Oh damn, I forgot about that one too.

In any case it doesn't hurt to use it (especially since it indicates intent), just take into account that merely because you don't include the inline keyword that doesn't mean that the compiler won't inline the function if it's short enough (and now there are linker optimizations too, so you may have inline optimization across files, which is nice). Of course you need to have optimizations turned on, but it's important to understand if you're trying to speed up slow code.

EDIT: actually for a better explanation: inline was always used to specify intent. It tells the compiler that you expect the function to be inlined, but if the compiler thinks it's too large it won't be inlined. This was the case since it was introduced. The only thing that changed since then is that now compilers do the inverse too if they think it's appropriate (it's OK as long as the behavior of the program remains the same, performance aside), but it's still useful if you want to affect its semantics instead of its performance.
« Last Edit: October 24, 2014, 02:03:43 PM by Sik » Logged
Geti
Level 10
*****



View Profile WWW
« Reply #218 on: October 24, 2014, 02:03:42 PM »

Fwiw there are ways to force inlining on each major compiler, and building a nice macro to put the right identifier for your compiler in, and default to "inline" isn't hard.

 Re: the function pointers there, I'm not concerned about whether the compiler will want to inline or not for a given case, but whether it would be able to given that (as far as I can see) they are decided on locally and passed out of the ternary as function pointers. I realise it's a very local transformation but I'm curious how well that construct would optimise in practice.
Logged

tjcbs
Level 1
*


View Profile WWW
« Reply #219 on: October 24, 2014, 04:53:42 PM »

I tried on VS2008, and the trinary function pointer thingy does indeed inhibit inlining.
Logged

Pages: 1 ... 9 10 [11] 12
Print
Jump to:  

Theme orange-lt created by panic