params parameter must be a single dimensional array - (It is! Tell me it isn't!)<g>

Wasn't the goal, and hope for .Net 2 / the next version of C# not to rely on boxing of objects For it is the cornerstone of Generics...typesafe arrays and no more boxing!

But one area was overlooked.....take for example this code using the params keyword

public void Columns(params string[] ColumnNames) { ... }

Nice convention! It saves keystrokes and makes code easier to use...but it was not updated to use generics! The following code in .Net 2 gets the dreaded CS0225 error erronously telling the user that a single dimensional array is not being used....

public void Columns(params List<string> items ) { ... }

Feel free to tell me that List<string> is not a single dimensional array. I sure think it is. Obviously the error text should say "params parameter must be a single dimensional array and must not be a generic list" but that is not the direction of the post.

The question is this, "Why wasn't the params lexical analysis for version two changed to handle generics "

All thoughts appreciated and welcome. How about in the next version






Answer this question

params parameter must be a single dimensional array - (It is! Tell me it isn't!)<g>

  • kadabba

    I think this hits the root of why you think List<> is like an array:

    OmegaMan wrote:

    If one peels back the layers and looks lower into the generated machine code....An array is fundamentally a specialized structure that holds pointers to memory locations. How is that different from a generic list (collection) structure that also has to hold pointers to memory locations

    It is where the compiler interprets what it sees, way before it is changed into machine code that is the key. At that point, the C# compiler could handle this situation and pass it on via the params construct; for it is just a list of memory pointers.

    An array is a single pointer to a block of references or values. A list is an ordered collection of pointers to references or values. This is why there is no easy way to insert a new value into the middle of an array. Fundimentally, an array is no more similar to a List<> than it is to a hashtable or stack.

    And as an aside, don't forget you can call List<>'s ToArray() method

    List<int> aList = new List<int>();
    ...
    Method( aList.ToArray() );


  • elainel311

    What would having the params collected into a List<string> versus a string[] buy you An example would make your suggestion more compelling.

    -Tom Meschter

    Software Dev, Visual C# IDE



  • Ultrawhack

     Peter Ritchie wrote:
    I think you're missing the point of params. It's not there to "save keystrokes", it's there to support variable number of arguments, of the same type.


    I agree with the your point of supporting variable arguments, but I also have to respectfully disagree...It also saves the user having to do these steps: create and allocate an array, then add the items, and then pass it in....if that is not saving keystrokes....<g> but this is not my intention of the original post.

     Peter Ritchie wrote:
    Arrays for params would always have to be supported for the case of calling a .NET 1.1 assembly; why introduce another method of doing something where it is not needed


    I agree with you that arrays need to be supported. But, my point in a nutshell is that programming languages have to be symmetrical in design and implementation. The grammar of a language that orchestrates the lexical analyses is built on such symmetry. (IMHO) I believe that this post points out the failure of such symmetry currently not found in C#; let me explain why

    The definition of params as found in the C# language:

    A parameter array is declared with a params modifier. There can be only one parameter array for a given method, and it must always be the last parameter specified. The type of a parameter array is always a single dimensional array type.

    If one looks at the grammar of C# concerning the params this is what one sees

    parameter-array:

    attributesopt params array-type identifier

    Array-type and its identifier…. The disconnect must be that array-type does not allow for a generic List<>. I consider List<> to be an array type.

    If one specifies that the array-type on the target method declaration as List<T> vs. T[ ], shouldn’t that work Remember .Net 2 has already expanded the params grammar to handle generic functions such as

    void PushMultiple<T>(Stack<T> stack, params T[ ] values)

  • EtherealSky

    Why do you insist that a List<string> is an array   While it has some SIMILARITIES to arrays, its not at all the same thing as an array.  And just being similar isn't sufficient.  I can't create a class thats SIMILAR to an existing one, and use it in place of that class.  The compiler wont allow it.  Now, if I declare my new class to derive from the other class, then it is allowed.  But, List<stirng> is not derived from string[] or Array, nor should it be.  Yes, I agree that they COULD have decided to allow the syntax you describe.  But doing so would require more than just lexical analysis changes.  And beyond that, where would it stop   Should we allow them to use non-generic List, or LinkedList, or any number of other list-like variations   No, they stuck with Array, because its simple and does the job.

    And, using strongly-typed arrays does NOT cause boxing, btw.


  • RMooreFL

    Tom Meschter MSFT wrote:
    What would having the params collected into a List<string> versus a string[] buy you An example would make your suggestion more compelling


    I consider the strength of C# to be the fact that it is a generational language, meaning that it is continuing to evolve. I look at C/C++ and to a lesser extent Java and don't feel they are (or were) as dynamic as the growth of C#.

    When .Net 1 came out with C#, the modus operandi was the array and array list. An infrastructure was built around those items to support them, and one was the params keyword. With .NET 2 one of the new paradigms was generics lists, which in my mind are far superior, in most respects, to the arrays, arraylist and hashtable (I will refer to them as array paradigm here on out). I hardly use the array and exclusive use the generic counterparts.

    To me what is missing is the ability to use a generic list with params keyword. It feels like the infrastructure to facilitate the usage of the new paradigm was not completed for generic lists. In my mind, to be consistent, if a user wants have parameter data consumed from a generic list, instead of an array when using the params...why not The infrastructure should accommodate both and we are on a new paradigm of handling data.

    List<x> has a toArray(), but there is not counterpart in the array world to output a generic list. Its Gen2 accommodating for Gen 1. It just feels the infrastructure should also accommodate for Gen 2 in the same manner.


    ...IMHO




  • Mike36

    I strongly support this as well. The whole point is we should be coding functions that take interface types, rather than concrete types, in order that the function only cares about what the interface can do, rather than what concrete type it is.

  • Argus.Antony

    Well, I need to change my moniker to Virgil Caine and acknowledge the war is over. <g>

    Here is the official response from Microsoft. Thanks to all that have participated in this thread and gave opinions.

    Microsoft wrote:
    Thank you for your suggestion.

    We are probably not going to consider params generating anything but arrays - that is a little to magical. However, we consider allowing params to be specified not just with array types directly, but also with the interfaces that arrays implement: for T[] that would be IList<T> and its super-interfaces ICollection<T>, IEnumerable<T> and IEnumerable. So you could say:

    public void Columns(params IList<string> items) { ... }

    which could be called as

    Columns("one","two","three");

    passing a newly created string[], or

    Columns(new List<string>{"one","two","three"});

    passing a List<string>.

    I cannot promise that we will do this, but it was high enough on the list for Orcas that we only reluctantly cut it because of time constraints, so it is certainly on the table again post-Orcas.

    Thanks again,

    Mads Torgersen, C# Language PM






  • MukilanP

    As an update I decided to post this as a Connect suggestion Allow params parameter to be a generic list for the next version. Feel free to post thoughts on the issue...I thought it might be interesting to get Microsoft's angle on the suggestion.


  • Hooper

    I concur with your conclusions concerning my misrepresenting/misstating of what the list is; its not a defined array as the underlying levels see it. I appreciate your understanding of why to me, at the top level of it all, they seem to be the same. Thanks!


  • Christopher Lusardi

    OmegaMan wrote:
    It also saves the user having to do these steps: create and allocate an array, then add the items, and then pass it in....if that is not saving keystrokes....<g> but this is not my intention of the original post.

    static void Method(params String[] parameters)

    {

    }

    static void Form1Test()

    {

    Method("one", "two", "three");

    Method(new String[] { "one", "two", "three" });

    Doesn't seem like a big time-saver to me. You'd have no less work if params supported List<T>.
    OmegaMan wrote:
    I agree with you that arrays need to be supported. But, my point in a nutshell is that programming languages have to be symmetrical in design and implementation. The grammar of a language that orchestrates the lexical analyses is built on such symmetry. (IMHO) I believe that this post points out the failure of such symmetry currently not found in C#; let me explain why

    The definition of params as found in the C# language:

    A parameter array is declared with a params modifier. There can be only one parameter array for a given method, and it must always be the last parameter specified. The type of a parameter array is always a single dimensional array type.

    If one looks at the grammar of C# concerning the params this is what one sees

    parameter-array:

    attributesopt params array-type identifier

    Array-type and its identifier…. The disconnect must be that array-type does not allow for a generic List<>. I consider List<> to be an array type.

    What symmetry There may be a certain consistency in a language's grammar; but symmetry is something else. I don't see what sort of "symmetry" you're alluding to between the definition of params and the BNR notation of params. They both say the type is Array, seems consistent to me.

    List<> is not an array type, if it were you could use it as a params type.

    params isn't just a C# thing, there's also the ParamArrayAttribute that can be used in VB, or any other language that doesn't have syntax for params compatibility. Changing the way params works would need symmetry amounts all other .NET languages, good luck with that.

    params essentially uses a built-in type, or a type that's specified to be in all CLI implementations (because Array is in the BCL which is specified to be supported by the Kernel profile--the base implementation requirement for a CLI implementations). Generics are also in the BCL; but, the parametrized type may not. For example, I can define a type MyClass to be used as the argument for List<>. Since MyClass isn't in the BCL there's no way for external applications to call a method defined as Method(params List<MyClass>) because it can't be sure that's legal in any baseline CLI implementation.

    By the way, the type of the parameter is Array; but the argument need only derive, or implement, Array (hence String[], MyClass[], etc. all work, which is done by the compiler--you can directly derive from Array). You get type safety with params. There's nothing to be gained by supporting List<T> or any other generic.

    Array may be been a poor choice, an IList interface may have been better, but that's moot now.



  • jepptje

    Nimrand wrote:
    Why do you insist that a List<string> is an array While it has some SIMILARITIES to arrays, its not at all the same thing as an array.


    This hits exactly on the issue. I fully believe that List<T> as introduced in version two of C# is just as much of an array as the array introduced in version one, T[ ]. I will explain why after responding to a section in Peter's post relating to the low-level params umbrella.

    Peter Ritchie wrote:

    params essentially uses a built-in type, or a type that's specified to be in all CLI implementations (because Array is in the BCL which is specified to be supported by the Kernel profile--the base implementation requirement for a CLI implementations). Generics are also in the BCL; but, the parametrized type may not. For example, I can define a type MyClass to be used as the argument for List<>. Since MyClass isn't in the BCL there's no way for external applications to call a method defined as Method(params List<MyClass>) because it can't be sure that's legal in any baseline CLI implementation.


    Its to my understanding that if one creates an array of unsigned data types, that those are not cross-language compatible, yet one can create and pass them via the params construct. I simply cannot believe that it is the payload that is nixing the fact that List<t> cannot be used. An array is the highway, the data are cars. The generic list/collection is a highway just as an array. It can carry safe items or explosive items....and as stated by you, both are in the BCL.

    WHY

    If one peels back the layers and looks lower into the generated machine code....An array is fundamentally a specialized structure that holds pointers to memory locations. How is that different from a generic list (collection) structure that also has to hold pointers to memory locations

    It is where the compiler interprets what it sees, way before it is changed into machine code that is the key. At that point, the C# compiler could handle this situation and pass it on via the params construct; for it is just a list of memory pointers.


  • Mark Marquis

    I agree that what you suggest could probably be accomplished. But, you keep muddling the issue by calling a List<int> and array. Its not. List<int> is what it is and an array is an array. They are similar and that similarity is captured in the fact that both are examples of IList. So, one could argue that the params construct should be supported for any type that implements IList and has a parameterless constructor, or something along that lines. But calling List<int> an Array is an incorrect use of the vocabulary. An Array means a very specific kind of object in .NET, and arbitrarily applying it to other objects will only create confusion and impede one's ability to talk about .NET code in a concise manner.


  • TRID

    OmegaMan wrote:
    Wasn't the goal, and hope for .Net 2 / the next version of C# not to rely on boxing of objects For it is the cornerstone of Generics...typesafe arrays and no more boxing!

    But one area was overlooked.....take for example this code using the params keyword

    public void Columns(params string[] ColumnNames) { ... }

    Nice convention! It saves keystrokes and makes code easier to use...but it was not updated to use generics! The following code in .Net 2 gets the dreaded CS0225 error erronously telling the user that a single dimensional array is not being used....

    public void Columns(params List<string> items ) { ... }

    Feel free to tell me that List<string> is not a single dimensional array. I sure think it is. Obviously the error text should say "params parameter must be a single dimensional array and must not be a generic list" but that is not the direction of the post.

    The question is this, "Why wasn't the params lexical analysis for version two changed to handle generics "

    All thoughts appreciated and welcome. How about in the next version
    I think you're missing the point of params. It's not there to "save keystrokes", it's there to support variable number of arguments, of the same type. You've already got a strongly-typed array; adding support for generics isn't going to reduce boxing, there isn't any. For example, with the following:

    static void Method(params int[] parameters)

    {

    // ...

    }

    // ...

    Method(new int[] { 1});

    The call to Method gets compiled to the following IL:[code language="IL"] .locals init (
    [0] int32[] CS$0$0000)
    L_0000: nop
    L_0001: ldc.i4.1
    L_0002: newarr int32
    L_0007: stloc.0
    L_0008: ldloc.0
    L_0009: ldc.i4.0
    L_000a: ldc.i4.1
    L_000b: stelem.i4
    L_000c: ldloc.0
    L_000d: call void WindowsApplication4.Program::Method(int32[])[/code]You'll notice there are no boxing instructions.

    Arrays for params would always have to be supported for the case of calling a .NET 1.1 assembly; why introduce another method of doing something where it is not needed



  • params parameter must be a single dimensional array - (It is! Tell me it isn't!)<g>