(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.
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?
faultblocks don't have filters like
- At the end of a
faultblock 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
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.
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.
Daniel 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 when
- 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 implement
IEnumerator<T> GetEnumerator(), for people who only have an
IEnumerable<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.
Via 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.
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
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.
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 email@example.com:username/repository.git
git push origin master
- To push subsequent Perforce changes to GitHub:
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 »