.NET Framework – What's New in C# 7.0
msdn.microsoft.com
msdn.microsoft.com
This is definitely an area where Microsoft has lead the market, not followed it.
I haven't spent much time with Scala, but I get the impression that a lot of the functional stuff is there by default (or at least easily accessibly via Scalaz) and therefore less inertia is needed to write functionally in Scala. Even with LINQ most C# programmers think it's just for querying databases or XML files, they don't realise they have built in monad semantics.
I found that I'd have an immutable collections library over there, that wasn't aware of the Option type in that library over there. (So Map.Find(key) couldn't return an Option<V> for example - this makes composition more difficult).
So although the language has been steadily going in the right direction, there has been less of a concerted effort on the library front. And therefore C# is still behind IMHO.
This is something I've been trying to rectify, by essentially building a functional BCL [1]. I welcome the increased pace of functional features recently. Although sometimes it's frustrating seeing the direction they're going and wishing they'd get there much quicker (expressions everywhere, sum-types, record-types, better type inference).
It's interesting that often C# is held up for its inability to do type-classes or ad-hoc polymorphism. But it is in fact possible with C# today [2] [3], and with zero cost (i.e. no reflection, additional memory allocations, or side-stepping of the type-system). It just causes a massive head-ache of manually provided generic arguments... [4] [5] I'd love it if the Roslyn team took some time to deal with the generic parameters inference story. It would help bring ad-hoc polymorphic types to C#, but it would just be awesome in general.
[1] https://github.com/louthy/language-ext
[2] https://github.com/louthy/language-ext/blob/type-classes/Lan...
[3] https://github.com/louthy/language-ext/blob/type-classes/Lan...
[4] https://github.com/louthy/language-ext/blob/type-classes/Lan...
[5] https://github.com/louthy/language-ext/blob/type-classes/Lan...
At that point you might as well call a static method without polymorphic parameter types, because it's just as (in)convenient and 100% more readable to the developer maintaining the project after you move on to a better programming language.
Yes. I should have stated it's not real type-classes, but it is real ad-hoc polymorphism, which does get you much of the way there. The type-system won't infer the instance, you need to specify it manually. That doesn't make the solution less powerful from a generic programming point-of-view (if anything it makes it more powerful, because you can provide the instance you want to use); however it does make it more awkward to use.
> and fully impractical as a useful abstraction.
I disagree with this though. Finally being able to define a numeric type, or make types into real monads where a function can declare a constraint that requires an argument to be a monad is a good thing.
> At that point you might as well call a static method without polymorphic parameter types
From what I can tell, you're thinking of just the call site, but a whole call stack can carry through the constraint, and therefore the call site doesn't need the concrete implementation, it just needs a type that is constrained to the 'type class' (interface). The call site wouldn't know the type of the static method to call in your case.
For example with a numeric type:
public static T Add<T>(T lhs, T rhs) =>
// what static method can you call here?
If you don't use polymorphic types, then you're not writing generic code, which is what this is for: public static class Math
{
public int Add(int lhs, int rhs) => lhs + rhs;
public double Add(double lhs, double rhs) => lhs + rhs;
public float Add(float lhs, float rhs) => lhs + rhs;
public decimal Add(decimal lhs, decimal rhs) => lhs + rhs;
}
What about when you forget: BigInteger, short, byte, long, etc.But with the method I explained above:
public interface Num<A>
{
A Add(A lhs, A rhs);
}
public struct NumInt : Num<int>
{
public int Add(int lhs, int rhs) => lhs + rhs;
}
public struct NumBigInt : Num<BigInteger>
{
public BigInteger Add(BigInteger lhs, BigInteger rhs) => lhs + rhs;
}
etc.
Any code that works with numeric values can then be written once. I'm sure many C# programmers over the years have cursed over having to write N variants of something that should work with IArithmetic, or INumber, or something similar. This gets around that problem (and without causing any boxing either). So, personally, I think it has value. Even if it's only needed rarely.> because it's just as (in)convenient and 100% more readable to the developer maintaining the project after you move on to a better programming language.
My library isn't about the mindset of programmers who are stuck in OO-land with all the conservative nonsense that goes along with it. So although I agree there's a learning curve, I don't think this is too problematic for those who want to write truly generic code.
By the way, Microsoft are experimenting with this technique[1] (and new grammar) for future versions of C#. Whether it makes it or not, who knows, but I think it would be a super valuable feature for C#.
[1] https://github.com/CaptainHayashi/roslyn/blob/master/concept...
The new model used by .NET Core is to make everything a NuGet package; and not a single big one, but small packages comprising one particular bit of functionality, each of which can then be versioned separately. For example, collections are a NuGet package:
https://www.nuget.org/packages/System.Collections/
With this model, it's possible to iterate on the API much faster, so my expectation would be to see functional APIs in the standard library spread much faster from now on.
I could go on, but there's not a huge point to moaning about it, which is why I decided to do something about it. I'm not sure if it's even possible for there to be an official functional BCL without it being a totally new set of packages. It's something that F# would benefit from too.
This is just adding more functional programming aspects to their dominant language.
When I say "riding the wave", what I mean is that they are adding functional features as the regular OOP/imperative programmers in the mainstream are done "accepting" the previous ones they added, as opposed to adding everything in one shot and have people get overwhelmed.
I didn't mean they were following a wave or anything. Analogies are hard.
There seems to be no control, no feature lock, no "our language will be like language x" or definition they follow. It seems more like they listen to the whole community of developers.
All of them.
I'm not sure it's explicit in the blog, but it seems the deconstructor will be useful for pattern-matching using 'is'.
Tuples. Yay! Finally!
Pattern-matching-switch-statement: Not an expression. That's a bad call. We have expression based ternary, throws, method bodies, and LINQ; switches are the last and most painful omission.
Local functions: Fantastic for libraries like mine, which is trying to bring functional programming to the C# world, but takes a hit with the allocation of delegates for common operations [3] It should be a boon for anything LINQ based (implementations, rather than usage).
Return by ref and out parameters: I'd be happy if they just removed them from the language. Ugly, error magnets.
All in all, good progress. Hopefully they can make more progress on facilitating expression-based programming, and bring in record types for the next release. The pain of creating immutable types is truly tedious. And I'd desperately like to see partial generic parameter specifying (for when one of the generic arguments can't be inferred by the type-system, so you then end up having to specify them all).
[1] https://github.com/louthy/language-ext/blob/master/LanguageE...
[2] https://github.com/louthy/language-ext/blob/master/LanguageE...
[3] https://github.com/louthy/language-ext/blob/type-classes/Lan...
And I don't know about you, but I rarely switch over polymorphic types these days, I mostly switch over values, so the pattern matching overall is way less useful to me without records/discriminated unions.
I guess you can't really remove 'ref' and 'out' due to interop. Maybe the ref returns stuff will be nice if we get more performant string/array views in the next version, and I do like the inline 'var out'.
I also want type inference for field declaration+initialization, but I think Eric Lippert once explained why that was a difficult problem to solve, albeit I can't remember the reason.
var area = switch
(
case Line l => 0;
case Rectangle r => r.Width * r.Height;
case Circle c => Math.PI * c.Radius * c.Radius;
default: throw new ApplicationException();
)
That 'feels' to me to be consistent with the expression approach taken elsewhere, whilst making it clear to anybody used to seeing the statement based switch that it's different.> so the pattern matching overall is way less useful to me without records/discriminated unions.
I agree partially. I think it's possible (I'll investigate tomorrow) to provide an 'is' operator override. So for example in my implementation of Option<T> [1] (which would usually be a sum-type of Some(x) and None, I instead use a struct (to remove a 3rd state of null).
With the 'is' operator I'm hoping to do this:
public static class Some
{
public static bool operator is(Option<T> option, out T value)
{
value = option.Value; // Value is internal
return option.IsSome;
}
}
switch(option)
{
case Some x: ...; break;
default: ...; break;
}
I'm not sure if I can do this: public static class None
{
public static bool operator is(Option<T> option)
{
return option.IsNone;
}
}
switch(option)
{
case Some x: ...; break;
case None: ...; break;
}
So although it doesn't solve the general need for sum-types and record-types, it should hopefully facilitate some of the common use cases.Agreed about ref and out; I understand their purpose, I just despise them with a passion. Their whole syntax and ickyness makes me feel queesy. The inline var out feels like an imbalanced expression. They're clearly more useful now, but they still feel odd.
[1] https://github.com/louthy/language-ext/blob/master/LanguageE...
Switch is more of an effort to integrate patterns in the way C# is used right now.
Could you expand upon that? If I can do this:
var area = shape is Line l ? 0
: shape is Rectangle r ? r.Width * r.Height
: shape is Circle c ? Math.PI * c.Radius * c.Radius
: throw new ApplicationException();
How is this, a collection of predicates and expressions, not the same? var area = switch(shape)
{
case Line l => 0;
case Rectangle r => r.Width * r.Height;
case Circle c => Math.PI * c.Radius * c.Radius;
default => throw new ApplicationException();
}
I realise you work on Roslyn (and you said semantics, so my example may be a bit off), so I'd love the detail on why the above is problematic.Which case does null match?
If you match the first type, that's somewhat unsatisfying. But if you only match with default, that's also unsatisfying because now we would have a problem with completeness -- if the match doesn't succeed then you have a potentially unassigned variable.
So now every match expression would have to have a default case just to handle null, but you also don't gain the advantages of static matching because everything matches default, so if you do legitimately forget a case you get no warning.
Existing switch statements are much more resilient to these matters simply because they aren't expected to be exhaustive right now. People are used to the fact that they have to deal with unassigned variables or completeness failures.
The match expression, however, I want to be more like ML where you can get strong guarantees on the "irrefutability" of a match.
> Which case does null match?
None of them, it should be a case on its own:
var area = switch(shape)
{
case Line l => 0;
case Rectangle r => r.Width * r.Height;
case Circle c => Math.PI * c.Radius * c.Radius;
case null => throw new ArgumentNullException();
}
That would allow for completeness checking, and if you do want a catch-all then you'd add a default clause.I have since looked at the proposal for the expression based switch. TBH, I'll just be happy when it's in the language, the syntax is less important to me; but I am not quite sure it needed such a drastic change - it does feel a touch awkward.
> The match expression, however, I want to be more like ML where you can get strong guarantees on the "irrefutability" of a match.
Music to my ears.
https://github.com/dotnet/roslyn/blob/future/docs/features/p...
CLR supported the concept since 1.0. Surfacing it in C# has been long overdue, and makes it possible to write more low-level stuff without having to go to C++.
I disagree. Firstly, more high-performance non-allocating code can now be written safely instead of dropping down into unsafe languages.
Secondly, ref and out parameters are address types, which the CLR and C# need to properly handle to support value types/structs.
Awesome! Greatly reduces "ugly" boilerplate code like this:
if (control is TextBox)
{
var textBox = (TextBox)control;
textBox...
}
Also, it would be great if Microsoft could make full properties in another way so that you do not have to write a backing field for it. Something like this: public string LastName
{
get;
set
{
if (value == "Batina")
RaisePropertyChanged();
}
}
It would make code more cleaner.Normal auto-implemented properties are fine:
public string LastName {get; set;}
As are read-only ones: public string LastName {get; private set;}
Yet, I feel that if you are writing logic in there then you should fully control it. Or else there is too much being done that is non-obvious and could cause problems down the line (for others or your future self).However, they might be able to achieve something with data annotations that wouldn't be too magic. For example:
[RaisePropertyChanged("Batina")]
public string LastName {get; set;}
Tip: In VS you can just type "prop" then press tab to auto-generate the code for a class property. You can then easily auto-change this to a fully implemented version. This also works for "for" and "foreach" loops etc.I haven't done much Java in a while but do you still have to write out all of your property accessors fully? Might not be too bad if the IDE can generate this code.
I would just like to see get working like in auto-implemented property (without backing field) but setter to be manually implemented (with value keyword).
Also you can use propfull snippet for full property implementation.
It bundles everything you need. And for the tutorial you can check links from other people.
It's nice. I went on to modify and hack with what I created to form it into a back end for a mobile app I'm playing around with. There are still some warts in the process (Namely just figuring out how everything fits together and which packages to import) but I've been pleasantly surprised.
It looks like the new Visual Studio for Mac (ie An updated Xamarin Studio) has an ASP.Net Core template. At least I thought I saw that on the live stream earlier today. Might want to check that out!
The lack of coloration and gray background gave me a little bit of a headache.
The blog platform particularly suffers for it.
Does anyone know any alternative .NET documentation viewers (usable without Visual Studio and Windows)?
A bit of history: game developers have been crying for a solution to the matrix operator problem. A 4x4 matrix is 64 bytes of data. Implement the mathematical operators using C# operators and you're looking at 192 bytes copied per invocation. The workaround is the fake ref operator: void Add(ref Matrix, ref Matrix, out Matrix). The problem is that this results in code smell at the call sites. The ref return was the first compromise, allowing that method to become: ref Matrix Add(...). The ultimate solution would be to allow ref returns and ref parameters on operators, but you need ref returns first.
This feature misses all of that. Maybe we'll get out returns, but the argument against it would be language bloat, and even I'd agree. Sigh.
/rant
Also, could you elaborate what you mean by out returns? Normal returns could be considered "out returns", no?
[0] http://tryroslyn.azurewebsites.net/#f:>ilr/A4VwRgNglgxgBDCBD...
In the by-value case: a stack frame of 192 bytes is allocated (+ space for other locals). The values of the matrices are copied into it from the parent stack frame (128 bytes). The method does its work and then calls "new Matrix". This occupies the final 64 bytes. Immediately this value is copied out of the method to the parent stack frame.
In the by-ref case: a stack frame of 0 bytes is copied (+ space for other locals). The pointers to the two matrices are passed in, as well as a pointer to the memory for the result. The method does its work and then calls "new Matrix". The result of the .ctor is stored directly in the calling stack frame.
You might consider that this is nit-picking, but consider that this has to happen 60 times per second. Calculating an MVP matrix for 1000 objects 60 times per second, results in 32MB of memory copied around per second. That assumes you are doing no additional math (which is definitely not the case). The performance benefit is substantial enough that even XNA had these overloads (which is where I think the workaround originated)[1].
I'm refactoring it to ASP.NET Core on Service Fabric. Getting about 50x better real-world performance. Yes, that much. It's insane. Currently on Windows as Service Fabric on Linux is in preview (not comfortable using it in production), but I imagine I'll move it over once that's stable ️
A great time to be a .NET developer! Makes me happy I stuck with it.
Granted there should be assertions to prevent these conditions occurring but not everyone on the team is perfect 100% of the time. Sometimes an edge case slides in as well and you have to heavily assert everything and push to test/production to reproduce which isn't ideal.
Nice blog post, shame about the bloody awful presentation.
.codeSnippetContainer span { /* color: #000 !important; */ }
someMap = {1, 2}
{foo, bar} = someMap
foo # 1
bar # 2 var (ret, err) = Foo();
if (err != null) {
...
}EDIT: I don't know C#, so syntax is definitely not right.
But yes you can write a deconstructor for anything you like so it can participate in deconstructing assignment. And yes it can have side effects. And that would be VERY BAD.
So instead of having to declare that Foo returns a FooReturn, it can be declared as (say)
public (int ret, string err) Foo() { return (5, "something"); }EDIT: Looks like there's confusion... Yes, you can deconstruct a Tuple like this, but C# 7 also introduces a specific Deconstructor pattern in which ANY class can be deconstructed as though it were a Tuple.
The other new features seem like very welcome additions but the deconstructor seems a bit contrived and a rare use-case which does not directly solve an existing problem (also makes it easy to confuse desctructor/deconstructor for newbies).
var pix = (int R = 255, int G = 255, int B = 255);
var (r1, g1, b1) = pix;
Except what if you're also working with 3D location data? E.g.: var pos = (int X = 100, int Y = 100, int Z = 100);
var (x1, y1, z1) = pos;
Both pos and pix have the same underlying type of Tuple<int,int,int>, which could lead to confusion. Better to have concrete Pixel and Position classes. You can then give those classes a Deconstruct method and then use them the same way: var pix = new Pixel(255, 255, 255);
var (r1, g1, b1) = pix;
var pos = new Position(100, 100, 100);
var (x, y, z) = pos;But I keep wondering why F# doesn't really take off given a lot of peoples fascination with the functional world. It does functional nicely while still being able to bridge back to the OO world which allows you to easily leverage a LARGE amount of libraries in the .net world. It has a really good community, and F# specific frameworks for various things as well. It's like a hidden gem that people pass over as they look at functional languages with much much smaller ecosystems.
> I keep wondering why F# doesn't really take off given a lot of peoples fascination with the functional world
As a matter of fact there aren't that many people interested in FP, mostly due to a lack of education on the matter. Even many people talking about FP are confused about what FP is. And the problem with the FP ecosystem are the abstractions, which tend to be extremely high level and very productive, however these aren't taught in school and the cost of entry is high.
So let me throw this question right back at you: why F# and not Haskell? And note that the answer you give is going to be applicable to C# versus F# and at the same time flawed ;-)
And you see, raising the abstraction is one way humanity has always tackled complexity, however this is essentially about vertical scalability of talent - or in other words enabling the same people to handle more challenging problems by giving them better tools. But the trouble is that this is incompatible with horizontal scalability, which is about growing by hiring more and more people, i.e. building assembly lines.
So going back to your question, the reason for why not FP is actually simple, but hard to swallow: the software industry is growing due to huge demand, as a consequence a majority of people working in this field are beginners and when the industry has a choice between quality and quantity, it will go for quantity at the expense of quality.
On the other hand the good news is that with the proper education, mindset and tools, as a small team, you can still build products that compete with big companies having virtually unlimited resources.
But unlike Java world where J2EE suits and Scala/Clojure hipsters coexist (but hugely separated), .NET is in just beginning of transition from Windows-only Visual Studio-only. It's hard to convince people outside of old Windows Server .NET camp to even try these technologies. Recently I tried F#: build process is still painful, involving msbuild files designed for IDE first, build system second, based on XML, with reverse slashes and absolute paths, reminded me of mix between Windows Registry and Apache Ant. MSDN is painful and enterprisey, with 5-10 second page load times.
F# is quite nice (much cleaner and simplier than Scala for example) but still not feels really great. I can't figure out how to do basic polymorphism in it: someone recommended to use classes and interfaces but I don't want OOP at all. Standard library has few polymorphism too: Seq.map, List.map, Set.map. Records are great but type inference behaves strangely.
I think this is exactly right. Members can be declared visible only when viewing an object through a particular supertype, and you may simultaneously need to invoke methods from the supertype and the subtype.
It's unfortunate that this isn't readily possible even by explicitly reusing the name - C# shadowing rules for locals preclude it. So you can't do something like `if (x is int x) { ... }`.
Deconstruction implementation is scary, i would prefer to have a special symbol (like the desctrutor) and duples that ignores names are ok but sounds very error prone, maybe i just have to try them to understand, also order sensitive case makes my dev sense tingle...
It would look something like:
var (first, second, *) = ReturnsFourThings(foo);
Consequently, C# requires that control flow provably cannot reach the end of any non-empty case block (to avoid implicit fallthrough that normally happens in C, Java etc). Normally this means that you must use `break` (or something else that transfers control, like `continue`, `throw` or `return`). But fallthrough is actually useful sometimes, and `goto case` provides you with a way to request it explicitly - and then ramps it power up a notch, because why not?
Amusingly, this is something that C doesn't have, even though its case labels are true labels (allowing for Duff's device and similar tricks). If you want to goto them, you need to add an explicit named label there.