Coding: Fleeting Thoughts

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

Moderators: phlip, Moderators General, Prelates

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 16, 2012 4:36 am UTC

Protip: prefer nonmember begin and end over .begin() and .end() member functions. For types that have member begin and end, the non-member versions do the same thing. But the nonmember versions are more generic (they work with more types). You save a whole character, too! (begin(v) instead of v.begin())

And this is a personal preference, but I think code like the following is a little obtuse:

Code: Select all

 std::transform(std_string_buffer.begin(),
                std_string_buffer.end(),
                std::inserter(cstring_buffer, cstring_buffer.begin()),
                [](std::string const & str) {
                   return str.c_str();
                });

IMO this is better accomplished with a range for:

Code: Select all

for (const auto& str : std_string_buffer)
    cstring_buffer.push_back(str.c_str());


I think it's more clear and just as safe.

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

Re: Coding: Fleeting Thoughts

Postby EvanED » Sat Jun 16, 2012 6:33 am UTC

Sc4Freak wrote:Protip: prefer nonmember begin and end over .begin() and .end() member functions. For types that have member begin and end, the non-member versions do the same thing. But the nonmember versions are more generic (they work with more types). You save a whole character, too! (begin(v) instead of v.begin())

I didn't know about the generic begin; I'll keep that in mind.

And this is a personal preference, but I think code like the following is a little obtuse:

Code: Select all

 std::transform(std_string_buffer.begin(),
                std_string_buffer.end(),
                std::inserter(cstring_buffer, cstring_buffer.begin()),
                [](std::string const & str) {
                   return str.c_str();
                });

IMO this is better accomplished with a range for:

Code: Select all

for (const auto& str : std_string_buffer)
    cstring_buffer.push_back(str.c_str());


I think it's more clear and just as safe.

I view that as basically like map, so in my mind it chunks well. And unfortunately, the range-based for loop probably has to stay on my "don't use" list for a while due to its absence from VS2010. And I don't think it's worth expanding it out.

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 16, 2012 6:42 am UTC

Range-based for is in VS2012 if that makes you feel any better. :P

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

Re: Coding: Fleeting Thoughts

Postby EvanED » Sat Jun 16, 2012 6:57 am UTC

Sc4Freak wrote:Range-based for is in VS2012 if that makes you feel any better. :P

In a couple years it will. :-)

One of these days I need to make myself a guide that tells me what C++11 features I'm allowing myself to use so I don't have to keep looking it up. I am glad I re-found this guy a couple days ago, otherwise I'd have gone and made my own. It's even more detailed than the main GCC page too.

User avatar
Steax
SecondTalon's Goon Squad
Posts: 3038
Joined: Sat Jan 12, 2008 12:18 pm UTC

Re: Coding: Fleeting Thoughts

Postby Steax » Sat Jun 16, 2012 11:05 am UTC

Related to the earlier rant:

I really don't like how alarmist some people get. Not only are they happy to toss around flashy warnings, they're also happy to magnify their numbers till they're big enough.

In today's case, the revelation that holy crap, using getters and setters more than doubles your running speed! And even Google says so! Run for your lives! Behead the setters!

Setting and calling the name property directly can run up to 100% faster, as well as cutting down on development time.


Yeah... until you realize that the sample size is 1 million operations (one getter+setter each). Even so, my currently quite-busy mid-range desktop managed 0.5s for 1 million runs in the optimal scenario. Wowzers. A dedicated server would probably manage it much faster, and that's a mind-blowing fraction of a thousandth of a millisecond per pair of getters and setters!

This advice is sound when raw. If your getters do nothing but get and set, then by all means, don't use them. I know almost every single one of mine has some sort of added functionality, and it gives you peace of mind when you don't have to think about "should I just call the member, or use the getter?" And you always have caches... CDNs, HTTP caches, page caches, and bytecode caches, each of which can easily give at least a magnitude of performance. And if all goes wrong, latching on another server is dirt cheap nowadays.

But then you get armies of pedantic dicks who march around saying "ha! You're using getters! Sir Google Almighty says they're bad, you low-life cheating catfish!"

EDIT: Wait, what? PHP actually seems to like double quotes better than single quotes.

Code: Select all

php -d implicit_flush=off -r '$t = microtime(true); for($i=0;$i<1000000;$i++){$foo = 'bar';} echo microtime(true) - $t; echo "\n";'


Takes 0.58-0.66s on my machine, while switching to double quotes kills that down to 0.08-0.09s. Now that's a pretty big number, and strings are used a lot of times in a project. But then phpbench disagrees.

I'm just guessing PHP does some sort of optimization internally for my double quotes.
In Minecraft, I use the username Rirez.

User avatar
chridd
Has a vermicelli title
Posts: 843
Joined: Tue Aug 19, 2008 10:07 am UTC
Location: ...Earth, I guess?
Contact:

Re: Coding: Fleeting Thoughts

Postby chridd » Sat Jun 16, 2012 5:38 pm UTC

Steax wrote:EDIT: Wait, what? PHP actually seems to like double quotes better than single quotes.

Code: Select all

php -d implicit_flush=off -r '$t = microtime(true); for($i=0;$i<1000000;$i++){$foo = 'bar';} echo microtime(true) - $t; echo "\n";'


Takes 0.58-0.66s on my machine, while switching to double quotes kills that down to 0.08-0.09s. Now that's a pretty big number, and strings are used a lot of times in a project. But then phpbench disagrees.

I'm just guessing PHP does some sort of optimization internally for my double quotes.
Isn't that actually $foo = bar; (without quotes), since single quotes are surrounding the entire code and thus removed by the shell?

If I escape the single quotes properly, it gives similar results for both types of quotes for me.
~ chri d. d. /tʃɹɪ.di.di/ (Phonotactics, schmphonotactics) · she · Forum game scores
mittfh wrote:I wish this post was very quotable...

User avatar
Steax
SecondTalon's Goon Squad
Posts: 3038
Joined: Sat Jan 12, 2008 12:18 pm UTC

Re: Coding: Fleeting Thoughts

Postby Steax » Sat Jun 16, 2012 5:56 pm UTC

Please excuse myself as I go whack my head against a wall.
In Minecraft, I use the username Rirez.

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 » Sun Jun 17, 2012 1:44 am UTC

In a really large application though, how many get / set calls are you going to be making per second?
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
Steax
SecondTalon's Goon Squad
Posts: 3038
Joined: Sat Jan 12, 2008 12:18 pm UTC

Re: Coding: Fleeting Thoughts

Postby Steax » Sun Jun 17, 2012 2:02 am UTC

At most, a few thousand per request? Which takes you into the millisecond order. And you can always use bytecode accelerators to speed it up dramatically.
In Minecraft, I use the username Rirez.

Great Justice
Posts: 54
Joined: Sun Aug 15, 2010 5:28 am UTC

Re: Coding: Fleeting Thoughts

Postby Great Justice » Sun Jun 17, 2012 3:01 am UTC

Which part was "alarmist" there?

Steax wrote:This advice is sound when raw. If your getters do nothing but get and set, then by all means, don't use them.

Yes, that's why the section title is "Avoid writing naive setters and getters" [bolded for your convenience], and the body expands on that.

Steax wrote:latching on another server is dirt cheap nowadays

No it isn't; the hardware is cheap, but the setup becomes more complex, plus more network traffic, more maintenance, more points of failure. It might work for your self-hosted simple (or naive) websites, but is actually infeasible til you reach some threshold of unacceptable performance (or increased financial returns). It's also worthless advice for the [insert high number] percentage of websites which run on shared servers.

The point is that the advice may not be for your particular case (good for you), but should be kept in mind for everybody from library devs, to the phpbb/drupal/joomla/etc devs, to Joe Coder writing mods to those for his grandma's knitting club site running on $2.99/mo hosting.
It usually isn't Congress or the State that tries to abridge free expression or free speech, [...] actually, in the present situation, the main threat to expression comes from public opinion.
~Christopher Hitchens

User avatar
Steax
SecondTalon's Goon Squad
Posts: 3038
Joined: Sat Jan 12, 2008 12:18 pm UTC

Re: Coding: Fleeting Thoughts

Postby Steax » Sun Jun 17, 2012 3:19 am UTC

The google document wasn't vague. The people taking that tidbit and parading around, blaming everyone using getters and setters, was what I called alarmist. In my opinion, if you have just a handful of instances where getters or setters do something magical, or could need to do so in the future, all of your classes should use them for consistency.

I also call it alarmist because the sample size of 1 million operations is just excessive - without this context, it's easy to get the impression that these functions could add in seconds to execution time. There's no way any sane website would run into that many calls, unless something is going horribly wrong. In the thousands, it's a millisecond-level delay, and I'm pretty sure all those string concats and temporary variables are going to be worse than getters and setters.

Great Justice wrote:No it isn't; the hardware is cheap, but the setup becomes more complex, plus more network traffic, more maintenance, more points of failure. It might work for your self-hosted simple (or naive) websites, but is actually infeasible til you reach some threshold of unacceptable performance (or increased financial returns). It's also worthless advice for the [insert high number] percentage of websites which run on shared servers.


I already mentioned several layers of optimizations one can make before they add in another server. And I was mentioning that somewhat-not-so-seriously: if you have to add a server because your scripts are running to low, you have a really big problem at some part of your application. Most people only add servers for databases, more complex functionality, or to distribute user requests; it's hardly ever because the scripts take too long to execute.

And hence,
Great Justice wrote: to Joe Coder writing mods to those for his grandma's knitting club site running on $2.99/mo hosting.


That's gotta be one hell of a knitting club to have execution time issues due to minor things like this.

The advice is sound when you take everything into account. My rant was about how people love to throw around micro-optimizations which does nobody any good, without adding context ("twice as long" is no context), and make themselves superior over it.
In Minecraft, I use the username Rirez.

User avatar
Shivahn
Posts: 2200
Joined: Tue Jan 06, 2009 6:17 am UTC

Re: Coding: Fleeting Thoughts

Postby Shivahn » Sun Jun 17, 2012 6:52 am UTC

Haskell is excellent.

I suck at it, but it's pretty easy to pick a Project Euler problem and write a five line or less solution in less than half an hour.

Many problems are trivial to solve even on the command line.

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

Re: Coding: Fleeting Thoughts

Postby Ben-oni » Sun Jun 17, 2012 8:28 am UTC

Shivahn wrote:Haskell is excellent.

I suck at it, but it's pretty easy to pick a Project Euler problem and write a five line or less solution in less than half an hour.

All problems are trivial to solve even on the command line, given sufficient understanding.

FTFY

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

Re: Coding: Fleeting Thoughts

Postby headprogrammingczar » Sun Jun 17, 2012 11:31 am UTC

Ben-oni wrote:
Shivahn wrote:Haskell is excellent.

I suck at it, but it's pretty easy to pick a Project Euler problem and write a five line or less solution if you are already well-versed in number theory.

All problems are trivial to solve even on the command line, given sufficient understanding.

FTFY


Don't forget that PE problems aren't really meant to challenge your ability to code.
<quintopia> You're not crazy. you're the goddamn headprogrammingspock!
<Weeks> You're the goddamn headprogrammingspock!
<Cheese> I love you

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

Re: Coding: Fleeting Thoughts

Postby Jplus » Sun Jun 17, 2012 3:53 pm UTC

*Essay alert*

Shivahn wrote:This is sort of a broad question of the fleeting-thought type, so this seems like a good place for it.

What are some good programming tools? I mean, ok, there are good compilers. And a text editor I can configure to do what I want is important (I'm using SciTE now, I fucked my libraries up so I can't use the Code::Blocks IDE anyway.) An IDE combines a lot of these, but I'm getting by fine with SciTE, valgrind, gdb, makefiles and g++.

But I'm talking about more broad stuff. [...]

Basically, I don't just lack the knowledge of which tools are useful, I lack the metaknowledge to begin to explore this area.

So that said, does anyone have any suggestions, either of tools, or of broad programming primers that have lists of useful tools: not basic stuff like debuggers, but like graph visualizers and whatnot? I feel like I might be having a harder time than I need to, because I don't know more in terms of tools than what is needed.

In the list that you named I see a text editor, two complementary debuggers, a build tool and a compiler. As Steax pointed out there is no documentation tool in it. I can name a few other types of tools that you're missing on altogether.

Version control: software that keeps track of your changes, lets you maintain multiple versions in parallel, lets you easily find back specific changes and restore/discard them, provides a (central) backup of your project, lets you check who did what and when, etcetera. Examples that are currently popular include Subversion, Git and Mercurial. IDEs usually integrate support for some VCSs.

(Visual) profiling: optimizing compilers (like g++) usually have a built-in profiling tool, but some IDEs offer visual graphs that make the results easier to interpret. By analogy, some web browsers (such as Safari and Chrome) offer visual profiling information on your page loads.

GUI editor: create the GUI of your app by drag-and-drop. Usually bundled with or included in an IDE, for example Visual Studio, Xcode or Qt Designer.

As you can see, nearly every kind of programming tool can be found to be integrated in some IDE. I don't think you can go much broader than an IDE. To be honest, I still find feature-rich IDEs too complex to use one myself. I should probably learn how to use one some day.

I can also recommend to learn about more different tools within the categories that have already been named. As a build tool, SCons, CMake and Boost.Build are all more convenient than the traditional Make, though in very different ways. LLVM/Clang is a relatively new player in the field of compilers, but now already important to know about. I'm not knowledgeable about documentation tools, but I know there are many alternatives to Doxygen (not all with the same kind of functionality) and I can name Boost.QuickBook as an example.

Apart from tools many other things can make your job easier, for example libraries (like the recent OpenMP) and websites (like GitHub). You didn't ask for it, so I won't elaborate on those. :)
"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
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? » Sun Jun 17, 2012 9:03 pm UTC

Re: getters and setters (in general)

I'm a bit mixed on this pattern. Besides slowing the code down (especially in an obtuse language like php), a lot of the supposed time-saving you do by using accessor methods typically seem to be dwarfed by the time taken adding them to the stuff that is never going to benefit from them.
I edit my posts a lot and sometimes the words wrong order words appear in sentences get messed up.

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

Re: Coding: Fleeting Thoughts

Postby EvanED » Sun Jun 17, 2012 9:14 pm UTC

Jplus wrote:*Essay alert*

Oh, I can beat that. :-)

My warning is a lot of what I say is probably kinda appropriate to religious wars, but what the heck.

Things are not necessarily quoted in order or without editing. :-)

Shivahn wrote:I'm getting by fine with SciTE, valgrind, gdb, makefiles and g++.


As a build tool, SCons, CMake and Boost.Build are all more convenient than the traditional Make, though in very different ways.

I can't reiterate these enough. In my opinion, using plain Makefiles, especially for C and C++ programs, is something that you just shouldn't do. Either you wind up with a build system that is inaccurate (in the sense that it rebuilds too much or not enough) or it requires too much manual effort to get headers right. Make + a makedepends-style solution helps this a bit, but there are still other problems and there are tools that I consider leave Make in the dust. To the point where I'll say "if you're using unassisted Make for C/C++ programs by free choice, you don't actually care about your tools."

Way better is either an entirely different build system (like SCons and Boost.Build, or the unmentioned Waf) that will deal with all that for you, or makefile generators (like CMake or the autotools; if they even handle these things which I'm not sure if they do on a changing code base or not). By a "makefile generator" what I mean is that you run a program (either cmake/ccmake/etc. or configure) which produces your makefiles, then you run make. CMake has a major advantage in that it will generate more than just makefiles for *nix-like systems -- it can also produce things like Visual Studio projects for your Windows users, "for free" (I believe). I'm pretty sure that a developer would have to go well out of their way and put in a lot of effort to get a MSVC-based build using the autotools, but I think you'd have to go out of your way to not get one using CMake (assuming all your C/C++ code is portable).

The autotools (autoconf+automake) have a big benefit of people knowing exactly what to do when untarring a project and seeing the autotools files. I know that I go through the "configure && make && make install' sequence, I know that I can pass '--prefix' to 'configure', I know that if 'configure' can't find libraries it will usually tell me the flag to pass, etc. However, my impression of those tools from the developer's side is... let's just say "less flattering". From what I can tell, they're pretty arcane. But I don't have first-hand knowledge in using the autotools, so I can't speak fairly or intelligently.

I have similar things to say about CMake. I actually like CMake even more when building stuff than the autotools. It's got a wonderful mechanism for sort of incremental configuration -- you can use it so that you configure, then when it hits a dependency it can't find, it'll stop and you can set it, and it will pick up where it left off. It will also give you a nice "GUI" if you want (either ncurses or an actual GUI) that lists all the configuration variables it pays attention too, and where you can set right there. (It's much better about this than autoconf, which seems sort of hit & miss. There's more sort of folk-knowledge to do things with that.) It's also a lot better at cross-platform stuff, as mentioned above. Finally, it also very nicely gives you a progress indicator while building, which is something that almost nothing else does. However, it's also a bit funky to use; it's got its own syntax for configuration files and stuff like that. Again, I have little experience using it from the developer's side.

I can talk about SCons, since that's what I use for nearly all of my builds. SCons is a build system proper -- you run it and out comes the built file. It is actually pretty nice to use as the developer. Your build scripts are all written in Python, so if you know Python you already know how to do some things. (Of course you still have to learn the API and how to us it.) It definitely does proper tracking of #include files (well, almost proper). It also treats both the executable it's running and (more usefully) the *command line* it uses to build a file as dependencies -- so if you change the build script in a way that will affect some files and not others, it will just rebuild those files. IMO this is a killer feature. It also has a nice change-detection thing; instead of looking at mtimes, it can take an MD5 of the file's contents. This means if you change a file then change it back, it won't rebuild (or if you change a source file in a way that doesn't affect the outputted object file, it won't relink); it also deals better with clock skew (very nice when working in a networked environment). What I uses is a compromise between the extra time of the hash and the benefits, so that it will look at the mtime first and if it is different from the last build, it will take the hash.

SCons isn't perfect though. First, it's cross-platform support is decent but not great. You can specify some common things like "look in this directory for include files" in a compiler-independent way (is it -I or /I?), but not others like "compile with debugging information" or "turn on warnings", so you need an if statement in your build script to pick. (I would guess this is better than the autotools, but it's not as good as CMake or Boost.Build.) And from the perspective of someone who is trying to build, it's unfortunately not as nice, as there's not good built in support for things like "look in this location for this library" or "build to this prefix". While it's not hard to add this yourself as a developer, it means that the interface isn't as good for the user.

Boost.Build I can't say much about either. It's got it's own specialized language and is a builder on its own, but is more strongly cross-platform than SCons is. One note: I think Boost may be trying to move to a CMake-based system; I'm not sure what this means about the future of Boost.Build. It's definitely not widely-used; I build a lot of software and I don't think I've ever come across anything else that uses it.

Waf seems like a promising up-start, but who knows if it'll reach its potential. It's based off of an old version of SCons, though the APIs now bear basically no resemblance. Like SCons, you write your build script in Python. I think most of SCons's shortcomings are still there, but I don't have much experience with it so can't say for sure. It does have some nice things though, like a more consistent interface for someone building (though not at the autotools level), and it's the only system I know besides CMake that gives you a progress indicator without a lot of work.

CMake and SCons seem to me like the primary choices (with Waf a strong contender); which one you pick seems to me like the decision between making life better for the developer or the person building the package.


Version control: software that keeps track of your changes, lets you maintain multiple versions in parallel, lets you easily find back specific changes and restore/discard them, provides a (central) backup of your project, lets you check who did what and when, etcetera. Examples that are currently popular include Subversion, Git and Mercurial. IDEs usually integrate support for some VCSs.

Apart from tools many other things can make your job easier, for example websites (like GitHub).

Yes, definitely. Not using version control -- even for single-person projects -- to me is craziness. And the three options JPlus listed are definitely the three that I would recommend. If you're totally unfamiliar with the topic, I can toot my own horn a little and link to a version control overview I wrote for a course I taught. It tries to give a presentation that makes sense for Subversion, Git, and Mercurial. :-) (There are really good overviews of individual tools out there, but I didn't run across any that gave a good overall picture and explained how to use all three in an effort to be tool-neutral).

While the difference isn't entirely in favor of using Git/Mercurial, there's enough to recommend either of those over Subversion that I would do so unless you have some specific reason to not. This is true 10x if you're working on a project that you think might be a useful open-source project for the world; using a distributed tool like Git or Mercurial dramatically lowers the bar for contributors. And Github is

The choice of Git vs Mercurial is largely personal preference. Personally I like Git and I have good, concrete reasons for this (I looove the index and git add --interactive), but the differences are pretty minor overall.

(Visual) profiling: optimizing compilers (like g++) usually have a built-in profiling tool, but some IDEs offer visual graphs that make the results easier to interpret. By analogy, some web browsers (such as Safari and Chrome) offer visual profiling information on your page loads.

Note that Valgrind, if you run it with valgrind --tool=callgrind blah, will give you a profile. (And it's much more useful than gprof ones that G++ has built in.) Run your program like that, then open callgrind.out.pid with something like kcachegrind.

Related to profiling is coverage testing -- GCC + gcov + lcov does a pretty good job at this.

----

OK, so what else can I think of.

For unit testing, I like the gtest (or googletest) library. Boost also has a good one, but I think Google's is better; among other advantages, its "death tests" I consider a killer feature. (This allows you to write tests like "make sure this function asserts under this condition.")

Unfortunately I've never actually used this, but the Data Display Debugger looks like it could be really cool. (Check out this screenshot.)

Make sure you know your shells. One sort of obscure feature of Bash-like shells is ctrl-R's reverse-incremental-search. Also make sure you know about ** patterns for recursive globbing (present in Bash 4, or in Zsh for quite a long time). Set up aliases for things that you find useful. (I should start a thread about stuff like that.) One thing I like is to have functions path_append and path_prepend that I can use like path_append PATH /something/cool (instead of export PATH=$PATH:/something/cool -- more annoying with longer variables like LD_LIBRARY_PATH, especially considering you lose a finger holding shift). It is occasionally very useful to write a one-off function at the shell for carrying out a pretty-specialized but repetitive task -- it's nice to know how to do this.

Know about TAGS files and how to use them in your editor. They're still shit compared with a good "go to definition" from an IDE, but they're still a lot better than just grepping for stuff.

As a more obscure tool, check out either this or this "Delta Debugging" tool. If you've ever tried to diagnose a problem by doing something like "comment out half of the code, then try again, then comment out a smaller region, etc.", this automates that task. It's really good at minimizing test cases. The overhead to use it is fairly high though; you have to either write some Python code or a shell script to both run the failing task and determine whether a later run fails, succeeds, or does something else. Only very occasionally useful, but when it's useful, it can be really useful.

For drawing graphs (of the Excel chart variety), check out matplotlib. It's a Python library that uses matlab-like syntax (function names, parameters, etc.) to draw very nice charts. For drawing graphs (of the nodes/edges variety), check out Graphviz dot and neato.

If you're programming in Java, check out The Omniscient Debugger. I don't do any Java, but if it's as useful as it sounds like it'd be, then it'd be amazing. Bascially it records a trace of your program's execution. Then you can open it up afterword in a "debugger" that lets you step forward, step backward, you can set reverse breakpoints and watchpoints, see all the values a variable took on during execution, stuff like that. It also means that any nondeterminism is fixed -- if you can make a concurrency bug happen under the debugger, then you can actually effectively debug it. GDB 7 can sort of do something similar, which I forgot about but now have to try out. (I'm not sure if they're using the same mechanism or not; there are a couple different ways you can do reverse debugging.)

Also make sure you know about GDB 7's Python support, which allows you to have (and write) nice pretty printers for STL containers and such.

Tools like nm and objdump can help diagnose linker errors, or just give you information about an executable.

User avatar
Steax
SecondTalon's Goon Squad
Posts: 3038
Joined: Sat Jan 12, 2008 12:18 pm UTC

Re: Coding: Fleeting Thoughts

Postby Steax » Mon Jun 18, 2012 12:38 am UTC

You, sir, name? wrote:Re: getters and setters (in general)

I'm a bit mixed on this pattern. Besides slowing the code down (especially in an obtuse language like php), a lot of the supposed time-saving you do by using accessor methods typically seem to be dwarfed by the time taken adding them to the stuff that is never going to benefit from them.


My rule of thumb is simply: if more than a handful of them have magic functionality, everything uses them. And for me, it's actually pretty rare to have a native getters and setters. At least each of my objects have a variable that's lazy loaded, like how a blog post's $post->getBody(); will actually only load the body when requested instead of on construction. Once some use getters, everything really should, for the sake of consistency and developer sanity.

Declaring them does take time, I agree, but it's rarely significant (unless you have one of those massive enterprise-y libraries with thousands of member variables).

--

Re: Version Control:

I always suggest Git now. The distributed qualities become apparent in many, many ways. For example, I have a git repo in dropbox, which I can access on other computers, and I also have a git bare ('origin') repository there. Every time I finish coding somewhere, I examine and commit the stuff in the dropbox folder, and push it back to the origin. Every time I write code locally, I commit and push it up to the origin. So now my data is backed up to the cloud, accessible wherever I go, and at any point I can easily push it to Github or another coworker! It's like magic!
In Minecraft, I use the username Rirez.

User avatar
Aaeriele
Posts: 2127
Joined: Tue Feb 23, 2010 3:30 am UTC
Location: San Francisco, CA

Re: Coding: Fleeting Thoughts

Postby Aaeriele » Mon Jun 18, 2012 1:12 am UTC

Steax wrote:
You, sir, name? wrote:Re: getters and setters (in general)

I'm a bit mixed on this pattern. Besides slowing the code down (especially in an obtuse language like php), a lot of the supposed time-saving you do by using accessor methods typically seem to be dwarfed by the time taken adding them to the stuff that is never going to benefit from them.


My rule of thumb is simply: if more than a handful of them have magic functionality, everything uses them. And for me, it's actually pretty rare to have a native getters and setters. At least each of my objects have a variable that's lazy loaded, like how a blog post's $post->getBody(); will actually only load the body when requested instead of on construction. Once some use getters, everything really should, for the sake of consistency and developer sanity.

Declaring them does take time, I agree, but it's rarely significant (unless you have one of those massive enterprise-y libraries with thousands of member variables).


This is the thing I love about Python's implementation of getters/setters (via the @property decorator): they can be added after the fact to code that didn't use them before, and nothing else has to change - how the rest of the code uses the thing in question is exactly the same as it was before you made it a getter/setter property:

Without property:

Code: Select all

class Foo(object):
  def __init__(self):
    self.a = None

foo = Foo()
foo.a = "b" # Just a normal assignment
c = foo.a # Just a normal access


With property:

Code: Select all

class Foo(object):
  def __init__(self):
    self._a = None

  @property
  def a(self):
    print "Someone's looking up a!"
    return self._a

  @a.setter
  def a(self, val):
    print "Someone's setting a!"
    self._a = val

foo = Foo()
foo.a = "b" # Uses the setter
c = foo.a # Uses the getter
Vaniver wrote:Harvard is a hedge fund that runs the most prestigious dating agency in the world, and incidentally employs famous scientists to do research.

afuzzyduck wrote:ITS MEANT TO BE FLUTTERSHY BUT I JUST SEE AAERIELE! CURSE YOU FORA!

User avatar
Steax
SecondTalon's Goon Squad
Posts: 3038
Joined: Sat Jan 12, 2008 12:18 pm UTC

Re: Coding: Fleeting Thoughts

Postby Steax » Mon Jun 18, 2012 1:28 am UTC

Yeah, I wish we could have that in PHP too. Apparently the developers did make that a possibility, but since they somehow didn't want to ruin the old way, the method is roundabout.

You have to use the __get($variable) magic function, like this:

Code: Select all

class banana{
  private 
$data = Array('color' => 'yellow');

  function 
__get($v){
    if(isset(
$data[$v]) && $v == 'color'){  return magical_function_here($data[$v]);  }
  }
}
 


And yes, it makes no sense, and also slows the crap down of an application (not to mention being an expensive retrofit).

I'd leave PHP if I could, but it's still hard. =/
In Minecraft, I use the username Rirez.

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

Re: Coding: Fleeting Thoughts

Postby EvanED » Mon Jun 18, 2012 2:25 am UTC

Steax wrote:I always suggest Git now. The distributed qualities become apparent in many, many ways. For example, I have a git repo in dropbox, which I can access on other computers, and I also have a git bare ('origin') repository there. Every time I finish coding somewhere, I examine and commit the stuff in the dropbox folder, and push it back to the origin. Every time I write code locally, I commit and push it up to the origin. So now my data is backed up to the cloud, accessible wherever I go, and at any point I can easily push it to Github or another coworker! It's like magic!

First, you can do the same thing with Mercurial, but I read your post as "I always suggest DVCS now" anyway. :-)

Second, I don't want to deny the benefits of Git and Mercurial. Git in particular has a bunch of features (like the index and add --interactive) that would be wonderful to have in Subversion too, and fixes real issues I've had with it.

However, I still think there's at least one thing that Subversion does far, far better, which is organization of repositories of loosely-related things. If you have projects that are directly related, then you put them into a single repository and you're done with it. If you have projects that aren't related, you put them into different repositories and you're done. But if you have things that are sorta kinda related but not really, there's no non-sucky way to do it with Git and Mercurial. With Subversion, it's easy: you put them into the same repository, then if you're interested in Project A you check out Project A, if you're interested in Project B you check out Project B, and if you're interested in both, you check out both. Git's lack of partial checkouts means this solution doesn't work.

For instance, take my config files. This is what I mean by "sorta kinda related", in that conceptually my Xmonad configuration (soon to be Awesome configuration :-)) doesn't have anything to do with my Emacs configuration, but I will almost always want them at the same time. Under Subversion they'd go into the same repository, and everything would work really well (or as well as any Subversion repo). Originally, I put them into the same Git repository too -- and then later I spend a couple hours splitting that repository apart (the "right" way) so that I could check out my Emacs directory on its own. So now I've got a Git repository that I think literally just has my Xmonad.hs file. And another that just has my .xsession and xmodmap file. And another that has just my Emacs stuff.

And the problem is managing these repositories becomes annoying at best. You can reduce the pain a little with submodules, but the submodule feature still has substantial usability problems. And it has one enormous drawback: I'm pretty sure I can't have the container repository change the URLs of the submodules depending on where it was checked out from. (E.g. if I check out the container repository over SSH from mycomputer.myhost it should check out the submodules from mycomputer.myhost, and if I check out them over SSH from Github it should check out the submodules from Github.) And I don't think there even a reasonable way to do this, which just sorta reinforces my point. You need separate container repositories (or at least separate branches), which just adds to the overhead of using them.

The same thing arises with scripts. Instead of one "useful scripts" repository where most things go, I have a bunch of separate ones, each with one or two files. Pretty ridiculous, and annoying to manage. But better than the alternative IMO in the Git world.

In short, I think something like config files represent an extremal case. On one hand, they tend to be highly personal and you're unlikely to want to do much cloning or stuff from other people, which means some of the benefits of distributed are minimized. It also means that clumping things together isn't a huge deal. And this loosely-connected thing means that it brings out this weakness of Git (and to be fair, AFAIK every other DVCS) a lot more than other things.

Now, I'm still using Git for my config files -- but I did think about it. In general, coordination between separate repositories is something that no VCS does well at all I think, and DVCSes mean that situation arises more.

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

Re: Coding: Fleeting Thoughts

Postby webzter_again » Mon Jun 18, 2012 2:39 am UTC

You, sir, name? wrote:Re: getters and setters (in general)

I'm a bit mixed on this pattern. Besides slowing the code down (especially in an obtuse language like php), a lot of the supposed time-saving you do by using accessor methods typically seem to be dwarfed by the time taken adding them to the stuff that is never going to benefit from them.


This is one of the changes to C# that I appreciate; its auto-getters and setters.

Code: Select all

    public class SomeClass
    {
         public string Name { get; set; }
         public int Age { get; protected set; }
    }


There's another case in C# where properties, or more exactly the CLI spec for properties versus variables, that allows for some fun abuse.

Code: Select all

    public class SomeClass
    {
         public virtual string Name { get; set; }
         public virtual int Age { get; protected set; }
    }


Now I can simply return a proxy wrapper instead of the actual object and intercept calls to Name and Age. An example... NHibernate is a popular data access framework; one of its options is that, if you declare your properties virtual, then you can lazy load from the DB when you you fetch by id and only the id will be populated (since that was known at the time of request). It won't actually make the database call to hydrate your object until the first time you access any property on that object.

User avatar
Steax
SecondTalon's Goon Squad
Posts: 3038
Joined: Sat Jan 12, 2008 12:18 pm UTC

Re: Coding: Fleeting Thoughts

Postby Steax » Mon Jun 18, 2012 3:50 am UTC

@Evan: Yes, I kinda did mean DVCS, not just Git (but I recommend Git because that's my choice of the two). =p

I didn't see it from that perspective; you're right, when you have loose projects in one repository, Subversion wins. I guess the "DVCS way" is to have a lot of separate repositories, instead of a few master ones. That's interesting to think about.
In Minecraft, I use the username Rirez.

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

Re: Coding: Fleeting Thoughts

Postby Jplus » Mon Jun 18, 2012 11:43 am UTC

Nice essay, EvanED. :)

@getters and setters: Alexander Stepanov makes a strong case that they're grossly overused. Read pages 8 through 11 of this paper (highly recommended in its entirety anyway). He's primarily concerned with C++, but his argument is general enough that it applies to any situation where you might feel like adding getters and setters. (Though of course, part of what he's advocating is impossible in most languages because they don't have operator overloading or because they don't have generics.)

@git and loosely related repositories: you can do the same thing with subrepositories that can be checked out either separately or together, without submodules, but it takes a very different approach from what you'd expect. Suppose that your "overarching project" contains a subfolder with emacs config files and a subfolder with Xmonad configuration. You can commit only your emacs folder, then commit your Xmonad folder in a new branch without ancestors. What you get is a repository with two root commits, and two (initially disconnected) commit histories. As long as you don't merge one branch into the other, you can check out the subprojects separately; but you can also merge both into a third branch, and check out that branch to have both at the same time.

I think two other, related tricks in git are also worth mentioning. Rather than submodules you can use git-subtree, which is a lot more flexible and convenient. The other trick is that you can have two different checkouts from the same repository in different directories at the same time. It's regular business in SVN, but you can do it in git too.

@drawing graphs: I would like to add gnuplot and R to the mix.
"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 18, 2012 3:28 pm UTC

He replaced "get and set value" with "get const and non const reference", and added contiguous memory guarantees. The use of [] is just sugar -- T const & get( size_t n ) const is just as good as T const & operator[]( size_t n ) const in almost every way he talked about (with the exception that [] ducktypes a tad better than .get).
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
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 » Mon Jun 18, 2012 4:53 pm UTC

Jplus wrote:@getters and setters: Alexander Stepanov makes a strong case that they're grossly overused. Read pages 8 through 11 of this paper (highly recommended in its entirety anyway). He's primarily concerned with C++, but his argument is general enough that it applies to any situation where you might feel like adding getters and setters. (Though of course, part of what he's advocating is impossible in most languages because they don't have operator overloading or because they don't have generics.)
That doesn't seem to have much to do with getters/setters really. It's not even that he's removing the abstraction there, because with overloading the [] operators you could still hide they underlying implementation of the array if it doesn't happen to be contiguous (or isn't actually index based such as for a dictionary). Just seems like he's saying if you think the get/set functions have to be named "getBlah" or "setBlah" you've missed the point.

EDIT: I should have read Yakk's post more closely, because then I could have just gone "that" or something. :P

I'm spoiled by properties in C# though, even if they do come with a runtime cost similar to methods, the code I work with where I work is basically a public library to the clients, so they can call things directly, and breaking when we have to change an implementation is bad if we can avoid it (because implementations can and will change, always). That, and it's 2 keystrokes to turn a private member into a public property for me, so they're effectively free to write.

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

Re: Coding: Fleeting Thoughts

Postby Jplus » Mon Jun 18, 2012 5:02 pm UTC

No, now both of you are staying too close to the surface (to std::vector and the [] operator in particular). His point is that getters and setters were invented to hide the implementation, while in many cases (most, as far as Stepanov's concerned) it's better to expose the implementation. His criticism is that people are making the "data hiding" aspect of OOP a goal in itself rather than a means to an end. In fact, he's claiming that hiding the implementation is only good if doing otherwise might hurt the validity of the object.*

As you can probably tell, I agree with this viewpoint. :)

@Xeio: it's true that one can still hide the implementation with an overloaded operator, but note that Stepanov is arguing explicitly to not do that here. Passing a reference gives you direct access to the implementation, while getters and setters were invented to prevent such direct access.

____________________

* For example, a point is valid regardless of the values that you assign to the x and y coordinates, so you should expose the implementation rather than indirecting the coordinates through getters and setters. On the other hand, the pointer to the internal buffer of a std::vector must never dangle, so the client shouldn't get direct access to it. &(vec[0]) is the getter (doesn't let you affect the pointer directly) while vec.clear(), vec.reserve() and so on are the setters (don't let you affect the pointer directly).
"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
Shivahn
Posts: 2200
Joined: Tue Jan 06, 2009 6:17 am UTC

Re: Coding: Fleeting Thoughts

Postby Shivahn » Mon Jun 18, 2012 5:06 pm UTC

Wow, thanks for all that. I'll look into all of those tools.

I actually am using Mercurial, by the way, I just didn't mention it because it didn't occur to me that it counted as a tool. I'm not crazy enough to not have version control!

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 » Mon Jun 18, 2012 5:48 pm UTC

I don't like properties. They mask whether you're just calling a variable or a function. So if you hide any complexity in the property, the caller has no way of knowing that there's any complexity at all.
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
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 » Mon Jun 18, 2012 6:14 pm UTC

Jplus wrote:No, now both of you are staying too close to the surface (to std::vector and the [] operator in particular). His point is that getters and setters were invented to hide the implementation, while in many cases (most, as far as Stepanov's concerned) it's better to expose the implementation. His criticism is that people are making the "data hiding" aspect of OOP a goal in itself rather than a means to an end. In fact, he's claiming that hiding the implementation is only good if doing otherwise might hurt the validity of the object.*

As you can probably tell, I agree with this viewpoint. :)
But he doesn't even go the whole way in doing that? Why not make v public then? It doesn't change after all, so there shouldn't be an issue exposing the array and letting the caller access it directly? And if the memory position did change then you might already have a problem by returning an address rather than the value (though I'll admit, I'm not very familiar with C++ references, but I wouldn't imagine a reference to an array index is still valid after the array goes away).

Isn't it really just a question of how much implementation to expose, not just whether to expose it or not? Hiding everything might not be beneficial, but neither is exposing everything.

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

Re: Coding: Fleeting Thoughts

Postby Jplus » Mon Jun 18, 2012 6:52 pm UTC

Isn't that explained in the footnote of my previous post? Stepanov discusses exactly how much of the implementation should be exposed: those parts that may be altered by the client at will should, those parts that might be invalidated by exposure should not. That's why he doesn't make v public.
"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
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 » Mon Jun 18, 2012 7:32 pm UTC

My brain may have glossed over the smaller text. <_<

I'm still not entirely sure what the problem with hiding implementation details is though. It's not implicitly better to hide or expose details, it's entirely up to the design of the project and the requirements, and, in particular the potential future requirements. I can't easily hide implementation details after I've exposed them, I've essentially locked in the interface at that point (without a version breaking change, anyway). If I show you a public member, I can't suddenly go back and start to do validation so that you don't pass in something icky.

I mean, maybe this is different in C++? Things like passing references isn't relevant because you never get direct access like that. The scenario he lays out where sorting is done through a method external to the class is pretty strange coming from a C# world.

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 18, 2012 7:36 pm UTC

If you go back and do validation, then you have broken your interface. Even if you called it "Set" before, a "Set" that validates input is a different interface with different guarantees than a "Set" that doesn't. What this lets you do is change the meaning of the interface without having to modify any of the clients.
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.

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

Re: Coding: Fleeting Thoughts

Postby Ben-oni » Mon Jun 18, 2012 10:05 pm UTC

Stepanov seems mostly concerned about library design and generic code. And when it comes to that, preserving the basic C and C++ semantics is all well and good. But for high level project specific classes, I don't think it really applies.

As mentioned previously, there are plenty of scenarios where getters and setters need to hide the implementation details, like for caching, memoization, lazy-lookup, etc. I'll grant that these are generally optimization level things, but the point remains: there are valid reasons for using getters and setters. However, using them just because other code uses them isn't one of those reasons.

I'll also grant that properties, which are available in a host of languages from VB, C#, Objective-C, Lisp, Python, and who-knows-where else, allow you to add getters and setters after-the-fact.

But when it comes down to applications programming, I don't think Stepanov's ideas are really useful. While you can think of every program in terms of the data structure built and iterated over, doing so is less useful than considering the goals of the program. I, for one, much prefer to think of a program in terms of what it does rather than how it does it.

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 » Tue Jun 19, 2012 1:36 am UTC

As an aside, writing a property in C++ isn't hard. (A member of a class which, when read from or written do, runs arbitrary code).

Code: Select all

template<typename Scalar>
struct Property
{
  std::function< Scalar() > get;
  std::function< void(Scalar) > set;
  operator Scalar() const { return get(); }
  Property& operator=( Scalar src ) { set(src); }
  // etc.  Note that the above presumes cheap-copy Scalars
};

template<typename Scalar>
void MakeTrivialProperty( Property& p )
{
  std::shared_ptr<Scalar> data(new Scalar);
  p.set = [data]( Scalar s ) { *data = s; }
  p.get = [data]() { return *data; }
}

Now, to make it fancier, you actually need a gettor/settor factory/mover/swappor/etc, with a passed in this pointer context. And/or just make the Property itself be aware of the this pointer and pass it into the functors it calls.

It would be hard to get exactly right, but I'm guessing someone has written it much better than I have, and the above would be good enough for a few special cases. (and as efficient as C# code anyhow...)
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.

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

Re: Coding: Fleeting Thoughts

Postby webzter_again » Tue Jun 19, 2012 2:25 am UTC

Yakk wrote:(and as efficient as C# code anyhow...)


As an aside to an aside ;)

How it goes down in C# (spoilered for length/boredom)
Spoiler:
The following (now common) C# code (in the ever so original namespace ConsoleApplication1:

Code: Select all

   public class Person
   {
      public string Name { get; set; }
   }


Gets turned into this behind the scenes:

Code: Select all

  public class Person
  {
    [CompilerGenerated]
    private string <Name>k__BackingField;

    public string Name
    {
      get
      {
        return this.<Name>k__BackingField;
      }
      set
      {
        this.<Name>k__BackingField = value;
      }
    }

    public Person()
    {
      base..ctor();
    }
  }


Which is then turned into the following IL:

Code: Select all

.class public auto ansi beforefieldinit ConsoleApplication1.Person
       extends [mscorlib]System.Object
{
  .field private string '<Name>k__BackingField'
  .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
  .method public hidebysig specialname instance string
          get_Name() cil managed
  {
    .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
    // Code size       11 (0xb)
    .maxstack  1
    .locals init (string V_0)
    IL_0000:  ldarg.0
    IL_0001:  ldfld      string ConsoleApplication1.Person::'<Name>k__BackingField'
    IL_0006:  stloc.0
    IL_0007:  br.s       IL_0009

    IL_0009:  ldloc.0
    IL_000a:  ret
  } // end of method Person::get_Name

  .method public hidebysig specialname instance void
          set_Name(string 'value') cil managed
  {
    .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
    // Code size       8 (0x8)
    .maxstack  8
    IL_0000:  ldarg.0
    IL_0001:  ldarg.1
    IL_0002:  stfld      string ConsoleApplication1.Person::'<Name>k__BackingField'
    IL_0007:  ret
  } // end of method Person::set_Name

  .method public hidebysig specialname rtspecialname
          instance void  .ctor() cil managed
  {
    // Code size       7 (0x7)
    .maxstack  8
    IL_0000:  ldarg.0
    IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
    IL_0006:  ret
  } // end of method Person::.ctor

  .property instance string Name()
  {
    .get instance string ConsoleApplication1.Person::get_Name()
    .set instance void ConsoleApplication1.Person::set_Name(string)
  } // end of property Person::Name
} // end of class ConsoleApplication1.Person


Or, in other words, those getters and setters just become get_<propertyname> and set_<propertyname> methods.

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 3:12 am UTC

Doing some testing... there doesn't seem to be really be a performance penalty that I can see, though I'm a tiny bit wary of the program being too simple for the test (I tried to make it harder for the compiler to optimize all the logic away, but I may have failed). I tried another one with strings and it was also within the margin of error.

Spoiler:

Code: Select all

using System;

namespace Tuzz
{
    class Program
    {
        static void Main(string[] args)
        {
            System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();
            Tester t = new Tester();
            watch.Start();
            for (int i = 0; i < 100000000;)
            {
                t.Hello = i;
                t.Toggle();
                i = t.Hello;
            }
            watch.Stop();
            Console.WriteLine(watch.Elapsed);
            Console.ReadLine();
        }
    }

    class Tester
    {
        public int Hello {get; set;}
        public void Toggle(){
            Hello++;
        }
    }
}

For the other version change

Code: Select all

public int Hello;// {get; set;}


Debug Mode:
Property - 1.53s
Field - 0.49s

Release Mode (optimizations enabled):
Property - 0.29s
Field - 0.29s

The property might be a tiny bit slower in the release mode, but the margin of error for both overlapped in the few tests I ran.

I think this just confirms my suspicions that JIT compiling and inlining is deep magic.

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

Re: Coding: Fleeting Thoughts

Postby webzter_again » Tue Jun 19, 2012 4:00 am UTC

Xeio wrote:I think this just confirms my suspicions that JIT compiling and inlining is deep magic.


Here you go.... IL from a release mode build

tl;dr version: Yes, using properties is definitely slower. Especially if you don't hand-edit the IL to optimize the method for calling the resulting mutator methods. However, from a practical standpoint, speed of properties versus fields probably shouldn't be your primary consideration when choosing C#.

Spoiler:
The IL for your Main function with the property.

Code: Select all

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       79 (0x4f)
  .maxstack  2
  .locals init ([0] class [System]System.Diagnostics.Stopwatch watch,
           [1] class Tuzz.Tester t,
           [2] int32 i)
  IL_0000:  newobj     instance void [System]System.Diagnostics.Stopwatch::.ctor()
  IL_0005:  stloc.0
  IL_0006:  newobj     instance void Tuzz.Tester::.ctor()
  IL_000b:  stloc.1
  IL_000c:  ldloc.0
  IL_000d:  callvirt   instance void [System]System.Diagnostics.Stopwatch::Start()
  IL_0012:  ldc.i4.0
  IL_0013:  stloc.2
  IL_0014:  br.s       IL_002a
  IL_0016:  ldloc.1
  IL_0017:  ldloc.2
  IL_0018:  callvirt   instance void Tuzz.Tester::set_Hello(int32)
  IL_001d:  ldloc.1
  IL_001e:  callvirt   instance void Tuzz.Tester::Toggle()
  IL_0023:  ldloc.1
  IL_0024:  callvirt   instance int32 Tuzz.Tester::get_Hello()
  IL_0029:  stloc.2
  IL_002a:  ldloc.2
  IL_002b:  ldc.i4     0x5f5e100
  IL_0030:  blt.s      IL_0016
  IL_0032:  ldloc.0
  IL_0033:  callvirt   instance void [System]System.Diagnostics.Stopwatch::Stop()
  IL_0038:  ldloc.0
  IL_0039:  callvirt   instance valuetype [mscorlib]System.TimeSpan [System]System.Diagnostics.Stopwatch::get_Elapsed()
  IL_003e:  box        [mscorlib]System.TimeSpan
  IL_0043:  call       void [mscorlib]System.Console::WriteLine(object)
  IL_0048:  call       string [mscorlib]System.Console::ReadLine()
  IL_004d:  pop
  IL_004e:  ret
} // end of method Program::Main


The IL for your field version

Code: Select all

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       79 (0x4f)
  .maxstack  2
  .locals init ([0] class [System]System.Diagnostics.Stopwatch watch,
           [1] class Tuzz.Tester t,
           [2] int32 i)
  IL_0000:  newobj     instance void [System]System.Diagnostics.Stopwatch::.ctor()
  IL_0005:  stloc.0
  IL_0006:  newobj     instance void Tuzz.Tester::.ctor()
  IL_000b:  stloc.1
  IL_000c:  ldloc.0
  IL_000d:  callvirt   instance void [System]System.Diagnostics.Stopwatch::Start()
  IL_0012:  ldc.i4.0
  IL_0013:  stloc.2
  IL_0014:  br.s       IL_002a
  IL_0016:  ldloc.1
  IL_0017:  ldloc.2
  IL_0018:  stfld      int32 Tuzz.Tester::Hello
  IL_001d:  ldloc.1
  IL_001e:  callvirt   instance void Tuzz.Tester::Toggle()
  IL_0023:  ldloc.1
  IL_0024:  ldfld      int32 Tuzz.Tester::Hello
  IL_0029:  stloc.2
  IL_002a:  ldloc.2
  IL_002b:  ldc.i4     0x5f5e100
  IL_0030:  blt.s      IL_0016
  IL_0032:  ldloc.0
  IL_0033:  callvirt   instance void [System]System.Diagnostics.Stopwatch::Stop()
  IL_0038:  ldloc.0
  IL_0039:  callvirt   instance valuetype [mscorlib]System.TimeSpan [System]System.Diagnostics.Stopwatch::get_Elapsed()
  IL_003e:  box        [mscorlib]System.TimeSpan
  IL_0043:  call       void [mscorlib]System.Console::WriteLine(object)
  IL_0048:  call       string [mscorlib]System.Console::ReadLine()
  IL_004d:  pop
  IL_004e:  ret
} // end of method Program::Main


Or, in simpler terms, the difference is:

int32 Tuzz.Tester::Hello
versus
callvirt instance void Tuzz.Tester::set_Hello(int32)

The callvirt is actually a sort of expensive operation. One possible tuning would be to hand-edit the IL and change it to a straight call. You can read more about the decision to use callvirt here

There's also some slight savings between the field version and property version wrt the Toggle function.

Property version

Code: Select all

.method public hidebysig instance void  Toggle() cil managed
{
  // Code size       15 (0xf)
  .maxstack  8
  IL_0000:  ldarg.0
  IL_0001:  dup
  IL_0002:  call       instance int32 Tuzz.Tester::get_Hello()
  IL_0007:  ldc.i4.1
  IL_0008:  add
  IL_0009:  call       instance void Tuzz.Tester::set_Hello(int32)
  IL_000e:  ret
} // end of method Tester::Toggle



Field version

Code: Select all

.method public hidebysig instance void  Toggle() cil managed
{
  // Code size       15 (0xf)
  .maxstack  8
  IL_0000:  ldarg.0
  IL_0001:  dup
  IL_0002:  ldfld      int32 Tuzz.Tester::Hello
  IL_0007:  ldc.i4.1
  IL_0008:  add
  IL_0009:  stfld      int32 Tuzz.Tester::Hello
  IL_000e:  ret
} // end of method Tester::Toggle


So, in the property version, we're doing a call to a method to access the variable (since properties just compile to methods). This time, rather than callvirt, it's a straight call because it's to a local instance member that we know can never be null. There's some speed overhead there versus the field version since the just does a load field, adds, and stores.

And, for completeness, it's always fun to reverse-engineer the IL back to C#. Not only does it make for a good Seinfeld episode, it makes for fun to see what the compiler did to optimize your code:

Code: Select all

    private static void Main(string[] args)
    {
      Stopwatch stopwatch = new Stopwatch();
      Tester tester = new Tester();
      stopwatch.Start();
      for (int index = 0; index < 100000000; index = tester.Hello)
      {
        tester.Hello = index;
        tester.Toggle();
      }
      stopwatch.Stop();
      Console.WriteLine((object) stopwatch.Elapsed);
      Console.ReadLine();
    }

internal class Tester
  {
    [CompilerGenerated]
    private int <Hello>k__BackingField;

    public int Hello
    {
      get
      {
        return this.<Hello>k__BackingField;
      }
      set
      {
        this.<Hello>k__BackingField = value;
      }
    }

    public Tester()
    {
      base..ctor();
    }

    public void Toggle()
    {
      ++this.Hello;
    }
  }

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

Re: Coding: Fleeting Thoughts

Postby Thesh » Tue Jun 19, 2012 4:46 am UTC

So I'm developing an app in C with a command line interface which will be built cross platform. I'm wondering if there's a cross platform library (I want to be able to build it for mac, windows, linux, and unix) with the following requirements:

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)

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.

Most of the program's very simple, so I really don't need functionality beyond those two requirements. My software is going to be licensed under the MIT license, so it needs to be compatible, preferably released under a similar license. I intend to build it with Visual Studio 10 under windows, and GCC on *nix,

So, does anyone have any suggestions?
Summum ius, summa iniuria.

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:36 am UTC

webzter_again wrote:
Xeio wrote:I think this just confirms my suspicions that JIT compiling and inlining is deep magic.


Here you go.... IL from a release mode build

tl;dr version: Yes, using properties is definitely slower. Especially if you don't hand-edit the IL to optimize the method for calling the resulting mutator methods. However, from a practical standpoint, speed of properties versus fields probably shouldn't be your primary consideration when choosing C#.

Spoiler:
The IL for your Main function with the property.

Code: Select all

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       79 (0x4f)
  .maxstack  2
  .locals init ([0] class [System]System.Diagnostics.Stopwatch watch,
           [1] class Tuzz.Tester t,
           [2] int32 i)
  IL_0000:  newobj     instance void [System]System.Diagnostics.Stopwatch::.ctor()
  IL_0005:  stloc.0
  IL_0006:  newobj     instance void Tuzz.Tester::.ctor()
  IL_000b:  stloc.1
  IL_000c:  ldloc.0
  IL_000d:  callvirt   instance void [System]System.Diagnostics.Stopwatch::Start()
  IL_0012:  ldc.i4.0
  IL_0013:  stloc.2
  IL_0014:  br.s       IL_002a
  IL_0016:  ldloc.1
  IL_0017:  ldloc.2
  IL_0018:  callvirt   instance void Tuzz.Tester::set_Hello(int32)
  IL_001d:  ldloc.1
  IL_001e:  callvirt   instance void Tuzz.Tester::Toggle()
  IL_0023:  ldloc.1
  IL_0024:  callvirt   instance int32 Tuzz.Tester::get_Hello()
  IL_0029:  stloc.2
  IL_002a:  ldloc.2
  IL_002b:  ldc.i4     0x5f5e100
  IL_0030:  blt.s      IL_0016
  IL_0032:  ldloc.0
  IL_0033:  callvirt   instance void [System]System.Diagnostics.Stopwatch::Stop()
  IL_0038:  ldloc.0
  IL_0039:  callvirt   instance valuetype [mscorlib]System.TimeSpan [System]System.Diagnostics.Stopwatch::get_Elapsed()
  IL_003e:  box        [mscorlib]System.TimeSpan
  IL_0043:  call       void [mscorlib]System.Console::WriteLine(object)
  IL_0048:  call       string [mscorlib]System.Console::ReadLine()
  IL_004d:  pop
  IL_004e:  ret
} // end of method Program::Main


The IL for your field version

Code: Select all

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       79 (0x4f)
  .maxstack  2
  .locals init ([0] class [System]System.Diagnostics.Stopwatch watch,
           [1] class Tuzz.Tester t,
           [2] int32 i)
  IL_0000:  newobj     instance void [System]System.Diagnostics.Stopwatch::.ctor()
  IL_0005:  stloc.0
  IL_0006:  newobj     instance void Tuzz.Tester::.ctor()
  IL_000b:  stloc.1
  IL_000c:  ldloc.0
  IL_000d:  callvirt   instance void [System]System.Diagnostics.Stopwatch::Start()
  IL_0012:  ldc.i4.0
  IL_0013:  stloc.2
  IL_0014:  br.s       IL_002a
  IL_0016:  ldloc.1
  IL_0017:  ldloc.2
  IL_0018:  stfld      int32 Tuzz.Tester::Hello
  IL_001d:  ldloc.1
  IL_001e:  callvirt   instance void Tuzz.Tester::Toggle()
  IL_0023:  ldloc.1
  IL_0024:  ldfld      int32 Tuzz.Tester::Hello
  IL_0029:  stloc.2
  IL_002a:  ldloc.2
  IL_002b:  ldc.i4     0x5f5e100
  IL_0030:  blt.s      IL_0016
  IL_0032:  ldloc.0
  IL_0033:  callvirt   instance void [System]System.Diagnostics.Stopwatch::Stop()
  IL_0038:  ldloc.0
  IL_0039:  callvirt   instance valuetype [mscorlib]System.TimeSpan [System]System.Diagnostics.Stopwatch::get_Elapsed()
  IL_003e:  box        [mscorlib]System.TimeSpan
  IL_0043:  call       void [mscorlib]System.Console::WriteLine(object)
  IL_0048:  call       string [mscorlib]System.Console::ReadLine()
  IL_004d:  pop
  IL_004e:  ret
} // end of method Program::Main


Or, in simpler terms, the difference is:

int32 Tuzz.Tester::Hello
versus
callvirt instance void Tuzz.Tester::set_Hello(int32)

The callvirt is actually a sort of expensive operation. One possible tuning would be to hand-edit the IL and change it to a straight call. You can read more about the decision to use callvirt here

There's also some slight savings between the field version and property version wrt the Toggle function.

Property version

Code: Select all

.method public hidebysig instance void  Toggle() cil managed
{
  // Code size       15 (0xf)
  .maxstack  8
  IL_0000:  ldarg.0
  IL_0001:  dup
  IL_0002:  call       instance int32 Tuzz.Tester::get_Hello()
  IL_0007:  ldc.i4.1
  IL_0008:  add
  IL_0009:  call       instance void Tuzz.Tester::set_Hello(int32)
  IL_000e:  ret
} // end of method Tester::Toggle



Field version

Code: Select all

.method public hidebysig instance void  Toggle() cil managed
{
  // Code size       15 (0xf)
  .maxstack  8
  IL_0000:  ldarg.0
  IL_0001:  dup
  IL_0002:  ldfld      int32 Tuzz.Tester::Hello
  IL_0007:  ldc.i4.1
  IL_0008:  add
  IL_0009:  stfld      int32 Tuzz.Tester::Hello
  IL_000e:  ret
} // end of method Tester::Toggle


So, in the property version, we're doing a call to a method to access the variable (since properties just compile to methods). This time, rather than callvirt, it's a straight call because it's to a local instance member that we know can never be null. There's some speed overhead there versus the field version since the just does a load field, adds, and stores.

And, for completeness, it's always fun to reverse-engineer the IL back to C#. Not only does it make for a good Seinfeld episode, it makes for fun to see what the compiler did to optimize your code:

Code: Select all

    private static void Main(string[] args)
    {
      Stopwatch stopwatch = new Stopwatch();
      Tester tester = new Tester();
      stopwatch.Start();
      for (int index = 0; index < 100000000; index = tester.Hello)
      {
        tester.Hello = index;
        tester.Toggle();
      }
      stopwatch.Stop();
      Console.WriteLine((object) stopwatch.Elapsed);
      Console.ReadLine();
    }

internal class Tester
  {
    [CompilerGenerated]
    private int <Hello>k__BackingField;

    public int Hello
    {
      get
      {
        return this.<Hello>k__BackingField;
      }
      set
      {
        this.<Hello>k__BackingField = value;
      }
    }

    public Tester()
    {
      base..ctor();
    }

    public void Toggle()
    {
      ++this.Hello;
    }
  }

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).


Return to “Coding”

Who is online

Users browsing this forum: No registered users and 10 guests