share
Stack OverflowShould C# introduce a syntactic short-hand for IEnumerable<T>?
[+53] [17] Atif Aziz
[2009-04-27 16:56:57]
[ c# syntax polls ]
[ http://stackoverflow.com/questions/794369/should-c-introduce-a-syntactic-short-hand-for-ienumerablet ] [DELETED]

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# [1] but then what would be an alternative? T+?

Bear in mind:


Rationale:

With the introduction of LINQ, the IEnumerable<T> [5] 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> [6] 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*?

(1) Darn... I'd been giving thought to the same thing! So an absolute unequivocal yes-vote! - Cerebrus
(1) Man you're lazy :-P - BFree
Is "T?" supposed to be shorthand for Nullable<T>? I always felt Nullable<T> was just a way of easily implementing "T?" in the BCL. ;) - Jabe
@BFree: But isn't laziness the mother of invention? :P - Atif Aziz
(13) We considered doing this for C# 4 but it was not a high enough priority to meet the bar. We agree that * would be delightful, but the potential confusion with pointers is too high. T{} is still available though, and has a nice correspondance to T[]. Maybe in a future version of the language. - Eric Lippert
@Eric Lippert: Thanks for pitching in. Why not post your comment as an answer instead? That way, others can comment and vote on it directly. - Atif Aziz
@BFree: All good developers are lazy developers. (Not necessarily the other way around though!) - peSHIr
Oh man, it's funny how nobody below has suggested {} and yet now reading that idea makes it seem like such an obviously good choice. - Dan Tao
@Dan Tao: I almost posted it, but thought it would be confused with statement blocks. - Jimmy Hoffa
@Jimmy: I guess that's a good point. I just think it'd have a nice association with the collection initialization syntax. - Dan Tao
Should you also have a shortcut for IQueryable<> then? - comecme
[+24] [2009-04-27 19:23:07] Jabe

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# !


(3) +1 for # character, would have added it myself if you hadn't :) - Binary Worrier
Actually Adam Robinson was first ... ;) - Jabe
(1) 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
[+10] [2009-04-27 19:37:24] mquander

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


And what happens to arrays? - leppie
(8) 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
2
[+8] [2009-04-27 16:59:50] Konrad Rudolph

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.


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
(4) 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
3
[+5] [2009-04-28 09:30:42] ShuggyCoUk

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.


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: 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: blogs.msdn.com/ericlippert/archive/2009/02/17/…. 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
4
[+4] [2010-09-01 15:19:50] Jordão

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; [1]

The syntax can also be used for enumerable literals:

[string] theBugs = ["John", "Paul", "George", "Ringo", "Y2K"];
[1] http://en.wikipedia.org/wiki/Apple_II_series

Funny Apple ][ :)) - Andrei Rinea
5
[+2] [2009-04-27 18:50:14] isntn

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.


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
6
[+2] [2009-04-27 19:35:45] ScottS

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.


7
[+2] [2009-04-30 23:13:58] Joel Mueller

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


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
8
[+1] [2009-04-27 17:08:43] Adam Robinson

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!?


(1) 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
(1) 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
(1) 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
9
[+1] [2009-04-27 19:01:49] Steve Willcock

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;
    	}
    }
}

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
10
[+1] [2009-04-27 19:21:50] Jason Morse

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.


11
[+1] [2009-04-27 19:23:39] Erich Mirabal

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.


12
[+1] [2009-04-28 09:43:21] Mudu

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?


You can add your vote or comments to: connect.microsoft.com/VisualStudio/feedback/… - Atif Aziz
13
[+1] [2010-09-01 15:39:36] Dan Tao

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 (♯) [1] is not the same as the number sign (#) [2]?

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.

[1] http://en.wikipedia.org/wiki/Sharp_%28music%29
[2] http://en.wikipedia.org/wiki/Number_sign

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
14
[0] [2009-04-27 17:02:22] Jeff Yates

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


<> 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
15
[0] [2009-04-27 17:04:13] mhenrixon

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.


Same here. Var saves me some typing. - Min
16
[0] [2009-04-28 10:10:31] John Saunders

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.


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
17