I have posted a C# critique at http://www.heron-language.com/c-sharp-critique.html. To summarize I bring up
the following issues :
- unsafe code
- attributes
- garbage collection
- non-deterministic destructors
- Objects can't exist on the stack
- Type / Reference Types
- Boxing / Unboxing
- Mutability
- Classes as Modules and Programs
- Polymorphism through Class Inheritance
- Interface Delegation
- Interface Extensions
- C# Missing Template Template Parameters
- Late Added Generics
- Source File Layout
- Public Fields
- Special Primitives
- Is it a Property or is it a field?
- Microsoft
I am perhaps guilty somewhat of being a flame baiting troll, but at the same
time I honestly want to improve on the critique.
Thanks in advance for your responses.
--
Christopher Diggins
yet another language designer http://www.heron-language.com 188 7036
1) Unsafe Code - Sometimes you need it, plain and simple. .NET is still
work in progress and there aren't managed wrappers for everything.
Developers don't have the luxury of deciding whether or not they use unsafe
code if the project demands something that necessitates it. Moreoever,
there's a good amount of legacy code that may well (and often is) in need of
using Unsafe
2) Attributes - Huh? Take for example FileIOPermission attribute...you can
mark 10 different directories with only Read permissions thereby eliminating
the need for checking hardcoded values and ugly branch logic before reading
or writing a file. I could go on and on about this, but I think you are way
off base here. And you aren't forced to use them...I bet there are tons of
..NET developers that barely know they exist for God's sake.
3- Garbage Collection - Yes, all of the benefits you get from Managed code
aren't totally free.
4- Allows non-deterministic destructors - If you dispose of your objects
when you are done with them, I'm not sure what the problem is. What problem
is this causing you?
5- Type/Reference Types.... Dude, there's so few value types I could recite
them off the top of my head. That's hardly a chore and so simple most
college CS freshman would love to have that as a Question on a test
As far as Objects can't exist on the stack....that's part and parcel to your
other complaint
6-Boxing vs. UnBoxing Depends on the types...I agree that it's not the most
intuitive concept, but once again, it's hardly a concept that can't be
understood.
7-Mutability - Ok, but what does that stop you from doing? Couldn't you use
Attributes to set the objects value and not provide accessors to change it?
8-Class as Modules and Programs - <<A static class with only static data and
static methods should either be a module or a program.>> Why?
9-Polymorphism - Why can't you use multiple Interfaces?
10-Generics and Missing Templates.... ok, they didn't get everything up
front, but if you want to use it, use it, if not, don't. Would it be better
for them to not provide this functionality? What if you were just starting
C# programming with the advent of 2.0 and didn't have legacy code? Wouldn't
you want generics?
11- Source File Layout - Can't you get all of that information via
reflection or using the CodeModel?
12 - Public Fields---Not if you don't do it. Is it really Microsoft's
responsibilty to ensure that every programmer doesn't violate the rules of
OOP? Besides, if they tried stopping this, there'd be so many VB
Programmers screaming bloody murder it wouldn't be funny. And while I
believe that you shouldn't break encapsulation, there are lots of people
that have...or have inherited code from people that did and prohibiting it
would impede adoption. Say what you want about MS, they bend over backwards
to support legacy code.
Special Primitives - Once again, so what?
13- Is it a field..
If it were a function, you'd see the () around it. Go ahead and try, if you
don't put the parens around it, it won't compile. As testimony to this, go
see how many VB Programmers constantly complain about forgetting the parens
when they call ToString without the Parens.
And finally, other than the issue of unsafe code which VB.NET doesn't
support, aren't all of these related to the CLR and the Framework rather
than C#?
"christopher diggins" <cd******@videotron.ca> wrote in message
news:V7********************@weber.videotron.net... I have posted a C# critique at http://www.heron-language.com/c-sharp-critique.html. To summarize I bring
up the following issues :
- unsafe code - attributes - garbage collection - non-deterministic destructors - Objects can't exist on the stack - Type / Reference Types - Boxing / Unboxing - Mutability - Classes as Modules and Programs - Polymorphism through Class Inheritance - Interface Delegation - Interface Extensions - C# Missing Template Template Parameters - Late Added Generics - Source File Layout - Public Fields - Special Primitives - Is it a Property or is it a field? - Microsoft
I am perhaps guilty somewhat of being a flame baiting troll, but at the
same time I honestly want to improve on the critique.
Thanks in advance for your responses.
-- Christopher Diggins yet another language designer http://www.heron-language.com
I think C#/.Net is great, except that there is no mature Virtual Machine /
Class Library for non-windows platform.
mono is not a good solution...
what I want is a truely java-like write once run everywhere
"christopher diggins" <cd******@videotron.ca> wrote in message
news:V7********************@weber.videotron.net... I have posted a C# critique at http://www.heron-language.com/c-sharp-critique.html. To summarize I bring
up the following issues :
- unsafe code - attributes - garbage collection - non-deterministic destructors - Objects can't exist on the stack - Type / Reference Types - Boxing / Unboxing - Mutability - Classes as Modules and Programs - Polymorphism through Class Inheritance - Interface Delegation - Interface Extensions - C# Missing Template Template Parameters - Late Added Generics - Source File Layout - Public Fields - Special Primitives - Is it a Property or is it a field? - Microsoft
I am perhaps guilty somewhat of being a flame baiting troll, but at the
same time I honestly want to improve on the critique.
Thanks in advance for your responses.
-- Christopher Diggins yet another language designer http://www.heron-language.com
While some of your comments about C# do have a point, most of the time the
case is that you can work around the issues in one way or another.
However, I could not disagree more with what you say about attributes.
Attributes allow you to move out code that is not essential to the logic of
your function. E.g.,
// non-attributes version
public void DoASensitiveThing()
{
if (!LookUpUserAuthenticationInfoAndCheckHeHasProperR oles())
throw new AccessDeniedException();
// do the actual logic here
}
// attributes version
[RolesRequired("Admin")]
public void DoASensitiveThing()
{
// do the actual logic here
}
The code is more readable in the version that uses attributes because things
that are not really part of the business logic have been moved out of the
code. It makes it easier for the reader to see what is happening because the
business logic is not cluttered with extra code.
I do not understand your comparison of attributes with C++ macros. C++
macros are somewhat evil in that they can lead to very obscure and hard to
find bugs due to the fact that they are preprocessed, not compiled. The way
macro arguments are evaluated can cause nasty problems due to side-effects,
double-evaluation and operator precedence. Attributes do not suffer from any
of these problems.
Regards,
Sami
christopher diggins <cd******@videotron.ca> wrote: I have posted a C# critique at http://www.heron-language.com/c-sharp-critique.html. To summarize I bring up the following issues :
- unsafe code
If you don't like it, don't use it. I never have.
- attributes
Couldn't disagree more - attributes are lovely, when used
appropriately. I rarely need to use them. but when I do they're very
handy.
- garbage collection
Yes, you're effectively forced to use garbage collection. I don't see
that as a bad thing.
- non-deterministic destructors
So don't rely on destructors being deterministic. Don't assume the RAII
idiom of C++ works in C# - it doesn't. Use the IDisposable idiom
instead.
- Objects can't exist on the stack
Using reference types for almost everything simplifies things
enormously, I find. Then again, I come from a Java background.
- Type / Reference Types
No, a type itself doesn't decide whether it'll be on the stack or the
heap - not directly, anyway. Reference types will always be on the
heap, but value types will be wherever the variable is declared - only
local variables and variables within other objects on the stack will be
on the stack. Again, I just don't see why this is a problem.
- Boxing / Unboxing
Your example is flawed - boxing will only occur in the case where
"anothertype" is object. Otherwise there has to be a user-defined
implicit conversion occurring, which is much more dangerous, IMO.
Boxing can indeed be confusing, but I believe that it's a necessary
evil to some extent.
- Mutability
Objects can certainly be immutable - take string, for instance. You
can't, however, declare a variable or method to be "const" - is that
what you're really after?
- Classes as Modules and Programs
The System namespace most certainly *shouldn't* export a method called
WriteLine. WriteLine is acting on a console, so rightly belongs in a
console class. I don't see anything wrong with a type itself having
data.
- Polymorphism through Class Inheritance - Interface Delegation
Both of these (which are basically one complaint, as far as I can see)
are reasonably valid.
- Interface Extensions
Yes, that could be nice.
- C# Missing Template Template Parameters
I don't know enough about generics to comment, but yes, that's
possible. Of course, Whidbey hasn't actually shipped yet, so things can
still change.
- Late Added Generics
I think there are far better examples here - namely the many collection
classes which would have been unnecessary had generics been there at
the start.
- Source File Layout
Not sure what you mean by "Heron code", but I agree that usually one
class per file is the best option.
- Public Fields
It doesn't violate "the principle of objects" in my view but it's
certainly a bad idea. It's not like C# forces you to do this though,
and if you're worried about it
- Special Primitives
In what way does it reduce the flexibility of the language? What is the
alternative?
- Is it a Property or is it a field?
Assuming you're using classes which follow the conventions, it's always
clear what you're doing. I would be reticent to use a library which
didn't follow the naming conventions anyway.
- Microsoft
I don't see how you can really compare what MS did with Java to what it
can do with C#. C# can already be used in a practical sense outside
Windows. Even if it could only be used on Windows, however, that
wouldn't make it a useless language by any means.
I am perhaps guilty somewhat of being a flame baiting troll, but at the same time I honestly want to improve on the critique.
It strikes me that absolutely none of these is a convincing reason not
to use C#. A few are interesting ideas for future development, but many
just don't seem to be an issue to me.
--
Jon Skeet - <sk***@pobox.com> http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
I'm not at all an expert on the whole comparison thing between different languages, despite that even I can notice that your trying too hard to criticize C#
What language are you offering as the alternitive? And what problems does that one have?
> - unsafe code
I think that if you would not allow mixed managed/unmanaged code, then no
one is going to jump on .NET since too much tested code exists and it will
take years to port to .NET code. The transition process is slo, but the
programs wil become more and more stable.
I think that the User interfaces will become more and more pure .NET,the but
the none-user interface functionality will be ported in time.
- Objects can't exist on the stack
Objects on the stack are an open door to the dreaded buffer overflows.
I think that this is a very good step forward towards stability of the
software.
Others already commented other points. - Public Fields
For very simple fields: the code is reduced and you can always extend them
to private field/public property.
--
Miha Markic - RightHand .NET consulting & software development
miha at rthand com www.rthand.com
In addition to responses already given:
You seem to be championing "Heron" instead of c#, based on the page you
linked to. However, the available "spec" for Heron is so bare as to be
un-critiqueable ( for example you mention calling destructors, but not
defining them)
However, there are some huge real-world problems already: - here's a very
partial list from a quick perusal
-it mentions specifically that there will be no support for concurrency.
So this language can only be used for small tools and hobby applications?
- No namespaces : what do you do for name clashes if you are importing
multiple libraries? Real example: I am using a third party library that has
bugs. They release a new version, but it has twelve new public classes that
have the same name as that in another third-party library I have. What now?
There's very good reasons why modern languages support namespaces, but Heron
does not seem to address these at all.
- No RTTI: if I were passed a "variant array" of different objects, how
would I verify (or utilize) that they all implement a specific interface?
would the "please pass me IDoThisable" constraint be just a documented? What
if my method can use either IDoThisable or IDoThatable -- there would be no
way for me to choose other try-ing it and catching casting exceptions.
- No "Protected": due to the nature of the inheritance method you are using,
there is no (and possibly can never be) concept of protected access. So
when designing a type I must either decide to break encapsulation and expose
implementation details to the world, or make it extremely difficult (or
impossible) for derived classes to alter that implementation.
And many, many questions (that you may have considered but not answered in
the specs) - some of them:
- How would I call into a library written in a language other than Heron?
- Memory uses reference counting: what is done about circular references?
- If I am extending two interfaces that have type conversion operators to
"int" delegated to two separate classes, which is called? Or do I need to
produce type conversion for any class I create regardless of interfaces
delegated (sounds like repeating lots of work)?
- Streams are used but only have one method of access : the "|>" operator.
How about rewinding? Peeking? Application-defined buffering? And I guess I
don't have to ask about asynchronous reads from slow media, as no
concurrency is allowed.
It seems like a half-baked language. C# is designed and evolving to allow
for real-world usage by the masses - it has constraints imposed on it by the
environments that it must run under, so it does have some quirks. c# doesn't
omit multiple inheritance because the designers think it's useless -- it's
left out because it is such a huge effort to include that the time is deemed
better spent elsewhere.
Boxing and unboxing isn't included in c# as a "feature", it's there to solve
a problem introduced because of design decisions elsewhere (that is, it is
the consequence of a decision to keep the simplicity of "everything is an
object" and still perform acceptably). Yes, it can be difficult for some to
understand -- but removing it would cause larger and more undesirable
problems (in my opinion).
But keep critiquing c# : each time a person does ( if it's informed and
intelligent or not), c# gets another opportunity to either improve or be
better understood.
"christopher diggins" <cd******@videotron.ca> wrote in message
news:V7********************@weber.videotron.net... I have posted a C# critique at http://www.heron-language.com/c-sharp-critique.html. To summarize I bring
up the following issues :
- unsafe code - attributes - garbage collection - non-deterministic destructors - Objects can't exist on the stack - Type / Reference Types - Boxing / Unboxing - Mutability - Classes as Modules and Programs - Polymorphism through Class Inheritance - Interface Delegation - Interface Extensions - C# Missing Template Template Parameters - Late Added Generics - Source File Layout - Public Fields - Special Primitives - Is it a Property or is it a field? - Microsoft
I am perhaps guilty somewhat of being a flame baiting troll, but at the
same time I honestly want to improve on the critique.
Thanks in advance for your responses.
-- Christopher Diggins yet another language designer http://www.heron-language.com
"Jon Skeet [C# MVP]" <sk***@pobox.com> wrote in message up the following issues :
- unsafe code If you don't like it, don't use it. I never have.
When someone else uses it, then I have a problem. i.e. Other assemblies,
libraries, etc. - attributes
Couldn't disagree more - attributes are lovely, when used appropriately. I rarely need to use them. but when I do they're very handy.
I have seen some really dastardly usage of the things by Microsoft hackers.
This is why I compared them to Macros, reminded me of the level of
obfuscation introduced into C++ by MFC. Nonetheless, I removed the macro
comparison, and I am desperately looking for that example I had seen in
order to back up my position. - garbage collection
Yes, you're effectively forced to use garbage collection. I don't see that as a bad thing.
Yes, I can see that for some people that is fine. - non-deterministic destructors
So don't rely on destructors being deterministic. Don't assume the RAII idiom of C++ works in C# - it doesn't. Use the IDisposable idiom instead.
And assuming no one else does neither. Again, problems are not always of our
own creation. - Objects can't exist on the stack
Using reference types for almost everything simplifies things enormously, I find. Then again, I come from a Java background.
It does lead to the boxing/unboxing problem. - Type / Reference Types
No, a type itself doesn't decide whether it'll be on the stack or the heap - not directly, anyway. Reference types will always be on the heap, but value types will be wherever the variable is declared - only local variables and variables within other objects on the stack will be on the stack. Again, I just don't see why this is a problem.
sometype x;
is that a pointer/reference to sometype, or is it a actually an initialized
instance of sometype. Depends on whether sometype is a struct or a class.
That is the problem. The single simple declaration statement is now horribly
unclear. - Boxing / Unboxing
Your example is flawed - boxing will only occur in the case where "anothertype" is object. Otherwise there has to be a user-defined implicit conversion occurring, which is much more dangerous, IMO.
class Test
{
static void Main() {
sometype x;
anothertype y;
x = y; // boxed or unboxed???
y.ModifyState();
// Now what is the state of x?
}
}
Yes thanks for pointing out that my example is flawed. Interestingly enough
so is your explanation. It should be "boxing will only occur in the case
where "sometype" is object.
Boxing can indeed be confusing, but I believe that it's a necessary evil to some extent.
If you want an object to always be a reference, then it is neccessary I
agree. - Mutability
Objects can certainly be immutable - take string, for instance. You can't, however, declare a variable or method to be "const" - is that what you're really after?
Yes I want :
const myobject x;
In other words I want to be able to declare a immutable instance of
myobject. I changed the wording :
"C# does not allow immutable user defined objects."
Am I making sense now? - Classes as Modules and Programs
The System namespace most certainly *shouldn't* export a method called WriteLine. WriteLine is acting on a console, so rightly belongs in a console class. I don't see anything wrong with a type itself having data.
Why shouldn't another namespace export methods? It can be very practical to
define modules that do things without always requiring that the exact object
that provides it. I don't recommend modifying the system namespace, but I
would write a new namespace with long nasty old functions shortened to
somethign more usable.
Just because it isn't object oriented doesn't mean that it isn't a useful
technique.
As for types having their own data. This is a delicate stance that I have
very little support in the OO community for. Essentially my argument is that
the role of a class is to define the implementation, methods and data for
instances. Static data is something we have all gotten used to but is
information that would possibly be better suited for a namespace then in the
class IMHO. - Polymorphism through Class Inheritance - Interface Delegation
Both of these (which are basically one complaint, as far as I can see) are reasonably valid.
- Interface Extensions
Yes, that could be nice.
- C# Missing Template Template Parameters
I don't know enough about generics to comment, but yes, that's possible. Of course, Whidbey hasn't actually shipped yet, so things can still change.
- Late Added Generics
I think there are far better examples here - namely the many collection classes which would have been unnecessary had generics been there at the start.
- Source File Layout
Not sure what you mean by "Heron code", but I agree that usually one class per file is the best option.
- Public Fields
It doesn't violate "the principle of objects" in my view but it's certainly a bad idea. It's not like C# forces you to do this though, and if you're worried about it
- Special Primitives
In what way does it reduce the flexibility of the language? What is the alternative?
- Is it a Property or is it a field?
Assuming you're using classes which follow the conventions, it's always clear what you're doing. I would be reticent to use a library which didn't follow the naming conventions anyway.
- Microsoft
I don't see how you can really compare what MS did with Java to what it can do with C#. C# can already be used in a practical sense outside Windows. Even if it could only be used on Windows, however, that wouldn't make it a useless language by any means.
I am perhaps guilty somewhat of being a flame baiting troll, but at the
same time I honestly want to improve on the critique.
It strikes me that absolutely none of these is a convincing reason not to use C#. A few are interesting ideas for future development, but many just don't seem to be an issue to me.
I agree that no single problem here is enough even for me to reject the
language. But definitely things add up when you start taking two or three.
Thanks for the insightful comments.
--
Christopher Diggins
yet another language designer http://www.heron-language.com
OK ladies and gentlemen, don't feed the troll.
This guy is just trying to gather support for his language (Heron).
For proof of this, one only needs to look at and follow the link that
appears at the bottom of his post and the bottom of his, so called,
"critique" page.
It's perfectly fine that this guy wants to rally support for his "new
language" but he should do it a constructive way, perhaps a "mine vs.
theirs" approach would better support his cause his cause.
The "critique" would be more aptly named, "Why I hate C#"
My 2 cents
Brian W
"christopher diggins" <cd******@videotron.ca> wrote in message
news:V7********************@weber.videotron.net... I have posted a C# critique at http://www.heron-language.com/c-sharp-critique.html. To summarize I bring
up the following issues :
- unsafe code - attributes - garbage collection - non-deterministic destructors - Objects can't exist on the stack - Type / Reference Types - Boxing / Unboxing - Mutability - Classes as Modules and Programs - Polymorphism through Class Inheritance - Interface Delegation - Interface Extensions - C# Missing Template Template Parameters - Late Added Generics - Source File Layout - Public Fields - Special Primitives - Is it a Property or is it a field? - Microsoft
I am perhaps guilty somewhat of being a flame baiting troll, but at the
same time I honestly want to improve on the critique.
Thanks in advance for your responses.
-- Christopher Diggins yet another language designer http://www.heron-language.com
Brian W wrote: For proof of this, one only needs to look at and follow the link that appears at the bottom of his post and the bottom of his, so called, "critique" page.
Or you could just read the very first sentence:
<quote>
This is not a formal critique of C# but more of a personal opinion piece and
a defence of the for my own programming language Heron.
</quote>
--
There are 10 kinds of people. Those who understand binary and those who
don't. http://code.acadx.com
(Pull the pin to reply)
There doesn't need to be a comparative language to be critical of this one.
Jax wrote: I'm not at all an expert on the whole comparison thing between different languages, despite that even I can notice that your trying too hard to criticize C#. What language are you offering as the alternitive? And what problems does that one have?
--
Bret Pehrson
mailto:br**@infowest.com
NOSPAM - Include this key in all e-mail correspondence <<38952rglkwdsl>>
"William Ryan" <do********@nospam.comcast.net> wrote in message
news:%2****************@TK2MSFTNGP09.phx.gbl... 1) Unsafe Code - Sometimes you need it, plain and simple.
Then I would argue it illuminates weakness in the language to begin with.
2) Attributes - Huh? Take for example FileIOPermission attribute...you
can mark 10 different directories with only Read permissions thereby
eliminating the need for checking hardcoded values and ugly branch logic before
reading or writing a file.
You haven't eliminated ugly branch logic. It is just hidden in the
attribute. Because something has been moved into a library and looks pretty
is not sufficient. There are other attributes that people write that are a
complete mystery making understanding someone else's code a real headache
because the branch logic is no longer apparent.
I could go on and on about this, but I think you are way off base here. And you aren't forced to use them...I bet there are tons
of .NET developers that barely know they exist for God's sake.
Yes, but when they use them wrongly it is the biggest nightmare you can
imagine. (i.e. My code doesn't work, oh I see the problem this harmless
little attribute is written wrong).
3- Garbage Collection - Yes, all of the benefits you get from Managed code aren't totally free.
Yep. And some of us just plain don't want a GC. Hence the title, "Why I
don't use C#"
4- Allows non-deterministic destructors - If you dispose of your objects when you are done with them, I'm not sure what the problem is. What
problem is this causing you?
The destructor gets called when the Garbage collector deallocates the
memory. When will that happen?
5- Type/Reference Types.... Dude, there's so few value types I could
recite them off the top of my head. That's hardly a chore and so simple most college CS freshman would love to have that as a Question on a test As far as Objects can't exist on the stack....that's part and parcel to
your other complaint
Plus user defined structs.
7-Mutability - Ok, but what does that stop you from doing? Couldn't you
use Attributes to set the objects value and not provide accessors to change
it?
A guarantee of immutability of object across functions and modules is
important for designing well behaved and correct software.
8-Class as Modules and Programs - <<A static class with only static data
and static methods should either be a module or a program.>> Why?
Okay, I definitely don't have enough ammo to back this one up.
9-Polymorphism - Why can't you use multiple Interfaces?
You can, but you have to redeclare every function in every class that
implements an interface. That can quickly become really unmaintainable with
sophisticated interfaces.
10-Generics and Missing Templates.... ok, they didn't get everything up front, but if you want to use it, use it, if not, don't. Would it be
better for them to not provide this functionality? What if you were just
starting C# programming with the advent of 2.0 and didn't have legacy code?
Wouldn't you want generics?
I am just saying that they missed the boat, and are now grafting it on
painfully with some important features missing.
11- Source File Layout - Can't you get all of that information via reflection or using the CodeModel?
Yes you can. I meant parsing as in reading source code is hard to do.
12 - Public Fields---Not if you don't do it. Is it really Microsoft's responsibilty to ensure that every programmer doesn't violate the rules of OOP?
A language has a responsability to try and make it difficult to write bad
code.
Besides, if they tried stopping this, there'd be so many VB Programmers screaming bloody murder it wouldn't be funny.
Replace them all with properties I say (public fields not the VB
Programmers)
And while I believe that you shouldn't break encapsulation, there are lots of people that have...or have inherited code from people that did and prohibiting it would impede adoption. Say what you want about MS, they bend over
backwards to support legacy code.
C# is a new language, it doesn't need to support legacy code. It is
incompatable with all other languages.
Special Primitives - Once again, so what?
I can't write my own.
13- Is it a field.. If it were a function, you'd see the () around it. Go ahead and try, if
you don't put the parens around it, it won't compile. As testimony to this,
go see how many VB Programmers constantly complain about forgetting the
parens when they call ToString without the Parens.
What I am referring to is that assigning to a property behind the scenes can
map to a Set function call.
And finally, other than the issue of unsafe code which VB.NET doesn't support, aren't all of these related to the CLR and the Framework rather than C#?
Nope. All of these issues are part of the C# specification.
--
Christopher Diggins
yet another language designer http://www.heron-language.com
"babylon" <am***@hotmail.com> wrote in message
news:Oc**************@TK2MSFTNGP09.phx.gbl... I think C#/.Net is great, except that there is no mature Virtual Machine / Class Library for non-windows platform. mono is not a good solution...
Why?
what I want is a truely java-like write once run everywhere
You mean write once, and run everywhere where there is an up to date,
efficient and correct VM installed. "Write once run everywhere" is simply a
marketing catch phrase with no true meaning.
--
Christopher Diggins
yet another language designer http://www.heron-language.com
*** NO MULTIPLE INHERITANCE ***!!!
Biggest fault of C# in my opinion.
christopher diggins wrote: I have posted a C# critique at http://www.heron-language.com/c-sharp-critique.html. To summarize I bring up the following issues :
- unsafe code - attributes - garbage collection - non-deterministic destructors - Objects can't exist on the stack - Type / Reference Types - Boxing / Unboxing - Mutability - Classes as Modules and Programs - Polymorphism through Class Inheritance - Interface Delegation - Interface Extensions - C# Missing Template Template Parameters - Late Added Generics - Source File Layout - Public Fields - Special Primitives - Is it a Property or is it a field? - Microsoft
I am perhaps guilty somewhat of being a flame baiting troll, but at the same time I honestly want to improve on the critique.
Thanks in advance for your responses.
-- Christopher Diggins yet another language designer http://www.heron-language.com
--
Bret Pehrson
mailto:br**@infowest.com
NOSPAM - Include this key in all e-mail correspondence <<38952rglkwdsl>>
"Sami Vaaraniemi" <sa***************@jippii.fi> wrote in message
news:bv**********@phys-news1.kolumbus.fi... While some of your comments about C# do have a point, most of the time the case is that you can work around the issues in one way or another.
Yes I agree there are work-arounds for a good programmer. But nothing to
prevents less experienced programmers from going in and doing a heck of a
lot of damage. My problem is using other people's code, which is crucial for
any kind of serious development.
However, I could not disagree more with what you say about attributes. Attributes allow you to move out code that is not essential to the logic
of your function. E.g.,
// non-attributes version public void DoASensitiveThing() { if (!LookUpUserAuthenticationInfoAndCheckHeHasProperR oles()) throw new AccessDeniedException(); // do the actual logic here }
// attributes version [RolesRequired("Admin")] public void DoASensitiveThing() { // do the actual logic here }
The code is more readable in the version that uses attributes because
things that are not really part of the business logic have been moved out of the code. It makes it easier for the reader to see what is happening because
the business logic is not cluttered with extra code.
That is fine, but then what can appear to be an error in the "actual logic"
could be an error in the attribute itself. Attributes are fine to use in
trivial well written cases, but when everyone and their dog start writing
attributes there will be some serious problems debugging and understanding
non-trivial software.
I do not understand your comparison of attributes with C++ macros. C++ macros are somewhat evil in that they can lead to very obscure and hard to find bugs due to the fact that they are preprocessed, not compiled. The
way macro arguments are evaluated can cause nasty problems due to
side-effects, double-evaluation and operator precedence. Attributes do not suffer from
any of these problems.
Yes I should not have compared attributes to macros in retrospect. I have
updated the critique. But I do wish to say an attribute can just as easily
have unexpected side effect which can be difficult to uncover if it is badly
written. Regards, Sami
Thanks for the good insight and useful points.
--
Christopher Diggins
yet another language designer http://www.heron-language.com
<Ol**********@skyscan.be> wrote in message
news:40**********************@news.skynet.be... - unsafe code I think that if you would not allow mixed managed/unmanaged code, then no one is going to jump on .NET since too much tested code exists and it will take years to port to .NET code. The transition process is slo, but the programs wil become more and more stable.
..NET has nothing to do with C#. C# is a new language specification with no
support for any kind of legacy code whatsoever.
I think that the User interfaces will become more and more pure .NET,the
but the none-user interface functionality will be ported in time.
In Windows world maybe. - Objects can't exist on the stack Objects on the stack are an open door to the dreaded buffer overflows. I think that this is a very good step forward towards stability of the software.
Which dreaded buffer overflow are you referring to? How is allowing structs
on the stack okay while objects aren't?
--
Christopher Diggins
yet another language designer http://www.heron-language.com
Oh, it's not that important. *** NO MULTIPLE INHERITANCE ***!!!
Biggest fault of C# in my opinion.
christopher diggins wrote: I have posted a C# critique at http://www.heron-language.com/c-sharp-critique.html. To summarize I
bring up the following issues :
- unsafe code - attributes - garbage collection - non-deterministic destructors - Objects can't exist on the stack - Type / Reference Types - Boxing / Unboxing - Mutability - Classes as Modules and Programs - Polymorphism through Class Inheritance - Interface Delegation - Interface Extensions - C# Missing Template Template Parameters - Late Added Generics - Source File Layout - Public Fields - Special Primitives - Is it a Property or is it a field? - Microsoft
I am perhaps guilty somewhat of being a flame baiting troll, but at the
same time I honestly want to improve on the critique.
Thanks in advance for your responses.
-- Christopher Diggins yet another language designer http://www.heron-language.com
-- Bret Pehrson mailto:br**@infowest.com NOSPAM - Include this key in all e-mail correspondence <<38952rglkwdsl>>
christopher diggins <cd******@videotron.ca> wrote: - unsafe code If you don't like it, don't use it. I never have.
When someone else uses it, then I have a problem. i.e. Other assemblies, libraries, etc.
Somewhere, there *has* to be unsafe code - otherwise you'll never be
able to access the file system etc. Where do you draw the line? - attributes
Couldn't disagree more - attributes are lovely, when used appropriately. I rarely need to use them. but when I do they're very handy.
I have seen some really dastardly usage of the things by Microsoft hackers. This is why I compared them to Macros, reminded me of the level of obfuscation introduced into C++ by MFC. Nonetheless, I removed the macro comparison, and I am desperately looking for that example I had seen in order to back up my position.
I'd be interested to see it. - non-deterministic destructors
So don't rely on destructors being deterministic. Don't assume the RAII idiom of C++ works in C# - it doesn't. Use the IDisposable idiom instead.
And assuming no one else does neither. Again, problems are not always of our own creation.
If you have a magical language which lets people write libraries but
*not* let them make mistakes in those libraries, I'm all for it. I have
yet to see such a beast. - Objects can't exist on the stack
Using reference types for almost everything simplifies things enormously, I find. Then again, I come from a Java background.
It does lead to the boxing/unboxing problem.
Not necessarily - there's no boxing/unboxing No, a type itself doesn't decide whether it'll be on the stack or the heap - not directly, anyway. Reference types will always be on the heap, but value types will be wherever the variable is declared - only local variables and variables within other objects on the stack will be on the stack. Again, I just don't see why this is a problem.
sometype x;
is that a pointer/reference to sometype, or is it a actually an initialized instance of sometype. Depends on whether sometype is a struct or a class. That is the problem. The single simple declaration statement is now horribly unclear.
If you're planning to use the type, you need to know considerably more
about it anyway - why shouldn't you know whether it's a value type or a
reference type? In practice, I find that value types are rare, beyond
those supplied by the framework itself. - Boxing / Unboxing
<snip>
Yes thanks for pointing out that my example is flawed. Interestingly enough so is your explanation. It should be "boxing will only occur in the case where "sometype" is object.
Yes, true. Mine was flawed due to a typo, though, rather than being an
actually important flaw :)
- Mutability
Objects can certainly be immutable - take string, for instance. You can't, however, declare a variable or method to be "const" - is that what you're really after?
Yes I want :
const myobject x;
In other words I want to be able to declare a immutable instance of myobject. I changed the wording :
"C# does not allow immutable user defined objects."
Am I making sense now?
No, because you can write your own classes which are immutable. What
you can't do is have a class which has some mutable instances and some
immutable instances. - Classes as Modules and Programs
The System namespace most certainly *shouldn't* export a method called WriteLine. WriteLine is acting on a console, so rightly belongs in a console class. I don't see anything wrong with a type itself having data.
Why shouldn't another namespace export methods? It can be very practical to define modules that do things without always requiring that the exact object that provides it. I don't recommend modifying the system namespace, but I would write a new namespace with long nasty old functions shortened to somethign more usable.
The point is that the logical realm of WriteLine is Console -
Console.WriteLine isn't to do with "the system", it's to do with the
console.
If you want to write code with very short names though, don't let me
stop you - I just hope I don't have to read your code. The names in
..NET are generally descriptive without being overly long.
Just because it isn't object oriented doesn't mean that it isn't a useful technique.
As for types having their own data. This is a delicate stance that I have very little support in the OO community for. Essentially my argument is that the role of a class is to define the implementation, methods and data for instances. Static data is something we have all gotten used to but is information that would possibly be better suited for a namespace then in the class IMHO.
But a namespace is precisely that - a space for names. They're not a
"space for stuff there isn't room for elsewhere". Namespaces are
primarily about grouping things and avoiding name collisions. It strikes me that absolutely none of these is a convincing reason not to use C#. A few are interesting ideas for future development, but many just don't seem to be an issue to me.
I agree that no single problem here is enough even for me to reject the language. But definitely things add up when you start taking two or three.
Even then, they really don't, in my view...
--
Jon Skeet - <sk***@pobox.com> http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
I would like to transition this thread to a more appropriate newsgroup so
please post any responses in comp.lang.misc, thank you very much.
----- Original Message -----
From: "Philip Rieck" <st***@mckraken.com>
Newsgroups:
Sent: Monday, January 26, 2004 11:26 AM
Subject: Re: Another C# critique You seem to be championing "Heron" instead of c#, based on the page you linked to.
That is but one link, the critique has enough meat on its bone to stand
alone. I haven't seen yet any serious attempts to critique the language.
However, the available "spec" for Heron is so bare as to be un-critiqueable ( for example you mention calling destructors, but not defining them)
Yes. The published spec is very bare-bones. I need to work on it and I am
actively seeking input and feedback like yours.
However, there are some huge real-world problems already: - here's a very partial list from a quick perusal
I truly appreciate the input.
-it mentions specifically that there will be no support for concurrency. So this language can only be used for small tools and hobby applications?
Your implication is that medium and large sized or non-hobby applications
all require concurrency. I disagree.
- No namespaces : what do you do for name clashes if you are importing multiple libraries? Real example: I am using a third party library that
has bugs. They release a new version, but it has twelve new public classes
that have the same name as that in another third-party library I have. What
now? There's very good reasons why modern languages support namespaces, but
Heron does not seem to address these at all.
Heron requires the unit name as a preface to any name-clashes.
- No RTTI: if I were passed a "variant array" of different objects, how would I verify (or utilize) that they all implement a specific interface? would the "please pass me IDoThisable" constraint be just a documented?
What if my method can use either IDoThisable or IDoThatable -- there would be
no way for me to choose other try-ing it and catching casting exceptions.
Only variants support RTTI. This is not clear, I realize now.
- No "Protected": due to the nature of the inheritance method you are
using, there is no (and possibly can never be) concept of protected access. So when designing a type I must either decide to break encapsulation and
expose implementation details to the world, or make it extremely difficult (or impossible) for derived classes to alter that implementation.
Classes can not derive from other classes in Heron.
And many, many questions (that you may have considered but not answered in the specs) - some of them: - How would I call into a library written in a language other than Heron?
Using the external module.
- Memory uses reference counting: what is done about circular references?
There is no garbage collector. Memory must be freed explicitly, this means
that there is no circular reference problem. I will be explaining this
further in a technical paper soon.
- If I am extending two interfaces that have type conversion operators
to "int" delegated to two separate classes, which is called? Or do I need to produce type conversion for any class I create regardless of interfaces delegated (sounds like repeating lots of work)?
The interface does not have conversion operators, only functions. All
operators are considered as being implementation details and hence are found
in classes not interfaces. A small amount of extra work but makes
programemrs think twice about overusing operators on their classes. The
principle is that Operators are best not overloaded unless extremely useful.
- Streams are used but only have one method of access : the "|>" operator. How about rewinding? Peeking? Application-defined buffering? And I guess
I don't have to ask about asynchronous reads from slow media, as no concurrency is allowed.
Streams have a full compliment of functions but only one operator. The core
library does support asynchronous reads (if available on the target OS).
There just can not be multiple entry points into a Heron program.
It seems like a half-baked language.
Don't be mislead by weaknesses in the specification document, there has been
a lot of work gone into the design of this language.
C# is designed and evolving to allow for real-world usage by the masses - it has constraints imposed on it by
the environments that it must run under, so it does have some quirks. c#
doesn't omit multiple inheritance because the designers think it's useless -- it's left out because it is such a huge effort to include that the time is
deemed better spent elsewhere.
Boxing and unboxing isn't included in c# as a "feature", it's there to
solve a problem introduced because of design decisions elsewhere (that is, it is the consequence of a decision to keep the simplicity of "everything is an object" and still perform acceptably). Yes, it can be difficult for some
to understand -- but removing it would cause larger and more undesirable problems (in my opinion).
But keep critiquing c# : each time a person does ( if it's informed and intelligent or not), c# gets another opportunity to either improve or be better understood.
Thanks for the input on Heron, I appreciate it and will update the spec
shortly to try and address some of the inadequacies you have brought to my
attention.
-
Christopher Diggins
yet another language designer http://www.heron-language.com
Jon and Christopher,
For Christopher's example regarding boxing and unboxing:
class Test
{
static void Main() {
sometype x;
anothertype y;
x = y; // boxed or unboxed???
y.ModifyState();
// Now what is the state of x?
}
}
There is only one way that the code above would compile, and that is if
anothertype was derived from sometype. Since value types can not be derived
from in .NET, so it must be a reference type. The state of x is the state
of y, since x is a reference to the same object that y points to.
--
- Nicholas Paldino [.NET/C# MVP]
- mv*@spam.guard.caspershouse.com
"Jon Skeet [C# MVP]" <sk***@pobox.com> wrote in message
news:MP************************@msnews.microsoft.c om... christopher diggins <cd******@videotron.ca> wrote: > - unsafe code
If you don't like it, don't use it. I never have. When someone else uses it, then I have a problem. i.e. Other assemblies, libraries, etc.
Somewhere, there *has* to be unsafe code - otherwise you'll never be able to access the file system etc. Where do you draw the line?
> - attributes
Couldn't disagree more - attributes are lovely, when used appropriately. I rarely need to use them. but when I do they're very handy.
I have seen some really dastardly usage of the things by Microsoft
hackers. This is why I compared them to Macros, reminded me of the level of obfuscation introduced into C++ by MFC. Nonetheless, I removed the macro comparison, and I am desperately looking for that example I had seen in order to back up my position.
I'd be interested to see it. - non-deterministic destructors
So don't rely on destructors being deterministic. Don't assume the
RAII idiom of C++ works in C# - it doesn't. Use the IDisposable idiom instead.
And assuming no one else does neither. Again, problems are not always of
our own creation.
If you have a magical language which lets people write libraries but *not* let them make mistakes in those libraries, I'm all for it. I have yet to see such a beast. - Objects can't exist on the stack
Using reference types for almost everything simplifies things enormously, I find. Then again, I come from a Java background.
It does lead to the boxing/unboxing problem.
Not necessarily - there's no boxing/unboxing
No, a type itself doesn't decide whether it'll be on the stack or the heap - not directly, anyway. Reference types will always be on the heap, but value types will be wherever the variable is declared - only local variables and variables within other objects on the stack will
be on the stack. Again, I just don't see why this is a problem.
sometype x;
is that a pointer/reference to sometype, or is it a actually an
initialized instance of sometype. Depends on whether sometype is a struct or a
class. That is the problem. The single simple declaration statement is now
horribly unclear.
If you're planning to use the type, you need to know considerably more about it anyway - why shouldn't you know whether it's a value type or a reference type? In practice, I find that value types are rare, beyond those supplied by the framework itself. - Boxing / Unboxing <snip>
Yes thanks for pointing out that my example is flawed. Interestingly
enough so is your explanation. It should be "boxing will only occur in the case where "sometype" is object.
Yes, true. Mine was flawed due to a typo, though, rather than being an actually important flaw :) - Mutability
Objects can certainly be immutable - take string, for instance. You can't, however, declare a variable or method to be "const" - is that what you're really after?
Yes I want :
const myobject x;
In other words I want to be able to declare a immutable instance of myobject. I changed the wording :
"C# does not allow immutable user defined objects."
Am I making sense now?
No, because you can write your own classes which are immutable. What you can't do is have a class which has some mutable instances and some immutable instances.
> - Classes as Modules and Programs
The System namespace most certainly *shouldn't* export a method called WriteLine. WriteLine is acting on a console, so rightly belongs in a console class. I don't see anything wrong with a type itself having data.
Why shouldn't another namespace export methods? It can be very practical
to define modules that do things without always requiring that the exact
object that provides it. I don't recommend modifying the system namespace, but
I would write a new namespace with long nasty old functions shortened to somethign more usable.
The point is that the logical realm of WriteLine is Console - Console.WriteLine isn't to do with "the system", it's to do with the console.
If you want to write code with very short names though, don't let me stop you - I just hope I don't have to read your code. The names in .NET are generally descriptive without being overly long.
Just because it isn't object oriented doesn't mean that it isn't a
useful technique.
As for types having their own data. This is a delicate stance that I
have very little support in the OO community for. Essentially my argument is
that the role of a class is to define the implementation, methods and data
for instances. Static data is something we have all gotten used to but is information that would possibly be better suited for a namespace then in
the class IMHO.
But a namespace is precisely that - a space for names. They're not a "space for stuff there isn't room for elsewhere". Namespaces are primarily about grouping things and avoiding name collisions. It strikes me that absolutely none of these is a convincing reason not to use C#. A few are interesting ideas for future development, but
many just don't seem to be an issue to me.
I agree that no single problem here is enough even for me to reject the language. But definitely things add up when you start taking two or
three. Even then, they really don't, in my view...
-- Jon Skeet - <sk***@pobox.com> http://www.pobox.com/~skeet If replying to the group, please do not mail me too
Replies inline:
"christopher diggins" <cd******@videotron.ca> wrote in message
news:Gj*****************@weber.videotron.net... "Jon Skeet [C# MVP]" <sk***@pobox.com> wrote in message up the following issues :
- unsafe code If you don't like it, don't use it. I never have.
When someone else uses it, then I have a problem. i.e. Other assemblies, libraries, etc.
1. Why do you have a problem? because they are accomplishing what they
advertise? If you just don't want other people to call unsafe code, then
you can stop it - the CLR supports code access security and verifiability
concetpts that allow you to limit the access of running code, or code you
call (in fact, you have your code set up an appdomain and limit the library
to a small subset of permissions).
2. Then do you have a problem with calling COM objects or native functions
(p/invoke) from C#? Both are much more "unsafe", but both are required to
accomplish many tasks. - attributes Couldn't disagree more - attributes are lovely, when used appropriately. I rarely need to use them. but when I do they're very handy.
I have seen some really dastardly usage of the things by Microsoft
hackers. This is why I compared them to Macros, reminded me of the level of obfuscation introduced into C++ by MFC. Nonetheless, I removed the macro comparison, and I am desperately looking for that example I had seen in order to back up my position.
I've sen dastardly usage of lots of different simple syntaxes from lots of
different languages. People will always write unreadable code. My firm
opinion is that attributes do not signifigantly increase this ability to
write unreadable code, yet provide enourmous value. If you've never
utilized custom attributes, you may not realize the functionality they
provide, and the difficulty in implementing this functionality without them. - garbage collection
Yes, you're effectively forced to use garbage collection. I don't see that as a bad thing.
Yes, I can see that for some people that is fine.
This is a no-win argument. I like GC'd apps, because of my time having to
write and maintain large libraries in C++ (where the #1 through #10 problems
were memory leaks or other memory management issues). Some people feel
strongly that they can manually code much better memory management in each
application. I normally smirk when I hear it, because I've looked at lots
of code with problems, but it is possible. However, I applaud them for not
making it optional. Look at managed C++, and the trials of writing
unmanaged and managed object code side by side. - non-deterministic destructors
So don't rely on destructors being deterministic. Don't assume the RAII idiom of C++ works in C# - it doesn't. Use the IDisposable idiom instead.
And assuming no one else does neither. Again, problems are not always of
our own creation.
A poorly written library is going to be poorly written, no matter what. in
a RAII-type world, they can make mistakes. in the IDisposable workd, they
can make mistakes.... are you saying that c++ is less prone to resource
management mistakes by library vendors than c#? - Objects can't exist on the stack Using reference types for almost everything simplifies things enormously, I find. Then again, I come from a Java background.
It does lead to the boxing/unboxing problem.
You mean using value types leads to boxing. using reference types for
everything removes boxing, as they are not boxed. - Type / Reference Types No, a type itself doesn't decide whether it'll be on the stack or the heap - not directly, anyway. Reference types will always be on the heap, but value types will be wherever the variable is declared - only local variables and variables within other objects on the stack will be on the stack. Again, I just don't see why this is a problem.
sometype x;
is that a pointer/reference to sometype, or is it a actually an
initialized instance of sometype. Depends on whether sometype is a struct or a class. That is the problem. The single simple declaration statement is now
horribly unclear.
No, x will not be any of the above, no matter what sometype is. It will not
be an instance of sometype, an intitialized instance, or a pointer to
anything.
sometype x;
What that line says (clearly) is that I have a variable of type "sometype"
named "x" to be initialized later.
It may be an "int" (or a struct) , in which case the actual memory it
contains may (or may not) contain zeros, but it doesn't matter, since I cant
read the value until I initialize the variable. - Boxing / Unboxing Your example is flawed - boxing will only occur in the case where "anothertype" is object. Otherwise there has to be a user-defined implicit conversion occurring, which is much more dangerous, IMO.
class Test { static void Main() { sometype x; anothertype y; x = y; // boxed or unboxed??? y.ModifyState(); // Now what is the state of x? } }
Yes thanks for pointing out that my example is flawed. Interestingly
enough so is your explanation. It should be "boxing will only occur in the case where "sometype" is object.
Boxing can indeed be confusing, but I believe that it's a necessary evil to some extent. If you want an object to always be a reference, then it is neccessary I agree.
- Mutability
Objects can certainly be immutable - take string, for instance. You can't, however, declare a variable or method to be "const" - is that what you're really after?
Yes I want :
const myobject x;
In other words I want to be able to declare a immutable instance of myobject. I changed the wording :
"C# does not allow immutable user defined objects."
Am I making sense now?
Sort of. By immutable do you mean that 1) all properties are read only? or
2) do you mean that you want to create a field of some type that has public,
writeable properties, and mark it const so that nothing that you pass it to
can modify those properties?
I'm sure it isn't 1), as that would mean you haven't used c#.
If it's 2) then a class marked "const" would have to be written to support
it anyway - in that case why not use a factory pattern and access modifiers
and stick to well resarched and documented practices instead?
[snip out things which I may not agree with but have no response to at this
time.] - Polymorphism through Class Inheritance - Interface Delegation
Both of these (which are basically one complaint, as far as I can see) are reasonably valid.
I don't think they are all that valid, but I may be wrong.
Wouldn't "interface delegation" simply be a shortcut of implementing each
interface function and calling a member object's methods instead? While
this syntactic sugar might be nice, it really doesn't give you anything
else. In fact, with explicit implementation, you can "delegate" one
interface to different members based on call or on condition.
However, removing class inheritance means that you must treat all your
parameters as an interface, not an object if you want to support
extensibility. (since there is no "is-a" type relationship). That means
that you must have an interface tree as large as your object tree. If your
interfaces can not support inheritance, then have to implement every
interface in the tree in each object as well. - Interface Extensions
Yes, that could be nice.
Interface extensions: do you mean like to abstract classes with abstract
member functions, except in interfaces? I would argue that when you start
writing implementation in an interface (even if it's just calling members of
the same interface), it is now a class.
[snip]
I agree that no single problem here is enough even for me to reject the language. But definitely things add up when you start taking two or three.
Thanks for the insightful comments.
-- Christopher Diggins yet another language designer http://www.heron-language.com
C# does have some faults. I agree on public fields, especially... but it
has fewer than any I've used in production. And it does come with some
shackles (MS-only, CLR-only). But as that's where I am anyway they are not
issues to me (and are in fact plusses).
But I'll use it until a better alternative comes along. And from what I've
read on your site, Heron is not it. Perhaps it will be. I do wish you
luck. However, when and if that happens, promote by telling me why I
should use it instead of the "I hate c#" rant. Give me a reason to want to
try it. Give me a Pet Shop example with less code and/or more readable
code. Tell me how I can use it to go home earlier at night.
"Brian W" <brianw@gold_death_2_spam_rush.com> wrote in message
news:OP**************@TK2MSFTNGP12.phx.gbl... OK ladies and gentlemen, don't feed the troll.
This guy is just trying to gather support for his language (Heron).
Yes this is part of my motive. I also want to look critically at other
languages and have my ideas exposed to the best kind of critical reading
available.
For proof of this, one only needs to look at and follow the link that appears at the bottom of his post and the bottom of his, so called, "critique" page.
Proven.
It's perfectly fine that this guy wants to rally support for his "new language" but he should do it a constructive way, perhaps a "mine vs. theirs" approach would better support his cause his cause.
Identifying potential weaknesses in a language is productive. Or should I
just roll over and say C# is just fine. At least I am being honest with
regards to my bias as opposed to thinly disguising it in a "mine vs theirs
approach".
The "critique" would be more aptly named, "Why I hate C#"
Are you suggesting that the critique is entirely baseless? I would
appreciate it if you could have shown some kind of weakness to my article
rather than criticizing it because I link to my own language at the bottom.
--
Christopher Diggins
yet another language designer http://www.heron-language.com
"Jon Skeet [C# MVP]" <sk***@pobox.com> wrote in message
news:MP************************@msnews.microsoft.c om... When someone else uses it, then I have a problem. i.e. Other assemblies, libraries, etc. Somewhere, there *has* to be unsafe code - otherwise you'll never be able to access the file system etc. Where do you draw the line?
Best left to a standard library I would suggest, don't let every amateur
programmer hack using unsafe contexts. I think unsafe context is a cheap
workaround.
If you have a magical language which lets people write libraries but *not* let them make mistakes in those libraries, I'm all for it. I have yet to see such a beast.
That is just a bait and switch argument. It is an over-generalization of
what I am trying to suggest. A high level language has a responsability to
make it more diffcult for programmers to shoot themselves in the foot as
opposed to easier. > - Objects can't exist on the stack
Using reference types for almost everything simplifies things enormously, I find. Then again, I come from a Java background.
It does lead to the boxing/unboxing problem.
Not necessarily - there's no boxing/unboxing
I meant boxing/unboxing is needed to unify a type system that is un-unified
to being with (i.e. every object is a reference)
If you're planning to use the type, you need to know considerably more about it anyway - why shouldn't you know whether it's a value type or a reference type? In practice, I find that value types are rare, beyond those supplied by the framework itself.
I think it is easier for a programmer when there is a consistent treatment
of types. Otherwise you need to look up too much in order to decode
statements
like : x = y;
Yes, true. Mine was flawed due to a typo, though, rather than being an actually important flaw :)
I still significantly dislike boxing.
No, because you can write your own classes which are immutable. What you can't do is have a class which has some mutable instances and some immutable instances.
Okay. I stand corrected again. I can't have classes with both mutable and
immutable instances. That is still the same problem as was so clumsily
trying to refer to previously.
The point is that the logical realm of WriteLine is Console - Console.WriteLine isn't to do with "the system", it's to do with the console.
Scope is different than logical realms. Every programmer should be able to
decide his/her own problem realms and place things accordingly where they
find most appropriate. For example in my software I always include a general
purpose unit (I mostly use Delphi) with a couple hundred useful utility
functions. It is nice to not always have to preface them with some kind of
"Utility.".
But a namespace is precisely that - a space for names. They're not a "space for stuff there isn't room for elsewhere". Namespaces are primarily about grouping things and avoiding name collisions.
And so are pascal style units. There is no reason to force programmers to
prefix everything. Leaving it as an option is better. Globally scoped does
not automatically mean bad nor does it mean automatically unresolvable name
clashes. It strikes me that absolutely none of these is a convincing reason not to use C#. A few are interesting ideas for future development, but
many just don't seem to be an issue to me.
I agree that no single problem here is enough even for me to reject the language. But definitely things add up when you start taking two or
three. Even then, they really don't, in my view...
That is your perogative.
-
Christopher Diggins
yet another language designer http://www.heron-language.com
christopher diggins wrote: "Sami Vaaraniemi" <sa***************@jippii.fi> wrote in message news:bv**********@phys-news1.kolumbus.fi... While some of your comments about C# do have a point, most of the time the case is that you can work around the issues in one way or another.
Yes I agree there are work-arounds for a good programmer. But nothing to prevents less experienced programmers from going in and doing a heck of a lot of damage. My problem is using other people's code, which is crucial for any kind of serious development.
Which is true for just about every language feature. Writing good programs
always has required and always will require thoughful use of the language
features one has at his/her disposal. As always: A fool with a tool (or C#
for that matter) is still a fool.
One *can* write much more expressive code because of C# attributes and
that's all that matters. BTW, the same is true for C++ macros (much less
frequently though).
Regards,
Andreas
Sorry about editing the original post so heavily, most of the stuff I
snipped was because I was agreeing with Philip and need to update my
critique :)
"Philip Rieck" <st***@mckraken.com> wrote in message > "christopher diggins"
<cd******@videotron.ca> wrote in message 1. Why do you have a problem? because they are accomplishing what they advertise? If you just don't want other people to call unsafe code, then you can stop it - the CLR supports code access security and verifiability concetpts that allow you to limit the access of running code, or code you call (in fact, you have your code set up an appdomain and limit the
library to a small subset of permissions).
This is true.
2. Then do you have a problem with calling COM objects or native functions (p/invoke) from C#? Both are much more "unsafe", but both are required to accomplish many tasks.
I see your point but unsafe contexts across languages is different than
unsafe contexts within the same language. I do see some utility in unsafe
contexts. I am just not convinced it is the best solution. > - non-deterministic destructors
So don't rely on destructors being deterministic. Don't assume the
RAII idiom of C++ works in C# - it doesn't. Use the IDisposable idiom instead.
And assuming no one else does neither. Again, problems are not always of
our own creation.
A poorly written library is going to be poorly written, no matter what.
in a RAII-type world, they can make mistakes. in the IDisposable workd, they can make mistakes.... are you saying that c++ is less prone to resource management mistakes by library vendors than c#?
I would say that C++ with non-deterministic finalizers, would be a much
worse C++. That's all. > - Type / Reference Types No, x will not be any of the above, no matter what sometype is. It will
not be an instance of sometype, an intitialized instance, or a pointer to anything.
sometype x; What that line says (clearly) is that I have a variable of type "sometype" named "x" to be initialized later.
It may be an "int" (or a struct) , in which case the actual memory it contains may (or may not) contain zeros, but it doesn't matter, since I
cant read the value until I initialize the variable.
My error, I didn't realize that a struct doesn't have default constructors.
I also managed to get myself confused in a couple of other respects.
By immutable do you mean that 1) all properties are read only? or 2) do you mean that you want to create a field of some type that has
public, writeable properties, and mark it const so that nothing that you pass it
to can modify those properties?
I'm sure it isn't 1), as that would mean you haven't used c#.
If it's 2) then a class marked "const" would have to be written to support it anyway - in that case why not use a factory pattern and access
modifiers and stick to well resarched and documented practices instead?
You are arguing then that const is pointless? And it seems you are
suggesting it is not a well researched and documented practice? > - Polymorphism through Class Inheritance > - Interface Delegation
Both of these (which are basically one complaint, as far as I can see) are reasonably valid.
I don't think they are all that valid, but I may be wrong. Wouldn't "interface delegation" simply be a shortcut of implementing each interface function and calling a member object's methods instead?
Yes that is exactly what it is.
While this syntactic sugar might be nice, it really doesn't give you anything else.
It saves you writing out potentially hundreds of trivial interface function
implementations for every class.
In fact, with explicit implementation, you can "delegate" one interface to different members based on call or on condition.
Yes explicit implementation is not replaced by delegation techniques but
complimented.
However, removing class inheritance means that you must treat all your parameters as an interface, not an object if you want to support extensibility. (since there is no "is-a" type relationship). That means that you must have an interface tree as large as your object tree.
As large as your *original* object tree. The interface tree supplants the
object tree.
If your interfaces can not support inheritance, then have to implement every interface in the tree in each object as well.
Interfaces can support inheritance in Heron, Java, C#, Delphi and most all
other languages with interfaces. > - Interface Extensions
Yes, that could be nice.
Interface extensions: do you mean like to abstract classes with abstract member functions, except in interfaces? I would argue that when you start writing implementation in an interface (even if it's just calling members
of the same interface), it is now a class.
It is similar to an abstract class with function defintions but it
differentiates itself by not allowing member data.
But I'll use it until a better alternative comes along. And from what
I've read on your site, Heron is not it. Perhaps it will be. I do wish you luck. However, when and if that happens, promote by telling me why I should use it instead of the "I hate c#" rant. Give me a reason to want to try it. Give me a Pet Shop example with less code and/or more readable code. Tell me how I can use it to go home earlier at night.
I will take you up on that offer at some point soon in the future Philip and
thanks for the good wishes.
--
Christopher Diggins
yet another language designer http://www.heron-language.com
christopher diggins <cd******@videotron.ca> wrote: When someone else uses it, then I have a problem. i.e. Other assemblies, libraries, etc. Somewhere, there *has* to be unsafe code - otherwise you'll never be able to access the file system etc. Where do you draw the line?
Best left to a standard library I would suggest, don't let every amateur programmer hack using unsafe contexts. I think unsafe context is a cheap workaround.
Most of the time, libraries *won't* use unsafe code, and as another
poster pointed out, you can always make sure that you *don't* use
unsafe code using the attributes you so dislike. If you have a magical language which lets people write libraries but *not* let them make mistakes in those libraries, I'm all for it. I have yet to see such a beast.
That is just a bait and switch argument.
Not really - it's a "criticising something for not doing the impossible
is unreasonable" argument.
It is an over-generalization of what I am trying to suggest. A high level language has a responsability to make it more diffcult for programmers to shoot themselves in the foot as opposed to easier.
And C# does that. It just doesn't make it *impossible* for programmers
to shoot themselves in the foot. Not necessarily - there's no boxing/unboxing
I meant boxing/unboxing is needed to unify a type system that is un-unified to being with (i.e. every object is a reference)
Yes, boxing is needed for that. I really don't see there's that much of
a problem though. If you're planning to use the type, you need to know considerably more about it anyway - why shouldn't you know whether it's a value type or a reference type? In practice, I find that value types are rare, beyond those supplied by the framework itself.
I think it is easier for a programmer when there is a consistent treatment of types. Otherwise you need to look up too much in order to decode statements like : x = y;
All you've got to know is whether or not x is of type "object" and y is
a value type. Other than that (assuming implicit conversions aren't
going on, which are a whole different matter), there won't be boxing.
Do you often have that situation? I rarely use variables of type
"object" myself. Yes, true. Mine was flawed due to a typo, though, rather than being an actually important flaw :)
I still significantly dislike boxing.
It's something to be avoided where possible, but I don't think it's
nearly as bad as you make out. No, because you can write your own classes which are immutable. What you can't do is have a class which has some mutable instances and some immutable instances.
Okay. I stand corrected again. I can't have classes with both mutable and immutable instances. That is still the same problem as was so clumsily trying to refer to previously.
Right. Lack of const-correctness is indeed a shame. I believe MS are
looking into this for a future version, and I know there's a modified
version of Rotor available which *does* support it. The point is that the logical realm of WriteLine is Console - Console.WriteLine isn't to do with "the system", it's to do with the console.
Scope is different than logical realms. Every programmer should be able to decide his/her own problem realms and place things accordingly where they find most appropriate. For example in my software I always include a general purpose unit (I mostly use Delphi) with a couple hundred useful utility functions. It is nice to not always have to preface them with some kind of "Utility.".
I disagree for almost all cases, as it shows exactly where the method
is coming from, which I believe is a good thing. I believe C# v2 will
have something to satisfy you though, just as Java 1.5 will. But a namespace is precisely that - a space for names. They're not a "space for stuff there isn't room for elsewhere". Namespaces are primarily about grouping things and avoiding name collisions.
And so are pascal style units. There is no reason to force programmers to prefix everything. Leaving it as an option is better. Globally scoped does not automatically mean bad nor does it mean automatically unresolvable name clashes.
No, but it makes them more likely, and makes the code harder to
understand to someone not intimately familiar with the codebase.
--
Jon Skeet - <sk***@pobox.com> http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
"christopher diggins" <cd******@videotron.ca> wrote in message
news:V7********************@weber.videotron.net... I have posted a C# critique at http://www.heron-language.com/c-sharp-critique.html. To summarize I bring
up the following issues :
[snip] I am perhaps guilty somewhat of being a flame baiting troll, but at the
same time I honestly want to improve on the critique.
Thanks in advance for your responses.
-- Christopher Diggins yet another language designer http://www.heron-language.com
Unsafe Code: Mixing regular code with unsafe code means that any security and
robustness guarantees can too easily be overridden. A garbage collector which is overridden is
pointless. The problem surfaces when multiple people work together on a large project.
Ideal - if everything were in managed space. However, and I find this to be
one of Java's weaknesses, was it's interface to existing code (most of which
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 i
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.
Attributes: Code quickly becomes extremely illegible when attributes are used.
Attributes result in essentially an obfuscation of the language specification and expected
behaviour. Debugging code becomes trickier when attributes have potentially subtle side effects.
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 didn't
are recently seeing its adoption. However, the obfuscation part hardly
seems like a justifiable case for your argument against attributes, because
if we were to replace "attributes" with a compiler or library function, you
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 language,
other than assembly with no macros, whether it has declaritive elements or
not would be guilty of the same crime.
Garbage Collection: You are effectively forced to use garbage collection. Turning off the
garbage collection in C# can lead to extremely subtle and hard to find bugs due to a mix of garbage
collected and non-garbage collected code. Turning off garbage collection can only be done by
switching to an unsafe context with all of what that implies.
I see several problems with this argument. First of all is the inconsistancy
of your arguments. Remember the first point I made above that I said i would
revisit? You wanted the language to be less flexible in favor of enforcing
robustness (which you are happy to point out elsewhere in your dissertation
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. GC
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."
C# allows non-deterministic destructors: Garbage collection with destructors means the destructors can be called at
unpredicatable moments during execution.
That is the nature of GC. The thing to remember is: you shouldn't use
destructors for deterministic management (eg. clean-up) of resource (that's
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 opinion
is valid, because the only way to get deterministic finalization, is if the
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 that
clean-up code is being called "now", use Dispose. That is deterministic. Of
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 ;-)
Objects can't exist on the stack We are forced to use structs if we want to create an object which exists
on the stack. This can cause problems for users of a library which has locked in an object
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 hell..
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 the
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 going
to more or less look exactly the same from his point of view for that member
invokation.
But lets look at the flipside of the coin. Why would you want objects on the
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 the
increment of the allocation pointer, making it almost exactly the same as
stack allocation in terms of performance. To make reference types available
on the stack, you'd have to change GC infrastructure, which would
effectively make reference type allocation on the stack SLOWER. In addition,
value types are rather small in comparison with reference types, especially
if you consider strings, which make up the majority of data in a program. Do
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#.
Type / Reference Types A type decides whether it will be on the stack or the heap. Which means a
programmer has to be aware of each types specific semantics when using it to know whether they
are passing things by reference or by value. This leads to subtle and confusing bugs.
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.
Boxing / Unboxing The semantics of boxing and unboxing are subtle and confusing. There is a
problem of needing to know too much information about a type to decode the semantics of a simple
assignment. Boxing is a feature designed to compensate for the fact that objects must be used
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 to
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 it
were not for boxing/unboxing, the programmer would have to be far MORE aware
of the details of the type implementations and code such scenarios
SEPARATELY.
Mutability C# does not allow declaration of immutable instances of user defined
objects.
I understand what you want to do here - create a const instance of a class.
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 data
imbedded in the program (as it can easily do for numbers and strings because
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 in
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 - value
types have no constructors.
Also, the lack of literal declarations doesn't mean you can't have immutable
objects. You can certainly program immutable objects in C#. Again, you might
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.
Classes as Modules and Programs C# allows static information within a class and not outside of one.
Therefore a class in C# has concepts that are a hack designed to compensate for missing modules.
Classes and modules are very distinct concepts that deserve to be treated as seperate
identities. When we do so, as in Heron and Object Pascal, the semantics of classes is simplified
somewhat. One example of where not being allowed to place data into the global scope of a namespace is
noticeably lacking : using System; class Hello { static void Main() { Console.WriteLine("hello, world"); } } The System namespace can not export a function named WriteLine it can
only export static classes. A static class with only static data and static methods should either be a
module or a program. It could be argued all static data should occur outside of classes since it
is not directly related to objects themselves.
Not sure I agree completely with you here. First of all Classes and modules
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 perfectly
capable of performing both roles. Your gripe seems to be more about the
invokation syntax, which is purly compiler syntactical sugar and a few rules
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 VB
compiler also allows you to invoke said members without qualifying it to the
module's (class') name - in essence letting you "export" what appears to be
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 there
are a lot of people that prefer it the way it is rather than the way VB.NET
does it. For starters, you are introducing a level of ambiguity and issues
revolving around name resolution that otherwise wouldn't be there... and for
a guy who doesn't like ambiguity, this argument seems rather contradictory
with your previous line of thinking.
Polymorphism through Class inheritance C# supports polymorphism only through class inheritance. Class inheritance
does not encapsulate code as well as interface delegations. Interface implementations can not be
delegated to member fields. Every time you want to implement an interface you must explicitly write all of
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 to
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.
C# Missing Template Template Parameters In C#, a generic type parameter cannot itself be a generic, although
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 allowing
this. There was a rather good explanation in one of the blogs (probably
reachable via C# Corner).
Late Added Generics By adding generics so late, among other things there is the pointless
redundancy of having two kinds of arrays. The int a[]; and array<int> a;
Not a good argument at all. First of all, few languages support generics to
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 a
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?
Special Primitives Special rules exist for so-called "primitive" types. This significantly
reduces the expressiveness and flexibility of the language. The programmer can not add
new types that are at fully at par with existing primitives.
What on earth are you tryign to do with user-defined types that can only be
done with primitives?
Remember that the compiler has no earthly idea what to do with types nobody
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.
Source File Layout C-Sharp code is not readable without automatic documenting tools or
editor. It takes a long time to read a source file and find out what classes are
included and what the member fields and methods of those classes are. This promotes an
unstructured coding style and often leads to bugs that are not immediately obvious without reading the
automatically generated documentation.
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 like
any C languages, why are you even critiquing C# specifically?
Public Fields Classes can expose their fields as being public. This violates the
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 performance
hit of going through an accessor/mutator method. And before you cry
"HERASY!", remember, best practices are there to stop people who can't think
from doing dumb things - not there to prevent people from thinking.
Is it a property or is it a field? Are you setting a field named m or are you calling a property which leads
to a function which can throw an exception? A language should allow only properties or only
public fields but having both gives us the worst of both worlds.
If a tree falls in the woods, and nobody is around to hear it, does it make
a sound? If you use proper exection handling, does it matter?
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 scientific
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 worth-while
critique would leave you with a rather slim list. Your page stopped being a
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 in
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). People
can argue over a true critique, but its merits will weather those arguments
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]
>> A poorly written library is going to be poorly written, no matter what. in a RAII-type world, they can make mistakes. in the IDisposable workd, they can make mistakes.... are you saying that c++ is less prone to resource management mistakes by library vendors than c#?
I would say that C++ with non-deterministic finalizers, would be a much worse C++. That's all.
Why? Are you suggesting that GC, Finalization and Dispose is more
error-prone than C++ style reference-counted pointers and RAII?
Regards,
Andreas
> > > - unsafe code I think that if you would not allow mixed managed/unmanaged code, then
no one is going to jump on .NET since too much tested code exists and it
will take years to port to .NET code. The transition process is slo, but the programs wil become more and more stable.
.NET has nothing to do with C#. C# is a new language specification with no support for any kind of legacy code whatsoever.
I was refering to 2 situations regarding unsafe code.
1. C++ .NET creates mixed managed/unmanaged code .NET dll's. In my opinion
these contain "unsafe code".
I program in C# but uses these (unsafe) C++ dll's in order to have something
operational. No need in 2 years development throwing in the garbage and
restart redesigning from scratch.
2. I also convert existing C++ source code to C# code and in that case,
unsafe block is the closest thing to the original C++ code, and the fastest
way to convert things.
I would be crazy to tell my boss that I need 2 years development before he
gets the next release of the version of the program that does exactly the
same thing I have now. No, I prefer to start using C# using existing and
tested unsafe C++ code, to extend my program, and when I find time the
unsafe C++ code gets converted to safe C#.
Basically I would never jump to C# if I didn't have the possibility for
unsafe code in the transition process.
> > > - Objects can't exist on the stack Objects on the stack are an open door to the dreaded buffer overflows. I think that this is a very good step forward towards stability of the software.
Which dreaded buffer overflow are you referring to? How is allowing
structs on the stack okay while objects aren't?
It isn't!! Structs on the stack can cause buffer overflows too, this is why
I avoid the struct in the first place and use the class instead.
I only have one struct in my code, and that is to dynamically map a record
to a file that I read in. This file has variable size records.
Bufferoverflows will still exist in classes, but if they are not located on
the stack, then it cannot be misused by worms and viruses as return address
to execute code.
> *** NO MULTIPLE INHERITANCE ***!!! Biggest fault of C# in my opinion.
Multiple enheritance makes the code pretty complex and almost unreadable
adding more potential bugs to the code!
So far I never needed it, and I did write >1 million lines of code in Delphi
and C++ in the last 11 years.
<Ol**********@skyscan.be> wrote: It isn't!! Structs on the stack can cause buffer overflows too, this is why I avoid the struct in the first place and use the class instead.
In safe code, you can't have buffer overflows. If you believe you can,
please give an example.
--
Jon Skeet - <sk***@pobox.com> http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
> > C# allows non-deterministic destructors: Garbage collection with destructors means the destructors can be called
at unpredicatable moments during execution. That is the nature of GC. The thing to remember is: you shouldn't use destructors for deterministic management (eg. clean-up) of resource
(that's 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
opinion is valid, because the only way to get deterministic finalization, is if
the 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
that clean-up code is being called "now", use Dispose. That is deterministic.
Of 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 ;-)
In my opinion, Constructors and Destructors should only perform actions that
guarantees that it will not crash.
Mainly initializing variables, allocating memory, copying,....
Then we have a second set of methods that actually open an close
files/resources/connection/....
This way, a file is closed, memory freed, connections closed,... outside the
destructor and it doesn't matter then when the destructor is then called.
> > It isn't!! Structs on the stack can cause buffer overflows too, this is
why I avoid the struct in the first place and use the class instead.
In safe code, you can't have buffer overflows. If you believe you can, please give an example.
Probably not, but if you use structs then you also probably need unsafe code
blok too because I do not see any other reason to use Structs than to map
the structs to a memory block. For example, loading a file in binary data
and map the structs to that memory in a dynamic way.
I would not know why I would use structs for something else.
<Ol**********@skyscan.be> wrote: It isn't!! Structs on the stack can cause buffer overflows too, this is why I avoid the struct in the first place and use the class instead. In safe code, you can't have buffer overflows. If you believe you can, please give an example.
Probably not
More than that - definitely not!
but if you use structs then you also probably need unsafe code blok too because I do not see any other reason to use Structs than to map the structs to a memory block.
So you don't use ints, DateTimes, bytes etc yourself? Those are all
structs.
I would not know why I would use structs for something else.
Convenient stack-based allocation, basically, and simple value
semantics.
--
Jon Skeet - <sk***@pobox.com> http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
> > > > It isn't!! Structs on the stack can cause buffer overflows too, this
is > why I avoid the struct in the first place and use the class instead.
In safe code, you can't have buffer overflows. If you believe you can, please give an example.
Probably not
More than that - definitely not!
Don't bet on that "definitely not!".
Hackers are very resourcefull people you know. I would not know why I would use structs for something else.
Convenient stack-based allocation, basically, and simple value semantics.
I very rarely need these things like that so far.
I avoid custom made Structs, I prefer to use the classes instead, far more
flexibel in use.
Ints, DateTime and other generic structs are logical to use, but so far even
in C++ I do not need custom structs unless using it as a memory mapper.
Everyone programs in a different way. ;-)
"Andreas Huber" <ah****@gmx.net> wrote in message
news:40**********@news.bluewin.ch... A poorly written library is going to be poorly written, no matter what. in a RAII-type world, they can make mistakes. in the IDisposable workd, they can make mistakes.... are you saying that c++ is less prone to resource management mistakes by library vendors than c#?
I would say that C++ with non-deterministic finalizers, would be a much worse C++. That's all.
Why? Are you suggesting that GC, Finalization and Dispose is more error-prone than C++ style reference-counted pointers and RAII?
No I am not suggesting that, you are mis-attributing something that is
completely unrelated to what I stated.
--
Christopher Diggins
yet another language designer http://www.heron-language.com
"Andreas Huber" <ah****@gmx.net> wrote in message
news:40**********@news.bluewin.ch... christopher diggins wrote: "Sami Vaaraniemi" <sa***************@jippii.fi> wrote in message news:bv**********@phys-news1.kolumbus.fi... While some of your comments about C# do have a point, most of the time the case is that you can work around the issues in one way or another. Yes I agree there are work-arounds for a good programmer. But nothing to prevents less experienced programmers from going in and doing a heck of a lot of damage. My problem is using other people's code, which is crucial for any kind of serious development.
Which is true for just about every language feature. Writing good programs always has required and always will require thoughful use of the language features one has at his/her disposal. As always: A fool with a tool (or C# for that matter) is still a fool. One *can* write much more expressive code because of C# attributes and that's all that matters. BTW, the same is true for C++ macros (much less frequently though).
The argument that all features that increase flexibility are neccessarily
equally good falsely assumes that all potential for programmer error are
also equivalent. Some language features lead to relatively insignficant
bugs, while others lead to potential disastrous consequences. For more on
the differences between classes of programmer error see my article on scale
of magnitude for Programmer Error in Programming Languages at http://www.heron-language.com/scale-of-errors.html.
On the other hand to lend support to your argument there is a definite
advantage of increased expressiveness. I need to give credit to C# for
achieving that.
Regards,
Andreas
--
Christopher Diggins
yet another language designer http://www.heron-language.com
"Rob Teixeira [MVP]" <RobTeixeira@@msn.com> wrote in message
news:eS**************@TK2MSFTNGP09.phx.gbl... Unsafe Code: Mixing regular code with unsafe code means that any security and robustness guarantees can too easily be overridden. A garbage collector which is overridden is pointless. The problem surfaces when multiple people work together on a large project.
Ideal - if everything were in managed space. However, and I find this to
be one of Java's weaknesses, was it's interface to existing code (most of
which 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
i 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.
You make good points. I am working on an improved and more educated argument
with regards to unsafe contexts. Attributes: Code quickly becomes extremely illegible when attributes are used. Attributes result in essentially an obfuscation of the language specification and expected behaviour. Debugging code becomes trickier when attributes have potentially subtle side effects.
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
didn't are recently seeing its adoption. However, the obfuscation part hardly seems like a justifiable case for your argument against attributes,
because if we were to replace "attributes" with a compiler or library function,
you 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
language, other than assembly with no macros, whether it has declaritive elements or not would be guilty of the same crime.
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. Garbage Collection: You are effectively forced to use garbage collection. Turning off the garbage collection in C# can lead to extremely subtle and hard to find bugs due to a mix of
garbage collected and non-garbage collected code. Turning off garbage collection can only be done by switching to an unsafe context with all of what that implies.
I see several problems with this argument. First of all is the
inconsistancy of your arguments. Remember the first point I made above that I said i
would revisit? You wanted the language to be less flexible in favor of enforcing robustness (which you are happy to point out elsewhere in your
dissertation 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.
GC 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."
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.
C# allows non-deterministic destructors: Garbage collection with destructors means the destructors can be called
at unpredicatable moments during execution. That is the nature of GC. The thing to remember is: you shouldn't use destructors for deterministic management (eg. clean-up) of resource
(that's 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
opinion is valid, because the only way to get deterministic finalization, is if
the 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
that clean-up code is being called "now", use Dispose. That is deterministic.
Of 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 ;-)
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?
Objects can't exist on the stack We are forced to use structs if we want to create an object which exists on the stack. This can cause problems for users of a library which has locked in an object 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
hell.. 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
the 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
going to more or less look exactly the same from his point of view for that
member invokation. But lets look at the flipside of the coin. Why would you want objects on
the 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
the increment of the allocation pointer, making it almost exactly the same as stack allocation in terms of performance. To make reference types
available on the stack, you'd have to change GC infrastructure, which would effectively make reference type allocation on the stack SLOWER. In
addition, value types are rather small in comparison with reference types,
especially if you consider strings, which make up the majority of data in a program.
Do 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#.
Not a very strong point that I made, I agree. Type / Reference Types A type decides whether it will be on the stack or the heap. Which means
a programmer has to be aware of each types specific semantics when using it to know whether
they are passing things by reference or by value. This leads to subtle and confusing bugs. 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.
I will try and update this as well.
Boxing / Unboxing The semantics of boxing and unboxing are subtle and confusing. There is
a problem of needing to know too much information about a type to decode the semantics of a
simple assignment. Boxing is a feature designed to compensate for the fact that objects must be
used 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
to 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
it were not for boxing/unboxing, the programmer would have to be far MORE
aware of the details of the type implementations and code such scenarios SEPARATELY.
Hmm... I will need to look into that argument more deeply.
Mutability C# does not allow declaration of immutable instances of user defined objects.
I understand what you want to do here - create a const instance of a
class. 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
data imbedded in the program (as it can easily do for numbers and strings
because 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
in 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 -
value types have no constructors.
I don't understand what you mean by "truly const". How could you bypass
class behaviours?
Also, the lack of literal declarations doesn't mean you can't have
immutable objects. You can certainly program immutable objects in C#. Again, you
might 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.
Yes I realize the verbiage is weak there. Classes as Modules and Programs C# allows static information within a class and not outside of one. Therefore a class in C# has concepts that are a hack designed to compensate for missing modules. Classes and modules are very distinct concepts that deserve to be treated as seperate identities. When we do so, as in Heron and Object Pascal, the semantics of classes is simplified somewhat. One example of where not being allowed to place data into the global scope of a namespace is noticeably lacking : using System; class Hello { static void Main() { Console.WriteLine("hello, world"); } } > The System namespace can not export a function named WriteLine it can only export static classes. A static class with only static data and static methods should either be
a module or a program. It could be argued all static data should occur outside of classes since it is not directly related to objects themselves.
Not sure I agree completely with you here. First of all Classes and
modules 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
perfectly capable of performing both roles. Your gripe seems to be more about the invokation syntax, which is purly compiler syntactical sugar and a few
rules 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
VB compiler also allows you to invoke said members without qualifying it to
the module's (class') name - in essence letting you "export" what appears to
be 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
there are a lot of people that prefer it the way it is rather than the way
VB.NET does it. For starters, you are introducing a level of ambiguity and issues revolving around name resolution that otherwise wouldn't be there... and
for a guy who doesn't like ambiguity, this argument seems rather contradictory with your previous line of thinking.
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.
Polymorphism through Class inheritance C# supports polymorphism only through class inheritance. Class
inheritance does not encapsulate code as well as interface delegations. Interface implementations can not be delegated to member fields. Every time you want to implement an interface you must explicitly write all of 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
to 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.
Yes that statement is false.
C# Missing Template Template Parameters In C#, a generic type parameter cannot itself be a generic, although 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
allowing this. There was a rather good explanation in one of the blogs (probably reachable via C# Corner).
Late Added Generics By adding generics so late, among other things there is the pointless redundancy of having two kinds of arrays. The int a[]; and array<int> a;
Not a good argument at all. First of all, few languages support generics
to 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
a 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?
Special Primitives Special rules exist for so-called "primitive" types. This significantly reduces the expressiveness and flexibility of the language. The programmer can not
add new types that are at fully at par with existing primitives. What on earth are you tryign to do with user-defined types that can only
be done with primitives? Remember that the compiler has no earthly idea what to do with types
nobody 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.
Just because "other languages do this" doesn't make a feature a good idea. I
can still take up issue with the feature.
Source File Layout C-Sharp code is not readable without automatic documenting tools or editor. It takes a long time to read a source file and find out what classes are included and what the member fields and methods of those classes are. This promotes an unstructured coding style and often leads to bugs that are not immediately obvious without reading the automatically generated documentation.
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
like any C languages, why are you even critiquing C# specifically?
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. Public Fields Classes can expose their fields as being public. This violates the 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
performance hit of going through an accessor/mutator method. And before you cry "HERASY!", remember, best practices are there to stop people who can't
think from doing dumb things - not there to prevent people from thinking.
Best practices are usually ignored most by the people they are intended for.
Nonetheless, properties make public fields redundant. Is it a property or is it a field? Are you setting a field named m or are you calling a property which
leads to a function which can throw an exception? A language should allow only properties or only public fields but having both gives us the worst of both worlds.
If a tree falls in the woods, and nobody is around to hear it, does it
make a sound? If you use proper exection handling, does it matter?
It doesn't really matter that much I suppose if one consistently assumes
that x.m = y is actually a function call.
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
scientific 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
worth-while critique would leave you with a rather slim list. Your page stopped being
a 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
in 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).
People can argue over a true critique, but its merits will weather those
arguments 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]
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
Would be quite easy for you to come up with a Java critique as
well--they're quite similar now. Although the current version of Java
doesn't have some of the features you dislike, they will have it soon
(J2SE 1.5).
In fact, C# is "better" if you compare it against Java in some of your
points in that article. You have to use structs if you want to create
objects that exist on the stack? You can't even have structs on the
stack in Java! Everything is a class, too bad.
BTW, since you didn't criticize Java... have you ever wondered why they
added the C# features you didn't like to Java (metadata/attribute,
boxing-unboxing)? That, by itself, should tell you that a lot of people
see value in having those features.
I do agree with you on mutability, source file layout, and the property
stuff though.
christopher diggins wrote: "Brian W" <brianw@gold_death_2_spam_rush.com> wrote in message news:OP**************@TK2MSFTNGP12.phx.gbl...
OK ladies and gentlemen, don't feed the troll.
This guy is just trying to gather support for his language (Heron).
Yes this is part of my motive. I also want to look critically at other languages and have my ideas exposed to the best kind of critical reading available.
For proof of this, one only needs to look at and follow the link that appears at the bottom of his post and the bottom of his, so called, "critique" page.
Proven.
It's perfectly fine that this guy wants to rally support for his "new language" but he should do it a constructive way, perhaps a "mine vs. theirs" approach would better support his cause his cause.
Identifying potential weaknesses in a language is productive. Or should I just roll over and say C# is just fine. At least I am being honest with regards to my bias as opposed to thinly disguising it in a "mine vs theirs approach".
The "critique" would be more aptly named, "Why I hate C#"
Are you suggesting that the critique is entirely baseless? I would appreciate it if you could have shown some kind of weakness to my article rather than criticizing it because I link to my own language at the bottom.
<Ol**********@skyscan.be> wrote: Probably not More than that - definitely not! Don't bet on that "definitely not!". Hackers are very resourcefull people you know.
Okay, let's just say that if the CLR doesn't have any bugs, you won't
get a buffer overflow. If the CLR has bugs in this respect, however,
nothing's guaranteed anyway. I would not know why I would use structs for something else.
Convenient stack-based allocation, basically, and simple value semantics.
I very rarely need these things like that so far. I avoid custom made Structs, I prefer to use the classes instead, far more flexibel in use.
Yes, I rarely create my own value types.
Ints, DateTime and other generic structs are logical to use, but so far even in C++ I do not need custom structs unless using it as a memory mapper. Everyone programs in a different way. ;-)
All I'm trying to point out is that everyone *does* use value types,
even if they don't create their own ones.
--
Jon Skeet - <sk***@pobox.com> http://www.pobox.com/~skeet
If replying to the group, please do not mail me too Ol**********@skyscan.be wrote: C# allows non-deterministic destructors: Garbage collection with destructors means the destructors can be called at unpredicatable moments during execution.
That is the nature of GC. The thing to remember is: you shouldn't use destructors for deterministic management (eg. clean-up) of resource (that's 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 opinion is valid, because the only way to get deterministic finalization, is if the 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 that clean-up code is being called "now", use Dispose. That is deterministic. Of 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 ;-)
In my opinion, Constructors and Destructors should only perform actions that guarantees that it will not crash.
You must be disapointed by the .NET framework then. There are many types
like e.g. FileStream, where the constructors can throw and the finalizers
perform actions that can fail. Why exactly do you think a constructor should
not propagate exceptions? Why is it better to first construct a type and
then call Open/Init/Whatever?
Regards,
Andreas
christopher diggins wrote: "Andreas Huber" <ah****@gmx.net> wrote in message news:40**********@news.bluewin.ch... christopher diggins wrote: "Sami Vaaraniemi" <sa***************@jippii.fi> wrote in message news:bv**********@phys-news1.kolumbus.fi... While some of your comments about C# do have a point, most of the time the case is that you can work around the issues in one way or another.
Yes I agree there are work-arounds for a good programmer. But nothing to prevents less experienced programmers from going in and doing a heck of a lot of damage. My problem is using other people's code, which is crucial for any kind of serious development. Which is true for just about every language feature. Writing good programs always has required and always will require thoughful use of the language features one has at his/her disposal. As always: A fool with a tool (or C# for that matter) is still a fool. One *can* write much more expressive code because of C# attributes and that's all that matters. BTW, the same is true for C++ macros (much less frequently though).
The argument that all features that increase flexibility are neccessarily equally good falsely assumes that all potential for programmer error are also equivalent.
I did not suggest that, did I? I also think that some features are hard to
abuse while others blow up at least once in just about everybodys face.
However, often the most dangerous features are also the most useful (e.g.
some programs would be extremely hard to write without multi-threading
support).
Some language features lead to relatively insignficant bugs, while others lead to potential disastrous consequences. For more on the differences between classes of programmer error see my article on scale of magnitude for Programmer Error in Programming Languages at http://www.heron-language.com/scale-of-errors.html.
On your scale some multi-threading bugs would classify as second-worst. Are
you suggesting that a "proper" language should not support MT because it is
so dangerous?
Regards,
Andreas
C# (or more correctly, .NET CLR) doesn't allow two types of buffer overrun
issues, which to my knowledge are THE two exploits. I've yet to find a third
scenario that doesn't fit into one of the two.
Buffer overflows exist because "extra" data is allocated on the stack, and
overwrites the return execution address of the stack frame, causing the
function to return to an incorrect address that either crashes the program,
or more malevolently, goes to execute malicious code, or system code using
inappropriate thread security permissions.
However, .NET stack frames are FIXED in size. Only variables of known type
(and therefore size) are allowed on the stack. You cannot allocate ambiguous
or anonymous data chunks on the stack. Also, throughout the execution of the
function, the stack frame size cannot change. All variables slots are
pre-allocated and never changed.
The second kind of buffer overrun is induced by index parameters to buffers
(or more generically, arrays of "stuff") that aren't correctly checked for
exceeding array bounds. This prompts the code to overwrite data in some
unspecified segment of memory (if the buffer is on the stack, you get the
idea). So, basically, Hacker Joe sets your index param to some obscene high
or negative number, and your code overwrites all sorts of data it shouldn't.
..NET protects against this in two ways : first, all array access is
bounds-checked by default, but you can turn this off. Secondly, arrays
aren't allowed on the stack. Therefore, even if you were able to pass a bad
index off AND array bounds checking was turned off, AND you were using
unsafe code to access the array, you would still be completely unable to
overwrite the return execution pointer.
Given that, I highly doubt someone can come up with a good example of how to
cause a buffer overflow using managed code.
-Rob Teixeira [MVP]
"Jon Skeet [C# MVP]" <sk***@pobox.com> wrote in message
news:MP************************@msnews.microsoft.c om... <Ol**********@skyscan.be> wrote: It isn't!! Structs on the stack can cause buffer overflows too, this is
why I avoid the struct in the first place and use the class instead.
In safe code, you can't have buffer overflows. If you believe you can, please give an example.
-- Jon Skeet - <sk***@pobox.com> http://www.pobox.com/~skeet If replying to the group, please do not mail me too
inline:
"christopher diggins" <cd******@videotron.ca> wrote in message
news:Z7********************@weber.videotron.net... "Rob Teixeira [MVP]" <RobTeixeira@@msn.com> wrote in message news:eS**************@TK2MSFTNGP09.phx.gbl...
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.
Does it help any that custom attributes can't change core behaviours of the
compiler? In other words, if i add a custom attribute, i need to provide a
library that "does" something using reflection against those attributes. The
core runtime/compiler have no clue and ignore the custom attributes. As the
library provider, I document the custom attribute usage. I don't see that as
being much different from providing library functionality without
attributes, except in the fact that it's declarative vs. imperative code.
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.
Not necessarily. I'm saying that you value robustness, yet the GC, which is
arguably one of the greatest tools of robustness, is something you want to
avoid. That puzzles me. Manual allocation/deallocation of variables has got
to be one of, if not THE worst culprit of bugs.
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?
I agree with this statement. In fact, the .NET developers published two
lengthy articles in 2001 covering the GC (very insightful, if you haven't
read them). They actually did document how one could have both a GC and
deterministic finalizers. The problem is the complexity and performance
overhead added to the GC infrastructure for arguably little return.
The second part of what I'm saying is that while the "finalizer" itself is
not deterministic in its execution, the Dispose method is - so you are not
losing a deterministic clean-up method. A finalizer is basically there as a
safty net in case Bob from the next cubicle forgets to call Dispose. But
let's pretend for a moment that Bob is working in a language with manual
deallocation... now he forgets to call the deallocation keyword or function.
Bob's program is now in deep S#!t, and there is no safty net of the GC
calling a finalizer to help him lessen the impact of his mistake. His
process will leak resources until it is either shut down or crashes.
I don't understand what you mean by "truly const". How could you bypass class behaviours?
To make a const statement, you have to do several things. First, you have to
provide the programmer with some sort of syntax that describes a literal
"value" of the object instance. This can be quite complicated in and of
itself. How are you going to deal with a single object that potentially has
an extremely deep object graph (and potentially circular references) as an
example? Secondly, you have to "freeze-dry" this literal value data into the
compiled program. If you use serialization to do this, then you can only
have literal const statements using serializable objects. Not a good
limitation IMO. To remove that limitation, you would have to find some other
mechanism of storing the literal data, but if that bypasses class
constructors, you are potentially bypassing important class behaviors built
into the constructors. If you don't bypass the constructor, then you are
creating a new instance of the class at runtime through normal means, which
makes the reference only "sort-of-immutable". This is one reason primatives
can have literal const values - they don't have constructors, and can be
reconstituted easily from compiled data, and thus don't need to worry about
these issues.
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.
I cited VB.NET, because it too uses the .NET CLR/CLI and compiles to the
same set of IL instructions. This proves that C# could indeed have the
features as you described them. However, my main point is that there are
people, most developers and users of C# in particular it seems, that
*prefer* not have things done that way. To me, this is entirely a matter of
personal opinion.
Just because "other languages do this" doesn't make a feature a good idea.
I can still take up issue with the feature.
I agree, but I'm still curious about what you are trying to do with UDTs
that can only be done with primatives? You still haven't provided an
example. There are very legitimate reasons why C# and other languages impose
these limits :-)
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.
Is there a clear advantage to *having* a header file? The C# devs and users
don't seem to think so.
The metadata is available and readable, just not in notepad (or your text
editor of choice), but i think that's hardly a good reason to enforce the
usage of header files :-)
Could be this is just another case of personal preference, which goes back
to the analogy of programmers of one language not liking how the other
language reads.
It doesn't really matter that much I suppose if one consistently assumes that x.m = y is actually a function call.
Or if one writes code that uses structured execption handling. I hope you
aren't implying that people would write a Try block, put code in it, end the
Try block, just to assign a field, then start another Try block after the
assignment :-)
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.
You're welcome Christopher. I'm glad to see the more cooperative attitude.
Now if I could only convince the other open-sourcers to do the same, we
might actually get somewhere :-)
Cheers,
-Rob
Christopher Diggins yet another language designer http://www.heron-language.com
In my opinion, Constructors and Destructors should only perform actions
that guarantees that it will not crash. Mainly initializing variables, allocating memory, copying,....
Then we have a second set of methods that actually open an close files/resources/connection/.... This way, a file is closed, memory freed, connections closed,... outside
the destructor and it doesn't matter then when the destructor is then called.
I agree with the Destructor comments, and that's precisely what C# does (or
more correctly, prefers that programmers do).
The destructor should never raise exceptions, and should handle them
privately if they occur, but more imporantly, they are minimal pieces of
code used as a safety net in case somebody accidentally forgets to call a
Dispose or Close method. If you don't do that, then contained resouces are
never *properly* freed during the execution of your process, or worse yet -
even after your process is terminated in some cases. If you are dealing
exclusively with managed code, there is really no need to have destructors
IMO.
However, do be careful in how you word things. Initializing variables,
allocating memory, and copying *can* in fact raise exceptions.
-Rob Teixeira [MVP]
<"Rob Teixeira [MVP]" <RobTeixeira@@msn.com>> wrote: You're welcome Christopher. I'm glad to see the more cooperative attitude. Now if I could only convince the other open-sourcers to do the same, we might actually get somewhere :-)
Actually, open source folks tend to be very co-operative - otherwise
they don't get anywhere. That's certainly true in my experience,
anyway.
--
Jon Skeet - <sk***@pobox.com> http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
> > In my opinion, Constructors and Destructors should only perform actions that guarantees that it will not crash. You must be disapointed by the .NET framework then. There are many types like e.g. FileStream, where the constructors can throw and the finalizers perform actions that can fail. Why exactly do you think a constructor
should not propagate exceptions? Why is it better to first construct a type and then call Open/Init/Whatever?
Ok, with the use of exceptions constructors could do more things that might
fail.
The big problem lays in the fact that if something goes wrong, you have no
access to internal error information since the class does not exist since it
failed.
You have to rely on specialized exception classes that pass on enough
information. For small classes that generates only one unique error, this is
not a problem, but classes that could generate multiple errors (e.g.:
copying multiple files,...loading a big document and parse multiple fields
that might contain errors) could be a big problem.
Since I do not like to program in a mixed style, I try to use this general
rule to create constructors that normally do not fail. But sometimes you
have exceptions of course.
But destructors should not! (e.g.: close files) .
The class that opens files should have at least one exposed method to
release the resources used, for example close a file.
Some .NET components do not have this, and I had this very annoying problem
that when I opened the same file 2 times in a row, then it sometimes failed
the second time because it was still locked the first time. The destructor
was not called yet, so the file did not close when I tried to reopen it. It
did not show up in the debug version, but only the release version. This thread has been closed and replies have been disabled. Please start a new discussion. Similar topics |
by: Long |
last post by:
How to include an HTML doc in another HTML doc
Problem: to insert the body section of an HTML doc in another HTML document
at a specific location.
One possible way is to add a WebCharm tag...
|
by: TC |
last post by:
Are there any good sites or forums for a web critique? I went to
alt.html.critique and it's pretty dead.
|
by: bowsayge |
last post by:
Inspired by fb, Bowsayge decided to write a decimal integer
to binary string converter. Perhaps some of the experienced
C programmers here can critique it. It allocates probably
way too much...
|
by: Eric |
last post by:
There is a VB.NET critique on the following page:
http://www.vb7-critique.741.com/
for those who are interested. Feel free to take a look and share your
thoughts.
Cheers, Eric.
Ps: for those...
|
by: marktang |
last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
| |
by: Hystou |
last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
|
by: Oralloy |
last post by:
Hello folks,
I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>".
The problem is that using the GNU compilers,...
|
by: jinu1996 |
last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
|
by: Hystou |
last post by:
Overview:
Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
|
by: conductexam |
last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and...
|
by: TSSRALBI |
last post by:
Hello
I'm a network technician in training and I need your help.
I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs.
The...
| |
by: 6302768590 |
last post by:
Hai team
i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated ...
|
by: muto222 |
last post by:
How can i add a mobile payment intergratation into php mysql website.
| |