Simulating INumeric with dynamic in C# 4.0

-

When I wrote my Excel fi­nan­cial li­brary I ag­o­nized over the de­ci­sion of which nu­meric type to use to rep­re­sent money. Logic would push me to­ward dec­i­mal, but com­mon us­age among fi­nan­cial li­brary writ­ers would push me to­ward dou­ble. I ended up pick­ing dou­ble, but I re­gret hav­ing to make that choice in the first place.

Conceptually, I’d like my nu­meric func­tions to work for any­thing that sup­ports the ba­sic arith­metic op­er­a­tors (i.e. +, -, *). Unfortunately that is not pos­si­ble in .NET at this point in time. In essence you have to write your code twice as be­low.

   static double SumDouble(double a, double b) { return a + b; }
   static decimal SumDecimal(decimal a, decimal b) {return a + b;}

Granted, this is not a good state of af­fairs. We of­ten dis­cussed how to make it work, but we could­n’t find a so­lu­tion that was both fast to run and cheap for us to im­ple­ment. More of­ten than not we spec­u­lated about hav­ing the nu­meric types im­ple­ment a spe­cific INumeric in­ter­face and add a generic con­straint to the C#/VB lan­guages to make it work. Hence the ti­tle of this post.

With we im­ple­mented dy­namic in C# 4.0 it oc­curred to me that you can fake your way into writ­ing your code just once. For sure, this so­lu­tion does­n’t have the same per­for­mance char­ac­ter­is­tics of writing your code twice’, but at least it does­n’t du­pli­cate your code.

This is how it looks like:

    static dynamic Sum1(dynamic a, dynamic b) { return a + b; }

The call to the +’ op­er­a­tor is re­solved at run­time, by the C# binder, hence a per­for­mance penalty is in­curred. The penalty is less than you might think, given that the DLR caches things un­der the cover so that no v-table lookup is per­formed the sec­ond time around. The whole thing is ex­plained in more de­tail here. But still, it is not as fast as a nor­mal +’ op­er­a­tor over a prim­i­tive type. I’ll let you en­joy mi­cro per­for­mance test­ing this one 🙂

A slight re­fine­ment is to make the code generic so that a caller does­n’t see a sig­na­ture with dy­namic types as ar­gu­ments.

   static dynamic Sum2<T1, T2>(T1 a, T2 b)
   {
       dynamic ad = a;
       dynamic bd = b;
       return ad + bd;
   }

I could make the re­turn type generic as well, but that would force the caller to be ex­plicit about the types, mak­ing the call­ing code much less read­able. The other good thing about this sig­na­ture is that you get a dif­fer­ent call site with each com­bi­na­tion of type ar­gu­ments and, since they are sep­a­rate, the bind­ing caches should stay small. With the for­mer sig­na­ture there is only one call site and the cache could pile up to the point where the DLR de­cides to dis­card it.

Here is how the call­ing code looks like right now:

       Console.WriteLine(Sum2(2m, 4m));
       Console.WriteLine(Sum2(2.0, 4.0));
       Console.WriteLine(Sum2(new DateTime(2000,12,1), new TimeSpan(24,0,0)));

Yet an­other way to write this code is as fol­lows:

   public static T Sum3<T>(T a, T b)
   {
       dynamic ad = a;
       dynamic bd = b;
       return ad + bd;
   }

This gets around the prob­lem of show­ing a dy­namic re­turn value and give you some more com­pile time type check­ing. But it pre­vents sum­ming not co­ercible types. The com­piler does­n’t let you get there. The last line be­low wont’ com­pile:

       Console.WriteLine(Sum3(2m, 4m));
       Console.WriteLine(Sum3(2.0, 4.0));
       //Console.WriteLine(Sum3(new DateTime(2000,12,1), new TimeSpan(24,0,0)));

Also no­tice that in VB you could have done this a long time ago 🙂

   Function Sum(Of T1, T2)(ByVal a As T1, ByVal b As T2)
       Dim aa As Object = a
       Dim bb As Object = b
       Return aa + bb
   End Function

In sum­mary, by us­ing dy­namic you can write your nu­meric code just once, but you pay a per­for­mance price. You are the only one who can de­cide if the price is worth pay­ing in your par­tic­u­lar ap­pli­ca­tion. As of­ten, the pro­filer is your friend.

Tags

30 Comments

Comments

Simulating INumeric with dynam

2009-02-05T14:01:59Z

David Nelson

2009-02-06T00:06:03Z

You don’t just pay a per­for­mance price, you pay a us­abil­ity price. With the du­pli­cated ver­sion, the com­piler ver­i­fies that the types you are us­ing are cor­rect. With the dy­namic ver­sion, the com­piler can’t ver­ify any­thing. What hap­pens if two types are used which do not have an ad­di­tion op­er­a­tor de­fined? A run­time ex­cep­tion oc­curs. What hap­pens if this call ex­ists in a code path which al­lows many dif­fer­ent ob­jects to be sup­plied to the dy­namic func­tion? The chances that any amount of test­ing will find all the po­ten­tial run­time er­rors in such a cir­cum­stance are slim; whereas the com­piler could have found the prob­lem im­me­di­ately.
The lack of a com­mon in­ter­face for nu­meric types has been a top-rated is­sue on Connect for 5 years. It is clearly very im­por­tant to the com­mu­nity, and yet there has still been no so­lu­tion im­ple­mented. Frankly I am baf­fled by this.

Pop.Catalin

2009-02-06T04:16:24Z

I think that this is some­thing that dy­namic was­n’t meant for. In VS 10 we will also have F# and I’d rather use F# for this kind of things to have bet­ter per­for­mance and type safety. Actually I’d be more than happy to use F#, it’s pro­gram­ming model fits bet­ter with com­pu­ta­tional code.
This seems like play­ing at the edge of C#. C# was never de­signed for nu­meric pro­gram­ming an will prob­a­bly stay that way for the fore­see­able fu­ture. Which is a shame, be­cause it’s see­ing more use in games, 3d ap­pli­ca­tions and com­pu­ta­tion in­ten­sive ap­pli­ca­tions.

David: agreed with the com­ment on the need for INumeric. Agreed with the pit­fall of run-time er­rors vs com­pile time er­rors. I thought I said it in the post, maybe I should have said it strongly.
Pop.Catalin: F# does­n’t help in this sce­nario. You still need to write du­pli­cate code.

Justin Etheredge

2009-02-06T11:28:42Z

Of course there are is­sues with this im­ple­men­ta­tion, but what you have done is take what you have and used a cre­ative idea to get around a prob­lem that has ex­isted in C# for a long time. I say you have done an ex­cel­lent job!

Very sim­ple an­swer:
Generics are bro­ken in C# and CLR in gen­eral.
That ought to have been fixed be­fore any re­lease.
Two, it just re­flects dif­fer­ent num­ber sys­tems, and dec­i­mal won’t cut it just the same (not to men­tion the perf penalty).
C# is un­us­able for nu­meric pro­gram­ming (without be­ing dog slow and full of hacks), be­cause its model (in gen­eral Java VM model) is bro­ken not in us­abil­ity, but in im­ple­men­ta­tion of mem­ory-ab­stracted-away­ness, its id­ioms that are very weak, and gener­ics (both in lan­guage and run­time). Quite ob­vi­ous re­ally.. just ask ex­perts that do nu­meric li­braries in C++ for your lo­cal gov­ern­ment in the past 20 years..

Qwr: can you give me more de­tails on the points you raise?
Apart from the lack of an INumeric in­ter­face, I’m not aware of any other big is­sue with C#/CLR for nu­meric com­put­ing.
Notice that PInvoke and un­safe fea­tures in C# helps you in these (hopefully lim­ited) cases when you need di­rect mem­ory ac­cess.

Sure, if you at­tempt to play with gener­ics, you will see that sub­sti­tu­tion fea­tures are bro­ken. Meta-programming is im­pos­si­ble, pol­icy-based de­sign is hard and bloated etc. Word hack’ is all over IL :)
That’s the lan­guage de­sign­ers fault and yet we are at 4.0 and still away from pro­gram­ming the com­piler (but C# is look­ing more like mod­ern C++ by the day, hmm).
The un­safe and man­aged mix, in terms of mem­ory brings an­other di­men­sion to the prob­lem which is re­lated to com­plex data flow and al­most guar­an­teed mem­ory leak­age ie. it is im­pos­si­ble to get the de­ter­min­is­tic be­hav­iour that is es­sen­tial for large datasets. Moreoever, every­thing in CLR 3.0+ is so heav­ily ob­ject-pe­nalised that even be­fore a large dataset ap­pears over­head is al­ready huge and sub­par to any­thing in the in­dus­try (WPF or large apps for one).
Not to men­tion copy-con­struc­tion hacks.. and so on. Numeric com­put­ing in Java and CLR is so far away from hard­ware re­al­ity of to­day it sim­ply can­not be taken se­ri­ously in any HPC en­vi­ron­ment or other non-hobby work.
And if we are to be­lieve the funny managed’ speak, what on earth is the point of PInvoke or VM sand­box/​se­cu­rity ap­proaches any­way.. for nu­meric com­put­ing, games, video, au­dio, real-time apps, and much more, CLR just does­n’t have an ap­pro­pri­ate so­lu­tion with­out some sort of un­man­aged so­lu­tion or hack in sight.
This is all due to Java+Delphi in­flu­ence if you ask me, but we told you so 10 years back when you com­pleted the first beta, yet no one lis­tened. It is sur­pris­ing to see that even using’ can­not be done twice over an in­di­rec­tion and the lan­guage de­sign­ers keep talk­ing of meta fea­tures, com­piler ex­ten­si­bil­ity ( CodeDOM Nulls? ) and so on..Seems to me C# is be­com­ing a toy lan­guage re­ally.
It just does­n’t tally.. A type sys­tem with sin­gle-in­her­i­tance, no mix in sup­port, ob­ject ap­proach, is like plac­ing a void* every­where in nu­meric and other dis­ci­plines.
Why does­n’t some­one stand up and tell that se­ri­ous com­put­ing is not for the guys that will keep push­ing lan­guage in­te­gra­tion and pop­u­lar­ity and sim­plic­ity against proper en­gi­neer­ing?

And of course, gener­ics with value types are so lim­ited it is­n’t funny any­more.. how did that get pass any stan­dard (ECMA or in­ter­nal) is be­yond me.
Numeric com­put­ing is hap­pen­ing else­where and your com­pe­ti­tion is mak­ing bet­ter tools in na­tive and sym­bolic space.. I have to say it, al­though I would have liked for MS to take it on se­ri­ously (and it is a se­ri­ous dis­ci­pline and work, not ASP.NET or some such).

Hello Luca,
Very in­ter­est­ing ar­ti­cle. I like the idea of an INumeric in­ter­face; if noth­ing else at least it would save me from writ­ing tons of du­pli­cated code.
Now, my two cents (a cou­ple of thoughts I’d like to share with every­one):
In my view, the un­der­ly­ing prob­lem that I think INumeric tries to solve, or at least al­le­vi­ate (i.e. clos­ing the gap be­tween num­bers and numbers as com­put­ers un­der­stand them’), has much deeper roots. It seems to me that at the dawn of com­put­ing sci­ence, some­one de­cided than a few mil­len­nia of Mathematics were re­ally not that im­por­tant and that, in the com­put­er’s world they were cre­at­ing, the fol­low­ing was go­ing to hold true:
1/2 = 0
and yet
1./2 = 0.5
The above is just math­e­mat­i­cally ab­surd and yet it propagated’ every­where; for 60+ years (and count­ing) com­puter sci­en­tists have lived hap­pily with this. Now com­bine it with:
1./0. => A di­vi­sion by zero er­ror has been caught.”
???
So, I can’t di­vide by zero in the field of real num­bers - which makes per­fect sense - and yet, mag­i­cally, I can di­vide by two in the ring of in­te­gers. Simply put, this breaks some of the most ba­sic prin­ci­ples of Mathematics. In this ex­am­ple, I can think of at least three pos­si­ble op­tions:
1/2 = {1,0} => one cake for two guys and you as­sume you can’t cut it: one guy gets the cake, the other one gets noth­ing (I don’t like this idea though).
1/2 = 0.5 => you pro­mote the ar­gu­ments to the (smallest) set where the op­er­a­tion is de­fined and re­turn the rel­e­vant el­e­ment from that set (I kind of like this one).
1/2 = Error! Division by a non-in­vert­ible el­e­ment.” => in re­al­ity, the ex­act same stuff that is re­ported when di­vid­ing by zero (I like this one).
What seems to­tally un­jus­ti­fied to me is to re­turn 0 just be­cause it hap­pens to be the in­te­gral part of 0.5.
I’m aware of the fact that the nu­meric rep­re­sen­ta­tion of a num­ber in a com­puter is fi­nite, but I don’t think that’s rea­son enough for this state of af­fairs. In my opin­ion, a higher level of nu­mer­i­cal ab­strac­tion is needed; one that would serve as a bridge’ be­tween num­bers - in the Mathematical sense of the word - and numbers as un­der­stood by com­put­ers’.
I find it in­trigu­ing that every sin­gle as­pect of hard­ware and soft­ware has evolved at an in­cred­i­ble speed and yet, to a large ex­tent, things like the way we de­fine, store and ma­nip­u­late num­bers in com­put­ers seem to have frozen the very day those mech­a­nisms were first de­fined.
Finally, I do think that this re­lates to INumeric: on top of more solid foun­da­tions one could build up to the point where INumeric is not needed any­more, sim­ply be­cause the con­cept is al­ready there im­ple­mented at a much lower level (but this post is too long al­ready).
Regards,
  dfg

These are very good thoughts. Thanks for shar­ing.

Hi Luca,
Thanks; al­ways glad to con­tribute in the lit­tle I can. Here’s an­other thought; luck­ily this one a bit more prag­matic.
What does INumeric look like in your mind at pre­sent? Would it al­low me to write (in F#) some­thing like this (for sim­plic­ity, I’m leav­ing out left-side op­er­a­tions with an INumeric):
type Complex =
   {   Re: INumeric
       Im: INumeric }
   static mem­ber ( + ) (left: Complex, right: INumeric) =
       { Re = left.Re + right; Im = left.Im }
   static mem­ber ( * ) (left: Complex, right: INumeric) =
       { Re = left.Re * right; Im = left.Im * right }
If this is the idea, then I sup­pose I’d have two op­tions: ei­ther Complex im­ple­ments INumeric or it does­n’t. If it does­n’t, then I’d need to add to the code above other meth­ods like
   static mem­ber ( * ) (left: Complex, right: Complex) =
{ Re = left.Re * right.Re - left.Im * right.Im ; Im = left.Re * right.Im + left.Im * right.Re }
On the other hand, if Complex im­ple­ments INumeric, then I sup­pose I could write just one method:
   static mem­ber ( * ) (left: INumeric, right: INumeric) =
with two branches: one for Complex and an­other one for all other INumeric types.
Having Complex im­ple­ment INumeric would be a great ad­van­tage be­cause then I could cre­ate a new type, say, Matrix, tak­ing INumeric as the en­tries, and com­plex en­tries would be au­to­mat­i­cally con­sid­ered. But in this case my ques­tion is: How would the (+) op­er­a­tion be re­solved with­out some sort of hi­er­ar­chi­cal ap­proach? For ex­am­ple, sup­pose that I cre­ate a new Matrix type im­ple­ment­ing INumeric and I add to that type an­other
   static mem­ber ( * ) (left: INumeric, right: INumeric) =
de­tail­ing ma­trix mul­ti­pli­ca­tion as well as (element-by-element) ma­trix-times-scalar mul­ti­pli­ca­tion.
Next, I type
let B = A * z;;
where A is a ma­trix and z is a com­plex.  Which of the two meth­ods would be in­voked? Since I’m the one im­ple­ment­ing INumeric, how would the frame­work make it pos­si­ble for me to guar­an­tee that the Matrix method will be in­voked? The prob­lem is that if the Complex method is in­voked in­stead, then that forces me to du­pli­cate code for Complex-Matrix mul­ti­pli­ca­tion (note that when I cre­ated the Complex type, Matrix did not ex­ist yet).
I sup­pose it would be very use­ful to al­low some kind of hi­er­ar­chy (or some other ap­proach to user con­trol) over the call res­o­lu­tion, be­cause then I would not have to du­pli­cate code any­where (neither for prim­i­tive types nor for my own types im­ple­ment­ing INumeric).
Best re­gards,
  dfg
PS.- I’m not sure if what I’m sug­gest­ing is al­ready pos­si­ble in sim­i­lar con­texts.

I for­got a cou­ple of things:
- I’m aware that one can avoid prob­lems by care­fully us­ing a unique non-sta­tic method:
let B = A.Times(z);;
I’m just cu­ri­ous to know how far flex­i­bil­ity and code unique­ness can be taken when us­ing op­er­a­tor over­load­ing in­stead.
- Is it cor­rect that it is rec­om­mended to keep op­er­a­tor over­load­ing in .NET to a min­i­mum?
Thanks in ad­vance,
  dfg

Melitta Andersen

2009-02-24T04:42:51Z

Hi dfg,
I’m Melitta, a mem­ber of the Base Class Library team, which would own the INumeric fea­ture.  I have a cou­ple of an­swers around what we’ve been think­ing.  We don’t have all the de­tails and all of this is of course sub­ject to change.
Currently our think­ing has been along the lines of an INumeric<T> that sim­ply guar­an­teed that a type had par­tic­u­lar meth­ods.  So if you were to im­ple­ment a generic Complex num­ber as in your ex­am­ple, it would need to spec­ify that both Re and Im were INumeric<T>.  INumeric<T> would have meth­ods like Add(left: T, right: T) that would re­turn type T.  Then you could per­form the op­er­a­tions on the el­e­ments them­selves, us­ing the stan­dard for­mu­las for com­plex arith­metic.  You would end up with a sta­tic mem­ber ( + ) (left: Complex, right: Complex) = {Re = left.Re + right.Re; Im = left.Im + right.Im} in­stead of sta­tic mem­ber ( + ) (left: Complex, right: INumeric).  And then you could have your Complex struc­ture it­self im­ple­ment INumeric<Complex>, and it could be used in larger struc­tures like Matrices.
We haven’t been think­ing of INumeric as a way to au­to­mat­i­cally in­ter­act with any pos­si­ble nu­meric type.  You still have to spec­ify the T.  This means that you still have to de­ter­mine which other types your type will in­ter­act with and cast to im­plic­itly or ex­plic­itly.  In your Matrix ex­am­ple, if Matrix im­ple­mented INumeric, the mul­ti­pli­ca­tion func­tion (it could only be an op­er­a­tor if in­ter­faces al­lowed sta­tic meth­ods, or if the com­pil­ers knew to com­pile the op­er­a­tor down to a par­tic­u­lar in­stance method) would only mul­ti­ply two ma­tri­ces of the same type.  So if you wanted to mul­ti­ply a ma­trix by a com­plex scalar, you’d have to im­ple­ment that specif­i­cally (and not call it through the in­ter­face, un­less you found a way to treat com­plex scalars as ma­tri­ces).  However, INumeric may help sim­plify the task of mul­ti­ply­ing a Matrix<T> by a scalar of type T.
As for your ques­tion about op­er­a­tor over­load­ing rec­om­men­da­tions, you may want to check out our Framework Design Guidelines on the topic: http://​msdn.mi­crosoft.com/​en-us/​li­brary/​2sk3x8a7.aspx.
Thanks,
Melitta
Base Class Libraries

Hi Melitta,
Thanks a lot for tak­ing the time to de­scribe the INumeric<T> plan. With re­gards to sta­tic meth­ods in in­ter­faces, I found this:
http://​dot­netjunkies.com/​WebLog/​malio/​archive/​2007/​03/​01/​204317.aspx
Thought you might find it in­ter­est­ing.
Thanks and re­gards,
  dfg

Adam Pursley

2009-02-26T00:45:59Z

I’d like the abil­ity to de­clare my own in­ter­face and then de­clare that other classes that I don’t con­trol im­ple­ment my in­ter­face, pro­vided of course that those classes ac­tu­ally do have the ap­pro­pri­ate meth­ods/​prop­er­ties.
If I could do that, then in this sit­u­a­tion I could pos­si­bly de­fine my own INumeric<T> in­ter­face and de­clare that var­i­ous prim­i­tive types do im­ple­ment my in­ter­face.
I think ex­ten­sion meth­ods in­tro­duced in 3.0 was kind of a step in this di­rec­tion.
In gen­eral that would al­low the con­sumers to iden­tify sim­i­lar­i­ties be­tween dis­tinct com­po­nents and pull them to­gether with­out hav­ing to wait for the own­ers of those com­po­nents to en­hance the li­brary with com­mon in­ter­faces in a fu­ture ver­sion.
Think about the com­mon in­ter­faces in the System.Data name­space in .Net 2.0.  We had to wait for it to be­come part of the stan­dard frame­work in 2.0, even though we could al­ready see the sim­i­lar­i­ties in .Net 1.1 be­tween the com­po­nents in the OdbcClient name­space classes and the com­po­nents in the SqlClient name­space.

Marc Gravell

2009-02-26T02:48:36Z

Note that you can get a lot of this func­tion­al­ity *today* with­out us­ing dynamic”. One ap­proach is to use Expression as a mi­cro-com­piler to do the duck-typ­ing, and cache the del­e­gate away. This is pre­ci­cely what the generic op­er­a­tor sup­port in MiscUtil does.
See here for the overview:
<a rel=“no­fol­low” tar­get=“_new” href=“http://​www.yoda.arach­sys.com/​csharp/​mis­cu­til/us­age/​gener­i­c­op­er­a­tors.html”>http://​www.yoda.arach­sys.com/​csharp/​mis­cu­til/us­age/​gener­i­c­op­er­a­tors.html
or here for the ac­tual code:
http://​www.yoda.arach­sys.com/​csharp/​mis­cu­til/

Thomas Eissfeller

2009-02-26T05:39:36Z

Just a com­ment on per­for­mance:
I im­ple­mented the BLAS func­tion daxpy in dif­fer­ent lan­guages. And see what per­for­mance I got on my work­sta­tion (Intel Q9550 CPU, every­thing’s run­ning sin­gle threaded in 32bit). n = 1000000 and per­for­mance is av­er­aged over 1000 runs. Each ad­di­tion and each mul­ti­pli­ca­tion is con­sid­ered one FLOP. If you want to re­pro­duce the re­sults, make sure you start the pro­grams with­out at­tach­ing a de­bug­ger.
––––––––––––––––––
Visual C++: 398.96 MFlops/s
void daxpy(int n, dou­ble a, dou­ble* xp, dou­ble* yp, dou­ble* rp)
{
for (int i = 0; i < n; i++)
{
rp[i] = a * xp[i] + yp[i];
}
}
––––––––––––––––––
Intel Fortran: 557.41 MFlops/s
sub­rou­tine daxpy(n,a,r,x,y)    
in­te­ger (kind=4) :: n    
real (kind=8) :: a    
real (kind=8), di­men­sion(n) :: r,x,y  
in­te­ger (kind=4) :: i  
do i=1,n      
r(i) = a * x(i) + y(i)    
end do  
end sub­rou­tine daxpy
––––––––––––––––––
C# (Microsoft CLR): 399.43 MFlops/s
pri­vate sta­tic void Daxpy(int n, dou­ble a, dou­ble[] x, dou­ble[] y, dou­ble[] r)
{
for (int i = 0; i < x.Length; i++)
       {
r[i] = a * x[i] + y[i];
       }
}
––––––––––––––––––
The JIT com­piler team did a great job. Only Intel Fortran out­runs the CLR code. The nice thing about c# is that bound­aries checks come for free. However, the ma­jor draw­back is that CLR ar­rays can’t be larger
than 2GB.

Thomas,
>Only Intel Fortran out­runs the CLR code
Did you use au­tovec­tor­iza­tion with the Intel com­piler?
This one place where the the CLR re­ally lacks. MS should im­ple­ment some­thing like Mono.SIMD and Intel’s au­tovec­tor­iza­tion for C#/F#.

In my view Adam’s com­ment above is in the right di­rec­tion and very much what I’ve had in mind for a while now. I would­n’t go as far as to al­ways force the use of an in­ter­face for that though. I think the ar­chi­tec­ture would ben­e­fit from the equiv­a­lent to the math­e­mat­i­cal con­cept of category”:
http://​en.wikipedia.org/​wiki/​Cat­e­go­ry_(mathematics)
Or, in Adam’s words:
allow the con­sumers to iden­tify sim­i­lar­i­ties be­tween dis­tinct com­po­nents and pull them to­gether”
Roughly speak­ing, the same un­der­ly­ing idea.
In some as­pects, these categories” could be seen as a light-weight ver­sion of the con­cept of in­ter­face.
But I sup­pose com­ing up with a con­cept is one thing and im­ple­ment­ing it in the ar­chi­tec­ture is an­other thing. There I can’t help much, but I’ll elab­o­rate a bit more on the idea in a later post.

R&amp;#252diger Klaehn

2009-02-27T11:50:57Z

What is re­ally needed is some­thing like a struc­tural type con­straint. See this feed­back item for how this would work
https://​con­nect.mi­crosoft.com/​Vi­su­al­Stu­dio/​feed­back/​ViewFeed­back.aspx?Feed­backID=412848
But I must con­fess that af­ter five years I have given up on C#. The lan­guage is just get­ting more and more bloated while still miss­ing es­sen­tial fea­tures.
I am try­ing to con­vince my boss to write the next big pro­ject in java with the more nu­mer­i­cally com­plex parts writ­ten in scala.

David Nelson

2009-02-27T22:50:08Z

@Rudiger
You’re giv­ing up on C# and switch­ing to JAVA? Talk about tak­ing a step back­wards…

R&#252diger:
structural type con­straint”?
Do you mean as in using gener­ics but com­bined with some stuff that makes gener­ics not be so generic?“
I guess my ques­tion is: If gener­ics have to come with some stuff to not make them so, say, generic”, then what’s the point in us­ing gener­ics in the first place?
I mean, what’s next, peo­ple us­ing gener­ics to
rep­re­sent 2 + 2 = 4 us­ing gener­ics just for the sake of us­ing gener­ics?

R&amp;#252diger Klaehn

2009-02-28T04:46:27Z

Re: David Nelson
At least with java you know that they won’t add a dozen su­per­fi­cial lan­guage features” for each re­lease. C# has be­come much too com­plex and non-or­thog­o­nal.
But the lan­guage I am plan­ning to use for the more com­plex al­go­rithms is scala http://​www.scala-lang.org/
The com­mon base classes and in­ter­faces will be writ­ten in java since that is the low­est com­mon de­nom­i­na­tor for the java plat­form.
Re: dfg
A struc­tural type con­straint is not less generic than an in­ter­face con­straint. It is just a dif­fer­ent ap­proach to gener­ics.

David Nelson

2009-02-28T14:52:58Z

@Rudiger
To each his own. Yes C# is con­tin­u­ing to evolve, and yes there is a lot to keep up with, but per­son­ally I am glad to be us­ing a lan­guage and a plat­form that is still try­ing to keep up with the needs of mod­ern de­vel­op­ers, rather than one which has re­signed it­self to liv­ing in the past.

Paulo Zemek

2009-02-28T16:56:59Z

R&#252diger Klaehn, I will not say that Java has any ad­van­tages over .net than be­ing multi-plataform, but I re­ally liked your pro­posal for stru­tural con­straints.
I, for ex­am­ple, al­ways liked the C++ tem­plate be­cause I could cre­ate a tem­plate for any class with a GetName() method.
I re­ally liked your so­lu­tion. I ex­pect the .net team can use some struc­tural so­lu­tion like yours for gener­ics.
But, for Luca, I liked Luca post also. Luca in­tended to show how dy­namic could be used, and this has been done suc­cess­fully.
I will re­ally like to see num­bers of per­for­mance com­par­i­son us­ing dy­namic and real prim­i­tive types.

R&amp;#252diger Klaehn

2009-03-01T06:25:10Z

Re: David Nelson
The lan­guage I am go­ing to use is not java but scala. We are just us­ing java for the com­mon in­ter­faces to en­sure in­ter­op­er­abil­ity.
I have noth­ing against adding fea­tures to a lan­guage, but the fea­tures should be gen­eral pur­pose fea­tures and not just spe­cial syn­tax to ad­dress a spe­cial use case.
For ex­am­ple, in­stead of pro­vid­ing spe­cial syn­tax for nul­lable types, they should have made gener­ics more flex­i­ble so that adding spe­cial op­er­a­tors for nul­lable types could be done in a li­brary.
And don’t get me started about the new col­lec­tion ini­tial­izer syn­tax. It uses struc­tural typ­ing (a class that im­ple­ments IEnumerable and has an add method is as­sumed to be a col­lec­tion), but it does not pro­vide a generic mech­a­nism for those of us that would like to use struc­tural typ­ing for their own pur­poses.
Re: Paulo Zemek
I would love to do some bench­marks. But is there a ver­sion of the .net 4.0 frame­work avail­able that is not ob­so­lete and does not re­quire vir­tual pc? I did not find one.

Eduard Dumitru

2009-03-02T11:46:38Z

Hello every­one,
First of all I would like to thank Anders Hejlsberg for ex­ist­ing, on be­half of the peo­ple who think, who de­sign so­lu­tions and pro­ject them into re­al­ity and also thank Eric, Luca, Charlie, and every­one in the Visual Studio, .NET, C#… teams.
I don’t ac­tu­ally un­der­stand the term programmer” but, I have been pro­gram­ming since the 4th grade (started with BASIC on a Z80 com­puter, con­tin­ued with Pascal, C++, moved to Visual Basic, Visual C++, Delphi, Assembler, (the or­der is just tem­po­ral, there is no ac­tual logic in it), Delphi for .NET, Java, Prolog, C#, F#, Javascript, Python, Ruby ).
At first I lacked a stack (there was only a GOSUB rou­tine which had a 1-length stack”). Then I lacked mem­ory, load­ing (of bi­nary mod­ules at run­time). Then I lacked a Garbage Collector. I’m not say­ing that the things I was look­ing for weren’t out there, some­where, but they surely weren’t in the pos­si­bil­i­ties of­fered by that par­tic­u­lar lan­guage. It is maybe the first time in my life when I am wait­ing for the next re­lease of a frame­work, know­ing what will be in it and every­thing I want to use as a lan­guage is not yet made.
I’m not try­ing to say what is good or bad, in gen­eral. There are many para­doxes in the hu­man - com­puter com­mu­ni­ca­tion that we call pro­gram­ming (it is good to have GC / it is bet­ter if I’m al­lowed to de­stroy things as I please).
The rea­son I dared to be so idio­syn­cratic when writ­ing this com­ment is that oth­ers also dared. I don’t re­ally want to read these blogs to know what peo­ple choose for a lan­guage, what pro­jects they are work­ing on. I’m not sure what the pur­pose of these blogs are but it is my be­liev­ing that it has noth­ing to do with the pe­cu­liar tastes of the read­ers.
I’m only writ­ing this be­cause a dis­tur­bance was made (in the Force :)) and I be­lieve all things re­side in sym­me­try.
In my opin­ion, the power of C# stands not in the power to com­pute large sets of num­bers (I would prob­a­bly use PLINQ some­how to ask a num­ber of proces­sors to do a lot of work, or will make a dif­fer­ent ex­e­cutable process and con­nect to it through I/O, or a dif­fer­ent mod­ule and load it through PInvoke Loading”), but rather in the el­e­gance and sim­plic­ity of thread-flow and heap-state de­scrip­tion. Please don’t be fooled by my pas­sion and think that I can­not syn­chro­nize threads in C us­ing POSIX, or don’t know how to throw an ex­cep­tion from a Java method that states it does not throws” any.
I think it’s all about the main­te­nance of your ideeas while cod­ing. I’m sorry to here that things like type in­fer­ence cause a rash to some who ap­pre­ci­ate multi in­heri­tence in con­trast. I don’t think there’s any doubt that re­flec­tion is a good thing (I mean in gen­eral, in hu­mans, in po­etry). Well Type is a great class (check it out if you haven’t, I mean re­ally check it out, see when in­stances are cre­ated and what hap­pens with all the threads).
And for Java lovers who think gener­ics are bet­ter in Java be­cause of straight-for­ward­ness I have two small tests:
1. Try to in­fer on the generic type at run­time.
2. Try to de­clare a generic type par­tic­u­lar­iza­tion in process A, use I/O to se­ri­al­ize and send it to process B and de­se­ri­al­ize it there (and of course, don’t men­tion the generic type par­tic­u­lar­iza­tion syn­tac­ti­cally in pro­gram B). I won­der what will hap­pen.
Please for­give me if I am wrong, but I sus­pect that those who said that C# is evolv­ing too fast never got to un­der­stand it as a whole. The evo­lu­tion of C# is nor­mal and it is hard to ac­com­plish. The rea­son Java is not evolv­ing (from within the core) is be­cause it can­not, not be­cause they don’t want it to.
They have made a se­ries of bad choices and are now stuck (they could ei­ther evolve and loose com­pat­i­bil­ity with tons of soft­ware al­ready made and tons of knowl­edge that is within pro­gram­mers’ heads).
You can only go as so far with the evo­lu­tion as you can. And it is the childhood sins” that keep you from go­ing any fur­ther.
C# is won­der­ful for me. In my case it is the best com­pro­mise be­tween speed, ex­pres­siv­ity, main­tain­abil­ity. Please don’t be fooled and think that I ap­pre­ci­ate the li­braries that are pre-writ­ten so dearly. I do. But I ap­pre­ci­ate the lan­guage and the frame­work the most.
It ap­proaches the power of Javascript and Python from a strongly-type, highly aware of what IS, per­spec­tive.
I don’t think the prob­lem of pro­gram­ming should be so highly bound to the en­gi­neer­ing is­sues (the proces­sor, mem­ory, etc). I’m say­ing this and I am a com­puter en­gi­neer.
It should, in my opin­ion, be ag­nos­tic (in the sense that the com­piler, the run­time and maybe part of the li­braries, are tak­ing care of those things). Isomorphisms don’t al­ways add value.
Thank you for read­ing this chunk of per­sonal be­liefs. I am look­ing for­ward to the com­ming of C# 4.0 (already got the CTP ma­chine :)).
Have a nice day every­one,
Eduard Dumitru
Please ex­cuse my looon com­ment,
and my eng­lish spelling.

I found in­ter­est­ing that we have a sim­i­lar sit­u­a­tion Java <-> Scala, with (VB/C#) <-> F#.

RE: dfg
I am a lit­tle late to the party here, but to the point made by dfg about violating the laws of math­e­mat­ics”, I think I can see a fourth op­tion that could be use­ful.
For 80x86 CPUs, I be­lieve the di­vi­sion in­struc­tion puts the re­sult of the di­vi­sion in one reg­is­ter and the re­main­der in an­other.  The prob­lem with in­te­ger di­vi­sion in high-level lan­guages is that we are only re­turned the re­sult, and the re­main­der is lost.  If I am not mis­taken, the mod­ulo op­er­a­tor is ex­actly the in­verse case, we are given the re­main­der, not the re­sult, even though at the hard­ware level, a di­vi­sion op­er­a­tion was still ex­e­cuted.
I think it would be pos­si­ble to cap­ture the re­main­der value and save it as a prop­erty of the in­te­ger vari­able (at least in a man­aged lan­guage).  I am not sure how this is im­pacted by in­te­gers be­ing value types in .Net.