"Rob Teixeira [MVP]" <RobTeixeira@@msn.com> wrote in message
news:eSmdb5J5DHA.2696@TK2MSFTNGP09.phx.gbl...[color=blue][color=green]
> > Unsafe Code:
> > Mixing regular code with unsafe code means that any security and[/color]
> robustness guarantees can[color=green]
> > too easily be overridden. A garbage collector which is overridden is[/color]
> pointless. The problem[color=green]
> > surfaces when multiple people work together on a large project.[/color]
>
> Ideal - if everything were in managed space. However, and I find this to[/color]
be[color=blue]
> one of Java's weaknesses, was it's interface to existing code (most of[/color]
which[color=blue]
> is, of course, unmanaged). Working with unmanaged code is sometimes better
> suited to unsafe code blocks. However, it's not true that the GC is
> circumvented by unsafe code. Unsafe code requires pinned variables in a
> local scope. You have to do something horribly wrong to undermine the GC,
> and that takes conscious effort on the part of the developer in most cases[/color]
i[color=blue]
> can think of. The crux of this issue is flexibility vs. forced robustness,
> and keep that in mind, because I'll revisit it soon. In the meantime,
> realize that unsafe code requires a special compiler switch. If you really
> don't want your team working on large projects to use it, then don't allow
> that switch to be used. Problem solved.[/color]
You make good points. I am working on an improved and more educated argument
with regards to unsafe contexts.
[color=blue][color=green]
> > Attributes:
> > Code quickly becomes extremely illegible when attributes are used.[/color]
> Attributes result in[color=green]
> > essentially an obfuscation of the language specification and expected[/color]
> behaviour. Debugging code[color=green]
> > becomes trickier when attributes have potentially subtle side effects.[/color]
>
> It may seem that way to you, but that may be due to your familiarity with
> large branches of visible code doing all the work, and this is a different
> paradigm. Many languages now use declarative elements and those that[/color]
didn't[color=blue]
> are recently seeing its adoption. However, the obfuscation part hardly
> seems like a justifiable case for your argument against attributes,[/color]
because[color=blue]
> if we were to replace "attributes" with a compiler or library function,[/color]
you[color=blue]
> would essencially end up with the exact same results - a small tag of code
> whose explicit details you are not privy to. In that respect, any[/color]
language,[color=blue]
> other than assembly with no macros, whether it has declaritive elements or
> not would be guilty of the same crime.[/color]
Attributes allow modification of such aspects of the language such as
parameter passing. I argue that this obfuscates the software but it does
definitely increase the flexibility and expressiveness of the language. I
also need to mention I don't have a problem with fixed or built-in
attributes but rather with custom attributes. I will try to improve this
section of the critique.
[color=blue][color=green]
> > Garbage Collection:
> > You are effectively forced to use garbage collection. Turning off the[/color]
> garbage collection in C#[color=green]
> > can lead to extremely subtle and hard to find bugs due to a mix of[/color][/color]
garbage[color=blue]
> collected and non-garbage[color=green]
> > collected code. Turning off garbage collection can only be done by[/color]
> switching to an unsafe context[color=green]
> > with all of what that implies.[/color]
>
> I see several problems with this argument. First of all is the[/color]
inconsistancy[color=blue]
> of your arguments. Remember the first point I made above that I said i[/color]
would[color=blue]
> revisit? You wanted the language to be less flexible in favor of enforcing
> robustness (which you are happy to point out elsewhere in your[/color]
dissertation[color=blue]
> as well). Here, you are completely reversing your position. What MS has
> done, is evaluate the top reasons in existing languages (primarily C/C++)
> for bugs that both slip notice and cause tremendous problems. As you might
> already have guessed, manual memory management is at the top of the list.[/color]
GC[color=blue]
> is the only way (that I know of, or that has been proven to date) to solve
> this issue. This is a mojor point of robustness, and I'm unlcear as to why
> you would be in favor of robustness above, but not here. Also, there is no
> way to "turn off" GC in C# (otherwise, you wouldn't be forced to use it,
> right? - seems like a contradictory statement there), and switching to
> unsafe mode will not turn off the GC. I have a feeling you are also
> confusing the issues between managed and unmanaged code here (which is
> completely different from safe vs. unsafe code). As Inigo said to Vezzini,
> "I do not think this means what you think it means."[/color]
You are oversimplifying that critiquing a language is a simple case of
robustness versus flexibility, and that we must choose one over the over all
the time for all language features. I was definitely confused with regards
to unsafe contexts and unmanaged code. I will be revising this.
[color=blue][color=green]
> > C# allows non-deterministic destructors:
> > Garbage collection with destructors means the destructors can be called[/color][/color]
at[color=blue]
> unpredicatable moments[color=green]
> > during execution.[/color]
>
> That is the nature of GC. The thing to remember is: you shouldn't use
> destructors for deterministic management (eg. clean-up) of resource[/color]
(that's[color=blue]
> what Dispose is for). Destructors are there as a safety net in case a
> consumer doesn't explicitly call Dispose. The Dispose pattern in my[/color]
opinion[color=blue]
> is valid, because the only way to get deterministic finalization, is if[/color]
the[color=blue]
> consumer knows he needs something to be managed "now" - so he MUST call
> something... whether that something is a memory deallocation keyword or a
> Dispose function is rather irrelevant. Bottom line: if you want to know[/color]
that[color=blue]
> clean-up code is being called "now", use Dispose. That is deterministic.[/color]
Of[color=blue]
> course, C# isn't the only language that uses a GC and deals with the same
> issue, but I'm betting you don't like any of them either ;-)[/color]
Not all GC languages support non-deterministic destructors. This was a
choice of the language designers. Yes we can avoid using them, but will bob
in the next cubicle over remember too?
[color=blue][color=green]
> > Objects can't exist on the stack
> > We are forced to use structs if we want to create an object which exists[/color]
> on the stack. This can cause[color=green]
> > problems for users of a library which has locked in an object[/color]
> implementation.
>
> I'm not sure your example fits the problem in this case. For starters, if
> that's the only problem with objects being limited to the heap, then[/color]
hell..[color=blue]
> what's the problem? :-) Your example only illustrates that you shouldn't
> poorly design class libraries, and the importance of not carrying
> implemenation details across boundries (which is why we deal in Interfaces
> at that point). Secondly, I'd like to see an example of how this impacts[/color]
the[color=blue]
> consumer of said class library. As far as the user knows, he is passing a
> parameter of a certain type to a member. If that parameter changes from
> reference type to value type, does that really impact him? His code is[/color]
going[color=blue]
> to more or less look exactly the same from his point of view for that[/color]
member[color=blue]
> invokation.
> But lets look at the flipside of the coin. Why would you want objects on[/color]
the[color=blue]
> stack to begin with? The primary reason for C/C++ programmers is that the
> speed of heap allocation sucks in comparison to stack allocation. That
> limitation doesn't exist in .NET. Heap allocation in .NET requires only[/color]
the[color=blue]
> increment of the allocation pointer, making it almost exactly the same as
> stack allocation in terms of performance. To make reference types[/color]
available[color=blue]
> on the stack, you'd have to change GC infrastructure, which would
> effectively make reference type allocation on the stack SLOWER. In[/color]
addition,[color=blue]
> value types are rather small in comparison with reference types,[/color]
especially[color=blue]
> if you consider strings, which make up the majority of data in a program.[/color]
Do[color=blue]
> you really want a programmer to accidentally put that on the stack? IMHO,
> this isn't a sticking point at all for or against C#.[/color]
Not a very strong point that I made, I agree.
[color=blue][color=green]
> > Type / Reference Types
> > A type decides whether it will be on the stack or the heap. Which means[/color][/color]
a[color=blue]
> programmer has to be[color=green]
> > aware of each types specific semantics when using it to know whether[/color][/color]
they[color=blue]
> are passing things by[color=green]
> > reference or by value. This leads to subtle and confusing bugs.[/color]
>
> Actually, types don't reside on the stack or heap, variables do. Secondly,
> types don't decide where the allocation goes, the runtime does.
> Again, I'm curious as to what sorts of bugs this would cause.[/color]
I will try and update this as well.
[color=blue][color=green]
> > Boxing / Unboxing
> > The semantics of boxing and unboxing are subtle and confusing. There is[/color][/color]
a[color=blue]
> problem of needing to[color=green]
> > know too much information about a type to decode the semantics of a[/color][/color]
simple[color=blue]
> assignment. Boxing[color=green]
> > is a feature designed to compensate for the fact that objects must be[/color][/color]
used[color=blue]
> by reference.
>
> Quite the contrary, IMO. Boxing/unboxing allows the programmer to need to
> know a lot LESS about whether a type is a reference type or not in order[/color]
to[color=blue]
> use it in the context of a reference type (for example, the common
> assignment of value types to a more general reference type reference). If[/color]
it[color=blue]
> were not for boxing/unboxing, the programmer would have to be far MORE[/color]
aware[color=blue]
> of the details of the type implementations and code such scenarios
> SEPARATELY.[/color]
Hmm... I will need to look into that argument more deeply.
[color=blue][color=green]
> > Mutability
> > C# does not allow declaration of immutable instances of user defined[/color]
> objects.
>
> I understand what you want to do here - create a const instance of a[/color]
class.[color=blue]
> Fair enough, but the semantics could get ugly. First of all, this wouldn't
> truly be CONST unless the compiler had a way to create literal instance[/color]
data[color=blue]
> imbedded in the program (as it can easily do for numbers and strings[/color]
because[color=blue]
> it's programmed to know how to do that). You can argue that serialization
> might do the trick, but then you'd be limited to only serializable objects
> being const. If the compiler is unable to do this, it would have to write
> code behind the scenes to create an instance at runtime, which isn't truly
> const and you'd be in no better position than using the "final" modifier[/color]
in[color=blue]
> Java, which only prevents you from modifying the value. But assuming you
> were able to freez-dry a literal instance (and have a mechanism for the
> programmer to specify the data for it in the first place), you could then
> run into issues of possibly bypassing class behaviors associated with
> constructors - and if you didn't, would it be truly const? This is one of
> the reasons that value types get literals and reference types don't -[/color]
value[color=blue]
> types have no constructors.[/color]
I don't understand what you mean by "truly const". How could you bypass
class behaviours?
[color=blue]
> Also, the lack of literal declarations doesn't mean you can't have[/color]
immutable[color=blue]
> objects. You can certainly program immutable objects in C#. Again, you[/color]
might[color=blue]
> want to check your verbiage here. One thing doesn't necessarily mean the
> other. And for the sake of a good critique, this can show lack of
> understanding of the principals you are critiquing against.[/color]
Yes I realize the verbiage is weak there.
[color=blue][color=green]
> > Classes as Modules and Programs
> > C# allows static information within a class and not outside of one.[/color]
> Therefore a class in C# has[color=green]
> > concepts that are a hack designed to compensate for missing modules.[/color]
> Classes and modules[color=green]
> > are very distinct concepts that deserve to be treated as seperate[/color]
> identities. When we do so, as[color=green]
> > in Heron and Object Pascal, the semantics of classes is simplified[/color]
> somewhat. One example of where[color=green]
> > not being allowed to place data into the global scope of a namespace is[/color]
> noticeably lacking :[color=green]
> > using System;
> > class Hello
> > {
> > static void Main() {
> > Console.WriteLine("hello, world");
> > }
> > }
> > The System namespace can not export a function named WriteLine it can[/color]
> only export static classes.[color=green]
> > A static class with only static data and static methods should either be[/color][/color]
a[color=blue]
> module or a program. It[color=green]
> > could be argued all static data should occur outside of classes since it[/color]
> is not directly related to objects[color=green]
> > themselves.[/color]
>
> Not sure I agree completely with you here. First of all Classes and[/color]
modules[color=blue]
> are both holding containers for members (whether data or functions). The
> difference is that modules cannot have distinct instances, and classes can
> (or not, if you're dealing with static members) - in effect being[/color]
perfectly[color=blue]
> capable of performing both roles. Your gripe seems to be more about the
> invokation syntax, which is purly compiler syntactical sugar and a few[/color]
rules[color=blue]
> about name resolution. For example, VB.NET allows you to create a "Module"
> (thusly named), which (for the reasons i stated earlier) is really just a
> static class that contains only static members (and you don't have to
> specify that, and they can't be changed to instance members either). The[/color]
VB[color=blue]
> compiler also allows you to invoke said members without qualifying it to[/color]
the[color=blue]
> module's (class') name - in essence letting you "export" what appears to[/color]
be[color=blue]
> a global function to the consumer. That could certainly be in C# as well,
> but honestly, it's a matter of personal preference at that point. And[/color]
there[color=blue]
> are a lot of people that prefer it the way it is rather than the way[/color]
VB.NET[color=blue]
> does it. For starters, you are introducing a level of ambiguity and issues
> revolving around name resolution that otherwise wouldn't be there... and[/color]
for[color=blue]
> a guy who doesn't like ambiguity, this argument seems rather contradictory
> with your previous line of thinking.[/color]
Invocation syntax has to do with a language specification rather than the
compiler. VB is not what I am discussing neither. My argument is not clear
and actually splits between two points. I will be fixing that. There are
separate issues with the lack of a module concept and with the inability to
export functions into the global namespace.
[color=blue][color=green]
> > Polymorphism through Class inheritance
> > C# supports polymorphism only through class inheritance. Class[/color][/color]
inheritance[color=blue]
> does not encapsulate code[color=green]
> > as well as interface delegations. Interface implementations can not be[/color]
> delegated to member fields. Every[color=green]
> > time you want to implement an interface you must explicitly write all of[/color]
> the functions.
>
> That is a completely false statement as worded. C# only allows you to
> inherit from one class (no multiple inheritance is even possible).
> Everything else *is* interface implementation. It is perfectly legitimate[/color]
to[color=blue]
> inherit an interface (or many) and not inherit any class at all. However,
> I'll grant you that the member delegation is more limited than some other
> languages, including VB.NET, which allows more explicit control over which
> members map to which interfaces. Again, this argument as stated appears to
> be extremely misinformed, lessening the validity of the critique.[/color]
Yes that statement is false.
[color=blue][color=green]
> > C# Missing Template Template Parameters
> > In C#, a generic type parameter cannot itself be a generic, although[/color]
> constructed types may be used as generics.
>
> Remember that generics in C# aren't macro-type replacements as is the case
> in C++. There are resolution and type safty issues with regards to[/color]
allowing[color=blue]
> this. There was a rather good explanation in one of the blogs (probably
> reachable via C# Corner).
>[color=green]
> > Late Added Generics
> > By adding generics so late, among other things there is the pointless[/color]
> redundancy of[color=green]
> > having two kinds of arrays. The int a[]; and array<int> a;[/color]
>
> Not a good argument at all. First of all, few languages support generics[/color]
to[color=blue]
> begin with... and some roughly equated to C# have had generics on the
> drawing board for years and haven't even gotten there yet. Considering the
> priorities and the grand scope of .NET in its entirety (not just C#), the
> progression has actually been very fast, especially if you take all the
> functionality into account. Note that the language designers actually had[/color]
a[color=blue]
> draft of how generics would work within the scope of the CLR/CLI during
> the .NET Beta. But where the argument really falls through is
> that having two arrays is *not* pointlessly redundant. Why go through the
> gernerics mechanism if you don't have to - especially for types which the
> compiler already knows how to build type-safe arrays for?
>[color=green]
> > Special Primitives
> > Special rules exist for so-called "primitive" types. This significantly[/color]
> reduces the[color=green]
> > expressiveness and flexibility of the language. The programmer can not[/color][/color]
add[color=blue]
> new[color=green]
> > types that are at fully at par with existing primitives.[/color]
>
> What on earth are you tryign to do with user-defined types that can only[/color]
be[color=blue]
> done with primitives?
> Remember that the compiler has no earthly idea what to do with types[/color]
nobody[color=blue]
> has written yet...
> You're going to need one hell of a good example to justify this one (in
> fact, the whole page could do with a LOT more concrete examples to explain
> what you're trying to get at). And again, C# isn't the only language to do
> this. Most languages are like this... though again, i'm betting you don't
> like any of them either.[/color]
Just because "other languages do this" doesn't make a feature a good idea. I
can still take up issue with the feature.
[color=blue][color=green]
> > Source File Layout
> > C-Sharp code is not readable without automatic documenting tools or[/color]
> editor.[color=green]
> > It takes a long time to read a source file and find out what classes are[/color]
> included and what the[color=green]
> > member fields and methods of those classes are. This promotes an[/color]
> unstructured coding style and[color=green]
> > often leads to bugs that are not immediately obvious without reading the[/color]
> automatically generated[color=green]
> > documentation.[/color]
>
> I'm sure you find it unreadable, but i'm betting C# developers find it
> perfectly readable ;-)
> This is like COBOL programmers saying they think pascal files are
> unreadable, or vice-versa.
> I'm not sure your cause-effect statement holds much water either.
> And if it's truly that unreadable, what on earth is your suggestion? C# is
> about as readable as any C-derived language will ever get. If you don't[/color]
like[color=blue]
> any C languages, why are you even critiquing C# specifically?[/color]
Not quite the same thing as COBOL vs Pascal readability. C# is virtually the
same (syntactically) as C++ but without any kind of header files. This saves
typing, but requires auto-generation of headers through one form or another.
Is not having header files an improvement of any kind? One may argue that C#
saves some typing and that auto-generation is sufficient, but there is
clearly no real advantage of not having header files.
[color=blue][color=green]
> > Public Fields
> > Classes can expose their fields as being public. This violates the[/color]
> encapsulation principle of objects.
>
> Oh Dear Lord! The humanity!!! In all seriousness, if C# didn't allow it,
> someone just like you would come in and complain that it didn't. All the
> encapsulation overkill aside, there are legitimate reasons for exposing
> public fields - primary of which is the ability to expose a field whose
> value is unlimited in the scope of its range, without taking the[/color]
performance[color=blue]
> hit of going through an accessor/mutator method. And before you cry
> "HERASY!", remember, best practices are there to stop people who can't[/color]
think[color=blue]
> from doing dumb things - not there to prevent people from thinking.[/color]
Best practices are usually ignored most by the people they are intended for.
Nonetheless, properties make public fields redundant.
[color=blue][color=green]
> > Is it a property or is it a field?
> > Are you setting a field named m or are you calling a property which[/color][/color]
leads[color=blue]
> to a function which can[color=green]
> > throw an exception? A language should allow only properties or only[/color]
> public fields but having both[color=green]
> > gives us the worst of both worlds.[/color]
>
> If a tree falls in the woods, and nobody is around to hear it, does it[/color]
make[color=blue]
> a sound? If you use proper exection handling, does it matter?[/color]
It doesn't really matter that much I suppose if one consistently assumes
that x.m = y is actually a function call.
[color=blue]
> As for the overall "critique", you need to cut out the personal opinion
> issues, and stick to good empirical data analysis and facts. The problem
> with programmers and techies in general is that they fall into an almost
> religious stupor about defending or bashing technology, facts and[/color]
scientific[color=blue]
> analysis be damned. Sadly, that just makes hordes of fodder for marketers.
> While I could see some potential in a few of your points, elminating the
> personal preference issues for the sake of a truly unbiased and[/color]
worth-while[color=blue]
> critique would leave you with a rather slim list. Your page stopped being[/color]
a[color=blue]
> critique and started becoming a soapbox RANT at your last paragraph, so i
> won't even justify that part's pathetic existance by commenting on it. So[/color]
in[color=blue]
> essence, your fear of being called a flame-bating troll is not only
> possible, but extremely likely. When you add to that the fact that you
> posted it in this group, one can only wonder why else you would even bring
> it up? If you "honestly want to improve on the critique", then consider
> carefully what i said - especially about the ranting. You ran off the tech
> rails and right into the blind-pundit/marketer path (take your pick).[/color]
People[color=blue]
> can argue over a true critique, but its merits will weather those[/color]
arguments[color=blue]
> unabashed and faultless when it is founded in pure fact. I can't say that
> about
> yours. And if you are promoting a product under these ideals, I certainly
> wouldn't do business with you. If you have a bone to pick with MS, you
> certainly have the right to do so, but don't disguise it as anything less.
>
> -Rob Teixeira [MVP][/color]
I see your point, and I will remove the crap about M$ at the end of my
article.
Overall thanks for the huge amount of work put into this letter. I will be
significantly overhauling the critique and will post when it is done. Thanks
again Rob.
--
Christopher Diggins
yet another language designer
http://www.heron-language.com