Sunday, February 25, 2007

Almost there... Orcas better get this right.

It's a pretty old post... but it's a big internet and I haven't found the end yet. :)

David Ebbo explains how to distribute an ascx UserControl without having to distribute the actual ascx file.

And then a litany of comments with people having trouble getting the secret sauce to work just right.

To introduce this on my team, I need to be able to have an "ascx project" that fits into studio as a first-class member of the solution, and that produces an assembly that the other projects can refer to as a project reference.

I need this to have build automation, and a project model that I can let beginner-intermediate developers go to town on without having to understand all the underlying twiddling. It's just not quite there. So we're still doing "reference this assembly and copy these ascx files into your /controls directory". That blows, but the beginners can handle it.

There must be a universe that I am not exposed to where you would be allowed and would actually want to edit a code-behind, aspx, or ascx file on a live, production server. I can only imagine this scenario in a small business fiddling with their own little website. Those people can have the ascx UserControl. For bigger business development, we really just need and want resource-based full design-time support for a Web.Control.

Monday, February 12, 2007

Apache / IIS Flamebait

There's a ZDNet blog posting by Richard Stiennon that shows two call graphs comparing the system calls that a Linux / Apache server makes to serve up a simple page versus the equivalent on Windows / IIS.

Surprise, Apache makes fewer system calls. The argument is that this makes it easier to secure a Linux / Apache implementation. That might be true. My experience is that ignorant administration is an orders-of-magnitude greater threat than the inherent limitations of either platform.

While it's sort of an interesting look... I've got a few big problems with the post:
a) The graphs are unreadable, and therefore FUD. I'm sure it was just a bandwidth issue not to have a version of the graph with enough resolution to actually read the system calls being made. However, just showing two pictures with lots of lines and basing your conclusion on the fact that one picture has way more lines in it is a pretty shoddy argument. I'll give Stiennon the benefit of the doubt that he both analyzed the original graphs, and is qualified to understand what they say. If that's not the case, then shame on you for stirring up a pointless religious debate.
b) Microsoft chose this implementation on purpose. You can make an intellectually honest argument that keeping most processing in user-space is inherently more secure, but that's just a (sensible) opinion, and not gospel fact. IIS7 moved most low-level processing into http.sys as a conscious decision in support of performance and stability. ASP.Net can blow chunks and IIS will restart it. IIS can blow chunks and http.sys will queue up the requests until the OS restarts IIS. You would be right in assuming that this puts the entire OS at the mercy of any holes in http.sys. But in closed-source land that means that http.sys is going to be something that they pay extra-special attention to, and also insulate from the feature-itis that ASP.Net (and thus IIS) are prone to.

Alright, that's enough defending Microsoft (like they need my help). In Linux-land, there's a fanatical devotion to moving as much code as possible out of kernel-space and into user-mode. Security is one of the concerns, but it also keeps the kernel simple and light (well, simple as far as kernels go). This is a design decision that gets repeated in lots of Linux projects, but it comes at a price, like all design decisions do. Until the code can cross the magic line where really almost everything is happening in user-mode, there's a not-irrelevant performance cost from the marshaling between memory spaces. Apache already crossed that line... it's a good decision. And really, under the open source model where defense-in-depth is even more important, it's usually a good decision for most projects.

Of course, this is only a "decision" you get to make if you're hacking straight at the API. And if you're one of those people... you knew all this already. :)

Oh, and thanks to Arno for pointing me at the post.

Thursday, February 08, 2007

Yet weirder nuances with C# interfaces

Brennan has a post about the differences between implicitly and explicitly implementing an interface in C#. He's got screenshots and better code formatting than I've figured out how to do yet, so really just go look there. But in brief, if you have an interface like this:

 public interface IDog  
     void Bark();  
     void Run();  
     void Catch();  
You have two ways you can implement it. Implicitly, which is what I'm used to seeing:

 public class Bulldog : IDog  
#region Implicit implementation of IDog
     // Implicit 
     public void Bark()  
         throw new NotImplementedException();  
     public void Run()  
         throw new NotImplementedException();  
     public void Catch()  
         throw new NotImplementedException();  
Or explicitly like this:

 public class Terrier : IDog  
#region Explicit implementation of IDog
     void IDog.Bark()  
         throw new NotImplementedException();  
     void IDog.Run()  
         throw new NotImplementedException();  
     void IDog.Catch()  
         throw new NotImplementedException();  

They both accomplish the same thing (sort of, here come the nuances). Brennan pointed out that the explicit implementation (Terrier) will not show intellisense for variables of type Terrier. But you can still pass it around to methods expecting an IDog. Bulldog behaves more like you would expect -- intellisense shows all the methods and you can still pass it anywhere you could pass an IDog.

So lately I've been playing with Reflector more than is healthy for a person. It prompted me to go out and read the CIL specification. (Well, I'm almost done with Partition I at any rate. Yes, I've become that kind of geek.)

So I compiled this little sample and dropped it into Reflector. Interesting. The "normal" implicit implementation in Bulldog.Bark:
.method public hidebysig newslot virtual final instance void Bark() cil managed
maxstack 8
      L_0000: nop 
      L_0001: newobj instance void [mscorlib]System.NotImplementedException::.ctor()
      L_0006: throw 
And the explicit implementation:
.method private hidebysig newslot virtual final instance void com.navelplace.IDog.Bark() cil managed
      .override com.navelplace.IDog::Bark
maxstack 8
      L_0000: nop 
      L_0001: newobj instance void [mscorlib]System.NotImplementedException::.ctor()
      L_0006: throw 
So everything after .maxstack 8 is identical, as you'd expect. That nop puzzles me. That's a CIL no-op (do nothing). I'm guessing it has to do with byte alignment. If I'm wrong I'd love somebody to explain that to me.

Anywho... before you wig out about looking at IL... what are the differences? The explicit version declares itself as a .override, and not the implicit version. They're both "virtual final instance void". I'll break that down: virtual and final have the same meaning as they do in C#, virtual because all methods from an interface are virtual, final meaning you could not override Bark() in a subclass of Bulldog or Terrier. CIL is a lot more statically-oriented, so "instance" means "not static". And void meaning, umm, void.

hidebysig and newslot are pretty obscure -- they have to do with overloading and overriding. I believe all .method's coming out of C# will be marked hidebysig, or at least I haven't stumbled across anything marked hidebyname yet. It means that foo() will hide but not With hidebyname, foo() would hide anything from base named foo, regardless of signature. Although "signature" includes more things than we're used to in C#.
newslot comes into play for overriding. Implementing an interface requires a new slot on the type, but overriding a virtual method on a class would not specify newslot.

But now the real difference, and the weird part. The explicit implementation is marked private, while the implicit implementation is marked public. This explains why the explicit implementation doesn't show up in intellisense -- it's a private member of the concrete class. But it's not just intellisense that thinks so. new Terrier().Bark() is a compile-time error. This would seem to violate the inheritance rules from the spec, since everything in an interface is public:
When a derived type overrides a virtual method, it can specify a new accessibility for the virtual method, but the accessibility in the derived class shall permit at least as much access as the access granted to the method it is overriding.
There would seem to be an exception made for interfaces. And notice the method that specifically says ".override" is the one apparently violating the accessibility rule. Haven't stumbled across the part of the spec that explains the reasoning. It doesn't violate the substitution principle, since anything expecting an IDog would get an implicit cast and the explicit implementations would become visible again. But it still seems weird.

Friday, February 02, 2007

Concurrency and C-Omega

The old name was Polyphonic C#. Both sound cool, but C-Omega is harder to type, but looks way cooler when you use the real symbol: Cw (that made blogger mad putting that in, and Firefox remains unimpressed with my font tag, so follow the link or read this in IE to see the symbol). Apparently it is not CW which would have looked cooler.
Anyway, I totally stumbled across it while trolling the Microsoft Research site. Concurrency stuff is becoming a lot more interesting to me -- from the geeky theory level just because of the increasing abundance of multi-core processors, but also because I'm running into these same issues at work. Cw dovetails a bunch of LINQ stuff into it too, but the concurrency stuff is what has me excited.
We implemented a pretty naive attempt at SOA here, and ran into the classic performance bottleneck. The extra network hop involved in talking to a web service caused all the same old kinds of performance issues that we used to run into with DCOM, just in new ways. Consuming too many discreet services means you're making too many network roundtrips, so the server spends most of its time waiting around for responses from other servers. And for us, it does all that waiting in a serial fashion. Ouch.
This is of course why all of .Net's auto-generated web service proxies have asynchronous equivalents to every call, but synchronizing all the callbacks in a way that isn't both confusing and brittle is pretty hard. And then there's the whole issue of defending your code from slash-and-burn programmers that just don't get it.

But check out their simple example (I made it simpler):

1 public class Buffer

2 {

3 public async Put(string s);


5 public string Get() & Put(string s)

6 {

7 return s;

8 }

9 }

The idea is that any call to Put just hands off the parameter and returns immediately (async implies a void return type). A call to Get is synchronous like a regular method call, but has to be paired with a call to Put. So if Put had already been called, the value s is waiting to be returned. If Put has not been called, the call to Get blocks until some other thread calls Put. Multiple calls to Put will stack up waiting to be consumed.
This example hurt my brain to look at the first time:

1 public class ReaderWriter

2 {

3 private async idle();

4 private async s(int n);


6 /// <summary>

7 /// We start out by dropping message to idle()

8 /// </summary>

9 public ReaderWriter()

10 {

11 //

12 idle();

13 }


15 /// <summary>

16 /// A call to Exclusive() will block unless or until

17 /// there is an idle() message dropped. It consumes

18 /// the idle() message, so another call to Exclusive()

19 /// will have to wait for someone else to call idle().

20 /// </summary>

21 public void Exclusive() & idle()

22 {

23 //We don't need to actually do anything.

24 //Consuming the idle() message is enough.

25 }


27 public void ReleaseExclusive()

28 {

29 //Makes us idle again.

30 idle();

31 }


33 /// <summary>

34 /// A call to Shared will block until there is a matching

35 /// message of either idle() or s(int). You only have

36 /// to match on one of the asynchronous methods. So a

37 /// call to Shared() will either match idle() or s(int),

38 /// but not both. (The & syntax makes that a little

39 /// confusing. You might think Shared would wait for

40 /// both idle and s(int).)

41 /// </summary>

42 public void Shared() & idle()

43 {

44 /*

45 * If we were idle, when somebody called Shared,

46 * then we go here, and drop a message that there

47 * is one reader.

48 */

49 s(1);

50 }

51 & s(int n)

52 {

53 /*

54 * If we were already in Shared mode and somebody

55 * called Shared again, then just bump up the counter.

56 */

57 s(n+1);

58 }


60 /// <summary>

61 /// This just needs to make the decision to either

62 /// decrement the shared counter or call idle. Either

63 /// way, it will drop another asynchronous message.

64 /// And if you follow the logic, ReleaseShared() will

65 /// always find that there is a waiting s(int) message.

66 /// </summary>

67 public void ReleaseShared() & s(int n)

68 {

69 if (n == 1)

70 idle();

71 else

72 s(n - 1);

73 }

74 }

It's a lot less painful once you grasp on to the fact that an asynchronous call is just dropping off a message. (The contents of the message being the parameters.) The & token groups together method signatures (you can group two or more, but only one can be synchronous). Together the grouped signatures form a chord, and the body will execute when a synchronous and an asynchronous call find a match. I found the concept got simpler as I started thinking about it in a similar way to signature matching for overloaded methods.
It is a little unsettling to see that state is being stored with no variables for you to look at. But there's at least a baseline here for debugging tools to latch onto that would making debugging a multi-threaded app a lot less painful.
And yah, this stuff is hard to wrap your brain around, but concurrency is hard to wrap your brain around. This is a big step into abstracting away the non-essentials.

There are some other equally-impressive things being baked into Cw, go check it out.