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).