Showing posts with label programming. Show all posts
Showing posts with label programming. Show all posts

Friday, January 20, 2012

Java

: what is a "RequestMappingHandlerAdapter"?
: this is what's wrong with modern OOP
: nigh unreadable, despite the letters expended vainly in the effort
: might as well call it LeftBallCheesecakeWizard

Thursday, January 20, 2011

User-space C++ application tracing on Fedora using Systemtap

Ever since DTrace came out I realized how much that was what I really wanted to do whenever my program was doing something other than what I assumed it was doing. "Tracing" -- I want that.

Debugging is fine; but you need to have debug symbols, you need to pick the right spot in the code to break at, you have to keep manual track if you're tracing a long-running execution, and real-time applications may not play nice when paused for arbitrary periods. Often I would want to not follow a thread of execution up and down its call stack -- rather I'd be interested in the "cross-cutting concerns" -- how a certain variable changes over time.

DTrace will never be coming to my favorite platform (GNU/Linux), but there is a similar library called SystemTap for Linux, which has had the Linux kernel instrumented for a while, but just recent has allowed tracing in user-space programs. I think you will need Fedora 14 to run user-space traces; at least that is what I am using. With the appropriate setup you can start tracing your own C++ applications without modifying the source.

SystemTap uses "static" (preprocessor macro-based source code) probes that are compatible with DTrace; so if you decide to mark-up your source with these macros (as Java, Python, MySQL, et al. are) you can use DTrace or SystemTap depending on your platform. These probes are turned into no-ops when not in use, so they are very fast. However the usage that I am interested in is ad-hoc tracing for the purpose of debugging or simple profiling. Thankfully for this case all you need is debug symbols.

Once you have SystemTap installed, and your program compiled with symbols, you can write your custom probes. The syntax of the probes is beyond our scope, but you can read about it here. Instead I will post a simple "hello world" demo as follows:


#include < iostream >
#include < vector >

using namespace std;

namespace Baz
{
struct Foo
{
int i; int n; float f;

Foo() : i (0), n (0), f (3.14) {}
Foo(int a, float b) : i (a), n (0), f (b) {}
Foo(Foo const &c) : i (c.i), n (c.n), f (c.f) {}
~Foo() {}

int dolart () { f += i; f /= 3.14; return 0; }
int dofizz (int a) { n = a; i += n; return n; }
};
}

int main()
{
vector < int > test;
vector < Baz::Foo > list;

for (int i=0; i<5; ++i)
{
test.push_back (i);
list.push_back (Baz::Foo (i, 1.1));
}

vector < Baz::Foo >::iterator i = list.begin();
vector < Baz::Foo >::iterator e = list.end();

for (int n=0; i != e; ++i)
i->dolart (), i->dofizz (++n);

return 0;
}

And if we use the following "tapset" on the code

global lart_count
global fizz_count
global push_back_count

probe process("a.out").function("Baz::Foo::do*").return
{ if ($return == 2) printf("Foo returned 2!\n"); }

probe process("a.out").function("Baz::Foo::dolart")
{ ++lart_count; }

probe process("a.out").function("Baz::Foo::dofizz")
{ ++fizz_count; }

probe process("a.out").function("vector < * >::push_back")
{ ++push_back_count; }

probe process("a.out").function("main").return
{
printf("dolart was called %d times.\n", lart_count);
printf("dofizz was called %d times.\n", fizz_count);
printf("vector::push_back was called %d times.\n", push_back_count);
}

And run it as follows:

$ g++ -g test.cpp
$ sudo stap probe.stp -c ./a.out

Then we should get the following result:

Foo returned a 2!
dolart was called 5 times.
dofizz was called 5 times.
vector::push_back was called 10 times.

A couple issues I noticed
  • You must run this as root. This is because stap has to compile and load a kernel module that has enormous power to probe your system.
  • Seems to run a bit slow on the simple example. This could be one-time start-up due to compiling a kernel module, or it could be a real-time overhead of not using the cheaper static probes.
  • It seems to spew a lot of strange mangled C++ names for an unknown reason.
  • Constantly respecifying process("a.out") seems redundant. There's probably a way to get around this overhead.

Saturday, May 29, 2010

Boost your Spirits

After struggling with Boost.Spirit for a couple days, I've finally gotten my head around the parser component (Qi) enough I thought I might share.

Most of the trouble getting things working is the same trouble one gets from most template-based libraries often found in Boost: since template programming is not based on a solid methodology (such as OO) that one can build intuition upon -- rather on C++ tricks or compile-time side effects, and the errors the compiler issues are nigh unreadable, when something goes wrong it's hard to know where or why.

However Spirit is quite redeemable because frankly I'm not sure how many ad-hoc parsers I wish to write in my life-time. Spirit is a recursive descent parser, where the grammar is specified directly in C++, using C++ operators to build the parser. This means Spirit could be a quick and simple way to add parsing to your projects without a lot of effort. Spirit is limited to LL(k) grammars, but most grammars one encounters are fairly simple, so this fits the bill quite ably.

There is some good documentation and examples on the Boost site, so I won't be writing a tutorial. Instead I'll try to give you advice and help you conceptualize what's going on, so you have an easier time reading the tutorials.

Basically, Spirit (or more accurately the Qi parsing component) has a beautiful design: parsers are built by joining simpler parse objects together, using overloaded C++ operators, to build complicated parsers. So,

char_


is a predefined boost::spirit::terminal (grammar[1]) that recognizes a single character.

char_("a")


recognizes the single character 'a'.

char_("a-z")


recognizes a single lower-case character from a to z.

int_ recognizes integers, hex recognizes hexadecimal integers, double_ recognizes double precision floating point numbers, etc.

Now using the grammar operators, we can recognize the following statement:

{0xbeef}


as 48879 with the following grammar:

char_('{') >> string("0x") >> hex >> char_('}')


If we had a list of such bracketed numbers, we could place a Kleene star in front[2] of the whole expression to recognize the list. The full detail of built-in parsers and grammar operators can be found in the documentation.

Spirit has another interesting idea called a skip parser. Basically this is what's used to help tokenize the input by deciding what is not semantically relevant. Usually the skip parser skips space and comments.

For example, if comments are "//-to-eol" delimited, the following may be your skip grammar:


ascii::space | "//" >> *(char_ - eol) >> eol;


So now we have handled white-space and comments, and recognized our number, how do we read 48879 into our program?

Each parser has an associated "attribute" that, in the case of terminals, is easy to deduce. For char_ it is char, for int_ and hex it is int, in the case of *double_ it is std::vector<double>, and so on.

Wait, how did that vector get in there? Good question. You see, the operator not only joins parsers together in a new modified parser, it joins the attributes together into a new modified type. For example if parser p has attribute a of type A, then parser *p has an attribute of type std::vector<A>

Each operator has its own modifier, and this is where things start to get messy. If you have built up recursively a fairly large grammar, the attribute type of the final grammar can be a mammoth unwieldy beast. This type (whatever huge amalgamation it may have turned out to be) is your output AST. Even with simplifying rules, this is a bit of an unwieldy representation.

The documentation tells you define your own sub-rules and sub-grammars so you can get a handle on the complexity, but my recommendation for non-trivial grammars is to skip this automatic attribute generation entirely, and use semantic actions to manually construct your own custom intermediate representation. The result will be more verbose boiler-plate code, but a cleaner representation and ultimately more readable, understandable code.

Quite simply, a semantic action is a callable object which is executed on successful recognition of a token. The parameter of the call is the attribute type. Since you are attaching functions to parsers at a low level, we don't have a problem with huge aggregate types.

Going back to our original example, given the following grammar:


*('{' >> lit("0x") >> hex >> '}'))


and the following test input:


// my data!
{0xabba}
{0xfeed}
{0xbeef}


if we add a semantic action ("got_it()") as follows:


std::list<int> list;

void got_it (int n) { list.push_back (n); }

*('{' >> lit("0x") >> hex[&got_it] >> '}'))


We have a our own custom made representation built in easy to debug steps. Reading this is simple: "when a hexadecimal number is recognized, call a function which pushes the number onto a list".

[1] Actually terminal doesn't appear to inherit from boost::spirit::qi::grammar at all.
[2] Because it's the C++ deference operator*() overloaded, it goes in front, not behind as is traditional.

Wednesday, February 10, 2010

Friday, February 5, 2010

Beautiful C++

It is possible.

I think this is possibly the most elegant code I've written as a professional programmer.

A lot of thought went into making it that small and simple.

Here's hoping it only gets better.

Tuesday, August 18, 2009

Handedness in coordinate systems

When I learned about handedness in coordinate systems, it was algebraically (AxB=C, BxA=-C), which is interesting but doesn't build much intuition. I enjoy analytic arguments, but ultimately it's the intuitive reasoning that tends to stick with me and inform new insights.

I often had trouble remembering which meant which, staring at my hands trying to remember how "that stuff" went, looking rather silly the while. I recently wanted to recall what OpenGL and D3D respectively do, and came across this discussion on real-time rendering, pointing out that even the pros get mixed up sometimes.

His example gave me, finally, a good piece of intuition about handedness: label your thumb X, index Y, and middle Z.

A right-handed coordinate system is what you have when you imagine your world relative to your desk: X goes east, Y goes north, and Z goes into the sky.

A left-handed coordinate system is what you get when you imagine your world relative to your monitor: X goes right, Y goes up, and Z goes into the monitor.

A perfectly good reason why modellers would prefer their object coordinates to be in a RHS, and programmers might convert it to LHS.

Sunday, June 7, 2009

On Platforms and the Convergence of 2D and 3D Internet

Working in Virtual Worlds, we are often given to wonderful discussions about what the future will hold for the Internet, and when and how various technologies will converge.

One popular school of thought is that virtual worlds should be embedded in existing web browsers as "light" plug-ins -- in order to make installation easy, and leverage history's most popular connected application platform.

The other is that there should be a "heavy" viewer designed completely around a unique virtual world experience; which happens to contain a superset of features, including web-browsing.

I belong to the second school; and in fact that opinion had lead to conflicts within my previous company. Thankfully, my current employer very much shares my vision.

However there are many in the first camp, and I am sometimes asked why I will not join them, especially in light of recent developments specifically aimed at bringing 3D to web browsers. Let me try to explain why despite all the momentum for adding 3D to web browsers:

I believe placing a 3D virtual world viewer within a 2D web viewer is somewhat comparable to embedding a gopher viewer, or ftp viewer, or email viewer within a web browser -- it's of course been done, but it's backwards, leads to awkward results, and has never proven to be very popular.

In the long term, computer code is plastic. If the world decided to morph a web browser into a 3D application platform overnight, there is no technological reason why it couldn't happen. So the question of where to put certain features is more ideological, metaphorical, or about user interaction concerns

What is a web browser?


Is it the ultimate convergence point for anything internet-related? Is it a new OS that should have it's own version of OpenGL? Is it just a safer sandbox for internet applications that the OS itself?

For me, issues of security or specific features are not interesting. Clearly any application platform needs to constrain the ways in which hosted applications can access raw resources. And clearly the needs of the platform evolve over time, and that requires adding new APIs.

For me, the question of what makes a web browser is a question of design, and mental modes; and how the totality of those decisions affect the expressiveness of applications written for the platform.

A web browser, for me, is a transaction-oriented 2D document-centred internet application platform. A virtual world viewer is a stream-oriented real-time interactive 3D scene-centred internet application platform. I am not sure there exists any easy abstraction that allows one to fluidly translate concepts between categories. The commonality that they host applications that run on the internet is not enough to unite disparate modes, and inform the design of a coherent platform.

Web browsers will indeed need 3D features. But they way in which 3D will be used on the web will be document-oriented, and happen in transactions (not real time). Things like e-commerce catalogues can be made available in full 3D. Any number of static scenes relating to the host web document will add a lot of value -- the way embedded streaming video adds value to many current websites.

But World of Warcraft will never run in Firefox (not at least without a severe redefinition of "browser", "runtime", or "OS").

What is a platform?


What might the average computer look like in 10 years from the perspective of application platforms?

I feel that each computer will consist of several rings or layers of runtime platform:
  1. Native: applications are programmed against the native OS libraries, and constrained by native OS security model (ex: win32, POSIX, OpenGL, etc.)
  2. Managed: applications are programmed against a large, general purpose, coherent, high-level API; and run in a virtual machine with detailed, explicit, and programmable security model (.NET, Java, Python, etc.)
  3. Internet: applications are programmed against a special-purpose API, with clearly defined semantics, which is exposed though a common data model (the DOM for web) and standard set of operating primitives (HTTP for the web); security model is highly sandboxed, limiting access to private data where not explicitly required by the data model or operating primitives (IE, Firefox, and one day Virtual World Viewers?)
I expect that in the future, each computer will come equipped with one OS, a handful of managed runtimes, and precisely two internet application platforms: a web browser and a virtual world viewer.

How would the web look in a VW viewer?


I think it would be wrong to assume that because 2D embeds in 3D mathematically, that the web browser should go away -- entirely subsumed in a 3D viewer. That really ignores the long and ongoing history of humans quite preferring to do a lot of their most abstract work in 2D documents. It would also really undermine my own argument that the web and VWs are really very different modes of interaction.

Instead, I believe that the VW viewer will know of the system's web browser, and rely on it directly for all web-related tasks. Examples might be embedding a browser window for the purpose of authenticating with an OpenID or oAuth provider for some network resource, such as gaining access to your facebook profile, or to send emails through gmail. Web applications like Google Apps would also make a simple and effective document sharing service available from within a virtual space.

So from a user's perspective, the web browser would be rendering elements of the regular user interface, or displaying discrete web pages in an integrated manner without appearing as a full web browser. There will also be cases of rendering to texture in order to display web pages as in-world objects, but their purpose will be peripheral.

As a some what related aside, I find it constantly amusing to see VW implementers try to embed 2D documents in 3D spaces. With few exceptions, there is no benefit whatsoever to being able to see your spread sheet in perspective projection as a texture. Give me a use case where having 2D documents in 3D is more than a gimmick, and I'll give you a modified use case where dimensionality is irrelevant, and the interaction feels much more natural.

Not just the browser


Other internet applications that I feel should not be subsumed within the virtual world viewer, but instead should integrate smoothly with them using an inter-process communication channel are things like E-mail, IM/Chat networks, Streaming Media, Office programs, etc.; all of which are regular desktop applications that the viewer calls out to in response to in-world stimulus; or alternatively, will respond in-world to a stimulus from the user's desktop.

Imagine a "meet in-world" button on your IM client, or having the streaming audio in your virtual home synced with your current desktop play-list (or vice versa).

Wednesday, June 3, 2009

Structured Streams

TCP done right, implemented over UDP, as a user-space library.

What more could you ask for? Seriously, the paper is simple yet beautiful.

Monday, April 27, 2009

A Programmers Work-day

When I first started working as a programmer full time outside of school, in the "real world", I was a bit unsure what to expect. Would I spend all my day slaving at a keyboard? Would I spend it all in endless meetings? Buried under mountains of TPS reports? How does a real software house organize it's labour force on the day-to-day?

Starting my career in some poorly managed companies didn't provide a shining example for me to learn from.

I was literally shocked to see how much of the day co-workers just surfing out of boredom, but I was a little ashamed to ask anyone about their workplaces. Would anyone be honest about such flagrant waste of time? Would they look down on my workplace as a joke? Was the big horrible secret of the "working world" the fact that very little work actually gets done?

It touched protestant work ethic I didn't know I had. So much wasted time and money felt dirty to me.

That said, it wasn't long before I too #$%@ed my day away on websites; and for the same reason co-workers did: there was no serious management structure. Management didn't give anyone serious goals, or give developers the resources needed to meet them. Management provided no structure or oversight to the development process, and morale was fairly low; no one cared. One place I worked some of the developers showed up at 3pm and left before 7pm, four days of the week!

Over the development of my career no one has yet come out and given me a clear definition of what the professional standard for work ethic, but I have managed to develop my own idea of what should be expected of all programmers from a work day (you'll note I do not include managerial job titles):

Organizational Overhead

2 hours per day

This is the overhead that is not an output itself, but is a natural requirement of any development process, and thus is has to be done every day.

It's often characterized by a series of interruptible tasks that center around communication with other human beings.
  • Face to face meetings
  • Phone calls
  • E-mail and mailing-lists
  • Bug triaging and code reviews
  • Work-related blogs, websites, and IMs

Development

4 hours per day

This is the "real" work, and is the measurable result by which your contribution to the group will be judged. If you're not producing here, you are not a developer.

This work is characterize by the necessity to spend long unbroken periods concentrating single-mindedly on the task(s) at hand.
  • Researching technologies or libraries
  • Devising designs
  • Proposing and discussing design details
  • Implementing code
  • Testing and debugging running code
  • Implementing tests and documentation

You'll also note that that accounts for only 6 hours, and the reason is that I essentially do not believe that knowledge workers' productivity, especially developers who are required to expend so much concentration for extended periods of time, scales linearly with time. Your brain needs breaks to open back up. Overwork just leads to burn-out.

The ideal work day for a programmer is some variation on the following:
  • 0900-1000: handle time-critical overhead tasks such as emails, bug reports, and meetings
  • 1000-1200: concentrate on priority work items
  • 1300-1400: regular meetings and emails
  • 1400-1600: concentrate on other important work items
It may look like a short day, but I do assume you have developed the ability to concentrate on your task, and you have the freedom to eliminate distractions. I do admit that it is often quite hard, and most people's day looks more like:
  • 1300-1700: try concentrate on work while being distracted by meetings and emails
If you really need to have an 8 hour work day for some reason, you'll only find that the extra two hours ends up going into work-place play or dawdling; and I'd personally prefer to go home to my family.

Trying to do too much per day leads to burn-out, which doesn't have to be emotional or dramatic; it can be intellectual, and manifest itself is a subtle lack of creativity that's hard to detect.

Do you agree with my experience-bought conclusion? Do you have your own? Let me know.

Friday, January 16, 2009

Finally a work-related post -- about Windows?!

I decided to force myself to make a technology blog. Its because I have made a very important discovery.

For a long time I've been a linux user working in a world where windows is overly common. Luckily though, I have often been able to make the argument to my bosses that cross-platform development is important, and that free-software tools are high quality and save much time and effort.

What often stymied my noble efforts however, was the pain in the arse, not in making cross-platform code, which is a problem well attended to over the decades, but the trouble of getting something to build on all platforms.

You have autotools on the unix side, Visual Studio solution-files on the windows side, and well-meaning cmake in the middle, with a down-trodden, lonely, underused look on his schoolboy face.

This is issue is oppressing me as we speak at work, with us trying to integrate the powerful and flexible Telepathy messaging framework, and its companion libraries GStreamer and D-Bus. All of it portable C. All of it buried under mounds of steaming autotools.

For the past week we have been doing the slop-work of trying to reverse-engineer the intended build process codified in the dead languages that make up autotools, and re-implement them in cmake in the hopes that it might be accepted upstream, and one day be liberated from the shackles of 1987.

It's not Happy.

And neither was I until I stumbled across this little gem. Long story short: Fedora 11 will ship with a fully functional windows cross compiler.


Autoconf-based programs can generally be cross-compiled by doing:

yum install mingw32-*
./configure --host=i686-pc-mingw32
make


Project page here.

That however means that the binary will not be build with VC++, rather GCC, which may cause some windows programmers to cringe. I'd like to learn just how much performance is really lost. I also wonder what sort of ABI boogie-men are lurking.

To summarize

1. Portable code - Done
2. Cross-platform build system (with no need for windows license!!) - Check
3. Broad binary compatibility - Future is Hazy

Thursday, April 10, 2008

How do you use your shell?

[ryanm@3Di0021d ~]$ history | awk '{a[$2]++ } END{for(i in a){print a[i] " " i}}'|sort -rn|head
177 make
144 ll
96 git
77 cd
59 grep
59 gvim
40 cp
38 git-svn
32 ./secondlife
30 svn

Thursday, February 7, 2008

Saturday, January 19, 2008

(Haskell) Monads for Imperative Peeps

Warning, since I am still learning Monads, it's quite possible the following is partially or even entirely wrong.

Why Monads


Functional programming languages have the constraint that their functions cannot have any side-effects. A function cannot do anything except produce a return value which is strictly dependent on its input values.

This is done for many good reasons. One such reason is to allow allowing some pretty mean performance optimizations: specifically allowing each individual "pure" function to run on their own processor core, since by definition each function is dependent on its input only, and can run efficiently this way.

However this constraint effectively eliminates entire sub-sets of useful and essential operations. Most notably IO operations such as printing or reading from the console.

A monad is a abstract idea that allows functional languages to stay theoretically coherent by encapsulating side-effect producing operations within themselves. Monadic functions can then be separated from the remaining pure functions when optimizing.

Monads are also extremely useful for encapsulating entire classes of behavior by type. For example a monad for functions that print or read from an OS provided data source is called IO. For functions that print or read strings from the console, the embedded type for IO would be String, and thus their type would be String -> IO String.

What are Monads


In programming languages, monads are meta-types that embed other types.

A monad has 3 parts:
1. A type construction, which defines how to embed a type in the monad
2. A unit function, which explains how to place a value of a type into a value of the monad, "as is"
3. A binding operation, which explains how pull out a value of a type from the monad, apply a pure function to it, and return the result to the monad

As an example we will construct a monad called Maybe that defines a type who's values are either invalid, or from a valid range:

1. data Maybe t = Just t | Nothing

Which says that the monadic type Maybe with parameter type t is a type who's values are of type "Just t" or "Nothing". Nothing is the type of invalid values.

2. return x = Just x

Which defines a function that wraps any value in the identity type Just, and thus embeds it the monad Maybe by our definition in 1.

3. (Just x) >>= f = f x
Nothing >>= f = Nothing

Which says that any function f can be applied to the type Just x as a normal, every-day function call; but any value of the Nothing type always yields Nothing. This means that whenever an invalid value is encountered, all functions from that point on are also invalid.

Friday, January 11, 2008

Always Plotting Something...

An amazing source for a tool I always found hard to figure out: gnuplot.

Friday, January 4, 2008

Thinking in git

"git" is a distributed source code management tool that is gaining a lot of interest from many corners of the international software development community due to its incredible flexibility and power. I like to compare it to powerful text editors like Vim or Emacs: it has a steep learning curve, but once you pick it up it will increase your productivity immensely, and if you are a professional programmer who takes himself seriously, you owe it to yourself to learn it fully.

However, using this new power-tool, like all specialized tools, requires readjusting you way of thinking about how you work before you can take advantage of the benefits.


1. Your local clone is also a repository in its own right



A repository is a .git directory. Every functional instance of a .git directory represents a full-featured repository, regardless how you came to possess it.

Its a deceptively simple but profound change in perspective. Ponder the implications fully.


2. All repositories are created equal



There is no inherent security policy in git (you have to piggy-back on SSH or Apache for that), and there is no sense of hierarchy among repositories that you do not define yourself through external policy.

Once you clone a branch from a remote repository, the originating branch is technically no more authoritative than yours is. The only technical constraint on branching and merging across repositories is that all branches must have a coherent history.

If two branches across repositories grow apart over time, and it is desired to reunite them into a common public branch, anyone attempting merge the two must reconcile the histories is such a way that other repositories are able to recognize the history as either a common ancestor of a local branch, or reachable future given their current state.


3. Branch everything



Branching and merging is the bread and butter of a SCM, so it hopefully goes without saying that branches are trivial, and merges are as smart as possible for a machine, so use them.

Branch to test out a idea. Branch to test out a merge. Branch to impress your friends at cocktail parties.


4. Git is a low-level tool



Git, from the beginning, was designed to be a low-level storage format for a Distributed SCM, and its only recently that git has included within itself some high-level commands for the kind of basic operations that programmers care most about. If you take the time to understand the basic representation that git uses, you will find it harder to get confused about why the high-level commands do things you didn't expect them to do.

Git assumes very little about a programmer's workflow, and converts your commands to into rather simplistic and literal manipulations upon the basic data structures within the .git directory, so it pays to take a look inside the internal representation once and a while to verify your assumptions.


5. You can break your own repository, and others'



Since git makes almost no assumptions about your work flow, contains no inherent security policy, and has no concept of repository hierarchy, it is very easy to do something that can seriously ruin anyone's repository.

Git tries hard to be non-destructive when making changes, but it will always do exactly what you ask of it. And while an experienced git user can likely recover from a whole host of mistakes, there is no guarantee that you can.

While learning git, always back up your working source and .git directory regularly. Always make new branches to test out your actions before you proceed on important branches. And finally, take care when pushing/pulling changes to/from someone else's repository.


6. Every commit is a change, uniquely identified by a SHA-1 hash number



The basic currency of git is a set of changes to the .git data structure represented by a commit, and every commit is uniquely identified by a SHA-1 number.


7. A repository is a directed acyclic graph of commits, with named branches



As commits succeed commits, a linear history is built within the .git directory. When a branch is made it is given a name, and when a commit follows, the history becomes a tree and thus non-linear. When a merge happens, the two histories are joined together under one of the named branches.

Since history only proceeds in one direction, the graph is acyclic.


8. Commits and branches exist in your .git directory, not your working directory



Git stores the above DAG compressed in data structures in your .git directory. The files that appear in your working copy is only a decompressed representation of those structures, after they have been processed by your git commands.

If files appear to be out of place or missing, consult the git command line tools to inspect the .git repository first.

Sunday, June 10, 2007

Mini-review of Foundations of GTK+ Development

Foundations of GTK+ Development is definitely recommended for anyone doing any serious GTK+ development. The authors style is easy to read, and the book serves as both a decent tutorial for any programmer fluent in C looking to learn GTK+, and a reference for intermediate programmers who want to broaden their knowledge of GTK+.

The author wisely spends his chapters on the most useful and most often misunderstood parts of GTK+, leaving the hand-holding chapters to a blessed minimum. This means there is little fluff, and a lot of meat. Since its based on GTK+ 2.10, we are able to skip the deprecated, or just plain old crufty parts, and get straight to the modern usages, such as GtkTreeView, GtkUIManager, and Glade. There is even a couple pages on cairo, within the context of GTK+ 2.10's new printer support.

His entire chapter on deriving existing types, and creating new ones (in the often arcane GType system) is sure to be a god-send to beginning programmers, and a well worn reference point for programmers in code mode. Add in the over 100 pages of appendix material documenting GTK+ properties, signals, styles, stock icons, and error types, and you've got a handy resource.

While all the information in the book is available somewhere free online, including the indispensable devhelp, the GNOME website, and even the GTK+ website itself, having a coherent narrative in handy physical form, I think, is worth the purchase.

Even though the book weighs in at over 600 pages, given the degree to which GTK's abstractions leak, I would have liked it if the author spent a little bit more time explaining the design issues that lead to these leaks.

For example, the author briefly mentions GObject's inherent ability to support the Pimpl (pointer to private implementation) idiom, and gives the boiler-plate code to achieve it (which is good). But when reading the code, one notices that MyObject appears to contain no reference to MyObjectPrivate, while the class constructor for MyObjectClass contains the function

g_type_class_add_private (klass, sizeof (MyObjectPrivate));

(which is mysterious, to me at least). If abstractions are going to leak, I would like it if the author could spare a couple sentences to give me an idea why such a call is necessary, if only avoid a mild state of incongruous bewilderment.

Lastly, I would have liked to get a bit more insight into some of the more fringe, but related, technologies, such as cairo or D-bus; and more details into tricker parts like threading, or a full working example of how to integrate foreign sub-systems using Glib. However this may be asking too much for one book, so perhaps we will have to wait for the author to spring "Advanced GTK+ Development" upon us!

Wednesday, June 6, 2007

More Monkey^wTemplate Magic

From Bjarn's paper here.

Same idea as before, but perhaps more clear.

template <bool b, class X, class Y>
struct if_ {typedef X type; };

template <class X, class Y>
struct if_ <false,x,y> { typedef Y type; };

void f() { if_<sizeof(foobar)<40,Foo,Bar>::type xy; }

Apparently, template programming is Turing complete.

Wednesday, May 30, 2007

Conditional statements in C++ Template meta-programming

C++ Template meta-programming is a black-frackin-art -- one of which I am totally in awe of -- that consists entirely of exploiting the corner cases of the specifications type deduction rules.

For your edutaining pleasure, the implementation of is_const <T> in GCC:

  /// @brief  helper classes [4.3].   
template
<typename T, T v>
struct integral_constant {
static const T value = v;
typedef T value_type;
typedef integral_constant type;
};
typedef integral_constant true_type;
typedef integral_constant false_type;

   /// @brief  type properties [4.5.3].    
template
<typename>
struct is_const : public false_type { };

template<typename T>
struct is_const
: public true_type { };

How it works depends entirely on the template (partial) specialization features of C++. When you have:

template <typename T>
void fun (T val, const true_type&) { do_foo(); }

template <typename T>
void fun (T val, const false_type&) { do_bar(); }

int main() {
typename const int a_type;
typename int b_type;
a_type a = 5;
b_type b = 3;

fun (a, is_const<a_type>);
fun (b, is_const<b_type>);
}

Temporary objects of types is_const<a_type> and is_const<b_type>, respectively, are made. C++ will try to pick the best match for each parameter type from the list of available classes for is_const<T>. In the case of b_type, the only suitable match is the non-specialized definition, for a_type, the specialization is_const<const> is a better match. That way the overloaded function fun is sent, in the case of a an is_const type that derives from true_type, and in the case of b an is_const type that derives from false_type, and thus is able to dispatch to different routines based on the overload.