Generic constructors in C# cannot use type inference, so I either have to specify the types manually or use a static factory method. I can't see why this would have been so hard...
hmmm, being as I haven't got onto 3 I haven't even used type inference. Presume it gets rid of the need to do umpteen overloads. I assume it handles it a bit better than VB6's evil type co-oercion? I really do like my type incompatibility errors at compile time rather than runtime...
Starting with generics. Let's say you want a KeyValuePair with a string key and integer value (for instance). Rather than creating a new class KeyValuePairStringInt you can create a class KeyValuePair<TKey,TValue> and then you can do this:
KeyValuePair<string,int> myKeyValuePair = new KeyValuePair<string,int>("Andy",37); Now, because you've specified the type, myKeyValuePair.Key is a string and myKeyValuePair.Value is an int - and thus any type errors will be caught at compile time - myKeyaluePair.Value = "Hello" would fail.
However - if I then write a method somewhere: KeyValuePair<TKey, TValue> CreateKeyValuePair<TKey,TValue>(TKey key, TValue value) { return new KeyValuePair<TKey, TValue>(key,value); } then C# will be smart - I can call that method like so: object o = CreateKeyValuePair("Andy",37); and it will say "There's only one setting for TKey and TValue that makes sense, the way that was called - clearly TKey is a string and TValue is an int, and I shall thus I shall assume they are that way. It's still strongly typed - it's just made a best guess at what the initial types are. If it's at all ambiguous then it will throw a compile error and demand you specify them.
However - it won't let you call the constructor directly like that - you have to go through a separate method (like the one I wrote). And this irks me.
Disclaimer: I know next to no C#. The only C# I've ever written was a hasty line-by-line translation of a couple of C functions for the sake of somebody who wanted to include them in a C# program, so I didn't get to use any of this exciting stuff anyway.
That said, and assuming I've understood correctly, is this not just because you narrow the choice by declaring specific creator functions?
I mean. What are the possible types of the expression 37? It could be int, or it could be implicitly promoted to float, or (assuming C# hasn't dispensed with the outmoded idea of different-size integer types) it could be short or long or char. So if you just said new KeyValuePair("Andy",37), it wouldn't know whether to instantiate a KeyValuePair<string,int> or a KeyValuePair<string,char> or whatever, and it can't even guess from the type of the thing you're assigning into. But doing it with the function, it can rule out all those other options: the reason it can tell you meant int rather than char is because you defined CreateKeyValuePair<string,int> and didn't define CreateKeyValuePair<string,char>. So the compiler does need some means of narrowing down the available choices, and although that function looks as if it didn't do anything interesting, the utility of it is not in the function itself but in the knowledge of which set of such functions you bothered to define.
Or have I completely misunderstood?
eta: no, I have completely misunderstood, oops. Somehow I failed to notice that your creation function was actually totally generic itself. I'll go back to sleep.
Checking the spec: http://www.ecma-international.org/publications/files/ECMA-ST-WITHDRAWN/ECMA-334,%203rd%20edition,%20June%202005.pdf doesn't tell me anything terribly useful here. I assume that using literal numbers in the code is automatically assumed to be an integer. I know that if I typed decimal myDecimal = 300.5; then it would fail to compile - assuming that 300.5 was a double. If I want it to be a decimal then I need to type decimal myDecimal = 300.5m;
point: I am well up on generics, used them day in and day out for years. I dunno why it's important to me too ensure that you know that but it just IS. Probably a geek thing.... But someone else may have found that explanation useful.
37 is a valid value for several different types (e.g int, long), I can see why in the absence of any other info that C# would not be able to make a reasonable guess. It does seem inconsistent not to do what it does for method sigs for constructor sigs - I can't think offhand if there is any technical aspect of constructor meachanics that might tell us why that might be so.
I tend to specify the types most of the time anyway. I like to be as explicit as possible as a general rule. I'd particularly favour it where automatic inference could assume it was (say) an int where I know that it will in general be a long....
there are nearly no situations where I'd be using literals like that anyway. A variable or property would have a type and so you'd know it explicitly anyway (or get it by reflection). IIRC the onlytime I really rely on inference is in dealing with .Value from DataRows or the like.
And I'm happy enough to specify it once, but when I'm already typing KeyValuePair
[Error: Irreparable invalid markup ('<string,int>') in entry. Owner must fix manually. Raw contents below.]
37 is always an int. If you wanted a long then it would be 37l. A decimal would be 37m.
http://dotnetperls.com/suffix-examples
And I'm happy enough to specify it once, but when I'm already typing KeyValuePair<string,int> = at the start of the line, having to specify it again at the end is just extraneous.
If i'm not mistaken the main restrictions in C# are to do with the Common Language Infrastructure, and .NET runtime architecture which is designed for portability to any .NET runtime enviroment be it Windows, WinCE or even xbox360
Yes - it has to conform to that CLI - but the CLI was updated to deal with generics at the same time that C# was, so there's no reason that they couldn't both have been updated to deal with this situation.
Also - if I can write my own code in C# to do it then there's no reason why they couldn't have written the code for me and built it into the language.
I'd like PHP to give me error messages in ENGLISH instead of talking about T_THINGAMY. I mean, how hard is a lookup array that turns that into 'unquoted string' for instance? Then again. I mostly wish it was perl.
no subject
Date: 2009-10-21 01:00 pm (UTC)Still irks me though.
no subject
Date: 2009-10-21 01:05 pm (UTC)no subject
Date: 2009-10-21 01:18 pm (UTC)Let's say you want a KeyValuePair with a string key and integer value (for instance). Rather than creating a new class KeyValuePairStringInt you can create a class KeyValuePair<TKey,TValue> and then you can do this:
KeyValuePair<string,int> myKeyValuePair = new KeyValuePair<string,int>("Andy",37);
Now, because you've specified the type, myKeyValuePair.Key is a string and myKeyValuePair.Value is an int - and thus any type errors will be caught at compile time - myKeyaluePair.Value = "Hello" would fail.
However - if I then write a method somewhere:
KeyValuePair<TKey, TValue> CreateKeyValuePair<TKey,TValue>(TKey key, TValue value)
{
return new KeyValuePair<TKey, TValue>(key,value);
}
then C# will be smart - I can call that method like so:
object o = CreateKeyValuePair("Andy",37);
and it will say "There's only one setting for TKey and TValue that makes sense, the way that was called - clearly TKey is a string and TValue is an int, and I shall thus I shall assume they are that way. It's still strongly typed - it's just made a best guess at what the initial types are. If it's at all ambiguous then it will throw a compile error and demand you specify them.
However - it won't let you call the constructor directly like that - you have to go through a separate method (like the one I wrote). And this irks me.
no subject
Date: 2009-10-21 02:03 pm (UTC)That said, and assuming I've understood correctly, is this not just because you narrow the choice by declaring specific creator functions?
I mean. What are the possible types of the expression
37? It could be int, or it could be implicitly promoted to float, or (assuming C# hasn't dispensed with the outmoded idea of different-size integer types) it could be short or long or char. So if you just saidnew KeyValuePair("Andy",37), it wouldn't know whether to instantiate aKeyValuePair<string,int>or aKeyValuePair<string,char>or whatever, and it can't even guess from the type of the thing you're assigning into. But doing it with the function, it can rule out all those other options: the reason it can tell you meantintrather thancharis because you definedCreateKeyValuePair<string,int>and didn't defineCreateKeyValuePair<string,char>. So the compiler does need some means of narrowing down the available choices, and although that function looks as if it didn't do anything interesting, the utility of it is not in the function itself but in the knowledge of which set of such functions you bothered to define.Or have I completely misunderstood?
eta: no, I have completely misunderstood, oops. Somehow I failed to notice that your creation function was actually totally generic itself. I'll go back to sleep.
no subject
Date: 2009-10-21 02:22 pm (UTC)Checking the spec:
http://www.ecma-international.org/publications/files/ECMA-ST-WITHDRAWN/ECMA-334,%203rd%20edition,%20June%202005.pdf
doesn't tell me anything terribly useful here. I assume that using literal numbers in the code is automatically assumed to be an integer.
I know that if I typed
decimal myDecimal = 300.5;
then it would fail to compile - assuming that 300.5 was a double. If I want it to be a decimal then I need to type
decimal myDecimal = 300.5m;
More suffixes:
http://dotnetperls.com/suffix-examples
no subject
Date: 2009-10-21 03:32 pm (UTC)37 is a valid value for several different types (e.g int, long), I can see why in the absence of any other info that C# would not be able to make a reasonable guess. It does seem inconsistent not to do what it does for method sigs for constructor sigs - I can't think offhand if there is any technical aspect of constructor meachanics that might tell us why that might be so.
I tend to specify the types most of the time anyway. I like to be as explicit as possible as a general rule. I'd particularly favour it where automatic inference could assume it was (say) an int where I know that it will in general be a long....
no subject
Date: 2009-10-21 03:37 pm (UTC)no subject
Date: 2009-10-21 04:17 pm (UTC)http://dotnetperls.com/suffix-examples
And I'm happy enough to specify it once, but when I'm already typing
KeyValuePair
http://dotnetperls.com/suffix-examples
And I'm happy enough to specify it once, but when I'm already typing
KeyValuePair<string,int> =
at the start of the line, having to specify it again at the end is just extraneous.
no subject
Date: 2009-10-21 04:29 pm (UTC)you can say
long myval = 37;
no subject
Date: 2009-10-21 08:02 pm (UTC)Anyway - the point of the code wasn't to use literals - you can (obviously) use variables rather than literals with type inference.
I could have said:
string name = "Andy";
int age = 37;
KeyValuePair
Anyway - the point of the code wasn't to use literals - you can (obviously) use variables rather than literals with type inference.
I could have said:
string name = "Andy";
int age = 37;
KeyValuePair<string,int> andyDetails = KeyValuePairCreate(name,age);
which would be identical to
KeyValuePair<string,int> andyDetails = new KeyValuePair<string,int>(name,age);
no subject
Date: 2009-10-21 01:06 pm (UTC)no subject
Date: 2009-10-21 01:20 pm (UTC)Also - if I can write my own code in C# to do it then there's no reason why they couldn't have written the code for me and built it into the language.
no subject
Date: 2009-10-21 02:54 pm (UTC)Then again. I mostly wish it was perl.