{"action":"created","issue":{"url":"https://api.github.com/repos/dotnet/roslyn/issues/120","labels_url":"https://api.github.com/repos/dotnet/roslyn/issues/120/labels{/name}","comments_url":"https://api.github.com/repos/dotnet/roslyn/issues/120/comments","events_url":"https://api.github.com/repos/dotnet/roslyn/issues/120/events","html_url":"https://github.com/dotnet/roslyn/issues/120","id":55792520,"number":120,"title":"Proposal: Slicing","user":{"login":"stephentoub","id":2642209,"avatar_url":"https://avatars.githubusercontent.com/u/2642209?v=3","gravatar_id":"","url":"https://api.github.com/users/stephentoub","html_url":"https://github.com/stephentoub","followers_url":"https://api.github.com/users/stephentoub/followers","following_url":"https://api.github.com/users/stephentoub/following{/other_user}","gists_url":"https://api.github.com/users/stephentoub/gists{/gist_id}","starred_url":"https://api.github.com/users/stephentoub/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/stephentoub/subscriptions","organizations_url":"https://api.github.com/users/stephentoub/orgs","repos_url":"https://api.github.com/users/stephentoub/repos","events_url":"https://api.github.com/users/stephentoub/events{/privacy}","received_events_url":"https://api.github.com/users/stephentoub/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/dotnet/roslyn/labels/Area-Language%20Design","name":"Area-Language Design","color":"5319e7"},{"url":"https://api.github.com/repos/dotnet/roslyn/labels/Feature%20Request","name":"Feature Request","color":"fc2929"},{"url":"https://api.github.com/repos/dotnet/roslyn/labels/Language-C%23","name":"Language-C#","color":"207de5"}],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":7,"created_at":"2015-01-28T18:05:57Z","updated_at":"2015-01-29T23:43:46Z","closed_at":null,"body":"(Note: this proposal was briefly discussed in #98, the C# design notes for Jan 21, 2015. It has not been updated based on the discussion that's already occurred on that thread.)\r\n\r\n## Background\r\nArrays are extremely prevalent in C# code, as they are in most programming languages, and it’s very common to hand arrays around from one method to another.\r\n\r\n## Problem\r\nHowever, it’s also very common to only want to share a portion of an array.  This is typically achieved either by copying that portion out into its own array, or by passing around the array along with range indicators for which portion of the array is intended to be used.  The former can lead to inefficiencies due to unnecessary copies of non-trivial amounts of data, and the latter can lead both to more complicated code as well as to lack of trust that the intended subset is the only subset that’s actually going to being used.\r\n\r\n## Solution: `Slice<T>`\r\nTo address this common need, .NET and C# should support \"slices.\"  A slice, represented by the `Slice<T>` value type, is a subset of an array or other contiguous region of memory, including both unmanaged memory and other slices.  The act of creating such a slice is referred to as \"slicing,\" and beyond the support on the `Slice<T>`, the C# language would include language syntax for declaring slices, slicing off pieces of arrays or other slices, and reading from and writing to them.\r\n\r\nAn array is represented using array brackets:\r\n```C#\r\nint[] array = …;\r\n```\r\nSimilarly, a slice would be represented using square brackets that contain a colon between them:\r\n```C#\r\nint[:] slice = …; // same as \"Slice<int> slice = ...\"\r\n```\r\nThe presence of the colon maps to the syntax for creating slices, which would use an inclusive 'from' index before the colon and an exclusive 'to' index after the colon to indicate the range that should be sliced (omission of either index would simply imply the start of the array or the end of the array, respectively, and omission of both would mean the entire array):\r\n```C#\r\nint[] primes = new int[] { 2, 3, 5, 7, 9, 11, 13 };\r\nint item = primes[1];   // Regular array access, producing the value 3\r\nint[:] a = primes[0:3]; // A slice with elements {2, 3, 5} \r\nint[:] b = primes[1:2]; // A slice with elements {3} \r\nint[:] c = primes[:5];  // A slice with elements {2, 3, 5, 7, 9} \r\nint[:] d = primes[2:];  // A slice with elements {5, 7, 9, 11, 13} \r\nint[:] e = primes[:];   // A slice with elements {2, 3, 5, 7, 9, 11, 13} \r\nint[:] f = a[1:2];      // A slice with elements {3}\r\n```\r\nArrays could also be implicitly converted to slices (via an implicit conversion operator on the slice type), with the resulting slice representing the entire array, as if both 'from' and 'to' indices had been omitted from the slicing operation:\r\n```C#\r\nint[:] g = primes[:];   // A slice with elements {2, 3, 5, 7, 9, 11, 13} \r\nint[:] h = primes;      // A slice with elements {2, 3, 5, 7, 9, 11, 13}\r\nint[:] i = h[:];        // A slice with elements {2, 3, 5, 7, 9, 11, 13}\r\n```\r\nA slice could also be used in a similar manner to arrays, reading from and writing to them via indexing:\r\n```C#\r\nint[:] somePrimes = primes[1:3];  // A slice with elements { 3, 5 }\r\n    \r\nDebug.Assert(primes is Array);// true\r\nDebug.Assert(somePrimes is Slice<int>);   // true\r\n    \r\nDebug.Assert(somePrimes.Length == 2);     // true\r\nDebug.Assert(somePrimes[0] == primes[1]); // true\r\nDebug.Assert(somePrimes[1] == primes[2]); // true\r\nsomePrimes[0] = 17;\r\nDebug.Assert(primes[1] == 17);            // true\r\n```\r\nAs demonstrated in this code example, slicing wouldn’t make a copy of the original data; rather, it would simply create an alias for a particular region of the larger range.  This allows for efficient referencing and handing around of a sub-portion of an array without necessitating inefficient copying of data.  However, if a copy is required, the ToArray method of `Slice<T>` could be used to forcibly introduce such a copy, which could then be stored as either an array or as a slice (since arrays implicitly convert to slices):\r\n```C#\r\nint[:] aliased = primes[1:3];        // Alias of a portion of the original array\r\nint[:] copied  = primes[1:3].Copy(); // Copy  of a portion of the original array\r\n```    \r\nThis gives developers the flexibility as to whether they want the recipient of the slice to be working with the original array or not, minimizing unnecessary copies and ensuring that only the appropriate areas of the larger region are used (by design, there would be no way through the public surface area of `Slice<T>` nor through the C# language syntax to get back from a slice to the larger entity from which it was sliced).\r\n\r\nAs creating slices would be very efficient, methods that would otherwise be defined to take an array, an offset, and a count can then be defined to just take a slice.\r\n\r\n## Solution: `ReadOnlySlice<T>`\r\nIn addition to `Slice<T>`, the .NET Framework could also includes a `ReadOnlySlice<T>` type, which would be almost identical to `Slice<T>` except that it would not provide any way for writing to the slice.  A `Slice<T>` would be implicitly convertible to a `ReadOnlySlice<T>`, but not the other way around.  \r\n\r\nAs with slicing an array, creation of a `ReadOnlySlice<T>` wouldn’t copy data, but rather would create a read-only alias to the original data; this means that while you couldn’t change the contents of a `ReadOnlySlice<T>` through it, if you had a writable reference to the underlying data, you could still manipulate it:\r\n```C#\r\nint[]  primes= new int[] { 2, 3, 5, 7, 9, 11, 13 };\r\nint[:] a = primes[1:3];     // A slice with elements {3, 5}\r\nReadOnlySlice<int> b = a;   // A read-only slice with elements {3, 5}\r\nDebug.Assert(a[0] == 3);    // true\r\nDebug.Assert(b[0] == 3);    // true\r\nb[0] = 42;                  // Error: no set accessor available\r\na[0] = 42;                  // Ok\r\nDebug.Assert(b[0] == 42);   // true\r\n```\r\nWhile C# would not have special syntax to represent a `ReadOnlySlice<T>`, it could still have knowledge of the type.  In particular, there is a very commonly-used type in C# that behaves like an array but that’s immutable: string.  It’s very common for developers to want to slice off substrings from strings, and historically this has been a relatively expensive operation, as it involves allocating a new string object and copying the string data to it.  With `ReadOnlySlice<T>`, the compiler could provide built-in support for slicing off substrings represented as `ReadOnlySlice<char>`.  This could be done using the same slicing syntax as exists for arrays.\r\n```C#\r\nstring helloWorld = \"hello, world\";\r\nReadOnlySlice<char> hello = helloWorld[0:5];\r\n```\r\nThis would allow for substrings to be taken and handed around in a very efficient manner.  In addition to new methods on String like Slice (a call to which is what the slicing syntax on strings would compile down to), String would also support an explicit conversion from a `ReadOnlySlice<char>` back to a string.  This would enable developers to work with substrings efficiently, and then only create a copy as a string when actually needed.  \r\n\r\nFurther, just as the C# compiler today has support for concatenating strings and switching on strings, it could also have support for concatenating `ReadOnlySlice<char>` and switching on `ReadOnlySlice<char>`:\r\n```C#\r\nstring helloWorld = \"hello, world\";\r\nReadOnlySlice<char> hello = helloWorld[:5];\r\nReadOnlySlice<char> world = helloWorld[7:];\r\nswitch(hello) { // no allocation necessary to switch on a ReadOnlySlice<T>\r\n    case \"hello\": Hello(); break;\r\n    case \"world\": World(); break;\r\n}\r\nDebug.Assert(hello + world == \"helloworld\"); // only a single allocation needed for the concatenation\r\n```"},"comment":{"url":"https://api.github.com/repos/dotnet/roslyn/issues/comments/72127616","html_url":"https://github.com/dotnet/roslyn/issues/120#issuecomment-72127616","issue_url":"https://api.github.com/repos/dotnet/roslyn/issues/120","id":72127616,"user":{"login":"redknightlois","id":1045411,"avatar_url":"https://avatars.githubusercontent.com/u/1045411?v=3","gravatar_id":"","url":"https://api.github.com/users/redknightlois","html_url":"https://github.com/redknightlois","followers_url":"https://api.github.com/users/redknightlois/followers","following_url":"https://api.github.com/users/redknightlois/following{/other_user}","gists_url":"https://api.github.com/users/redknightlois/gists{/gist_id}","starred_url":"https://api.github.com/users/redknightlois/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/redknightlois/subscriptions","organizations_url":"https://api.github.com/users/redknightlois/orgs","repos_url":"https://api.github.com/users/redknightlois/repos","events_url":"https://api.github.com/users/redknightlois/events{/privacy}","received_events_url":"https://api.github.com/users/redknightlois/received_events","type":"User","site_admin":false},"created_at":"2015-01-29T23:43:46Z","updated_at":"2015-01-29T23:43:46Z","body":"Having done some work already on Array Slices (https://github.com/Codealike/arrayslice) I will share some of the gotchas I had to deal with...\r\n\r\nIf slices are implemented in C# as a native construct understood by the compiler, you will make math oriented programmer like myself pretty happy. Which will be probably the ones that are seriously interested in having such a construct for performance reasons. IEnumerable<T>, IList<T>, etc have such a big performance impact that they are provided for convenience and/or interop with application code only. (see at the arrayslice link the performance impact).\r\n\r\nWhile the implementation details with structs or classes, readonly or not are very important at the language design level the biggest issue is behind the language surface.\r\n\r\nToday as it stands I know of 3 ways to handle this:\r\n- Implement an Slice<T> class which just \"overrides\" the index. (our implementation does that using IL rewriting for performance, Roslyn will just generate the proper IL).\r\n- Implement it as some kind of IEnumerable<T> (skip + take)\r\n- Do it properly where slices are actually arrays at the runtime level. \r\n\r\nThe first has a very important drawback, if your code doesn't support Slice<T> you are screwed. Implicit converting to an array would not work... you have to pass the whole array (defeating the purpose of the Slice<T>) or copy the array, a no-no for the audience that would really use it...\r\n\r\nThe second is clear, performance... again a no-no for the intended audience. \r\n\r\nThe third, AFAIK no support at the runtime level to actually create an array with \"shared\" memory. If there is IL to be able to do that, I am more than interested to know how :) ... therefore unless we can allow that at the runtime level slices will be useless or clash with code already written.\r\n   \r\nNeedless to say, that where this is going is that there is a serious need of a generic numeric constraints too (both fixed and floating) to really make C# shine for performance math code. Traits if implemented properly would work for that. \r\n\r\nI look forward to have an experience akind to what you have in Matlab or Python in terms of flexibility (not in syntax :D)\r\n\r\nFederico"}}