Obscure exception handling facts
July 28, 2009 at 08:22 PM | categories: Uncategorized | View Comments(The second in what seems to be a day of obscure .NET facts)
While looking at some C++/CLI code in Reflector today at work, we encountered the try ... fault
construct.
What's a fault
block?
It's like a finally
block, but it's only entered in the event of an exception.
So it's like a catch
block, then?
Not exactly:
fault
blocks don't have filters likecatch
blocks do- At the end of a
fault
block the exception is implicitly rethrown
Supposedly the benefit of a fault
block is performance: that throw;
statement at the end of a catch
block has the same overhead as any other throw
statement, whereas finally
and fault
blocks incur no runtime overhead. The stack is not unwound when a fault
block is entered: fault
blocks won't appear in the exception stack trace.
Where do fault
blocks show up?
In the code the C++/CLI compiler emits in order to make sure that local variables have their destructors called in the event of an exception.
Obscure IEnumerator facts
July 28, 2009 at 07:06 PM | categories: Uncategorized | View CommentsDaniel Fortunov wrote about an obscure use of duck typing in the C# spec for enumerators:
Although it is common to implement [IEnumerable and IEnumerator] when creating an enumerable class, if you were to drop the interfaces but leave the implementation, your class would still be enumerable by foreach. Voila! Duck-typing!
You can take advantage of this fact for a couple of performance tricks, as demonstrated by many of the standard collection classes in the base class library:
- Declare your
IEnumerator<T>
implementation as a struct, not a class. This saves you a heap allocation whenMoveNext
is called. - Define a
Enumerator<T> GetEnumerator()
method on your collection class - Note that you're returning your own struct, not
IEnumerable<T>
; this avoids a boxing operation. You'll still need to explicitly implementIEnumerator<T> GetEnumerator()
, for people who only have anIEnumerable<T>
reference to your collection. These performance tricks don't apply when you're making calls through this interface.
When somebody uses foreach
over your collection, the compiler sees a series of MoveNext
calls and accesses to the Current
property, and it emits code to call these efficiently on your struct.
What's more, the code in your struct's methods is a candidate for inlining by the JIT compiler. The segment of the MoveNext
method of System.Collections.Generic.List<T>+Enumerator
that can throw an exception is split into its own method, apparently for this reason.
I don't claim any kind of definite performance benefits from using these techniques, but it does look like the language designers put some thought into making it possible to use foreach
without incurring any overhead compared to some less elegant method.
dollop, a Python Lisp interpreter
June 15, 2009 at 09:00 AM | categories: Uncategorized | View CommentsVia Hacker News, Hans Nowak's proof of concept:
The proof-of-concept implementation that uses this concept is called dollop and is available at github. (Requires Python 3.0.) The name is because it's only a "dollop of Lisp" (or rather, Scheme); it only supports a few special forms (begin, define, if, lambda), and a few functions for example programs (+, -, *, =, list). It cuts corners in other ways as well, as my goal was to get a working proof-of-concept out, not to write a complete Scheme interpreter.
Hans explains how he avoids stack overflow, due to tail recursion, by replacing the machine call stack with an explicit stack data structure in his interpreter. A tail call replaces the token at the end of this stack, instead of pushing a new one.
This is a technique you can apply in an interpreter based around an eval-apply cycle: with a full compiler, the principle is the same, but you have to detect tail calls in advance and generate the correct bytecode -- say, a .NET tail.call instruction or an x86 jmp opcode.
Vague class names: "Manager" and "Helper"
June 06, 2009 at 06:48 PM | categories: Uncategorized | View CommentsFrom journal.stuffwithstuff.com:
Do not use "Manager" or "Helper" or other null words in a type name.
If you need to add "Manager" of "Helper" to a type name, the type is either poorly named or poorly designed. Likely the latter.
I always agreed with this: names like ConnectionManager
and XmlHelper
are too vague to be useful. But I never came up with a retort as pithy as this one of Robert Nystrom's:
Types should manage and help themselves.
Moving a Perforce project to GitHub
June 02, 2009 at 08:41 PM | categories: Uncategorized | View CommentsI keep all of my home projects in a local Perforce instance. I wanted to put my Lisp compiler code onto GitHub; since I'm not paying for a Perforce licence, I'm limited to a single user.
The GitHub user account and repository setup process was pretty straightforward, until it came to adding files. I haven't been able to find a single set of instructions for this, but I pieced it together thanks to Stack Overflow:
- You will need the git-p4 Python script from here: http://repo.or.cz/w/git.git?a=tree;f=contrib/fast-import;hb=HEAD
- From the some empty directory -- not the one that contains the Perforce project -- run the following command to import the entire Perforce version history:
python git-p4 clone --destination=. //depot/path/to/project/...@all
- You now have a brand new local git repository that contains a clone of the project from Perforce. You need to push it to GitHub:
git remote add origin git@github.com:username/repository.git
git push origin master - To push subsequent Perforce changes to GitHub:
git-p4 sync
git push origin master
Edit: I almost forgot to include the URL of the compiler source
Edit 2: Turns out you mustn't run git commands from a Perforce local directory: as always, Perforce doesn't like it if something else (in this case git) interferes with its local files.
« Previous Page -- Next Page »