none
C# - All About Span: Exploring a New .NET Mainstay RRS feed

  • General discussion

  • Span<t>is a new type in .NET that enables efficient access to contiguous regions of arbitrary memory.  This article introduces Span<t>, Memory<t>, and related functionality, and provides details on how they are quickly permeating their way throughout the .NET ecosystem.</t></t></t>

    Read this article in the Connect(); 2017 issue of MSDN Magazine

    Friday, December 15, 2017 6:22 PM
    Owner

All replies

  • I have a question about the 

    Span<T> = stackalloc T[218];

    syntax.

    Previously, only primitive types were allowed to be stackalloc'd. (You could get around this limitation, by some creative and highly unsafe pointer magic). To make this feature useful, I'd like to stackalloc different types of value types, like structs and value structs as well. Was the stackalloc syntax extended to allow for this use case?

    Also, if I stackalloc a bunch of structs with reference fields, (or easier yet, references) on the stack, how will the GC be able to track those references?

    Monday, December 18, 2017 11:05 AM
  • The jemalloc.NET project provides a memory manager for allocating and using native memory that uses Spans heavily. Things like huge arrays in NET is now much easier. The reinterpret cast to types like Vector<T> is pretty powerful too.

    https://github.com/allisterb/jemalloc.NET

    Monday, December 18, 2017 4:50 PM
  • Span (and other C# 7.2 features) seems not to be available for UWP, is it?

    Or at least not out-of-the-box, maybe I am just overseeing something?

    Tuesday, December 19, 2017 12:01 PM
  • I installed  VS 15.5, created a new .net core 2.0 project on C# 7.2, installed the System.Memory prerelease package, and tried to test a stackalloc creation without using unsafe:

    Span<byte> bizbaz = stackalloc byte[10];

    But the compiler complains:
    error CS8346: Conversion of a stackalloc expression of type 'byte' to type 'Span<byte>' is not possible.

    Doing the unsafe equivalent works just fine.
    What prerequisite am I missing to test the syntax as mentioned in the article?


    • Edited by dmmjdguy Sunday, December 24, 2017 1:53 AM clarify usage of .net core
    Sunday, December 24, 2017 1:49 AM
  • Span<t>is a new type in .NET that enables efficient access to contiguous regions of arbitrary memory.  This article introduces Span<t>, Memory<t>, and related functionality, and provides details on how they are quickly permeating their way throughout the .NET ecosystem.</t></t></t>

    Read this article in the Connect(); 2017 issue of MSDN Magazine


    Given that this is billed as a new .NET Mainstay and that it provides new constructors for some intrinsic types (once the right packages are installed), is this ever likely to see any degree of support in VB?  Are we likely to see it as a part of the CLR in 4.8?  If so, are these constructors and methods going to be hidden from VB's compiler/editor or are they going to be supported (if not all, at least the "safe" parts)?
    Tuesday, January 2, 2018 5:56 PM
  • As an ancient developer going back to the 8-bit embedded coding days, the optimization improvements offered by Span<T> and Memory<T> immediately bring back visions of code optimizations to squeeze out the maximum performance from little processors.  The ability to use stackalloc arrays without having to enable "unsafe" is seriously cool.

    All this new work to reduce dependence on heap allocations is great stuff.  In the "old wild west days" heap allocations were viewed as a bit "evil" and only to be done when really necessary.  Making languages "friendlier" and "easier to use" has been great, but it tended to bring along with it increasing laziness / sloppiness.

    Introducing constructs which allow experienced developers to seriously tighten up their code while maintaining "safety" is a great move.

    The fact they remain optional is also great because it keeps down the learning curve for more junior developers.  Microsoft should not lose focus on the importance of that.

    New junior developers should not be forced to immediately start-out having to deal with stack allocations versus heap allocation, etc.  They should always be easily able to get started being sloppy with just heap allocations. Once they get comfortable with the more junior basic stuff, they can then incrementally start learning more efficient "tricks of the trade".  Very steep learning curves are not very desirable and are a detriment to adoption.


    -- kburgoyne


    • Edited by kburgoyne Thursday, January 11, 2018 1:53 AM Typos
    Thursday, January 11, 2018 1:51 AM
  • This is really nice and useful feature, but Memory<T> seems redundant and introduces some confusion. It would be simplier to add to the Span<T> third field pointing to the head of allocated memory and use it for GC. Then pointer to actual position should not be tracked, of course.
    Thursday, January 11, 2018 1:47 PM
  • It appears Memory<T> is simply a classic struct that can be freely handled like any other struct.  However Span<T> is really only masquerading as a struct to fit into the language constructs. The compiler is treating it more like a simple (intrinsic) type like Int32.  So Span<T> is "special" while Memory<T> is just another struct. Since Span<T> is a special data type for the compiler, there would be a desire to keep it as small and simple as possible.  Thus Span<T> only includes the absolute bare necessities.  At least that's the understanding I get from the article.


    -- kburgoyne

    Thursday, January 11, 2018 5:05 PM
  • It appears Memory<T> is simply a classic struct that can be freely handled like any other struct.  However Span<T> is really only masquerading as a struct to fit into the language constructs. The compiler is treating it more like a simple (intrinsic) type like Int32.  So Span<T> is "special" while Memory<T> is just another struct. Since Span<T> is a special data type for the compiler, there would be a desire to keep it as small and simple as possible.  Thus Span<T> only includes the absolute bare necessities.  At least that's the understanding I get from the article.


    -- kburgoyne

    Good point, but it already has two fields and therefore it is not atomic. Third field would not change it too much, but it would allow to avoid conversions from Memory<T> to Span<T> and back.
    Wednesday, January 17, 2018 8:10 PM
  • It would have been tremendously helpful to indicate that these types require System.Memory (a prerelease Nuget package) at the beginning of the article rather than at the end in "What's Next?"

    I spent a week trying to figure out why my instances of Visual Studio (for Windows and Mac) did not appear to have this new type no matter how I set my compiler, instance of .Net framework, etc.

    Friday, January 19, 2018 9:08 PM
  • I found a related issue on github that gave the solution to my issue.

    I installed  VS 15.5, created a new .net core 2.0 project on C# 7.2, installed the System.Memory prerelease package, and tried to test a stackalloc creation without using unsafe:

    Span<byte> bizbaz = stackalloc byte[10];

    But the compiler complains:
    error CS8346: Conversion of a stackalloc expression of type 'byte' to type 'Span<byte>' is not possible.

    Doing the unsafe equivalent works just fine.
    What prerequisite am I missing to test the syntax as mentioned in the article?

    The solution is... install the System.Memory prerelease package from their myget feed, instead of the public nuget feed.

    https://dotnet.myget.org/feed/dotnet-core/package/nuget/System.Memory

    Apparently:
    1. There are two implementations of Span, once of which has the shape mentioned in this article, and the other of which exists for backwards compatibility for older .Net frameworks. (and has an extra field).

    2. The stackalloc expression only works for the 'fast' version of Span mentioned in the article.

    The version on the public nuget feed is apparently not the expected shape for the stackalloc expression, leading to this vague incompatible type error.

    It would be really nice if all of these prerequisites were clarified in the article, OR if it was published after everything was all stable... :)


    • Edited by dmmjdguy Tuesday, January 23, 2018 3:43 AM Reply doesn't quote?
    Tuesday, January 23, 2018 3:41 AM

  • It would be really nice if all of these prerequisites were clarified in the article


    Agreed!

    Wednesday, January 24, 2018 3:25 PM
  • Why not just optimize it behind the scenes if the heap allocation will fit within a stack allocation.  Can't the compiler reason about this?

    "constructs which allow experienced developers to seriously tighten up their code"

    Cool, as long as the implementation is "hidden" and junior developers don't have to figure out what is going on.

    Saturday, January 27, 2018 11:33 PM
  • Huh.  Well I have to admit there is something to this. :-)  I haven't looked to see to what extent the compiler may or may not be doing this already.

    It would be nice if a stackalloc could be done in "safe" code so long as the accesses to it remained within the domain of what the compiler could prove was "safe".  In other words, move the "unsafe" requirement away from the stackalloc itself and impose it upon the operations being performed on the object.  If the programmer avoids "unsafe" (or more precisely "can't be proved to be safe") operations then a stackalloc'd array, etc, would be permitted.

    I suppose one "question" that might arise is concern over the size of the stackalloc object (array, etc).  I don't know if the compiler authors have concerns over the actual allocation itself potentially creating an "unsafe" condition regardless of whether all the operations performed upon it proved safe.  If there is such a concern, then establishing a "safe" maximum size would start falling into the realm of arbitrary.

    "Why is int[50] allowed and not int[51]? I need one more element!"

    While all of this would be nice, it might also be redundant. I think the Span<T> stuff might still be necessary to extend "safe" code beyond where the compiler can reliably "automatically" detect whether accessing code remains safe or not.

    I think my input to the Microsoft team would be to implement the Span<T> stuff and use it as an exercise to investigate to what extent the compiler might be able to automatically make more stackalloc's "safe".  Kick the creative juices into gear in this area and see what comes of it.


    -- kburgoyne

    Sunday, January 28, 2018 3:10 AM
  • It would have been tremendously helpful to indicate that these types require System.Memory (a prerelease Nuget package) at the beginning of the article rather than at the end in "What's Next?"

    I spent a week trying to figure out why my instances of Visual Studio (for Windows and Mac) did not appear to have this new type no matter how I set my compiler, instance of .Net framework, etc.

    +100

    it's very subtle and unclear that C#7.2 is NOT enough to try all samples. not very accurate article...


    Sergei Dorogin, Lead Developer, CROC Inc. (www.croc.ru)

    Wednesday, February 21, 2018 12:32 AM
  • Can someone tell me - if I send info over TCP sockets (Socket.Send/Receive methods), will I benefit from these new types in terms of memory efficiency? It seems 2.1.0 preview already has necessary overloads to try this out
    Tuesday, March 13, 2018 10:46 AM
  • I would have been much happier if the article had said right from the start: even nine months later, using this is only barely supported for UWP apps, and even if you get it to work, expect to spent potentially days trying to get the resulting app into the store. I have repeated compiler failures and now a dandy set of WACK failures. 

    My code would run faster if I had spent the two+ days fighting Microsoft's own tooling, and instead had spent time actually optimizing my code.

    Wednesday, September 26, 2018 4:51 AM
  • The VB ref struct feature request is in the "16.0.P3" millstone of Roslyn.

    https://github.com/dotnet/roslyn/issues/28558

    Friday, January 11, 2019 9:32 AM
  • This type is just like Span<T>, except its indexer takes advantage of a new C# 7.2 feature to return a “ref readonly T” instead of a “ref T,” enabling it to work with immutable data types like System.String.

    I cannot figure out how read-only span enables work with immutable types. If immutable type is returned by ref it will return new instance on change the same as it will do if returned as readonly ref.

    What is crucial in read-only span that enables work with immutable types?

    • Edited by User919 Tuesday, December 3, 2019 12:10 PM
    Tuesday, December 3, 2019 12:08 PM