.NET Framework Cruft
-
I've been thinking about this a lot, but I have no particularly good solution for it. Sorry, this is going to be a bit "ranty". The .NET Framework has a ton of cruft in it, mostly due to Microsoft's incessant commitment to never breaking backwards compatibility. This adds a lot of unnecessary complexity to the framework and makes the initial learning curve a lot harder and less intuitive than it needs to be. It's not the fact that it is there that bothers me, it's that I have to look at it and deal with it all the time. There should be some kind of mechanism to deprecate stuff and build transformations so that old code still works but I can look at nicely cleaned up new code for new projects going forward. I don't really know what can be done at this point to fix it though. I was thinking that perhaps a new pseudo-language could be created - lets call it C##. It would use the same BCL under the hood, use the same C# compiler, there would just be a C## preprocessor that would do some clever transformations so that it was valid C# prior to running it through the compiler. That would mean that C## libraries would be fully compatible with C# projects (and vice versa), but for new development you could isolate yourself from all the old crap in the language and framework. Some issues I would fix in this "clean break" language (some of this may not be possible without CLR updates as well): - Transform foreach so the iteration variable is inside the loop (important for closures that close over the iteration variable, where this behavior is essentially always desired). - Add keyword "beforefieldinit" or attribute [BeforeFieldInit] that can be added to the static constructor definition to control class init behavior, instead of the asinine way it handles it now based on whether a static constructor is defined or not. There is absolutely no reason this shouldn't be easily and explicitly controllable by the developer. - Remove all non-generic collections and collection interfaces, or at least fix them so they match their generic equivalents, because this is a bloody nonsensical mess (ICollection != ICollection, IList != IList). Expand the list of interfaces if need be so it actually makes sense (ie why do I have to implement a whole wack of unnecessary IList members with throw new NotImplementedException() just to get a read-only indexable type that plays nice as an observable read-only collection?). I believe this last part has at least been partially addressed in .NET 4.5 though. - In order to h
-
I've been thinking about this a lot, but I have no particularly good solution for it. Sorry, this is going to be a bit "ranty". The .NET Framework has a ton of cruft in it, mostly due to Microsoft's incessant commitment to never breaking backwards compatibility. This adds a lot of unnecessary complexity to the framework and makes the initial learning curve a lot harder and less intuitive than it needs to be. It's not the fact that it is there that bothers me, it's that I have to look at it and deal with it all the time. There should be some kind of mechanism to deprecate stuff and build transformations so that old code still works but I can look at nicely cleaned up new code for new projects going forward. I don't really know what can be done at this point to fix it though. I was thinking that perhaps a new pseudo-language could be created - lets call it C##. It would use the same BCL under the hood, use the same C# compiler, there would just be a C## preprocessor that would do some clever transformations so that it was valid C# prior to running it through the compiler. That would mean that C## libraries would be fully compatible with C# projects (and vice versa), but for new development you could isolate yourself from all the old crap in the language and framework. Some issues I would fix in this "clean break" language (some of this may not be possible without CLR updates as well): - Transform foreach so the iteration variable is inside the loop (important for closures that close over the iteration variable, where this behavior is essentially always desired). - Add keyword "beforefieldinit" or attribute [BeforeFieldInit] that can be added to the static constructor definition to control class init behavior, instead of the asinine way it handles it now based on whether a static constructor is defined or not. There is absolutely no reason this shouldn't be easily and explicitly controllable by the developer. - Remove all non-generic collections and collection interfaces, or at least fix them so they match their generic equivalents, because this is a bloody nonsensical mess (ICollection != ICollection, IList != IList). Expand the list of interfaces if need be so it actually makes sense (ie why do I have to implement a whole wack of unnecessary IList members with throw new NotImplementedException() just to get a read-only indexable type that plays nice as an observable read-only collection?). I believe this last part has at least been partially addressed in .NET 4.5 though. - In order to h
So, you want to build a new framework to wrap the old framework, which wraps the older framework. Shew! Where will it all end. Maybe we should just go back to assembly, and be done with it.
When I was a coder, we worked on algorithms. Today, we memorize APIs for countless libraries — those libraries have the algorithms - Eric Allman
-
So, you want to build a new framework to wrap the old framework, which wraps the older framework. Shew! Where will it all end. Maybe we should just go back to assembly, and be done with it.
When I was a coder, we worked on algorithms. Today, we memorize APIs for countless libraries — those libraries have the algorithms - Eric Allman
Hey, as I said in my very first sentence, "I have no particularly good solution for it" :) How do you suggest dealing with increasing bloat and cruft in a constantly evolving framework?
-
Hey, as I said in my very first sentence, "I have no particularly good solution for it" :) How do you suggest dealing with increasing bloat and cruft in a constantly evolving framework?
I have never really seen it in your light to be perfectly honest. I have been doing .Net development since around 2002, and have just really had to learn the new stuff whenever they upgraded it. I guess if I had to start learning it all now, it would be a different story.
When I was a coder, we worked on algorithms. Today, we memorize APIs for countless libraries — those libraries have the algorithms - Eric Allman
-
I have never really seen it in your light to be perfectly honest. I have been doing .Net development since around 2002, and have just really had to learn the new stuff whenever they upgraded it. I guess if I had to start learning it all now, it would be a different story.
When I was a coder, we worked on algorithms. Today, we memorize APIs for countless libraries — those libraries have the algorithms - Eric Allman
I've been doing .NET development for a similar period of time, and while I don't personally have problems grasping it, the inconsistencies and design issues that can't be fixed now because they would break backwards compatibility are super annoying. I can see how wierd and confusing certain aspects of the framework are to new recruits that I train though. That, and inconsistencies such as the complete mismatch of IList ==> IList and ICollection ==> ICollection just set my OCD off like mad. I tend to be working on rather low level stuff by typical .NET standards though, so this stuff bothers me more (i.e. being able to control the beforeinitflag would remove hacky workaround code in several libraries we have).
-
I've been thinking about this a lot, but I have no particularly good solution for it. Sorry, this is going to be a bit "ranty". The .NET Framework has a ton of cruft in it, mostly due to Microsoft's incessant commitment to never breaking backwards compatibility. This adds a lot of unnecessary complexity to the framework and makes the initial learning curve a lot harder and less intuitive than it needs to be. It's not the fact that it is there that bothers me, it's that I have to look at it and deal with it all the time. There should be some kind of mechanism to deprecate stuff and build transformations so that old code still works but I can look at nicely cleaned up new code for new projects going forward. I don't really know what can be done at this point to fix it though. I was thinking that perhaps a new pseudo-language could be created - lets call it C##. It would use the same BCL under the hood, use the same C# compiler, there would just be a C## preprocessor that would do some clever transformations so that it was valid C# prior to running it through the compiler. That would mean that C## libraries would be fully compatible with C# projects (and vice versa), but for new development you could isolate yourself from all the old crap in the language and framework. Some issues I would fix in this "clean break" language (some of this may not be possible without CLR updates as well): - Transform foreach so the iteration variable is inside the loop (important for closures that close over the iteration variable, where this behavior is essentially always desired). - Add keyword "beforefieldinit" or attribute [BeforeFieldInit] that can be added to the static constructor definition to control class init behavior, instead of the asinine way it handles it now based on whether a static constructor is defined or not. There is absolutely no reason this shouldn't be easily and explicitly controllable by the developer. - Remove all non-generic collections and collection interfaces, or at least fix them so they match their generic equivalents, because this is a bloody nonsensical mess (ICollection != ICollection, IList != IList). Expand the list of interfaces if need be so it actually makes sense (ie why do I have to implement a whole wack of unnecessary IList members with throw new NotImplementedException() just to get a read-only indexable type that plays nice as an observable read-only collection?). I believe this last part has at least been partially addressed in .NET 4.5 though. - In order to h
Mike Marynowski wrote:
- In order to help facilitate removing non-generic collection types, let covariance and contravariance work on generic type parameters of classes as well as value types (i.e. IEnumerable<int> can be used as IEnumerable<object>).
How? Conceptually I agree that this makes sense, but I don't see how it could be implemented.
-
I've been thinking about this a lot, but I have no particularly good solution for it. Sorry, this is going to be a bit "ranty". The .NET Framework has a ton of cruft in it, mostly due to Microsoft's incessant commitment to never breaking backwards compatibility. This adds a lot of unnecessary complexity to the framework and makes the initial learning curve a lot harder and less intuitive than it needs to be. It's not the fact that it is there that bothers me, it's that I have to look at it and deal with it all the time. There should be some kind of mechanism to deprecate stuff and build transformations so that old code still works but I can look at nicely cleaned up new code for new projects going forward. I don't really know what can be done at this point to fix it though. I was thinking that perhaps a new pseudo-language could be created - lets call it C##. It would use the same BCL under the hood, use the same C# compiler, there would just be a C## preprocessor that would do some clever transformations so that it was valid C# prior to running it through the compiler. That would mean that C## libraries would be fully compatible with C# projects (and vice versa), but for new development you could isolate yourself from all the old crap in the language and framework. Some issues I would fix in this "clean break" language (some of this may not be possible without CLR updates as well): - Transform foreach so the iteration variable is inside the loop (important for closures that close over the iteration variable, where this behavior is essentially always desired). - Add keyword "beforefieldinit" or attribute [BeforeFieldInit] that can be added to the static constructor definition to control class init behavior, instead of the asinine way it handles it now based on whether a static constructor is defined or not. There is absolutely no reason this shouldn't be easily and explicitly controllable by the developer. - Remove all non-generic collections and collection interfaces, or at least fix them so they match their generic equivalents, because this is a bloody nonsensical mess (ICollection != ICollection, IList != IList). Expand the list of interfaces if need be so it actually makes sense (ie why do I have to implement a whole wack of unnecessary IList members with throw new NotImplementedException() just to get a read-only indexable type that plays nice as an observable read-only collection?). I believe this last part has at least been partially addressed in .NET 4.5 though. - In order to h
Mike Marynowski wrote:
There should be some kind of mechanism to deprecate stuff and build transformations so that old code still works but I can look at nicely cleaned up new code for new projects going forward.
The new stuff is hardly signature-compatible. The only alternative is that all your .NET 1.0 apps simply stop working. Or did you expect MS to magically know what you'd pass into that extra parameter? :) Keeping things compatible means keeping things from breaking. It means "reliable". And, as the market proves, that's worth a few bucks.
Bastard Programmer from Hell :suss: If you can't read my code, try converting it here[^]
-
Mike Marynowski wrote:
- In order to help facilitate removing non-generic collection types, let covariance and contravariance work on generic type parameters of classes as well as value types (i.e. IEnumerable<int> can be used as IEnumerable<object>).
How? Conceptually I agree that this makes sense, but I don't see how it could be implemented.
What do you mean? It already works for reference types, it would just needs some IL tricks or runtime support to allow auto-boxing for value types.
-
Mike Marynowski wrote:
There should be some kind of mechanism to deprecate stuff and build transformations so that old code still works but I can look at nicely cleaned up new code for new projects going forward.
The new stuff is hardly signature-compatible. The only alternative is that all your .NET 1.0 apps simply stop working. Or did you expect MS to magically know what you'd pass into that extra parameter? :) Keeping things compatible means keeping things from breaking. It means "reliable". And, as the market proves, that's worth a few bucks.
Bastard Programmer from Hell :suss: If you can't read my code, try converting it here[^]
I think you are missing the point and looking at the problem with blinders on. Many languages have successfully implemented better versioning mechanisms that allow for these kinds of changes. The old stuff would still be in there, so there would be no compatibility issues. It would just be hidden from projects that target newer framework versions. Some languages have a tag that you can put at the top of a source file, kind of like an html doctype tag, that indicates language version compatibility level, so you can even mix different versions in a single project. That way, if you want to copy and paste a class from a different project that targeted an earlier version, you can still do that. *EDIT* typo fixed...
-
What do you mean? It already works for reference types, it would just needs some IL tricks or runtime support to allow auto-boxing for value types.
Yes, but that's precisely the problem isn't it, where should auto-boxing happen? There isn't anywhere for the box instruction to go unless you wrap the IEnumerable<int> in a special class that does it - you can't put it at the consumer site because an IEnumerable<object> may be an IEnumerable<class>, and I don't see how you could put it at the producer site at all. So ok, you can do that wrapper, but the compiler needed special magic knowledge of IEnumerable<T> to be able to make that wrapper. What should the wrapper look like if it's some other type? How can it even know?
-
Yes, but that's precisely the problem isn't it, where should auto-boxing happen? There isn't anywhere for the box instruction to go unless you wrap the IEnumerable<int> in a special class that does it - you can't put it at the consumer site because an IEnumerable<object> may be an IEnumerable<class>, and I don't see how you could put it at the producer site at all. So ok, you can do that wrapper, but the compiler needed special magic knowledge of IEnumerable<T> to be able to make that wrapper. What should the wrapper look like if it's some other type? How can it even know?
It doesn't need special knowledge of IEnumerable, it needs special knowledge of generic type arguments that are value types. Instead of throwing a cast exception, in this special case it can auto-generate an invisible wrapper class that does the boxing, kind of how it auto-generates concrete classes for every different type parameter used in a generic class. It just needs to mirror all the method signatures and cast the value type to object.
-
I've been thinking about this a lot, but I have no particularly good solution for it. Sorry, this is going to be a bit "ranty". The .NET Framework has a ton of cruft in it, mostly due to Microsoft's incessant commitment to never breaking backwards compatibility. This adds a lot of unnecessary complexity to the framework and makes the initial learning curve a lot harder and less intuitive than it needs to be. It's not the fact that it is there that bothers me, it's that I have to look at it and deal with it all the time. There should be some kind of mechanism to deprecate stuff and build transformations so that old code still works but I can look at nicely cleaned up new code for new projects going forward. I don't really know what can be done at this point to fix it though. I was thinking that perhaps a new pseudo-language could be created - lets call it C##. It would use the same BCL under the hood, use the same C# compiler, there would just be a C## preprocessor that would do some clever transformations so that it was valid C# prior to running it through the compiler. That would mean that C## libraries would be fully compatible with C# projects (and vice versa), but for new development you could isolate yourself from all the old crap in the language and framework. Some issues I would fix in this "clean break" language (some of this may not be possible without CLR updates as well): - Transform foreach so the iteration variable is inside the loop (important for closures that close over the iteration variable, where this behavior is essentially always desired). - Add keyword "beforefieldinit" or attribute [BeforeFieldInit] that can be added to the static constructor definition to control class init behavior, instead of the asinine way it handles it now based on whether a static constructor is defined or not. There is absolutely no reason this shouldn't be easily and explicitly controllable by the developer. - Remove all non-generic collections and collection interfaces, or at least fix them so they match their generic equivalents, because this is a bloody nonsensical mess (ICollection != ICollection, IList != IList). Expand the list of interfaces if need be so it actually makes sense (ie why do I have to implement a whole wack of unnecessary IList members with throw new NotImplementedException() just to get a read-only indexable type that plays nice as an observable read-only collection?). I believe this last part has at least been partially addressed in .NET 4.5 though. - In order to h
Mike Marynowski wrote:
- Transform foreach so the iteration variable is inside the loop (important for closures that close over the iteration variable, where this behavior is essentially always desired).
Already done in 4.5: http://stackoverflow.com/a/12112959/124386[^]
Mike Marynowski wrote:
why do I have to implement a whole wack of unnecessary IList members with throw new NotImplementedException() just to get a read-only indexable type that plays nice as an observable read-only collection?
IReadOnlyCollection<T>[^], IReadOnlyList<T>[^] and IReadOnlyDictionary<TKey, TValue>[^] were added in 4.5: http://visualstudiomagazine.com/articles/2012/08/07/new-read-only-collection-interfaces-for-net.aspx[^]
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
-
Mike Marynowski wrote:
- Transform foreach so the iteration variable is inside the loop (important for closures that close over the iteration variable, where this behavior is essentially always desired).
Already done in 4.5: http://stackoverflow.com/a/12112959/124386[^]
Mike Marynowski wrote:
why do I have to implement a whole wack of unnecessary IList members with throw new NotImplementedException() just to get a read-only indexable type that plays nice as an observable read-only collection?
IReadOnlyCollection<T>[^], IReadOnlyList<T>[^] and IReadOnlyDictionary<TKey, TValue>[^] were added in 4.5: http://visualstudiomagazine.com/articles/2012/08/07/new-read-only-collection-interfaces-for-net.aspx[^]
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
I knew there were some new collection interfaces which is why I said that point was already at least partially taken care of in 4.5, but that's awesome regarding foreach! I'm kind of shocked about that, Jon Skeet had a few blog posts about the topic where he said they can't change it now as it could break existing applications and code. Thanks for sharing!