More readable CLR Panel notes


xmlns:w="urn:schemas-microsoft-com:office:word"
xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882"
xmlns:st1="urn:schemas-microsoft-com:office:smarttags"
xmlns="http://www.w3.org/TR/REC-html40">






Thursday, October 30, 2003
name="State"/>
name="place"/>
name="PersonName"/>


style='font-size:10.0pt;font-family:Verdana'>CLR Panel Discussion

style='font-size:10.0pt;font-family:Verdana'>The following is the "transcript" I
took of the "Designing the CLR" Panel discussion. 
We had probably around 200 people in attendance, with an open mic forum. 
The Panel was swamped with standing room only folks at the end (about 40
up around the stage with lot's of questions). 
At the panel we had Brad Abrams
(CLR BCL PM), Anders Hejlsberg (Distinguished Engineer, C# architect, Chris
Brumme (CLR Architect), Patrick Dussud
(lead CLR Architect), Jim Miller
(CLR Architect), Sean Trowbridge
(CLR Architect), George Bosworth (CLR Architect), and
Jonathan Hawkins
(CLR PM/Moderator).

style='font-size:10.0pt;font-family:Verdana'> 

style='font-size:10.0pt;font-family:Verdana'>Q style='font-size:10.0pt;font-family:Verdana'>: 
How low can you take the CLR, eg: could it go down into the kernel.

style='font-size:10.0pt;font-family:Verdana'>Patrick style='font-size:10.0pt;font-family:Verdana'>: 
Two versions of the CLR could be made, one with high availability which
runs in kernel mode.  The other is
the normal CLR as you know on top of that. 
AppDomains could become the next version of a Process on the machine.

style='font-size:10.0pt;font-family:Verdana'> 

style='font-size:10.0pt;font-family:Verdana'>Q style='font-size:10.0pt;font-family:Verdana'>: 
Is process recycling really required like asp.net.

style='font-size:10.0pt;font-family:Verdana'>Chris style='font-size:10.0pt;font-family:Verdana'>: 
We've done a ton of work on fixing internal mistakes and fault injection
testing, etc, and we expect it to work given the w:st="on">Yukon work that is being done.

style='font-size:10.0pt;font-family:Verdana'> 

style='font-size:10.0pt;font-family:Verdana'>Q: style='font-size:10.0pt;font-family:Verdana'> 
Have you considered how you can get OS VM and GC to communicate?

style='font-size:10.0pt;font-family:Verdana'>Patrick style='font-size:10.0pt;font-family:Verdana'>: 
Lot of OS system services already there (eg: GetMemoryStatus) to auto
tune the load on the machine.  If
you are in 90% utilization, CLR GC will back off on allocation pressure. style='mso-spacerun:yes'>  In XP there is a new low memory
notification service.  Finalizer
thread in 1.1++ CLR uses this to also back down. 
Future directions should include the CLR being able to get a "budget" from the
OS, and then the OS could guarantee that without paging and CLR could auto tune
within that limit.

style='font-size:10.0pt;font-family:Verdana'> 

style='font-size:10.0pt;font-family:Verdana'>Q: style='font-size:10.0pt;font-family:Verdana'> 
Do you have dynamic code gen limitations that would allow things like
writing code for an edit box, etc, like Smalltalk has.

style='font-size:10.0pt;font-family:Verdana'>George style='font-size:10.0pt;font-family:Verdana'>: 
We are introducing lightweight codegen; not as rich as what was in
Smalltalk, but the tool (aka VS) could help this. style='mso-spacerun:yes'>  No fundamental restrictions.

style='font-size:10.0pt;font-family:Verdana'>Jim style='font-size:10.0pt;font-family:Verdana'>: 
Less than restrictions, the bigger issue is integrating every feature
across the engine in the right way, such as including security,etc.

style='font-size:10.0pt;font-family:Verdana'>Anders/et al style='font-size:10.0pt;font-family:Verdana'>: 
Facilities do exist for compiling up code on the fly, like Reflection
Emit, etc.

style='font-size:10.0pt;font-family:Verdana'> 

style='font-size:10.0pt;font-family:Verdana'>Q: style='font-size:10.0pt;font-family:Verdana'> 
Will ability to add fields via Edit & continue be allowed in managed emit
code.

style='font-size:10.0pt;font-family:Verdana'>Sean: style='font-size:10.0pt;font-family:Verdana'> 
Currently only allowed through unmanaged api's, where support exists. 
We've talked about various options like this, but have not committed to any
immediate plan.

style='font-size:10.0pt;font-family:Verdana'> 

style='font-size:10.0pt;font-family:Verdana'>Q: style='font-size:10.0pt;font-family:Verdana'> 
What kind of safety features do you have around hosting multiple pieces
of user code.

style='font-size:10.0pt;font-family:Verdana'>Jim: style='font-size:10.0pt;font-family:Verdana'> 
Use app domains to provide CAS security around specific to each domain.

style='font-size:10.0pt;font-family:Verdana'>Brad: style='font-size:10.0pt;font-family:Verdana'> 
Examples are like wsdl parsing and hosting.

style='font-size:10.0pt;font-family:Verdana'>Patrick: style='font-size:10.0pt;font-family:Verdana'> 
Reflection Emit permission is highly privileged.

style='font-size:10.0pt;font-family:Verdana'> 

style='font-size:10.0pt;font-family:Verdana'>Q: style='font-size:10.0pt;font-family:Verdana'> 
SyncBlock pointer is used for edit & continue, what are you doing with
it?

style='font-size:10.0pt;font-family:Verdana'>Patrick: style='font-size:10.0pt;font-family:Verdana'> 
SyncBlock is actually the "Kitchen Sink Block" <laughs>. 
It's a general purpose field for lot's of things including locking algorithms,
COM interface plumbing, etc. 
Dynamically allocated as required to get going. 
We optimize for lock and hash because they are the most common case.

style='font-size:10.0pt;font-family:Verdana'> 

style='font-size:10.0pt;font-family:Verdana'>C: style='font-size:10.0pt;font-family:Verdana'> 
Thanks to Chris for an excellent blog <applause>

style='font-size:10.0pt;font-family:Verdana'>Q: style='font-size:10.0pt;font-family:Verdana'> 
Transparent proxy work/interception, what about limitations?

style='font-size:10.0pt;font-family:Verdana'>Chris: style='font-size:10.0pt;font-family:Verdana'> 
We intended for more than remoting, but haven't done a ton with it beyond
that.  Interception is very
interesting; lot's of options. 
Could do code rewriting using prolog method hooks, etc. 
Appealing because it is more performance, transparent, and less risky wrt
being bypassed.  Conceptually sounds
very simple, but digging through details is very complicated (eg: integrating
with ngen is tough since everyone shares the same copy, and do you want to
impact perf for everyone).

style='font-size:10.0pt;font-family:Verdana'>George style='font-size:10.0pt;font-family:Verdana'>: 
Pay as you go is very important. Considering heavy inlining and how you
would intercept that without a perf penalty.

style='font-size:10.0pt;font-family:Verdana'> 

style='font-size:10.0pt;font-family:Verdana'>Q style='font-size:10.0pt;font-family:Verdana'>: 
AppDomains:  currently cannot
unload assembly without unloading app domain. 
We are dynamically generating assemblies, and do not want to unload app
domains.  Why can't we unload assemblies
from an app domain?

style='font-size:10.0pt;font-family:Verdana'>Sean style='font-size:10.0pt;font-family:Verdana'>: 
Very common request.  We have
to hit a higher bar for secure and reliable programming environment. style='mso-spacerun:yes'>  In managed, you have to make sure no one
is still referencing an assembly, where if it were unloaded you could introduce
AV's or security.  To solve requires
a  ton of bookkeeping, and you wind
up wrapping an assembly with an app domain <stack fault> . style='mso-spacerun:yes'>  Instead, we're looking at making app
domains more performant to use.

style='font-size:10.0pt;font-family:Verdana'>Patrick style='font-size:10.0pt;font-family:Verdana'>: 
There are other systems that can unload code. style='mso-spacerun:yes'>  However unloading is not free of
semantic difficulties.  When you
unload, you must make sure you have no dangling references. 
You have to define a shut down policy, and that can introduce bad cycles
on shutdown.  These kinds of bugs
are very frequent.  I've implemented
this before, and it is very problematic and not without bugs. style='mso-spacerun:yes'>  We have a good story on app domains. style='mso-spacerun:yes'>  If we can make it cheaper to get in/out
of app domains, then this is the best container for code.

style='font-size:10.0pt;font-family:Verdana'>Jim style='font-size:10.0pt;font-family:Verdana'>: 
I've worked on systems where we used GC to collect code. style='mso-spacerun:yes'>  You fix perf issues, but then you add
more bookkeeping again.

style='font-size:10.0pt;font-family:Verdana'>Sean style='font-size:10.0pt;font-family:Verdana'>: 
You still have the cycle problem. 
If one person holds onto an instance of an assembly which holds onto the
other (a->b, b->a), you never get to unload reliably.

style='font-size:10.0pt;font-family:Verdana'>Jim style='font-size:10.0pt;font-family:Verdana'>: 
The system had to build stuff into the GC to fix this, "it wasn't a
pretty site", not recommended.

style='font-size:10.0pt;font-family:Verdana'>George/Jim style='font-size:10.0pt;font-family:Verdana'>: 
Security, performance, features. 
Lot's of trade offs.

style='font-size:10.0pt;font-family:Verdana'> 

style='font-size:10.0pt;font-family:Verdana'>Q style='font-size:10.0pt;font-family:Verdana'>: 
Why do I have to check if a delegate is null before I use it, why isn't
there language support for this?

style='font-size:10.0pt;font-family:Verdana'>Anders style='font-size:10.0pt;font-family:Verdana'>: 
Requested often, spent fair amount of time trying to figure out a ok way. 
The suggestion doesn't work well for delegates which return values, etc. 
Putting this kind thing "ages" the languages when you add kludges to help
solve minor confusion. 
In the end, decided to leave things be. 
If we had a chance to do it over we might have done something
differently, but solution suggested is no better than the problem.

style='font-size:10.0pt;font-family:Verdana'> 

style='font-size:10.0pt;font-family:Verdana'>Q style='font-size:10.0pt;font-family:Verdana'>: 
Is there any plans to given an app domain a CPU budget?

style='font-size:10.0pt;font-family:Verdana'>Chris style='font-size:10.0pt;font-family:Verdana'>: 
Common request in & out of company from folks writing server code. 
Folks want quotas around CPU or memory consumption, etc. 
Would be good to do something here, but instead of quotas, we may track resource
usage instead.  We would accumulate
your "charge account" of things you use, and then put the burden back on the
sophisticated host app to make decisions. 
That way they can apply their policy directly. style='mso-spacerun:yes'>  Another common request is trying to
track memory used by a particular request (say web page compile, sproc, etc). style='mso-spacerun:yes'>  Very difficult thing to track.

style='font-size:10.0pt;font-family:Verdana'>Jim style='font-size:10.0pt;font-family:Verdana'>: 
Also consider how you would interact with the OS scheduler. style='mso-spacerun:yes'>  The scheduler doesn't give you any hooks
to integrate closer.  Would be good
in the future to see if we could exploit this.

style='font-size:10.0pt;font-family:Verdana'> 

style='font-size:10.0pt;font-family:Verdana'>Q style='font-size:10.0pt;font-family:Verdana'>: 
How much do you consider other platforms in the CLI design.

style='font-size:10.0pt;font-family:Verdana'>Jim style='font-size:10.0pt;font-family:Verdana'>: 
when I first joined we were actively developing for multiple platforms. 
Doing this kept us reasonably honest, and standards process helped a lot more. style='mso-spacerun:yes'>  We also have the .NET Compact Framework
which can also helps.  There are
other systems one could "possibly, possibly consider" <chuckles>. style='mso-spacerun:yes'>  We also released Rotor which runs on
several other platforms and chips which also keeps us honest. style='mso-spacerun:yes'>  The Rotor team is now part of the CLR
team, and those builds are part of our build process.

style='font-size:10.0pt;font-family:Verdana'>Patrick style='font-size:10.0pt;font-family:Verdana'>: 
Example of tension:  in ecma
we tried to get a very specific memory model, but we realized that nobody would
code to it [jlz: advanced chips like ia64 allow for reordering of reads and
writes and let you do scheduling as a code generator; x86 is pretty simple and
less flexible, but simpler and easier], because it is really complicated and
most people target x86 which has much simpler semantics. style='mso-spacerun:yes'>  It's an example where the issues are so
sublte, that even though the architecture could have been more generic, we need
it to be stable across x86, ia64, amd64, etc. 
Don't test on x86 and deploy on ia64 and have it broken.

style='font-size:10.0pt;font-family:Verdana'>Jim style='font-size:10.0pt;font-family:Verdana'>: 
show of hands: how many of you have volatile in the right place? style='mso-spacerun:yes'>  This is required for a reordering
architecture, and people don't understand it.

style='font-size:10.0pt;font-family:Verdana'>Jim/Patrick style='font-size:10.0pt;font-family:Verdana'>: 
Java has tried to be inclusive here, but found themselves in a quagmire;
very hard to get right.  We decided
to simplify instead.

style='font-size:10.0pt;font-family:Verdana'>Sean/Chris style='font-size:10.0pt;font-family:Verdana'>: 
We try to keep complications under the hood for this kind of thing.

style='font-size:10.0pt;font-family:Verdana'> 

style='font-size:10.0pt;font-family:Verdana'>Q style='font-size:10.0pt;font-family:Verdana'>: 
Any plans for things like aspect oriented programming and related
techniques?

style='font-size:10.0pt;font-family:Verdana'>Chris style='font-size:10.0pt;font-family:Verdana'>: 
We view this as something you could do with interception, if you wanted
ot.

style='font-size:10.0pt;font-family:Verdana'>Anders style='font-size:10.0pt;font-family:Verdana'>: 
Programming by contract is something we've looked at a lot. style='mso-spacerun:yes'>  MSR has done a lot of work here. style='mso-spacerun:yes'>  In the end we decided it wasn't quite
cooked yet, and so we have abstained here. 
If we did aything like this, the solution must allow me to remove up front if ()
checks for entry conditions.  To be
truly viable, you need to have it in the CLR/CLS instead of just a language. style='mso-spacerun:yes'>  Must be through the libraries as well. style='mso-spacerun:yes'>  We're not there yet.

style='font-size:10.0pt;font-family:Verdana'>Anders style='font-size:10.0pt;font-family:Verdana'>:  
wrt AOP, it seems ok for debugging and monitoring. style='mso-spacerun:yes'>  But the notion you can inject code
anywhere makes it impossible to understand what your code will do. style='mso-spacerun:yes'>  Unless you have an IDE that can show you
the "aspect weaving" you won't know what is happening. style='mso-spacerun:yes'>  At this point I'm in wait and see mode
until someone can show large scale successes.

style='font-size:10.0pt;font-family:Verdana'>Jim style='font-size:10.0pt;font-family:Verdana'>: 
<Plug for Rotor>  design by
contract is one of the RFP projects that we funded. style='mso-spacerun:yes'>  We are looking at the results of that to
see if it is ready for prime time. 
Gregor is a close friend of mine and I reviewed it 8 years ago: there are two
halfs to this problem:  (1) weaving,
and (2) projecting.  As an engineer
I need to look at all the code I will run. 
I have a degree in MIT, and you don't just do engineering by combining a bunch
of things and adding them up without understanding how it works. style='mso-spacerun:yes'>  If you look at the union as the
requirement, you could have come up with a better solution. I think the
community is veered in the wrong direction; neither I or Gregor have been able
to get them off of this.

style='font-size:10.0pt;font-family:Verdana'> 

style='font-size:10.0pt;font-family:Verdana'>Q style='font-size:10.0pt;font-family:Verdana'>: 
Do you provide any utilities around lock ordering and dead lock
detections.

style='font-size:10.0pt;font-family:Verdana'>Chris style='font-size:10.0pt;font-family:Verdana'>: 
prior to Whidbey, the locks you take are your responsibility. style='mso-spacerun:yes'>  There is no leveling notions or anything
like that.  You get essentially a
critical section and you can hang yourself with it. 
In Whidbey, with integration with SQL Server, they wanted to do deadlock
detection and understand the lock graphs [jlz: the hierarchy of locks where
cycles can come from].  This is
still rocket science, for most people you should still take responsibility for
lock leveling.

style='font-size:10.0pt;font-family:Verdana'>Q2 style='font-size:10.0pt;font-family:Verdana'>: 
I'd like to do this in C# directly.

style='font-size:10.0pt;font-family:Verdana'>Anders style='font-size:10.0pt;font-family:Verdana'>: 
You should take advantage of the using statement. style='mso-spacerun:yes'>  We may not have put the lock
keyword in if using had proceeded it.

style='font-size:10.0pt;font-family:Verdana'> 

style='font-size:10.0pt;font-family:Verdana'>Q style='font-size:10.0pt;font-family:Verdana'>: 
In new C++, determinsitc finalization is there. style='mso-spacerun:yes'>  What about other languages?

style='font-size:10.0pt;font-family:Verdana'>George style='font-size:10.0pt;font-family:Verdana'>: 
they've provided scope destructors, not really deterministic behavior per
se.  If the scope goes away, you'll
get the dispose, but you can still make mistakes. style='mso-spacerun:yes'>  What people usually mean here is they
want to solve the whole thing, and this doesn't do that. style='mso-spacerun:yes'>  It is still useful. style='mso-spacerun:yes'>  But it isn't the silver bullet.

style='font-size:10.0pt;font-family:Verdana'>Anders style='font-size:10.0pt;font-family:Verdana'>: 
important to understand the syntax is really no more expressive than the
using statement in C#.  The
new pattern comes with some restrictions on patterns that using doesn't
have.  For example, you have to
declare vars in a separate scope instead of inline. 
Agree with George that this is not deterministic finalization.

style='font-size:10.0pt;font-family:Verdana'>Patrick style='font-size:10.0pt;font-family:Verdana'>: 
Absolute lifetime we looked at, and keep looking at it, but it is really,
really expensive.  You have to do
micro-management.  You have to
project to all processors the state, which doesn't scale well. style='mso-spacerun:yes'>  There are tricks, but so far cost >
benefit.  We don't believe in
general people want to do micro-management, instead they want good enough
guarantees that you don't leak and you want limit of population of some
resources to a finite number [jlz: like a pool with a quota enforced]. style='mso-spacerun:yes'>  HandleCollector is a good new example
where we are providing this kind of functionality. 
AddMemoryPressure is also another good example that allows you to help
tune the GC (good for cases like allocating bitmaps, where managed side holder
class is very small, but unmanaged memory hit of the resource could be huge).

style='font-size:10.0pt;font-family:Verdana'>Q2 style='font-size:10.0pt;font-family:Verdana'>: 
My problem is less about memory but the resources [jlz: like database
handles, expensive files, etc].

style='font-size:10.0pt;font-family:Verdana'>George/Patrick style='font-size:10.0pt;font-family:Verdana'>: 
but that is what Finalization is.

style='font-size:10.0pt;font-family:Verdana'>Jim style='font-size:10.0pt;font-family:Verdana'>: 
the language provides this from using and this is the right way to
solve this problem.

style='font-size:10.0pt;font-family:Verdana'> 

style='font-size:10.0pt;font-family:Verdana'>Q style='font-size:10.0pt;font-family:Verdana'>: 
Love integration idea with the OS. 
But how are you going to accomplish that in the long term? style='mso-spacerun:yes'>  Eg: wait for Moore's law to help, video
card processing [jlz:  GPU's are
incredibly good at bit vectors schemes]. 
Or even something like an IL machine ala Transmeta.

style='font-size:10.0pt;font-family:Verdana'>Patrick style='font-size:10.0pt;font-family:Verdana'>: 
Our codegen is pretty good, and getting much better (eg: dynamic and
static profiling).  The OS can use
this, so we are on track and efficiency is not the key issue. style='mso-spacerun:yes'>  The real problem is right now we don't
cover the entire range of services so you have to p/invoke. style='mso-spacerun:yes'>  Msft needs to provide a complete range
of these api's so that don't need this and Win32 can go away. style='mso-spacerun:yes'>  My dream is after Longhorn you could do
this, removing longhorn p/invoke statements.

style='font-size:10.0pt;font-family:Verdana'>Patrick style='font-size:10.0pt;font-family:Verdana'>: 
We actuallly are thinking the opposite of IL machine. style='mso-spacerun:yes'>  I did chip design at TI for lisp
machines.  The competitor was 6x
smaller than ours to run the same applications. 
You get better if we program to IL, and then let the JIT optimize for the
specific hardware where you can take advantage of subtle advantages in the
specific chip.  Several manufactures
are serious about adding advanced features along these lines. style='mso-spacerun:yes'>  With our pluggable optimizing codegen,
we can do great on the fly generation this way.

style='font-size:10.0pt;font-family:Verdana'>Jim style='font-size:10.0pt;font-family:Verdana'>: 
I was the PhD advisor for the chief designer at Transmeta. style='mso-spacerun:yes'>  His general comment was using IL as it
stands is not efficient.  We should
look instead at something like mips where you look for common codegen patterns
from compilers and make those go fast. 
Example is optimizing interface dispatch code pattern.

style='font-size:10.0pt;font-family:Verdana'> 

style='font-size:10.0pt;font-family:Verdana'>Q style='font-size:10.0pt;font-family:Verdana'>: 
Threading: do you have intent to write a scheduler in the CLR, for
example, something that could work with fiber mode.

style='font-size:10.0pt;font-family:Verdana'>Chris style='font-size:10.0pt;font-family:Verdana'>: 
In Whidbey we did a lot of work to integrate the CLR into SQL Server. 
Prior to this we also schedule on pre-emptively OS scheduled threads. 
But we knew we might change this, so System.Thread isn't semantically locked
this way.  In Whidbey, a
sophisticated host can integrate and target fiber code. 
We support this.  With a small box,
normal thread mode is fine.  If you
have very large machines (eg: 32-way), then it might give you value. style='mso-spacerun:yes'>  The hosting api's do allow you to
integrate your own scheduler around fibers just like SQL. 
Having said all that, I encourage you to stay away from it <laughs> 
The benefits are just getting smaller and it is very hard to use and do
correctly.

style='font-size:10.0pt;font-family:Verdana'>Patrick style='font-size:10.0pt;font-family:Verdana'>: 
the OS is making lot's of progress closing the gap here, and its value is
becoming less with every new release.

style='font-size:10.0pt;font-family:Verdana'>Chris style='font-size:10.0pt;font-family:Verdana'>: 
If we could get to the pure managed world Patrick was dreaming of, where
we don't know when/if we could ever get there, that we will be able to smooth
out the rough edges of this kind of programming style. style='mso-spacerun:yes'>  We could smooth async model and
marshalling,etc.  It will be a long
time before we could do this.

style='font-size:10.0pt;font-family:Verdana'> 

style='font-size:10.0pt;font-family:Verdana'>Q style='font-size:10.0pt;font-family:Verdana'>: 
Extremely difficult to write a generic library that is exception safe. 
Wouldn't it be nice if at compile time you verify code was exception safe.

style='font-size:10.0pt;font-family:Verdana'>Anders style='font-size:10.0pt;font-family:Verdana'>: 
Commonly asked for, not specifically related to generics. style='mso-spacerun:yes'>  I don't know of a solution that doesn't
simply exchange one set of problems for another set. style='mso-spacerun:yes'>  There is the Java solution where you can
declare what you've thrown and require caller to handle or push out further. 
There are some serious scalability problems with this model; you have to compute
the closure which winds up making people go to catch(…) which is no good.. 
It also has the versioning problem, where you can't add new exceptions in
future versions without breaking the already written clients.

style='font-size:10.0pt;font-family:Verdana'>Anders style='font-size:10.0pt;font-family:Verdana'>: 
what would probably be better is an Fxcop style checking, and we could do
a better job on documentation.

style='font-size:10.0pt;font-family:Verdana'>Q2 style='font-size:10.0pt;font-family:Verdana'>: 
I understand why you didn't do the Java solution; I don't like it either. 
But couldn't you do something around generics because it is very difficult to do
otherwise.

style='font-size:10.0pt;font-family:Verdana'>Anders style='font-size:10.0pt;font-family:Verdana'>: 
I'm not sure I see the connection between generics and exceptions.

style='font-size:10.0pt;font-family:Verdana'> 

style='font-size:10.0pt;font-family:Verdana'>Q style='font-size:10.0pt;font-family:Verdana'>: 
There are lot's of type systems now, do you see any chance of integration
(eg: CLR & XML).

style='font-size:10.0pt;font-family:Verdana'>Anders style='font-size:10.0pt;font-family:Verdana'>: 
There are differences and we keep whittling away the differences. style='mso-spacerun:yes'>  If you look at XAML you can extend with
tags/attributes that map to class and language elements. 
It's true that XSD dreams up extra stuff that doesn't map well. style='mso-spacerun:yes'>  It was design by committee effort so you
see things that don't necessarily see use in real life. style='mso-spacerun:yes'>  We're working towards equilibrium here.

style='font-size:10.0pt;font-family:Verdana'> 

style='font-size:10.0pt;font-family:Verdana'>Q style='font-size:10.0pt;font-family:Verdana'>: 
Any reason the Reflection API's didn't support reflecting on the IL?

style='font-size:10.0pt;font-family:Verdana'>Jim style='font-size:10.0pt;font-family:Verdana'>: 
No reason at all, we ran out of time <laughs>.


Comments (13)

  1. Ian Ringrose says:

    In Java, if I implement the observer pattern and do not want the “Subject” to keep the “Observer” alive I can use a week reference to an inner class that implants the IObserver interface. A good case of this, is when a form (as in WinForms) is updating it’s self whenever a object changes, often a programmer will forget to “unhock” the connection and the form will live for every, even if the app has no reference to it.

    Now in the CLR I would use a delegate (most likely Event) rather then an interface to hook the “Observer” to the “Subject”. The problem is that there are no week delegates! However do I stop the “Subject” keeping the “Observer” alive?

    contect: ringi at bigfoot dot com

  2. Amir Massourian says:

    If observer register to events of Subject, Observer will not be GC’ed when it goes out of scope. One possible way to solve this problem is to introduce a listener object that would register to events in the subject and delegate the events to the observer(if it is alive) using an internal/public method of observer.

    A sample illustrating the above pattern is attached.
    ——————————————————————-

    namespace Sample {
    using System;

    public static class Sample {

    static public void Main() {
    Subject subject = new Subject();
    Observer observer = new Observer(subject);

    // change subject Value and expect output from the Observer
    subject.Value = 5;

    // for this example – make sure Observer is not aggressively garbage collected
    GC.KeepAlive(observer);

    // force the observer to go away without explictly disposing it
    observer = null;
    GC.Collect();
    GC.WaitForPendingFinalizers();

    // change subject Value again and observer have output
    // listener will unregister it self since observer is gone
    subject.Value = 6;

    subject.Value = 7; // show listner is gone
    }
    }

    // define the Delegate
    public delegate void ObserverDelegateEventHandler(object sender,ObserverDelegateEventArgs e);

    // Event Args definition
    public sealed class ObserverDelegateEventArgs : EventArgs {
    private readonly string message;

    public ObserverDelegateEventArgs(string message) {
    this.message = message;
    }
    public string Message {
    get {
    return message;
    }
    }
    }

    // subject class which fires the event
    public class Subject{

    private int subjectValue;
    private ObserverDelegateEventHandler onPropertyChanged;

    public Subject() {
    }

    public int Value {
    get {
    return subjectValue;
    }
    set {
    subjectValue = value;
    OnPropertyChanged("Value is changed to " + value.ToString());
    }
    }

    public event ObserverDelegateEventHandler PropertyChanged {
    add {
    onPropertyChanged += value;
    }
    remove {
    onPropertyChanged -= value;
    }
    }

    private void OnPropertyChanged(string message) {
    ObserverDelegateEventArgs eventArgument = new ObserverDelegateEventArgs(message);
    OnPropertyChanged(eventArgument);
    }

    protected virtual void OnPropertyChanged(ObserverDelegateEventArgs e) {
    if (null == e) {
    throw new ArgumentException("e");
    }
    if (null != onPropertyChanged) {
    onPropertyChanged(this, e);
    }
    }
    }

    public class Observer : IDisposable {
    private readonly Subject subject;
    private Listener listener;

    public Observer(Subject subject) {
    if (null == subject) {
    throw new ArgumentException("subject");
    }
    this.subject = subject;
    listener = new Listener(this, this.subject);
    }

    protected virtual void PropertyChanged(object sender, ObserverDelegateEventArgs e) {
    Console.WriteLine(e.Message);
    }
    // Event would be delegated to here by Listener
    // Give option to derived class to handle the event as it wants
    internal void PropertyChangedInternal(object sender, ObserverDelegateEventArgs eventArgument) {
    PropertyChanged(sender, eventArgument);
    }

    // unregister from events
    public void Dispose() {
    Dispose(true);
    }

    protected virtual void Dispose(bool disposing) {
    if (disposing) {
    // avoid NullReferenceException if Dispose called multiple times
    Listener a = listener;
    if (null != a) {
    a.Dispose();
    listener = null;
    }
    }
    // else do not use other managed objects during finalization
    }
    }

    internal class Listener : IDisposable {
    private readonly Subject subject;
    private readonly WeakReference weakObserver;

    internal Listener(Observer observer, Subject subject) {
    this.subject = subject;
    weakObserver = new WeakReference(observer);
    this.subject.PropertyChanged += new ObserverDelegateEventHandler(PropertyChanged);
    }

    internal void PropertyChanged(object sender, ObserverDelegateEventArgs e) {
    Observer observer = (Observer) weakObserver.Target;
    if ((null != observer) && weakObserver.IsAlive) {
    // delegate the event handling to the Observer
    observer.PropertyChangedInternal(sender, e);
    }
    else {
    // make self available for GC after first invocation after the observer is GC’d
    // Obsever.Dispose was not explictly called by the user
    // Console.WriteLine("listern removing itself");
    Dispose();
    }
    }

    public void Dispose() {
    this.subject.PropertyChanged -= new ObserverDelegateEventHandler(PropertyChanged);
    }
    }
    }

    ——————————————————————–
    This posting is provided "AS IS" with no warranties,
    and confers no rights. You assume all risk for your use.
    © 2003 Microsoft Corporation. All rights reserved.

  3. Keith Patrick says:

    Funny that Anders mentioned an FxCop rule for detecting undocumented exceptions, as I was working on just such a tool, but got hung up on generating an execution tree. After I found out FxCop was going to support custom rules, I decided to wait on so I could just port it, but I wouldn’t surprised if someone beats me to it (or so I hope 🙂 )

  4. Jim Arnold says:

    Excellent stuff, very useful – thanks for the transcript!