Span<T> in C#
github.com
github.com
This makes my optimization skills less valuable as more developers will know how to do this ;)
However, this will greatly enhance awareness of C# as a language that can be used for reasonably high-performance code. Most people don't seem to understand how fast C# can be with good optimization techniques. This will help increase adoption of C# in the developer community.
(Aside: I still can't believe the number of developers I meet that seem to think of basic Linq concepts like `ToLookup` as "weird advanced things", which leads directly to long rants about `ToList` and why I consider it harmful.)
There will be an gain in ease of use. Granted, average developers aren't going to care about this (nor will they need to). But you should expect to see an increase in performance of many libraries, as most open source projects generally won't use unsafe code in order to increase performance.
Also this blog post has more examples and benchmarks for people interested: http://adamsitnik.com/Span/
Can be tempting to think of it as a Java clone because of its early history and the shared general category (OO-focused GC'd imperative statically typed language whose first major impl was bytecode/VM-based), but there's signs of more to it than that.
I took the AP CS test in high school with Java 6, and four years later, the jobs I was looking at after college were still Java 6. The ones where companies weren't still on Java 5, or even more archaic releases.
We released games written in C# for iOS, Android, Windows Phone, Windows PC and Linux servers.
- https://github.com/NetCoreApps/LiveDemos
- https://github.com/NetCoreWebApps/LiveDemos
Each project can also be opened and developed on Linux or Mac with VS Code or Rider. Xamarin's solutions has been making C# a popular language for developing native high-performance iOS/Android Apps for several years and the stigma of C# server apps being confined to Windows should be eradicated with the advent of .NET Core.That's interesting. Apparently I'm dreaming that I'm developing with C# on my macOS and deploying to Linux?
I've recently implemented a rich GUI software for embedded ARM linux, running on .net core 2.
Works OK, however I spent substantial time implementing GUI stack (dllimport, NanoVG, GLES, DRM/KMS).
Somebody at Microsoft said to themselves, these guys are clearly brilliant, let's see what happens if we hire them all, task them with creating a new object oriented programming language, pay them a tonne of money, and see what happens.
C# was the result, and it's awesome!
CoreFX? CoreCLR? No idea what these are or what they're for.
And don't get me started on the dumpster fire that is roslyn. I've tried no less than 10 times over the last few months to get "intellisense" working in emacs via roslyn and it has never worked.
C#'s a cool language that I want to like but it's just so much work to get started with.
If you’re trying to write C# in emacs you’re doing it wrong. C# has probably the best tooling in the world if you embrace it.
I love c#, but I've been using it since '05. I don't envy newcomers.
I am the current maintainer of omnisharp-emacs and would love to know out what are the most pressing problems people encounter using C# on emacs via omnisharp - https://github.com/OmniSharp/omnisharp-emacs
How does time travel debugging work in emacs?
So you are expected to download VS Code, use sdb or something else if you want to have step-by-step debugger...
I used to use omnisharp with atom and frankly it was just rubbish. It crashed all the time and required constant restarts, and (still) takes a massive amount of time (and memory) to start.
I went back to using golang, and didn’t regret it for a second. The tooling in go is excellent and you can use a simple editor for many things. That’s really compelling for people.
So... to be fair, if you were to idly pickup .net core as a linux user, and expect vim or emacs to do the job, you’ll find it a terrible experience.
...but, with the right tooling, it can be really great. vs, cscode or rider (not free) make using c# a pleasure to work with.
The dotnet cli tool is still quite terrible (how do you install dotnet watch again? why does it take 25s to restart a simple web app? You think git has obscure inconsistent incomprehensible command line flags...? ha! remind me why ‘dotnet build’ is running like 50 shell commands from the .csproj file...but only in this configuration you didn’t specify excplictly? surprise!) ...but its usable, and its slowly improving.
I feel like a lot of C# enthusiasts shoot down complaints as people being rubbish, or trolling or ‘doing it wrong’; but the reality is c# on a platform other than windows is new, and still pretty raw.
Pointing people in the right direction (you do need a proper IDE) and acknowledging that doesn’t suit everyone is better than telling them they’re ‘doing it wrong’; thats just jerk behaviour and comes off as fanboiism.
I've yet to see good Windows GUI support for Go.
Oh, and when I have to use Go, I find a chore to write generic code as if I was back in 1992 using Borland C++ 2.0 for MS-DOS, with pre-processor based code generation for BIDS or still using Java 1.4 (EOL in 2008).
I'm going to guess the answer is never, because it's basically impossible to do.
Do you care? I doubt it, but some people really do.
It's just different use cases for different things. Sure, go has its problems, but needing a large heavy IDE isn't one of them. That's really important to some people.
/shrug
> Oh, and when I have to use Go, I find a chore to write generic code...
Oh man, don't even start. If you don't like go, don't use it. It was just one example of tooling that's better than C#. Rust, node, clojure, heck, even python has a better story for 'pick up and start using' than C# does at the moment.
Do we really need to start digging down into how fundamentally terrible nuget is as a package manager, and how I personally find it like installing Master of Magic using 3 1/4 inch disks one by one when it screws up, or the feed screws up (like it did TODAY for about 4 hours)?
nah. No one cares.
Let's just leave it at: There are some valid concerns people have with the C# ecosystem, and using C# on non-windows platforms. It's a work in progress.
At least we now have a coherent direction for everything going forward~
You mean by using something like Mono -aot, CoreRT, IL2CPP?
> Do we really need to start digging down into how fundamentally terrible nuget is as a package manager,
No, because in spite its issues, it still runs circles around the half-baked solutions that Go devs are still trying to fix.
Nuget is such a pile of rubbish it's not even worth arguing about; if that's the best package manager you've ever used, you should really go check https://github.com/fsprojects/Paket out.
(they also helpfully articulate why nuget isn't really very good)
The irony is that the folk from go-world have finally acknowledged the package management solution they have is really terrible, and they're building a lovely new one (https://github.com/golang/dep).
Maybe sometime in the future you'll be eating your words, when go has a lovely package manager.
...and c# still has nuget.
:)
Would you be willing to submit an issue to github about the problems you have encountered (if not already?)
I would love to make the experience of using C# on emacs with omnisharp-emacs easier for people.
docs.microsoft.com is steadily improving this.
> I've tried no less than 10 times over the last few months to get "intellisense" working in emacs via roslyn and it has never worked.
https://github.com/OmniSharp/omnisharp-emacs
Are you not using this? Works great for me.
If you want getting started to be less of a chore use VS Code, VS, Rider, VS for Mac, Xamarin Studio, or Monodevelop.
I’m hoping that things will slow down and converge again in a while.
There's the languages (C#, F#), there's the runtime (CLR - Common Language Runtime), and then various frameworks (including the base framework, and the ASP.NET framework). Then there's the difference between the original variants of these and the new 'Core' variants.
Plus there's various other related bits like the .NET Standard projects which are meant for library developers to target to make library cross-platform portability easier.
As for difficulty getting intellisense working via emacs - that's certainly been something demoed, but it's not really a well tested use-case at this time.
If you're coming at it from a non traditional (Windows) developer perspective - then you're looking at a massive ecosystem in flux and in migration from being a primarily single platform to multiplatform.
> He currently works for Microsoft as the lead architect of C# and core developer on TypeScript.
HS/college was a lot of C(++). My work has been Perl (I'm old) and then Python/Django (with the usual sprinkling of other stuff: JS, bash, etc.). Go has been a surprisingly intense hobby over the past few years and it's probably the only lang I could bust something interesting out in soon without much of a learning curve. (I guess also some of the close cousins of JS out there, but not really a brand-new environment then.)
I did play with very early (pre-`var`) C# more than 10 years back (I'm old!), but that was before most of these improvements happened and before I understood the relevance of the things like value types that were in there from the start. It's interesting now mostly as another point in the space of programming languages/environments, e.g. different tradeoffs around GC, generics, etc. Guess it has somewhat more potential to be relevant to me as an open/cross-platform project, but it's hard to see myself making the big time investment to actually get up to building-stuff speed in it just for giggles. Similar feelings about Swift or Kotlin, FWIW. (Not that I'm totally ruling anything out, but I've got stuff to do!)
That specific discussion of proposals I just Googled up looking for the C# pattern matching stuff. I first heard about it via a different link posted on lobste.rs a while back, but it was faster to Google this than look for that.
Not many languages can claim a great web development, native GUI, native mobile apps, and first-class gaming development, story.
C# is superior to Java in every way I can think of. Just a couple examples, unsigned types, simple value types without boxing, and a real generics implementation (java generics are truly awful). The reflection API is c# is also far more useful and easy to understand.
In Java, a method might expect one instance of a class, to which you can pass an instance of anonymous class, whereas in C# a method might expect a set of delegates, to which you can pass a set of anonymous delegates or lambda expressions.
However, thanks to C#'s type inference, it actually ends up being far less verbose, yet more flexible, because anonymous delegates and lambdas can close over local variables. So, strictly speaking, they're more powerful than anonymous inner classes.
On the other hand, as someone that greatly admires Smalltalk, I sometimes envy Java's slightly better purity.
Anonymous classes have better oo organization than passing in two or more delegates. Sometimes variable capture doesn't cut it or isn't as clear.
..And the biggest thing. I can pass it in to a method that already takes a class and not a delegate.
One solution is the build a small inventory of "ad-hoc" classes that just wrap a delegate (usually a closure), as described here: https://stackoverflow.com/questions/20703002/does-object-exp...
The reasons why Java enums are better, is because they're actually constrained to the domain you specify. In C#, the range of values for any enum is the same as its underlying integer type - it's just that some of those values have names, while others don't. But it's always legal to cast (and few people know this, but 0 is always a valid enum value that you don't need to cast) - so any method you write that accepts an enum value has to validate it. In Java, since enum is basically a final class with a bunch of private singletons, you are guaranteed that the reference you get points to one of those.
That said, given that C# now has pattern matching, and it seems to be getting more powerful with every release, I'd be surprised if it didn't get something like case classes very soon.
//Java
Bax.addHandler(new Foo()
{
@Override
public void Bar()
{
doSomething();
}
@Override
public int Baz(X n)
{
return computeInt(n);
}
});
//C#
Bax.AddHandler(() => DoSomething(), n => ComputeInt(n));
But, anonymous delegates and lambdas are at once syntactically nicer and more powerful, because of type inference and the fact that they can capture local variables.Regarding Java enums, the actual equivalent feature in C# is class nesting. There is a tiny bit more ceremony involved in defining them, but they're more flexible than Java enums. For instance, you can decide whether or not to implement them as readonly (final) fields, or as static properties, depending on how much you care about cache friendliness.
public abstract partial class SomeEnum
{
private SomeEnum(){}
public abstract int Biz();
sealed class AFoo : SomeEnum { public override Biz() => 2 }
sealed class ABar : SomeEnum { public override Biz() => 4 }
sealed class ABaz : SomeEnum { public override Biz() => 8 }
}
//Singleton implementation:
public abstract partial class SomeEnum
{
public static readonly SomeEnum Foo = new AFoo();
public static readonly SomeEnum Bar = new ABar();
public static readonly SomeEnum Baz = new ABaz();
}
//Cache friendly implementation:
public abstract partial class SomeEnum
{
public SomeEnum Foo => new AFoo();
public SomeEnum Bar => new ABar();
public SomeEnum Baz => new ABaz();
}
It's also worth noting that extension methods on C# enums give you most (all?) of the power of Java enums. Bax.AddHandler(DoSomething, ComputeInt);From practical purpose, Java anonymous classes can be used in any scenario where you need to create a one-off object that derives from a class or implements one interface. A delegate can only be used in a scenario where the receiving variable or function wants a function type.
I'm not arguing that delegates are lambdas are bad, mind you. For the common scenario involving callbacks, they're vastly superior. But they're not a complete replacement for Java inner classes.
By the way, thanks for your work on PTVS, I just discovered it recently.
By the way, I totally forgot about F# object expressions! But they're a good example of this feature. Better than in Java, in fact, because they let you implement multiple interfaces. Also, IIRC, they're true closures (whereas Java only lets you close over finals, not writable locals).
Ideally, you'd have both those and lambdas in a language, like C# and Scala do. If I had to choose, though, I'd definitely pick lambdas - that is the 90% use case.
I'm not claiming that the technique is exactly equal to what Java gives you out of the box, but rather that C# can get within epsilon. In other words, for my purposes, the prefix AdHoc- might as well be a keyword (as in AdHocIEquality<T>, AdHocIEnumerable<T>†, AdHocDisposable, AdHocHttpHandler, etc...), because it's indistinguishable from syntax sugar.
On the other hand, the F# object expression really is more than just syntax sugar, because of the way it interacts with type inference (no need to upcast to satisfy the type checker), and (as you noted) that it can implement an arbitrary set of interfaces. But, it's not all carrots and apples: F# lambdas don't work well with protected members. Meanwhile, C# can close over just about anything (a ref local, such as Span<T>, being the obvious exception).
[1] https://github.com/noblethrasher/AdHoc-Implementations/blob/... (in a newer version, I implement the interfaces explicitly)
† which, really only works well in VB because lambdas can contain `Yield` statements.
- The way one can plug into JIT code generation via invokedynamic, methodhandles and varhandle bytecodes
- A JIT compiler written in Java (Graal), now pluggable in the reference JVM
- An actual roadmap to rewrite remaining C++ from OpenJDK in Java (Project Metropolis)
- The research being done in Graal and Sulong about using Java to write compiler infrastructure
- Being portable to devices where the CLR probably will never be ported to
- A a better JIT in what concerns dynamic code re-writting
- Multiple implementations, some of them with AOT support, from disparate vendors
I just enjoy using both eco-systems since they exist.
Very cool. I wasn't aware of that. Do you think this will help introduce more "low level" features in Java since it is paramount to at least keep the same level of performance, and definitely improve it in the future?
Jalapeño from IBM,
http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.25.8...
Sun's own Squawk VM, used on Sun SPOT before IoT was a thing.
https://www.researchgate.net/publication/221320697_The_squaw...
https://en.wikipedia.org/wiki/Sun_SPOT
Regarding Project Metropolis specifically, you can find the information here.
"Your next JVM: Panama, Valhalla, Metropolis by John Rose"
https://www.youtube.com/watch?v=OMk5KoUIOy4
http://cr.openjdk.java.net/~jrose/metropolis/Metropolis-Prop...
Note that I wasn't completely fair, the .NET team also has some plans to incrementally move the runtime into C#, but so far it has only been mentioned on an InfoQ interview, no official plans revealed.
https://www.infoq.com/articles/virtual-panel-dotnet-future
"So, in my view, the primary trend is moving our existing C++ codebase to C#. It makes us so much more efficient and enables a broader set of .NET developers to reason about the base platform more easily and also contribute."
Not entirely. .NET delegates don't support generic type parameters (aka first-class polymorphism). Methods in C# and Java do.
C# interfaces also don't support static methods, which are useful for factory patterns. C#'s factory patterns require a lot more code as a result.
C# also has a bunch of artificial limitations, like not being able to specify type constraints on Delegate, Enum, and a few other built-in types. It's just nonsense.
The rest of C# is overall better than Java though.
interface IFoo
{
void Bar<T>();
}
This is known as first-class polymorphism.Classes with methods are strictly more powerful than delegates, but they shouldn't be. It's even worse than that actually, because you can't even create an open instance delegate to a generic interface or abstract class method (you'll get a runtime error, not even a static error).
It's really annoying that you can't query a Java package to find out what classes it defines.
On the implementation side, Hotspot blows the CLR out of the water on performance. All things being equal that is, not handicapping the Java code, bottlenecks "for realism" and other benchmark-defeating tricks.
Java is the superior serverside solution. Other than Hotspot performance, the other big selling point is Java's vastly larger opensource library selection.
I like both. I like the fat OOP space. Maintenance reasons is a huge one, I don't want to get burned having to maintain some fly-by-night's code in 10 years from a Frankenstein's creation of random JS libraries. Both Java and C# are industrial-strength designs, with good tooling and a swath of devs.
Between the two, I'd still reach for C# myself, because at this point you can have an almost entirely C# codebase from the server to the client. It's good enough in the performance and library aspects that Java holds over its head. I'm expecting the C# package to be quite complete once it adds compiling to wasm to its list. But if I made a career switch, it would be from C# to Java, and nothing else. I admire Rust and (especially) Elixir but no jobs in my area for either of those.
Even for high-level code, it depends on the kind. E.g. Java generic collections have to box value types; I'm not sure if Hotspot even tries to avoid it - I think it does these days - but this kind of analysis is necessarily limited in scope. In C#, value type generics are fully reified, even on JIT level - every combination of type parameters gets its own JIT-compiled implementation.
The biggest problem is that no-one wants to do a Python3 on the pile of Java code written in the last 20 years, so of course that have been doing baby steps, which are starting to see the light now post-Java 9.
And they will come, because Java is feeling the pressure on Fintech from companies that want to move away from C++, but still feel some pain, ergo Pony.
Java also needs such features for Project Metropolis, the JVM can only be successfully rewritten in Java, if there are no performance regressions.
Also, IBM and Azul JVMs do have language extensions for value types.
Yes, Java will fix this eventually (although, doing this for generic collections would also require reified generics, no?). But, of course, C# will also advance further in that time.
The general problem, I think, is that the process that Java uses for language evolution is deliberately slower than C#, so C# can bring new features faster. There's a trade-off there in that there's also less breakage, and acquired Java skills take longer to become obsolete. Which probably has something to do with why Java is still very prominent in the enterprise, and in industries like banking.
Even C# does move slowly, these lovely C# 7.2 features that I can already use on my private projects, will take years to be allowed on my typical set of customers, the enterprise.
I just helped one transition to .NET 4.6.1.
Likewise another one just moved into Java 8 this year.
Worse is the Android situation, regardless of the features Java might get, even feature parity with C#, Google will cherry pick only the ones they care about.
Which is ironic that nowadays JVM gets more languages, with compiler backends pretending to be Java like, while .NET SDK 1.0 even had multiples examples of programming languages.
I recently made my career change to become a C# developer so I did a good indepth review on the overall landscape. Came down to Java and C# as my best bets, C# won because it fits a lot of my work history and I've heard multiple people that I trust say they just can't find .Net developers. To me that's a feature. I really like it and don't understand all the hatred and fashion-oriented programming trends going on. Honestly, I'm more about maintenance and all the best tooling to help me get complex tasks completed without issue. Of course, maintaining employment is important too, has to be jobs around. I spoke with a few companies, one is switching from a .Net stack to Node and I think that's insane. I'm not sure why you'd actually willingly accept a downgrade like that. Maybe if you're starting from scratch, sure do what you will, but overall I expect the "app" side to JS to dwindle away as wasm takes over. I intend to build most of my webpages leveraging as much of the native browser functionality as possible, leaving apps to Xamarin and wasm for native code solutions.
It can be put over an array (as per ByteBuffer); but also over stack allocated memory; a native pointer T* etc
The underlying allocation is separate from the type
JNI or Unsafe allow to create ByteBuffer from native pointers, created in C/C++ or in Java using malloc, memcopy them, etc. This is used (and abused) by most web servers, DataStax or LMAX-Exchange have even created their whole business on that.
You also have have CharBuffer, DoubleBuffer, FloatBuffer, etc
There is no stack allocated ByteBuffer in Java (Java provides no stack access, this is religious) but in Java can do relaxed data access on Buffer element, volatile access, opaque access, CAS, etc.
This is the same API.
Object, InetAddress, etc
Though only `struct` value types should be used in stack or native memory due to risk of GC holes
It was always interesting to see which features were just syntactic sugar (and thus backwards compatible) vs. which required runtime support.
Don't forget "server mode" GC. I have a long-running, memory-intensive console app which was taking about 45 minutes to process a typical batch of data. With some profiling I discovered that after the 20 minute mark, most of the time was spent in GC. Some of the classic optimisations (classes to structs, new list to list.clear) helped get the processing down to 30 minutes. After some more Googling I discovered and tried server mode GC. Suddenly it took less than 13 minutes.
In .NET (below C# level, in the VM itself), there are two fundamental types of pointers - managed (e.g. int&), and unmanaged (e.g. int* ).
An unmanaged pointer is basically the same as a C pointer. It points to whatever you tell it to point, and it's your responsibility to ensure that it's still valid when you dereference it. So you can get dangling pointers to locals that went out of scope, for example. If you point it at some memory that is managed by GC, you also need to make sure that GC doesn't automatically move that memory, because the pointer will not be updated - the VM provides an opcode for "pinning" managed objects so that they don't move to facilitate this. Also, because these pointers are "dumb", you can do pointer arithmetic on them, cast them to/from integer types, etc. And they can be used in any position a valid type can.
A managed pointer, in contrast, is a pointer that is guaranteed to be memory-safe. For managed pointers that reference managed objects and their fields, this means that GC is aware of those pointers, and adjusts them as it moves the objects around in memory, just like it adjusts regular object references (so you don't need to pin anything; things "just work"). When you have a managed pointer to stack-allocated data, the VM basically makes it illegal to return such a pointer, or stash it away into a variable that can outlive the scope - this is enforced by the bytecode verifier, simply by prohibiting fields of managed pointer types in heap-allocated objects (including, recursively, in any structs). So the only legal operation that you can do with a managed-pointer-to-local is to pass it into a function call - since the stack frame of the calling function is guaranteed to be there for the duration of the call, that is memory-safe.
On C# level, unmanaged pointers are just pointers (int* ), and managed pointers are used to implement ref types, as in "void Foo(ref int x)". Until recently, function arguments were really the only place they were permitted, so they were only used to pass arguments by reference. Recently, they've also added the ability to declare ref locals and return by reference, subject to all the verification rules - e.g. if you return a ref, you cannot return a ref to a local, it must be a ref to a field, or a ref argument that you got from the caller.
The runtime additionally has some types, that effectively wrap a managed pointer and add some functionality to it. One existing example is TypedReference (https://docs.microsoft.com/en-us/dotnet/api/system.typedrefe...) - this is basically a type-erased managed pointer, plus runtime type of whatever it points to. You can then "downcast" it to a proper typed managed pointer, and because it knows the target type, it can verify that the cast is valid. There's also a type called ArgIterator, which is basically the .NET type-safe equivalent of C's va_list. These are used for various low-level stuff like C++/CLI vararg functions.
Now, these wrapper types, because they encapsulate a managed pointer, have all the same verification restrictions that managed pointers themselves have. And all these types, including managed pointers themselves, are collectively called by-ref types.
Now, Span<T> is basically just a new by-ref type, that combines a managed pointer with span length under the hood. As such, it's subject to all the same restrictions, which together are sufficient to make sure that it's not possible to use it in such a way that it points to invalid memory.
It's nice that they the documented the interaction with the GC too.
Span<byte> stackSpan;
unsafe {
byte* stackMemory = stackalloc byte[100];
stackSpan = new Span<byte>(stackMemory, 100);
}
SafeSum(stackSpan);
You still need unsafe to allocate, but once allocated, you can access the memory in a type safe way. M Span<byte> stackSpan = stackalloc byte[100];
See https://github.com/dotnet/coreclr/pull/14503/files as an example.Being able to send 3 structs of e.g 32 bytes each (such as Vector4<double>) to a function without hidden copying will be great.
As for the future, I wish c# had const refs working like in c++ instead of readonly and a plethora of ireadonly collections! It could optimize away many things on the CLR level too. I guess it's not doable without breaking some things, but I think it is worth it.
https://github.com/dotnet/csharplang/blob/master/proposals/c...
What I really want is to have some basic code contracts (like pure methods) embedded in the language in as frictionless way as possible. It eliminates need for many simple unit tests, null checks, etc.
I'm not sure if this feature will be only for structs or also for classes - I hope both will work.
Although I switched to C# 7 years ago from C++, and I like it, I have to say that C++ syntax seems more readable to me - const T& seems more readable to me than ref readonly T.
Another thing that might be missing here is propagating immutability information down to JIT. AFAIK, codegen could optimize code better if immutability is guaranteed (at least that's part of the rationale of using const & in C++). There is PureAttribute in System.Diagnostics.Contracts, however CodeContracts seem to be mostly dead in terms of compiler and VS using information from them for static analysis.
I wish this ref readonly feature could basically render all IReadOnly* interfaces useless, so that collections would have proper "ref readonly" interfaces. I don't see that in proposal - I wonder if there is a way I could contribute with that remark? I think it makes a good reason that's missing from the rationale on that github page.
Lastly, I wish there was more discussion about how C++ or other languages with stronger checks do it. Pretty sure there's huge opportunity to learn on other's mistakes :).
As a side note - this is what makes HN great - I can post a comment and get response from Ben Adams himself! One of the greatest .NET Core contributors who made it really fast! Thank you for that link :)
The `in` modifier on parameters, to specify that an argument is passed by reference but not modified by the called method.
The `ref readonly` modifier on method returns, to indicate that a method returns its value by reference but doesn't allow writes to that object.
The `readonly struct` declaration, to indicate that a struct is immutable and should be passed as an `in` parameter to its member methods.
The `ref struct` declaration, to indicate that a struct type accesses managed memory directly and must always be stack allocated.
ReadOnlySpan also gives immutability; though will only work over contiguous memory rather than a more general collection type; for which you'd still need to use a IReadOnly* interface either as param or generic constraint.
I think that a C++'s const& equivalent would be very useful in C#, especially to simplify making objects and value types immutable by default and also more performant. I created https://github.com/dotnet/csharplang/issues/1118 as a starter point for discussion, although I'm not sure if linking it to "ref readonly" that's available for value types is the right association to make in terms of more general C# roadmap and design.
https://digitalmars.com/articles/b44.html
Slicing is an incredibly useful feature.
void foo1(char *p, size_t sz);
void foo2(char p[2]);
If I understand correctly, your proposal applies to the first case. The two arguments could be reduced to one, which is currently not possible for the general case without generic or template structs, but that alone would in my view not be worth introducing fat data types to the standard. An implementation doesn't need the new type either, it can already bounds check deferences of the pointer against the lvalue it was created from[1].For the second case, I agree that would be nice but it can be worked around by using a struct.
[1] "recalling that pointers are anchored to the lvalue from which they were created" Kell, Some Were Meant for C, 2017 (https://sjmulder.nl/dl/pdf/2017%20-%20Kell%20-%20Some%20Were...)
Not sure what you're thinking, since it does not require templates or generics, and works for the general case. I know it does, because I implemented it for D without generics or templates.
> it can be worked around by using a struct
Yes, but nobody does since it is clumsy, hence all the array bounds overflows in C. Even tiny bits of syntactic sugar, which is what this is, can have dramatic and transformative effects.
> [1]
That inescapably makes all pointers fat pointers, which is far more overhead than what I proposed. My proposal does not have any unavoidable overhead.
--
As for implementation experience, the D community finds they work extremely well. It's much more than an "it would be nice" feature.
This was in favour of your proposal, about how it isn't currently possible to implement this construct generically as a user of the language, hence, it would need to be implemented in the language itself.
I think I do see the point you're trying to make. However:
> Even tiny bits of syntactic sugar, which is what this is, can have dramatic and transformative effects.
This is true, but its use would come mainly from bounds checking at compile time and runtime (otherwise it's just the struct) which is hardly even done for regular arrays.
That is where the memory safety comes from. But the use comes from things like:
1. strlen, strcat, etc., become obsolete, replaced by far more efficient code
2. looping over an array contents becomes straightforward
3. documenting the extra variable holding the dimension of the array becomes unnecessary
I.e. a host of benefits.
Yet string_view, vector_view and other range<T>'s in C++. Yet Pythonic slices. Yet Rust.
The remaining eco-system needs to be relevant as well.
https://www.manning.com/books/c-sharp-in-depth-fourth-editio...
I notice an unofficial draft for C# 6 is available as markdown on https://github.com/dotnet/csharplang/blob/master/spec/README... (via https://docs.microsoft.com/en-us/dotnet/csharp/language-refe...)
checked { sum += bytes[i]; }
It's one obscure C# feature that I rarely see used, but which I find indispensable, and really wish more languages adopted it. Integer overflow vulnerabilities have become more prominent in the past few years, so perhaps there will be some uptake. Interestingly, C# had this feature since the very first release back in 2001.https://docs.microsoft.com/en-us/dotnet/csharp/language-refe...
Is a Span of byte (0-255) being added to a ulong(0-1.8e+19)
The maximum value it can produce is much less than a ulong: 2^31 * 255 = 547608330240
Here it seems there is a dependency on the 4.7 runtime, is this the case? Where can I see a matrix of what C# versions work on which (full/desktop) runtimes?
The runtime changes make it faster, smaller and include Jit optimizations for it (bounds check elimination etc)
The later runtime changes make it faster
It will have some limitations, like that it can only be used on the stack. One reason is that the efficient representation on new CLRs will use pointers into the middle of objects and they argue that supporting those on the heap will slow down the GC too much. (Go's approach to non-copying slices/strings was just to support pointers into the middle of allocations, and I guess accept the costs at GC time.) Other reasons relate to concurrency, etc.
I can't do much better than that not knowing more about C# and the CLR than I do!
Most C# developers won't use it directly, but rather benefit from wide ranging performance increases in the libraries they use.
However, an item I think is often overlooked is the safety:
ArraySegment or the triple: "array, offset, length" when used; only provides a suggestion to the called function - it still has full access to the array and can happily read and write out of offset->length portion of the array. Span only allows access to the window, so the called function can't operate out of its permitted bounds.
Further to this ReadOnlySpan finally gives read-only array elements; so rather than having to a defensive copy and passing out a newly allocated array; you can pass out (or in) a ReadOnlySpan
These, too, support the same types of backing memory (backed by native memory, stack-allocated memory, or a Java array), same access pattern, etc, and are also used by many third-party libraries now for such stuff (including many networking libraries, and graphics libraries such as LWJGL3)
What’s so innovative about these?
Aren't those Java types heap-allocated and GC managed? I think the big deal is that Span can be allocated anywhere (native, stack, heap).
For example, LWJGL3 has a separate stack where it allocates them.
LWJGL's MemoryStack emulates a C style stack by preallocating a set amount of off-JVM-heap memory and decrementing/incrementing an index into it.
Not directly, but most JIT compilers do it.
It is tricky and fragile, but one can make use of the JIT logs and try to re-write the code so that it takes the right decision regarding escape analysis.
As for an actual support at language level, we need to wait for the outcome of projects Valhalla and Panama.
So do all relevant game engines. Having a separate memorystack from the actual one for game objects is basically standard.
Not all improvements have to be innovative. The most mundane things can vastly improve the pleasure of using a language. Considering that array slicing originated in Fortran, Buffer is hardly innovative - yet, as you've pointed out, it has been a huge benefit for Java developers.