Coding: Fleeting Thoughts

A place to discuss the implementation and style of computer programs.

Moderators: phlip, Moderators General, Prelates

EvanED
Posts: 4331
Joined: Mon Aug 07, 2006 6:28 am UTC
Location: Madison, WI
Contact:

Re: Coding: Fleeting Thoughts

Postby EvanED » Tue Jun 19, 2012 5:57 am UTC

Thesh wrote:1) Provides easy parsing of command line options while also formatting a help screen (I know Glib has this, but I don't think it meets my second requirement and it's kind of bulky if I'm just using it for that)

Does it have to be C, or can it be C++? There are a couple okayish ones for C++, but I don't know any for C -- getopt_long may be the best there, and it's not very good. (It doesn't meet your second requirement and I don't know if there's a MSVC build and it may be GPL-only.)

For C++ you have Boost::program_options and gflags.

Neither is wonderful, and both have their benefits. I tend to prefer Boost's and a lot of the time it doesn't add an extra dependency, but gflags has a nice facility that lets you declare flags in a decentralized manner, which is nice. (You could rig something up for Boost, but you'd have to do it.)

There are a couple other libraries you can find as well, but I didn't run across anything that's C. (I was looking for one that's well-suited for writing wrapper programs, which neither of those nor TCLAP currently is. After looking at those three I gave up and patched Boost. :-)) <troll>Why are you using C anyway?</troll>

2) Allows me to read a password from the command line as wchar_t (which I will then convert to utf8 using ICU), preferably while also allocating memory for the string, and, of course, while hiding the keystrokes.

This I don't know a library for.

User avatar
Thesh
Made to Fuck Dinosaurs
Posts: 6577
Joined: Tue Jan 12, 2010 1:55 am UTC
Location: Colorado

Re: Coding: Fleeting Thoughts

Postby Thesh » Tue Jun 19, 2012 6:15 am UTC

Actually, I don't see any reason why the console app has to be C. It's an interface for a C library I'm developing as a stand-alone component, which I am developing in C for maximum compatibility, so I guess I was just thinking library in C, command line utility in C. So yeah, I should probably just go with C++ for that portion of it.

I guess I'll just have to learn how to use termios.h for *nix and use the windows specific stuff for windows to suspend console output and just use regular cin to read the password. I was hoping to avoid it, but I don't really see many other solutions online.
Summum ius, summa iniuria.

webzter_again
Posts: 119
Joined: Sun May 27, 2012 4:37 am UTC

Re: Coding: Fleeting Thoughts

Postby webzter_again » Tue Jun 19, 2012 12:25 pm UTC

Sc4Freak wrote:No, the performance really is actually exactly the same. In release mode there's no method call - empty getters and setters are JIT'd into direct field accesses. Both versions - whether properties or fields - compile down to the exact same assembly in the end (assuming of course that the properties don't do anything extra and you're running in Release mode).


Interesting. Would you mind delving into that more (via a spec or some code demonstration or something)? For reference, the above IL was generated using release mode with the .net 4 profile and optimizations turned on in vs2010. IL was provided by ILDasm.

User avatar
Xeio
Friends, Faidites, Countrymen
Posts: 5101
Joined: Wed Jul 25, 2007 11:12 am UTC
Location: C:\Users\Xeio\
Contact:

Re: Coding: Fleeting Thoughts

Postby Xeio » Tue Jun 19, 2012 5:02 pm UTC

The .Net runtime (I believe Java does something similar) actually compiles (into native code, not IL) and optimizes the IL code when it is actually run, and can do things like inlining an empty property so that it no longer has the overhead of a method call.

You can try running my example on the previous page, you can see there is effectively no overhead when actually run.

This appears to have a few examples in action. The complied IL still has the methods, but there is no difference in speed when run because the JIT compiler optimizes it away.

User avatar
Sc4Freak
Posts: 673
Joined: Thu Jul 12, 2007 4:50 am UTC
Location: Redmond, Washington

Re: Coding: Fleeting Thoughts

Postby Sc4Freak » Tue Jun 19, 2012 5:20 pm UTC

Yeah, that's basically the gist of it. The IL isn't really a very useful indicator of performance, because obviously the CPU doesn't run IL. The JIT compiles the IL into machine code at runtime, and performs optimizations along the way (like eliminating superfluous method calls for empty properties).

webzter_again
Posts: 119
Joined: Sun May 27, 2012 4:37 am UTC

Re: Coding: Fleeting Thoughts

Postby webzter_again » Tue Jun 19, 2012 5:51 pm UTC

Xeio wrote:The .Net runtime (I believe Java does something similar) actually compiles (into native code, not IL) and optimizes the IL code when it is actually run, and can do things like inlining an empty property so that it no longer has the overhead of a method call.

You can try running my example on the previous page, you can see there is effectively no overhead when actually run.

This appears to have a few examples in action. The complied IL still has the methods, but there is no difference in speed when run because the JIT compiler optimizes it away.


The problem is that both your test and the one on dotnetperls are basing that on black box observations of the JIT. I agree there is no observable difference. What I was asking for is if someone can post a spec or something that proves out that a callvirt (which would necessarily involve a vtable) IL instruction is replaced by the JIT with a field load call.

So, I did a bit more digging and am satisfied that, yes, the black box observation is correct in that side-effect free property calls are inlined as loads. Greatly simplified here but it proved out on the longer example too. It does reinforce that one should look at the JIT output and not the intermediate IL (my bad :oops: ). Note, I'm using the x86 JIT. x64 is a different beast but I don't care enough to, well, care.

Spoiler:
test harness:

Code: Select all

      static void Main(string[] args)
      {
         Tester t = new Tester();
         t.Hello = 1;
         t.Toggle();
      }
   }


auto-property or simple property with backing field:

Code: Select all

         Tester t = new Tester();
00000000  mov         ecx,592638h
00000005  call        FFD7FBE0
0000000a  mov         edx,eax
         t.Hello = 1;
0000000c  mov         dword ptr [edx+4],1
         t.Toggle();
00000013  mov         eax,dword ptr [edx+4]
00000016  inc         eax
00000017  mov         dword ptr [edx+4],eax
0000001a  ret


field:

Code: Select all

         Tester t = new Tester();
00000000  mov         ecx,752638h
00000005  call        FFF4FBE0
         t.Hello = 1;
0000000a  mov         dword ptr [eax+8],1
         t.Toggle();
00000011  inc         dword ptr [eax+8]
00000014  ret


property with side-effect: (calling set mutates the backing field plus another field)

Code: Select all

         Tester t = new Tester();
00000000  push        ebp
00000001  mov         ebp,esp
00000003  push        esi
00000004  mov         ecx,582644h
00000009  call        FFDEFBE0
0000000e  mov         esi,eax
         t.Hello = 1;
00000010  mov         dword ptr [esi+4],1
00000017  lea         ecx,[esi+8]
0000001a  call        687F3C00
         t.Toggle();
0000001f  mov         eax,dword ptr [esi+4]
00000022  inc         eax
00000023  mov         dword ptr [esi+4],eax
00000026  lea         ecx,[esi+8]
00000029  call        687F3C00
0000002e  pop         esi
      }
0000002f  pop         ebp
00000030  ret

mbrigdan
False Alarm! There's more rum.
Posts: 109
Joined: Wed Jun 25, 2008 2:45 am UTC

Re: Coding: Fleeting Thoughts

Postby mbrigdan » Tue Jun 19, 2012 8:32 pm UTC

Inspired by earlier comments in this thread:

Code: Select all

#include <iostream>

void* justwait(bool selector)
{
    if (selector)
    {
        DEARGOD:
        std::cout << 2+2 << std::endl;
        return NULL;
    }
    else
    {
        return &&DEARGOD;
    }
}

void print4(void * WHYGODWHY)
{
    goto *WHYGODWHY;
}

int main()
{
    void * oops = justwait(false);
    print4(oops);
    return 0;
}


I still can't believe this actually works. It doesn't even segfault before exiting.
This is with g++ 4.6.3, 64-bit ubuntu.
Spoiler:
TheNgaiGuy wrote:god is playing a huge trick on us and wants us to use our brains to come to the logical conclusion, even though wrong, that he doesn't exist and will send all atheists to heaven for exercising said gifts and send all theists to hell for having faith.

User avatar
Jplus
Posts: 1721
Joined: Wed Apr 21, 2010 12:29 pm UTC
Location: Netherlands

Re: Coding: Fleeting Thoughts

Postby Jplus » Tue Jun 19, 2012 11:18 pm UTC

That's crazy. I didn't know labels even had a value. It works in Apple g++ 4.2.1 and GNU g++ 4.7.0 as well.

It doesn't compile in Clang, though:

Code: Select all

address_of_label.cpp:13:16: warning: returning address of label, which is local
        return &&DEARGOD;
               ^~~~~~~~~
address_of_label.cpp:19:5: error: indirect goto in function with no address-of-label expressions
    goto *WHYGODWHY;
    ^
1 warning and 1 error generated.
"There are only two hard problems in computer science: cache coherence, naming things, and off-by-one errors." (Phil Karlton and Leon Bambrick)

coding and xkcd combined

(Julian/Julian's)

Ben-oni
Posts: 278
Joined: Mon Sep 26, 2011 4:56 am UTC

Re: Coding: Fleeting Thoughts

Postby Ben-oni » Tue Jun 19, 2012 11:20 pm UTC

mbrigdan wrote:Inspired by earlier comments in this thread:

Code: Select all

#include <iostream>

void* justwait(bool selector)
{
    if (selector)
    {
        DEARGOD:
        std::cout << 2+2 << std::endl;
        return NULL;
    }
    else
    {
        return &&DEARGOD;
    }
}

void print4(void * WHYGODWHY)
{
    goto *WHYGODWHY;
}

int main()
{
    void * oops = justwait(false);
    print4(oops);
    return 0;
}


I still can't believe this actually works. It doesn't even segfault before exiting.
This is with g++ 4.6.3, 64-bit ubuntu.


To be fair, g++ does warn, and calling justwait(true) does segfault (when it reaches print4(oops), that is).

It shouldn't be surprising, though. justwait doesn't use any local variables, and the address returned is for a position in code, so calling it from outside the scope is fine. The only tricky bit is that print4 never returns, but justwait returns twice.

You're not planning to create nextgen spaghetti code are you?

Rysto
Posts: 1460
Joined: Wed Mar 21, 2007 4:07 am UTC

Re: Coding: Fleeting Thoughts

Postby Rysto » Tue Jun 19, 2012 11:45 pm UTC

Jplus wrote:That's crazy. I didn't know labels even had a value.

They don't. It's a gcc extension.

User avatar
phlip
Restorer of Worlds
Posts: 7572
Joined: Sat Sep 23, 2006 3:56 am UTC
Location: Australia
Contact:

Re: Coding: Fleeting Thoughts

Postby phlip » Tue Jun 19, 2012 11:52 pm UTC

webzter_again wrote:The problem is that both your test and the one on dotnetperls are basing that on black box observations of the JIT. I agree there is no observable difference. What I was asking for is if someone can post a spec or something that proves out that a callvirt (which would necessarily involve a vtable) IL instruction is replaced by the JIT with a field load call.

I'd be surprised if anything is specced out at that level... as long as the behaviour (aside from runtime) is the same either way, the optimiser can implement it really however it wants. For instance, it wouldn't surprise me if the exact metrics varied slightly between the MS .net VM and Mono. In much the same way as how the generated assembly is different when you compile a C program with GCC or MSVC (or even the same compiler with different optimisation settings). The spec says that if the C program says "i++" the compiler needs to generate code that increments i... but if there are multiple ways to increment i, the spec doesn't say which one it needs to use. And if there's a way in context it can merely pretend it incremented i, and have the program behave the same, then that's cool too. None of this is specified anywhere.

Code: Select all

enum ಠ_ಠ {°□°╰=1, °Д°╰, ಠ益ಠ╰};
void ┻━┻︵​╰(ಠ_ಠ ⚠) {exit((int)⚠);}
[he/him/his]

mbrigdan
False Alarm! There's more rum.
Posts: 109
Joined: Wed Jun 25, 2008 2:45 am UTC

Re: Coding: Fleeting Thoughts

Postby mbrigdan » Wed Jun 20, 2012 12:33 am UTC

Ben-oni wrote:To be fair, g++ does warn, and calling justwait(true) does segfault (when it reaches print4(oops), that is).

It shouldn't be surprising, though. justwait doesn't use any local variables, and the address returned is for a position in code, so calling it from outside the scope is fine. The only tricky bit is that print4 never returns, but justwait returns twice.

You're not planning to create nextgen spaghetti code are you?


Of course there's a segfault when you do justwait(true), you're trying to goto *NULL in that case. I tried to make an even worse version:
Spoiler:

Code: Select all

#include <iostream>

void* justwait()
{
    return &&DEARGOD;
    DEARGOD:
    std::cout << 2+2 << "\n";
    return NULL;
}

void print4(void * WHYGODWHY)
{
    goto *WHYGODWHY;
}

int main()
{
    void * oops = justwait();
    print4(oops);
    return 0;
}

But even with -O0 -fno-inline, g++ optimizes the parts after return &&DEARGOD away*, so it doesn't work. I'm still surprised the original version doesn't do bad things to the stack. Maybe if justwait took two arguments, and print4 only took one.

*Which it really shouldn't. I mean, I told it not to optimize anything
Spoiler:
TheNgaiGuy wrote:god is playing a huge trick on us and wants us to use our brains to come to the logical conclusion, even though wrong, that he doesn't exist and will send all atheists to heaven for exercising said gifts and send all theists to hell for having faith.

User avatar
hotaru
Posts: 1045
Joined: Fri Apr 13, 2007 6:54 pm UTC

Re: Coding: Fleeting Thoughts

Postby hotaru » Wed Jun 20, 2012 12:45 am UTC

Jplus wrote:It doesn't compile in Clang, though:

Ben-oni wrote:To be fair, g++ does warn, and calling justwait(true) does segfault (when it reaches print4(oops), that is).

all fixed (compiles with clang and g++, no warnings, calling justwait(true) doesn't segfault):

Code: Select all

#include <cstdlib>
#include <iostream>

void *justwait(bool selector)
{
 if(selector)
  { DEARGOD:
    std::cout << 2+<< std::endl;
    exit(0); }
  else
  
{ void *pointy = &&DEARGOD;
    return pointy; }}

void print4(void *WHYGODWHY)
{
 goto *WHYGODWHY;
  STUFF:
  if(&&STUFF) std::cout << ""; }

int main()
{
 print4(justwait(false));
  return 0; } 


just one problem i haven't figured out how to fix yet: it breaks if you use -O1 or higher with clang.

Code: Select all

factorial product enumFromTo 1
isPrime n 
factorial (1) `mod== 1

mbrigdan
False Alarm! There's more rum.
Posts: 109
Joined: Wed Jun 25, 2008 2:45 am UTC

Re: Coding: Fleeting Thoughts

Postby mbrigdan » Wed Jun 20, 2012 1:50 am UTC

I have created an abomination!

Code: Select all

#include <cstdlib>
#include <iostream>

void *justwait(int filler1, int filler2, int filler3, int filler4, int filler5, int filler6, bool selector, long x, long y)
{ if(selector)
  { DEARGOD:
    std::cout << x+y << std::endl;
    exit(0); }
  else
  { void *pointy = &&DEARGOD;
    return pointy; }}

void addThenPrint(int filler1, int filler2, int filler3, int filler4, int filler5, int filler6, bool selector, long x, long y, void *WHYGODWHY)
{ goto *WHYGODWHY;
  STUFF:
  if(&&STUFF) std::cout << ""; }

int main()
{
void * ptr = justwait(0,0,0,0,0,0,false, 0, 0);
addThenPrint(0,0,0,0,0,0,true, 3, 3, ptr);
  return 0; }


addThenPrint will print the result of adding the eighth and the ninth arguments. This is probably the least portable thing in the world.
Spoiler:
TheNgaiGuy wrote:god is playing a huge trick on us and wants us to use our brains to come to the logical conclusion, even though wrong, that he doesn't exist and will send all atheists to heaven for exercising said gifts and send all theists to hell for having faith.

EvanED
Posts: 4331
Joined: Mon Aug 07, 2006 6:28 am UTC
Location: Madison, WI
Contact:

Re: Coding: Fleeting Thoughts

Postby EvanED » Wed Jun 20, 2012 2:36 am UTC

mbrigdan wrote:This is probably the least portable thing in the world.

This begs to differ:
Image

:-)

User avatar
hotaru
Posts: 1045
Joined: Fri Apr 13, 2007 6:54 pm UTC

Re: Coding: Fleeting Thoughts

Postby hotaru » Wed Jun 20, 2012 3:04 am UTC

mbrigdan wrote:I have created an abomination!

Code: Select all

#include <cstdlib>
#include <iostream>

void *justwait(int filler1, int filler2, int filler3, int filler4, int filler5, int filler6, bool selector, long x, long y)
{ if(selector)
  { DEARGOD:
    std::cout << x+y << std::endl;
    exit(0); }
  else
  { void *pointy = &&DEARGOD;
    return pointy; }}

void addThenPrint(int filler1, int filler2, int filler3, int filler4, int filler5, int filler6, bool selector, long x, long y, void *WHYGODWHY)
{ goto *WHYGODWHY;
  STUFF:
  if(&&STUFF) std::cout << ""; }

int main()
{
void * ptr = justwait(0,0,0,0,0,0,false, 0, 0);
addThenPrint(0,0,0,0,0,0,true, 3, 3, ptr);
  return 0; }


addThenPrint will print the result of adding the eighth and the ninth arguments. This is probably the least portable thing in the world.

i'm not sure what the point of all that filler nonsense is... this works for me:

Code: Select all

#include <cstdlib>
#include <iostream>

void *justwait(long x = 0, long y = 0)
{
 void *pointy = &&DEARGOD;
  if(!pointy)
  { DEARGOD:
    std::cout << x+<< std::endl;
    exit(0); }
  return pointy; }

void *addThenPrint(long x, long y, void *WHYGODWHY)
{
 goto *WHYGODWHY;
  STUFF:
  if(&&STUFF) std::cout << ""; }

int main()
{
 addThenPrint(2,3,justwait()); } 

Code: Select all

factorial product enumFromTo 1
isPrime n 
factorial (1) `mod== 1

User avatar
phlip
Restorer of Worlds
Posts: 7572
Joined: Sat Sep 23, 2006 3:56 am UTC
Location: Australia
Contact:

Re: Coding: Fleeting Thoughts

Postby phlip » Wed Jun 20, 2012 1:55 pm UTC

hotaru wrote:i'm not sure what the point of all that filler nonsense is...

I think it's to force the parameters to be passed on the stack... on x86_64, all those "filler" parameters will be passed in via registers (and then probably stored somewhere more permanent by the function, but not necessarily the same place every time). Meanwhile the on-stack parameters will be stored in the same place (relative to the base pointer) for both functions (with the standard calling convention, and modulo weird compiler or optimiser behaviour).

Code: Select all

enum ಠ_ಠ {°□°╰=1, °Д°╰, ಠ益ಠ╰};
void ┻━┻︵​╰(ಠ_ಠ ⚠) {exit((int)⚠);}
[he/him/his]

EvanED
Posts: 4331
Joined: Mon Aug 07, 2006 6:28 am UTC
Location: Madison, WI
Contact:

Re: Coding: Fleeting Thoughts

Postby EvanED » Wed Jun 20, 2012 3:15 pm UTC

phlip wrote:
hotaru wrote:i'm not sure what the point of all that filler nonsense is...

I think it's to force the parameters to be passed on the stack... on x86_64, all those "filler" parameters will be passed in via registers (and then probably stored somewhere more permanent by the function, but not necessarily the same place every time). Meanwhile the on-stack parameters will be stored in the same place (relative to the base pointer) for both functions (with the standard calling convention, and modulo weird compiler or optimiser behaviour).

To add weight to that, hotaru's suggestion works for me only with -m32:

Code: Select all

$ g++ -m32 mess.cc -o mess 
$ ./mess
5
$ g++ mess.cc -o mess
$ ./mess             
4196323


mbrigdan's version worked both ways:

Code: Select all

$ g++ mess2.cc -o mess -m32
$ ./mess
6
$ g++ mess2.cc -o mess     
$ ./mess             
6

mbrigdan
False Alarm! There's more rum.
Posts: 109
Joined: Wed Jun 25, 2008 2:45 am UTC

Re: Coding: Fleeting Thoughts

Postby mbrigdan » Wed Jun 20, 2012 6:55 pm UTC

Yeah, pushing the arguments onto the stack was indeed my goal with all the filler arguments. Apparently, AMD64 calling convention means that the first six arguments must go into registers, while additional arguments may go onto the stack. There's probably a bunch of compilers/systems that it doesn't work for though.
Also:
EvanED wrote:

Code: Select all

$ g++ -m32 mess.cc -o mess 
$ ./mess
5
$ g++ mess.cc -o mess
$ ./mess             
4196323



That's... eerily close to what I get when I do it without the filler. I get 4196319. I wonder what exactly is going on to make that happen.
Spoiler:
TheNgaiGuy wrote:god is playing a huge trick on us and wants us to use our brains to come to the logical conclusion, even though wrong, that he doesn't exist and will send all atheists to heaven for exercising said gifts and send all theists to hell for having faith.

Rysto
Posts: 1460
Joined: Wed Mar 21, 2007 4:07 am UTC

Re: Coding: Fleeting Thoughts

Postby Rysto » Wed Jun 20, 2012 7:08 pm UTC

mbrigdan wrote:Apparently, AMD64 calling convention means that the first six arguments must go into registers, while additional arguments may go onto the stack.

Actually, it's even more complicated than that. amd64 uses 6 integer registers and X floating-point (can't remember the exact number; too lazy to look it up) registers for passing parameters. So the first 6 integer (or pointer) arguments and the first X floating point arguments that you pass are passed in registers.

This makes implementing stdarg.h a lot of fun for compiler writers, I must add.

mbrigdan
False Alarm! There's more rum.
Posts: 109
Joined: Wed Jun 25, 2008 2:45 am UTC

Re: Coding: Fleeting Thoughts

Postby mbrigdan » Wed Jun 20, 2012 8:20 pm UTC

Rysto wrote:This makes implementing stdarg.h a lot of fun for compiler writers, I must add.


Ouch, that would be brutal. Although, in the minimal research I did, it looked like microsoft's version of X86_64 made it optional to pass things via registers versus stack, which I guess could be an even bigger PITA.
Spoiler:
TheNgaiGuy wrote:god is playing a huge trick on us and wants us to use our brains to come to the logical conclusion, even though wrong, that he doesn't exist and will send all atheists to heaven for exercising said gifts and send all theists to hell for having faith.

EvanED
Posts: 4331
Joined: Mon Aug 07, 2006 6:28 am UTC
Location: Madison, WI
Contact:

Re: Coding: Fleeting Thoughts

Postby EvanED » Thu Jun 21, 2012 2:07 am UTC

Suppose you are writing a build script in a system (*cough* scons *cough*) that doesn't have well-established conventions for how to do things like pass include paths to the compiler and such.

You want to be able to specify include and library paths (or prefixes) for dependencies, for people who have that library installed in non-standard locations (like I very frequently do). I'll just use include dirs below. (I'd do --with-boost-incdir but I don't think I can get the leading --.) Which of the following would you prefer? (Edit: oops, forgot the all-important question. :-))

Code: Select all

1)  scons with-boost-incdir=/path/boost/include with-cppunit-incdir=/path/cppunit/include
2)  scons include-paths=/path/boost/include:/path/cppunit/include
3)  scons CPPFLAGS="-I/path/boost/include -I/path/cppunit/include"

Option 3 would work regardless; voting for that means that there'd be no "special" facility for specifying include or library paths.

Here's an argument for (2) from the SCons mailing list:
I'm personally not a big fan of specifying the includepath/libpath for each library as it is:
  • misleading as the compilation will end up being like "gcc -I/path/to/a/include -I/path/to/b/include" so all headers are searched for in all places and having a big directory that includes several packages is not unusual
  • the order of search is unspecified (sometimes you have multiple versions around and you want to make sure one is found instead of the other)
  • and verbose:
    includepath="/path/to/a/include:/path/to/b/include"
    vs
    A_include="/path/to/a/include" B_include="/path/to/b/include"


And an argument for (1):
  • It seems to be closer to autoconf conventions, if that matters
  • If your script follows the usual autoconf convention of looking at CFLAGS, LDFLAGS, etc., then (2) can pretty much be emulated by (3); and the script should use those flags anyway for other purposes
  • If you are building multiple targets, perhaps not all of them will need to use the same libraries; separating the libraries means that your executable 1 can include and link libraries A and B, but your executable 2 can include and link just B.

AFS_Three
Posts: 3
Joined: Sat Jan 30, 2010 10:25 pm UTC

Re: Coding: Fleeting Thoughts

Postby AFS_Three » Thu Jun 21, 2012 6:10 am UTC

I just realized that I can crash a python interpreter (2.7) with a single line of python code:

Code: Select all

(lambda:0).__class__((lambda:0).func_code.__class__(0,1,2,3,"d",(),(),(),'','',4,'',(),()),{})()

And one for 3.2:

Code: Select all

(lambda:0).__class__((lambda:0).__code__.__class__(0,1,2,3,4,b"d",(),(),(),'','',5,b'',(),()),{})()

Now I see why rexec is deprecated.

User avatar
You, sir, name?
Posts: 6983
Joined: Sun Apr 22, 2007 10:07 am UTC
Location: Chako Paul City
Contact:

Re: Coding: Fleeting Thoughts

Postby You, sir, name? » Thu Jun 21, 2012 8:43 pm UTC

You know how sometimes you'll look at your code while writing it and go "What the fuck am I doing?!" Well, on that note, here's the hair raising slicing routine for a N-dimensional Q-tree (octree, tesseract-tree) I wrote.

Code: Select all

    void _subset(const Coordinate<AXES>& a, const Coordinate<AXES>& b, // Bounds
            function<void(Coordinate<AXES>, T)>& callback,  //
            int depth, // Current search depth
            Cell* node,
            Coordinate<AXES> acc)
    {

        const int width = 1 << (depth-1);
       
        if(depth == 0) {
            for(int i = 0; i < AXES; i++) {
                if(acc[i] < a[i] || acc[i] >= b[i]) return;
            }
            callback(acc, node->value);
            return;
        }
       
        Coordinate<AXES> value;

        for(int i = 0; i < (1 << AXES); i++) {
            value = acc;
           
            for(int j = 0; j < AXES; j++) {
                if(i & (1 << j)) value[j] += width;
            }
           
            for(int j = 0; j < AXES; j++) {
                bool low =  value[j] + width >= a[j];
                bool high = value[j] < b[j];
               
                if(!high || !low) goto skip;
            }

            if(node->axes[i].get() != nullptr)
                _subset(a,b,callback, depth-1, node->axes[i].get(), value);
           
            skip:;
        }
       
    }


I can't even remember why I wanted this structure.
I edit my posts a lot and sometimes the words wrong order words appear in sentences get messed up.

User avatar
sourmìlk
If I can't complain, can I at least express my fear?
Posts: 6393
Joined: Mon Dec 22, 2008 10:53 pm UTC
Location: permanently in the wrong
Contact:

Re: Coding: Fleeting Thoughts

Postby sourmìlk » Fri Jun 22, 2012 6:06 pm UTC

You, sir, name? wrote:goto


goto


goto


Image
Terry Pratchett wrote:The trouble with having an open mind, of course, is that people will insist on coming along and trying to put things in it.

User avatar
You, sir, name?
Posts: 6983
Joined: Sun Apr 22, 2007 10:07 am UTC
Location: Chako Paul City
Contact:

Re: Coding: Fleeting Thoughts

Postby You, sir, name? » Sat Jun 23, 2012 4:57 am UTC

I've gotten used to named breaks/continues. Can't live without them now, even if that means goto.
I edit my posts a lot and sometimes the words wrong order words appear in sentences get messed up.

User avatar
Sc4Freak
Posts: 673
Joined: Thu Jul 12, 2007 4:50 am UTC
Location: Redmond, Washington

Re: Coding: Fleeting Thoughts

Postby Sc4Freak » Sat Jun 23, 2012 6:07 am UTC

I have actually yet to see an elegant solution for multi-level breaks in C or C++ that don't involve goto. Sometimes, it's just necessary to nest loops several layers deep (eg. initializing a 3D texture). And if you want to break out early, you have two options: use a goto, or use a boolean to signal early exit and check it in every layer of the loop. Neither option seems particularly attractive.

User avatar
sourmìlk
If I can't complain, can I at least express my fear?
Posts: 6393
Joined: Mon Dec 22, 2008 10:53 pm UTC
Location: permanently in the wrong
Contact:

Re: Coding: Fleeting Thoughts

Postby sourmìlk » Sat Jun 23, 2012 6:27 am UTC

I tend to use the boolean flag, but I agree that there should be a break(stack_levels) function of some sort. Doesn't boost do something with that?
Terry Pratchett wrote:The trouble with having an open mind, of course, is that people will insist on coming along and trying to put things in it.

User avatar
PM 2Ring
Posts: 3713
Joined: Mon Jan 26, 2009 3:19 pm UTC
Location: Sydney, Australia

Re: Coding: Fleeting Thoughts

Postby PM 2Ring » Sat Jun 23, 2012 6:54 am UTC

Sc4Freak wrote:I have actually yet to see an elegant solution for multi-level breaks in C or C++ that don't involve goto. Sometimes, it's just necessary to nest loops several layers deep (eg. initializing a 3D texture). And if you want to break out early, you have two options: use a goto, or use a boolean to signal early exit and check it in every layer of the loop. Neither option seems particularly attractive.


I prefer to use goto. The only time you're likely to see goto in sane code is to implement a multi-level break, and such usage shouldn't be seen as bad coding, IMHO. Sure, it's not as elegant as a named break mechanism, OTOH, it's not actually spaghetti coding, so Dijkstra's dictum against goto doesn't really apply.

I've certainly used the boolean flag method, too. It's slightly more long-winded, but I doubt it's going to slow down execution that much. :) And I guess a good optimizer could be able to avoid executing the multiple redundant tests anyway.

I suppose the ugliest way of breaking out of nested for loops is to assign an out of bounds value to the control variables of the outer loops. I shamefully admit I've done that, but not for many years. :)

User avatar
You, sir, name?
Posts: 6983
Joined: Sun Apr 22, 2007 10:07 am UTC
Location: Chako Paul City
Contact:

Re: Coding: Fleeting Thoughts

Postby You, sir, name? » Sat Jun 23, 2012 7:19 am UTC

If I really wanted to avoid goto, I could rewrite the above code as

Code: Select all

            int j;
            for(j = 0; j < AXES; j++) {
                bool low =  value[j] + width >= a[j];
                bool high = value[j] < b[j];
               
                if(!high || !low) break;
            }
            if(j == AXES) {
                 if(node->axes[i].get() != nullptr)
                    _subset(a,b,callback, depth-1, node->axes[i].get(), value);
                 break;
             }



... but yeah. I'm having trouble convincing myself that's any less ugly than using goto.
I edit my posts a lot and sometimes the words wrong order words appear in sentences get messed up.

User avatar
Jplus
Posts: 1721
Joined: Wed Apr 21, 2010 12:29 pm UTC
Location: Netherlands

Re: Coding: Fleeting Thoughts

Postby Jplus » Sat Jun 23, 2012 11:00 am UTC

@EvanED: I'd prefer the second option.

My favourite example of "valid" usage of goto is actually with only one loop level. I was inspired for this case by the for-break-else construct in Python. You use it when you want to execute some instructions only if you DON'T break out of your loop:

(Python)

Code: Select all

while true:
    do_something
    if special_condition:
        non_default_behaviour
        break
else:
    default_behaviour
the_rest

(C, C++)

Code: Select all

while (true) {
    do_something;
    if (special_condition) {
        non_default_behaviour;
        goto finish;
    }
}
default_behaviour;
finish:
the_rest;
"There are only two hard problems in computer science: cache coherence, naming things, and off-by-one errors." (Phil Karlton and Leon Bambrick)

coding and xkcd combined

(Julian/Julian's)

User avatar
Dason
Posts: 1311
Joined: Wed Dec 02, 2009 7:06 am UTC
Location: ~/

Re: Coding: Fleeting Thoughts

Postby Dason » Sat Jun 23, 2012 1:18 pm UTC

Maybe it's just too early but under what condition does your "default_behaviour" actually run in that code? It looks like the only way to exit the loop is to meet the special condition and that kicks you past the default_behavior. Or am I being entirely too thick right now?
double epsilon = -.0000001;

User avatar
Yakk
Poster with most posts but no title.
Posts: 11128
Joined: Sat Jan 27, 2007 7:27 pm UTC
Location: E pur si muove

Re: Coding: Fleeting Thoughts

Postby Yakk » Sat Jun 23, 2012 2:56 pm UTC

Refactor the loop into a function, use the return value of the function as a control expression. Use lambdas and implicit capture to get rid of the boilerplate variable copies.

Mark up the return statements in the lambda to indicate to the reader that they aren't returning from the entire function:

Code: Select all

//SNIP         
            bool recurse = [&]()->bool
            {
               for(int j = 0; j < AXES; j++) {
                  bool low =  value[j] + width >= a[j];
                  bool high = value[j] < b[j];
                  
                  if(!high || !low) return false; // recurse false
               }
               return true; // recurse true
            }();

            if(recurse && node->axes[i].get() != nullptr)
               _subset(a,b,callback, depth-1, node->axes[i].get(), value);
// SNIP

Your python example is bad, because there is no way to reach the_rest. :) Presuming you mean:

Code: Select all

while condition:
  do_something
  if special_condition:
   special_behavior
   break
else:
  default_finishing_behavior

the_rest

That can be handled a few ways. One way would be to put the "default behavior" into the while conditional statement.

Code: Select all

auto finishing_behavior = [&]()->bool
{
  default_behavior;
  return false;
};
while( condition || finishing_behavior() )
{
  do_something;
  if (special_condition)
    non_default_behavior;
    break;
}
the_rest

which is a bit indirect and obscure and it puts the default_behavior in a strange spot. :)

Another way might be to wrap the entire while in a subprocedure:

Code: Select all

bool DoCleanup = [&]()->bool
{
  while( condition )
  {
    do_something;
    if (special_condition)
      special_finishing_behavior;
      return false; //DoCleanup
  }
  return true; // DoCleanup
}();
if (DoCleanup)
{
  default_behavior;
}
the_rest;

Yet another method would be to set up a cleanup function<void()> before the while loop, and optionally set it to [](){} (the do nothing lambda) if you want to skip cleanup. This one sadly requires heavy weight type-erasure on the implementation side by function<void()>.

Another approach might be a lambda-while-cleanup construct, where break gets you to cleanup while return bypasses cleanup:

Code: Select all

[&](){
  while( condition )
  {
    some_work;
    if (special_condition)
      special_cleanup;
      return; // bypass default_cleanup
  }
  default_cleanup;
}();
the_rest;

which looks most similar to the python example. In effect, we hijack return to allow a multi-level break to a specific level, losing the ability to return from the function as a whole, and gaining the ability to return from some sub-section of the function. This only fails to work if we have a situation where we would want to break to 3 different loops at once.

Going back to the original case, we have:

Code: Select all

//SNIP         
               [&]()
                {
                   for(int j = 0; j < AXES; j++) {
                      bool low =  value[j] + width >= a[j];
                      bool high = value[j] < b[j];
                     
                      if(!high || !low) return; // from lambda, skip recursion possibility
                   }
                   if(node->axes[i].get() != nullptr)
                      _subset(a,b,callback, depth-1, node->axes[i].get(), value);
                }();

    // SNIP
One of the painful things about our time is that those who feel certainty are stupid, and those with any imagination and understanding are filled with doubt and indecision - BR

Last edited by JHVH on Fri Oct 23, 4004 BCE 6:17 pm, edited 6 times in total.

User avatar
Jplus
Posts: 1721
Joined: Wed Apr 21, 2010 12:29 pm UTC
Location: Netherlands

Re: Coding: Fleeting Thoughts

Postby Jplus » Mon Jun 25, 2012 3:12 pm UTC

@Dason: my examples where a bit cheesy because I was looping indefinitely. That's not the point of the exercise so I changed 'true' into 'condition'. I hope this is clearer.

(Python)

Code: Select all

while condition:
    do_something
    if special_condition:
        non_default_behaviour
        break
else:
    default_behaviour
the_rest

(C, C++)

Code: Select all

while (condition) {
    do_something;
    if (special_condition) {
        non_default_behaviour;
        goto finish;
    }
}
default_behaviour;
finish:
the_rest;


@Yakk: excuse me, but what is your point? AFAICT you're just showing overly complicated ways to do the above. As for the Python code: I don't see how your code is fundamentally different from mine.
"There are only two hard problems in computer science: cache coherence, naming things, and off-by-one errors." (Phil Karlton and Leon Bambrick)

coding and xkcd combined

(Julian/Julian's)

User avatar
Yakk
Poster with most posts but no title.
Posts: 11128
Joined: Sat Jan 27, 2007 7:27 pm UTC
Location: E pur si muove

Re: Coding: Fleeting Thoughts

Postby Yakk » Mon Jun 25, 2012 7:08 pm UTC

Your condition in your python code loop was "true". There was no way to read the else case in your python code. :)

@Yakk: excuse me, but what is your point? AFAICT you're just showing overly complicated ways to do the above. As for the Python code: I don't see how your code is fundamentally different from mine.
I was looking into patterns that would avoid the goto statement in C++0x.

The best one I came up with didn't use goto, but used an anonymous lambda to give us a "second break" option in a chunk of code.

And yes, the code does the exact same thing -- I was trying to do the exact same thing, ideally with a similar structure, without using goto. Implementing an "else".

Structured python style while:

Code: Select all

enum { Continue, Break };

template<typename Condition, typename Body, typename Else >
void while_loop( Condition condition, Body body, Else elseClause )
{
  while (condition())
  {
    if (body() == Break)
      return;
  }
  elseClause ();
}

In that case, use would look something like this:

Code: Select all

while_loop([&](){return condition;},
  [&](){
    do_something;
    if (special_condition) {
      special_finishing_behavior;
      return Break;
    }
   return Continue;
  },
  [&](){
    default_behavior;
  }
);

which matches the pattern of a python while loop. I'm not happy with it, however.

In a theoretical language where blocks are implicit lambdas (with [&] and no arguments), and we have named parameters we label using :, and you could pass in a variable as a lambda (which returns itself), and we could accept lambdas where if they fail to return they return the value of our choice, we'd get:

Code: Select all

while_loop(
  Condition:condition,
  Body:{
    do_something;
    if (special_condition) {
      special_finishing_behavior;
      return Break;
    }
  },
  ElseCase:{
    default_behavior;
  }
);

which is starting to look slick.

To give us top-end control over flow (without needing goto, or the language to give us explicit permission), we'd need to be able to create types of lambdas that have "return hooks" injected into it.

But that is getting silly, and I cannot even think of how you'd make that syntax clean.
One of the painful things about our time is that those who feel certainty are stupid, and those with any imagination and understanding are filled with doubt and indecision - BR

Last edited by JHVH on Fri Oct 23, 4004 BCE 6:17 pm, edited 6 times in total.

User avatar
Xanthir
My HERO!!!
Posts: 5410
Joined: Tue Feb 20, 2007 12:49 am UTC
Location: The Googleplex
Contact:

Re: Coding: Fleeting Thoughts

Postby Xanthir » Mon Jun 25, 2012 11:19 pm UTC

Oh man, I finally understand monads. Everyone who said they were easier than they looked was RIGHT. They're so, so simple.

I credit the Typeclassopedia page for explaining everything so well and with such a nice progression. Once you understand functors, particularly in the "context" (rather than "container") sense, it's very easy to see what monads do and why they're useful.
(defun fibs (n &optional (a 1) (b 1)) (take n (unfold '+ a b)))

EvanED
Posts: 4331
Joined: Mon Aug 07, 2006 6:28 am UTC
Location: Madison, WI
Contact:

Re: Coding: Fleeting Thoughts

Postby EvanED » Tue Jun 26, 2012 12:53 am UTC

I'm not going to say I understand monads, but I had two big epiphanies about them. Unfortunately, I forget one of them. :-) But the other was that (in Haskell) I was incorrectly ascribing the characteristic that the IO monad is "infectious" to all monads, when in fact the IO monad is the only one that applies to. (At least, AFAIK. And if you say "unsafePerformIO" then shut up; you know what I mean. :-))

Ben-oni
Posts: 278
Joined: Mon Sep 26, 2011 4:56 am UTC

Re: Coding: Fleeting Thoughts

Postby Ben-oni » Tue Jun 26, 2012 3:52 am UTC

The Typeclassopedia is pretty cool. For me, the great epiphany came when I realized there isn't anything difficult or complicated about monads: Type classes are what's difficult, until you understand them. Then the Monad (which has kind * -> *) operators (return and >>=) are the only things left to understand, and there are a zillion explanations out there. I'm a bit partial to the analogy of monads as monsters.
Last edited by Ben-oni on Tue Jun 26, 2012 5:26 pm UTC, edited 1 time in total.

User avatar
headprogrammingczar
Posts: 3072
Joined: Mon Oct 22, 2007 5:28 pm UTC
Location: Beaming you up

Re: Coding: Fleeting Thoughts

Postby headprogrammingczar » Tue Jun 26, 2012 11:05 am UTC

Ben-oni wrote:The Typeclassopedia is pretty cool. For me, the great epiphany came when I realized there isn't anything difficult or complicated about monads: Type classes are what's difficult, until you understand them. Then the Monad (which has type * -> *) operators (return and >>=) are the only things left to understand, and there are a zillion explanations out there. I'm a bit partial to the analogy of monads as monsters.

Wow, that email is almost as good as the burrito analogy.

Xanthir wrote:Oh man, I finally understand monads. Everyone who said they were easier than they looked was RIGHT. They're so, so simple.

I credit the Typeclassopedia page for explaining everything so well and with such a nice progression. Once you understand functors, particularly in the "context" (rather than "container") sense, it's very easy to see what monads do and why they're useful.

Now you get to learn more monads! Beyond the ones in mtl, some of the more interesting ones are

ST (referentially transparent computations with mutation)
STM (software transactional memory)
ParsecT
ContT (gives you access to a function that is defined as "everything after the current instruction")
Free (the free monad for Functors)
Rev (revision control)
MarkupM (in blaze-html - abuses do-notation to make code look more like the document it generates)
<quintopia> You're not crazy. you're the goddamn headprogrammingspock!
<Weeks> You're the goddamn headprogrammingspock!
<Cheese> I love you

Dr. Willpower
Posts: 197
Joined: Wed May 28, 2008 3:55 pm UTC

Re: Coding: Fleeting Thoughts

Postby Dr. Willpower » Tue Jun 26, 2012 7:39 pm UTC

I'm finding this dynamic typing stuff to be very liberating. Kind of like living with your mother for years and then finally moving out. Of course, someone has to do all the housework and it will still probably be me...
Image
Hat me, bro


Return to “Coding”

Who is online

Users browsing this forum: No registered users and 7 guests