tags:

views:

1377

answers:

17

Just as C# 2 introduced T? as a short-hand for Nullable<T>, shouldn't C# consider introducing a short-hand for even the more popular IEnumerable<T>? Like T*?

Wouldn't this help make something that should be simple to read, like

Func<IEnumerable<string>, IEnumerable<string>> f;

in fact simple to read?

Func<string*, string*> f;

What would be the downside, if any? Naturally, T* introduces some syntactic overlap with pointers in C# but then what would be an alternative? T+?

Bear in mind:

  • Pointers are only allowed in C# when code is compiled with the /unsafe switch and even then in methods explicitly marked with unsafe.
  • Pointer syntax is not allowed in C# for a generic type argument. You cannot, for example, say IEnumerable<int*> today to mean a sequence of integer pointers. The compilation will fail with CS0306.


Rationale:

With the introduction of LINQ, the IEnumerable<T> has taken a center stage as the most generic way to represent a collection or sequence. The generic syntax, however, when used within delegates or method signatures can make code long and unreadable. For example, here is a simple use of Func<T, R> to declare a function variable that accepts and returns a sequence of strings:

Func<IEnumerable<string>, IEnumerable<string>> f;

This is a simple case and already makes the code unnecessarily long to write and read back. So, just as C# 2 introduced T? as a shorthand for Nullable<T>, should C# consider introducing a shorthand for IEnumerable<T>, like T*?

+8  A: 

I'll vote yes.

I'm not normally in favour of any such ASCII junk. However, IEnumerable is arguably the most fundamental type of the .NET framework since at least .NET 3.5. It is clearly much more imporant than native pointers (why have a syntax for unsafe pointers?!) or Nullable types.

Konrad Rudolph
I agree we should have sugar coating here but I'm not sure if the * or + make sense (Isn't plus going to be used to indicated variance). I don't think we need syntax for unsafe pointers except for the fact that we already have them.
JoshBerke
And the fact that some people, you know, might actually have a use for them ;)
Adam Robinson
@Adam: sorry but that's nonsense. I didn't say anything against unsafe pointers -- only against syntax sugar for them. There's absolutely no reason (except for the fact that it was copied from C) to have special syntax for such a rarely-used feature as unsafe pointers. These could very well be modelled by library Types and operator overloading, or even using only library functions, like in VB.
Konrad Rudolph
A: 

I like the idea but I think the syntax should have some relationship with array notation. Maybe string<> or string[?]?

Update
Considering that <> is already used and [?] is hard to type (though not as tough as IEnumerable<>), what about:

  • string[[]]

I'm sure there are many other variations, but the goal would be to come up with something that is intuitive to read and I don't think that string* or similar says "collection", hence dwelling on the array syntax.

Of course you could always alias the IEnumerable<T> via using statements without requiring any changes to the language and create declarations like Func<Strings, Strings>.

Jeff Yates
<> already has meaning in C# (for representing a generic type without specifying type arguments), but [?] might make sense. It's tough to type quickly, though.
Adam Robinson
Yeah, I know on both points. Just hoping to inspire a better option :)
Jeff Yates
[[]] is easier, though I'm still not completely in favor of a four-character shorthand ;)
Adam Robinson
:D Me neither. Just thinking aloud.
Jeff Yates
You could go with something like string[[ or string]].
Jeff Yates
@Jeff: string[[ or string]] looks too much like a typo.
Moose
The aliasing point is very good and is the technique I use when things get hairy especially with Func<IEnumerable<KeyValuePair<string, object>, IEnumerable<KeyValuePair<string, object>>. Gosh, now we need a short-hand for the only tuple we've got, KeyValuePair<,>. Maybe it's called IronPython? ;)
Atif Aziz
A: 

I've never thought of that but it sure makes sense in when you put it in context. I have however started abusing var for the reason of having to type less.

mhenrixon
Same here. Var saves me some typing.
Min
+1  A: 

I wholeheartedly support the idea of shorthand for IEnumerable, but I'd be hesitating to use the asterisk just for the sake of preventing confusion for developers in other languages where the asterisk denotes a pointer.

What about T# or T!?

Adam Robinson
Making developers of other languages comfortable should be a non-goal. :) However, looking for hints from C-family of languages may not be a bad idea.
Atif Aziz
Perhaps says you, Atif, but many developers write in other languages. * is a fairly standard decorator to indicate a pointer. I don't think it's exactly inappropriate to be wary of adopting an alternate (and completely unrelated) meaning.
Adam Robinson
True, but I reckon that ? for nullables, as in T?, was borrowed from regular expressions where it denotes optional. In the same light, T* seems like a natural way of saying one or several in a sequence. BTW, most C programmer view * like an array. Not assuming void*, pointer arithmetic permits moving linearly through memory (which can be seen as one fancy sequence). I think there's an analogy here with an enumerable, don't you?
Atif Aziz
I'm not sure that I'd say that "most C developers view * like an array". True enough that this is generally how they get represented in C, there are still plenty of other uses for them (like, say, creating pointers!). Add that to the fact that we already have * to indicate an unsafe pointer and I think the costs outweigh any potential gain. I can possibly see an analogy between this an something being enumerable, but often enumerable types aren't stored in a linear (or contiguous, anyway) fashion.
Adam Robinson
I think that `T!` should actually be used to denote a non-nullable reference type T. Pretty much the opposite of `T?`.
Jordão
+2  A: 

Hi,

Have you tried following?

using IES = System.Collections.Generic.IEnumerable<string>;

Does this serve purpose?

Edit: This would be still little more work then suffix way.

isntn
You would still have to introduce an alias for *every* type of class you want to enumerate. The point of the T+-construct is that T can be any class and since IEnumerable<T> is used quite often, it should be shortened, just as Nullable<T> has been.
J. Steen
Yeah, you are right. That is what I meant by saying that it is more work. Btw, like Nullable shorthand for value types, there should have been NotNullable shorthand for reference types.
isntn
+1  A: 

Well, maybe it's a good idea but you can't use an asterisk - C# already supports pointers using the asterisk. e.g. (You need to use the /unsafe compiler flag to get this to compile)

using System;

namespace ConsoleApplication7

    internal class Program
    {
     public static unsafe void Main()
     {
      var i = 5;

      // unsafe method: uses address-of operator (&)
      Add12ToTheInt(&i);
      Console.WriteLine(i);
     }

     private static unsafe void Add12ToTheInt(int* p)
     {
      *p += 12;
     }
    }
}
Steve Willcock
So? We have other context related grammar stuff in C# already. Like you say (right?), for this to compile you would need unsafe in the method. And I wouldn't want to mix IEnumerable<T> into unsafe methods, so there would be no problems for the compiler at all. I admit it [wc]+ould be confusing to some developer(s?). It's really too bad that C# 1.0 included limited pointer support it did. ;-)
peSHIr
+1  A: 

I'll vote no.

I believe adding an alias for IEnumerable at this point would create confusion.

If you want to save some typing either:

1) Create a snippet, or

2) If you use ReSharper, assign the expression to a var then jump to beginning of line and use the ReSharper context menu to change to explicit type. Using Visual Studio shortcuts it would be HOME, ALT+ENTER, ENTER.

Jason Morse
+21  A: 

Yeah, would be nice.

It's hard to find a character that doesn't look ugly inside the angle brackets. Maybe the hash sign:

Func<string#, string#> f;

Very visible, easy to type, only used by precompiler and stands for a number of items. The best: C# !

Jabe
+1 for # character, would have added it myself if you hadn't :)
Binary Worrier
Actually Adam Robinson was first ... ;)
Jabe
An `IEnumerable<T>` does not necessarily represent a finite sequence, which is implied by `#` meaning number of items. `#` is really only applicable to things with a `.Count` or `.Length` property, like lists and arrays.
Bryan Watts
+1  A: 

I like the idea.

Considering how IEnumerable is so pivotal to 3.5 as everyone is saying, why not borrow from the name of C# as it is? In other words, use

Func<string#, string#> f;

The # looks likes an array type-of-thing, which alludes to IEnumerable<T>.

Sure, you might have a little issue with #define's, but since it would come after a type, it should be relatively easy to parse without being ambiguous.

Erich Mirabal
+1  A: 

I'm undecided on the need for syntactic sugar, Resharper has gone a long way to reducing RSI for me.

For syntax I would suggest T~ e.g. string~

tilde is already an operator, but so are most of the other suggestions, and it is used pretty infrequently in most code.

ScottS
+9  A: 

Obviously C# can't do this now, but if I were starting C# from scratch, I'd be tempted to make T[] the shorthand for IEnumerable<T>.

mquander
And what happens to arrays?
leppie
If you want an array, then you ought to be able to make an Array<int>, same as any other strongly typed collection.
mquander
This seems so obvious and elegant, in hindsight.
Robert Harvey
+5  A: 

I think characters are reasonable for these and like how f# does it which is to call them Sequences and have seq<T>.

That said in most cases I rarely write IEnumerable<T> any where except at method definitions (where the extra verbosity is not a significant concern).

In most cases IEnumerables are either implicit (via fluent style chained method calls) or are assigned to a variable defined by var like so:

int[] list = {-2,-1,0,1,2,3,4,5,6,7,8,9 };

double d = list.Where(x => x > 0)
               .Select(x => Math.Sqrt(x))
               .Where(x => x < 5)
               .Max();

var evens = list.Where(x => x % 2 == 0);

If I change the type of list (say to an long the evens will cascade nicely)

I would strongly disagree with using * since the potential confusion with pointers is high. I also dislike +, and I'm pretty sure using it in that way would seriously complicate the parsing logic. In terms of widely available punctuation (on most keyboards) available for use you have $, ¬ and postfixed '@'.

  • ¬ has connotations of not in many languages so is a poor candidate.
  • @ is used already in prefix mode in two ways (string literals and escaping illegal variable names) so would become even more confusing.
  • $ has connotations as a variable identifier in many languages.

Really only $ is available but since that is the sole remaining character that could be used to extend the language I don't believe that shortening IEnumerable<T> justifies its use.

Assuming you ever wanted to add regex support as a language intrinsic then the $ would be an obvious choice for prefixing the resultant automatic variables. I believe that usage would trump this one. I am by no means certain that regexes should be a language intrinsic but would suggest them as a reasonable suggestion for why addition of syntax is a very careful weighing of priorities.

ShuggyCoUk
The fear of conflict with pointers could be put to rest considering they're only allowed when code is compiled with the /unsafe switch and that pointer syntax is not allowed in C# for a generic type argument. You can't say IEnumerable<int*> today. You'll get a CS0306: http://msdn.microsoft.com/en-us/library/72es69b8.aspx
Atif Aziz
but think of the LHS of an assignment...is T* foo = blah; indicating foo is a pointer to an instance of T or a sequence of T. To work this out your compiler would have to know what T is at that point (i.e. is it a generic type), this would be an unpleasant edge case for both intellisense and the actual compiler. It is by no mean insurmountable but looks to me a step too far (this is of course subjective)
ShuggyCoUk
Also what happens if the generics support is improved to allow pointers to instances of generic types (if it was made a lot cleverer this would work fine)
ShuggyCoUk
If you're in safe code :) then T* foo = blah would just make foo and blah hold references to the same enumerable object. Here, though, I'd just use var and let compiler infer foo's type from the expression on the RHS. Also, remember, a reference *is* a pointer. We've just done away with the star (except in unsafe context) so it could be put to better use now. ;)
Atif Aziz
a "reference *is* a pointer" ceased to be valid as a catch all statement detail the moment JIT compilers were allowed to enregister variables. Thinking it will only lead to heartache as sophisticated compiler techniques like escape analysis become more pervasive.I shall defer to the (always a good read) Eric Lippert: http://blogs.msdn.com/ericlippert/archive/2009/02/17/references-are-not-addresses.aspx.If in most cases you would use var then what's the point of more confusing syntax in the language? context based syntax without IDE highlighting is dangerous
ShuggyCoUk
+1  A: 

I'd vote yes, too. I'm quite sure I'd love this more than the Nullable-notation. :)

Personally I like the star, because it's a sign that is well-known for multiplicities in some model syntax definitions, e.g. conceptional DB models. But I do understand that it's bad for developers familiar with the "C-style pointer syntax".

By the way, is there already kind of official post to the C# language designers, or even some kind of discussion?

Mudu
You can add your vote or comments to:https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=434277
Atif Aziz
A: 

I'd vote no. How often do you find yourself typing this? Use var more often, or let ReSharper or Visual Studio do the typing for you.

John Saunders
Very, very often. I use IEnumerable<T> where ever I can get away with it, in stead of arrays, Lists or other collections. And it's not as much in typing per se (like you say, there are tools for that), it's just that this is turning into such a fundamental concept of the language/platform. If/as type inference is becoming more important, I don't want to read long types with listed IEnumerables in it if I don't have to. Think IntelliSense/debugger for instance.
peSHIr
+1  A: 

C# should adopt the F# seq<T> alias. Why have a six-syllable word for a two-syllable concept?

Joel Mueller
Also an option I could live with, yes.
peSHIr
I could deal with seq<T>, but not T*. The "*" doesn't refer back to any part of the IEnumerable<T> syntax, and in fact refers to pointers, which are not involved here.
John Saunders
+4  A: 

Why not just do it as in Haskell?

[string]

Examples:

Func<[string], [string]> f;

static [U] Map<T, U>(this [T] input, Func<T, U> mapper)

static [T] Flatten<T>(this [[T]] input)

There's a potential conflict with attributes, but the context would disambiguate it.

void Method([AnAttribute] [string] myStrings);

Also, an array of enumerables (or an enumerable of arrays) would be a little awkward (but it's a rare construct anyway):

[string][] myArrayOfStrings;
[string[]] myArraysOfStrings;

[ Apple ][ ] myAppleIIs;

The syntax can also be used for enumerable literals:

[string] theBugs = ["John", "Paul", "George", "Ringo", "Y2K"];
Jordão
Funny Apple ][ :))
Andrei Rinea
+1  A: 

Just to throw my own completely ridiculous suggestion out there: what about T...?

Then you could write:

Func<string..., string...> f;

More typing than the single character suggestions, obviously -- but I think that both * and + are problematic, for reasons already expressed (overlap with existing syntax).

# and ! on the other hand just seem kind of arbitrary. There's not really any logical connection between # or ! and the concept of a sequence (is there?). Plus: did you know the sharp symbol (♯) is not the same as the number sign (#)?

With ..., the implication of potentially multiple items is clear (to me, anyway). And I could be wrong, but I don't think there's any other context in which consecutive dots would compile; so I'm not seeing any syntactical overlap.

UPDATE: OK, I think the T{} suggestion is much better, actually.

Dan Tao
I thought about two dots when reading this question, i.e. `Func<string.., string..> f;`, `T.. enumeration;`. I think there is a programming language where it is like that (Delphi?). The `{}` I don't like so much actually.
herzmeister der welten