Re: [DOTNET] Constructive criticisms of C# and .NET FW
Doug Ransom <[email protected]> Tue, 21 May 2002 15:02:47 -0700
| Newsgroups | gmane.comp.windows.devel.dotnet.advocacy |
|---|---|
| Message-ID | <3C552E6ED5B7DC4F8BF603C030BB70BF04ACDFD9@HERMES.canada.corp.powermeasurement.com> |
I also miss A) partial application, B)lambda expressions, C) decent maps
and folds (from functional programming {Haskell} ), E) a lazy evaluation
keyword.
All of these things can be added to C# with either simple syntax additions
or just library additions, and wouldn't affect the CLR at all -- they should
all compile to the existing infrastructure.
A) Partial application:
I would like to see the compiler perform partial application to create a
delegate with syntax similar to this:
myDelegate=PartialApply(function,a,_,b);
This would be farily simple to do with the type information, and this is a
realy headache to do now (have to manually
create a class to hold a, b, write a constructor that stores a and b, give
it a method which calls function(a,delegateArg,b);
This would take about 12 lines of code and 12 minutes to write.
I believe jScript has a mechanism like this. Partial application works
perfectly well in object-oriented programming as functional programming.
B) lambda expressions and C) decent maps and folds
The foreach( ...) mechanism:
foreach(i in collection)
{
dosomething;
}
has the following disadvantage over
let l= void function(int a) { dosomething ; }. //l is assigned a lambda
expression -- basically a function with the statements dosomething;
// The compiler create a delegate for l.
This is similar to the local function idea from pascal
collection.map(l);
1. The loop logic with the foreach method is repeated over and over
throughout .net code. Its bloat. And there
is more likelihood of something going wrong -- the users specifies a
collection and a variable (at least not start and end logic) as opposed to
map where the user only specifies code to be applied.
2. Using the map function results in a far better use of CPU pipeline and
instruction cache, because the loop exist only in one memory location. As
one bit of code to the next invokes map, there is a much greater likelihood
of a cache hit.
Its generally faster to get code working and correct with functions that
apply other functions to a collection (lists, trees, or more complicated)
than for the user of those collections to manage the iteration (even using
iterators) themselves.
E) a lazy evaluation keyword
x=fn(a,b) is an assignment
let x=fn(a,b) could be a value.
In the example below, x would not be evaluated until it was needed in a
further calculation.
It would help for making code clearer, as one could say what they mean
without concern for order of evaluation. This also
gives the compiler a fair bit of freedom -- it can decide when to evaluate
x.
In the current C# days, we must manage when x is assigned ourselves.
void fn()
{
rc=3;
let x=fn(a,b,c,d,e); //expensive calcuation, best avoided
for( ...)
{
if(...)
{
rc=sq(x);
}
for(...)
{
if(j)
{
rc=x*x*x;
}
}
}
return rc;
}
I feel these features are the best features of functional programming the
apply equally well to object programming (like C#). There are several
aspects of functional programming that just won't map to C# or won't work
nicely in the .Net framework (like the full lazy evaluation of Haskell).