Wow! They seem to be adding lots of the things that make Python feel more convenient than C#, tuples being big.
Out parameters are going to make some things much nicer. I can certainly see local functions being useful as well.
Out of all of it, I think the thing I'm most excited about is pattern matching. Having used F# for a short time, that was the biggest stand-out feature; it really does make some code much more concise and expressive.
I love C# but lately I've been using Python for my quick-and-dirty work because in general I find it to be more expressive. It seems like C# 7 might make me reconsider.
> the thing I'm most excited about is pattern matching. Having used F# for a short time, that was the biggest stand-out feature; it really does make some code much more concise and expressive.
I'm all for C# getting more expressive, but what it calls "Pattern Matching" simply is not the same thing as real honest-to-goodness Pattern Matching.
C# "Pattern Matching" is little more than destructuring, or switch, on steroids.
Much like how the compiler assists you when writing subclasseses so that you've implemented all the required methods, real Pattern Matching (F#) gives you the same guarantees from the compiler that you've handled all the possible cases appropriately.
This makes real F# pattern matching much more useful than "switch with destructuring", and helps you grow your programs in a safe way.
The C# way has all the same problems as the switch statement, which gives no feedback about what cases you've handled.
It started its life as full fledged pattern matching, but there were just too many things there to cram it in a single release. If you look at proposals and discussions on Roslyn GitHub issue tracker, you'll see the backstory.
So, what we're seeing here is not necessarily the final stage. It's what we get in this release of the language, but more will likely follow.
Yep, I'm aware of the backstory, and the additional planned keywords. I'm reacting mostly to the continued usage of the term for this release without those features, because those being introduced to the term for the first time, won't understand there's supposed to be a difference (and thus not understand the main arguments in favor of pattern matching).
One feature F# has that would be great is that you can declare primitives as a a type. So you won't mix up your kilometer floats with your miles floats. And kilometers divided by hours ends up being a km/h value.
The other one we'll never see: Non null references as a default, optionals as a special case.
They specifically avoided that in the early days of designing the language. Typedefs, macros, meta-programmation, overloading operators like () or -> are common in C++ but lead many people to completely change the language. So much so that there are C++ codebases that cant be read by standard C++ developers. The C# guys avoided that pit. As a C# developer I can read any codebase and know what's happening. That's not so true in F# where people are prompt to create their own operators (like ||>) and types.
The F# ||> operator is provided by the core library. Over-use of custom operators is something I always push back on in F# codebases; they can sometimes be useful in making code more expressive, but the downside is it makes the code significantly more difficult to comprehend until you're familiar with what each operator does. I prefer readability over concision, and even without the custom operators F# code is fairly terse.
The big impediment imho between c# and scripting language is the whole Visual Studio project experience. With Roslyn they introduced the csx format for c# scripts so you can have a stand-alone 1-file executable c# script, but the tooling hasn't caught up yet.
I'm using LinqPad for all kinds of one-off scripting jobs and loving it. I was trying to learn PowerShell for that task but I've finally given up on that. PowerShell has some great features, but the overall chaotic syntax just kills me.
FYI if any java developers are looking for a one file script running environment checkout http://jpad.io/ I made it to scratch my own itch. It lets you run java snippets and view results as HTML even.
There can be some confusion between pipeline syntax and imperative syntax in Powershell, custom objects don't help either (i.e. `{...}` works differently than `[pscustomobject]{...}` for many cmdlets), but I'm curious what you consider chaotic enough to give up?
Either way, neither of them run "true CSX files", but their own homegrown format that predates csx. But it has made me hopeful for the future of C# scripts.
Tuples and deconstructing assignment are the big thing for me. They are the way to provide for reasonable multiple return values. Out parameters are bad, even with the improvements in C# 7. They're simply the Wrong Way to do multiple return values.
Out parameters are bad, even with the improvements in C# 7. They're simply the Wrong Way to do multiple return values.
I agree, but I fear that even with the new features, the according APIs will be missing for a considerable amount of time. It constantly surprises me is that MS has never bothered to update their old APIs with more modern methods; especally where out parameters are used for optional return values.
In almost all my projects I have extension methods like this:
public static V TryGetValue<K,V>(this IReadOnlyDictionary<K,V> dict, K key, V @default = default(V))
{
if (dict == null)
throw new ArgumentNullException(nameof(dict));
V result = default(V);
if (!dict.TryGetValue(key, out result))
return @default;
return result;
}
There is a considerable number of existing methods that would lead to sooo much nicer code if there would be some versions using modern C# features. In the case above, you can still use the original TryGetValue if there's no usable sentinel value you can use to distinguish "not found" cases from success.
There are also a lot of old methods using Type arguments and requiring a cast where a generic alternative is really overdue.
Edit: Of course, some Optional<T> type would also be nice for the dictionary example, but since C# has null-coalescing and null-conditionals since version 5/6, the above example suits almost all my use cases, and can be used in a Maybe Monad-style way anyway.
IIRC I saw an answer (from someone who seemed to know) last hear explaining that this was mostly about simplifying integration with code where this is common.
Still I agree with you and fear that this will result in developers using out parameters other places because - "why not?".
For what it's worth, I'm the one of the folks that designed the original tuple class (the reference type, System.Tuple, that shipped before hand).
At the time, we picked one based indexing because we felt it sounded more natural when spoken allowed (mirroring saying something like: This is the first Item in the tuple).
I would expect that the design bled over into ValueTuple, which looks very similar to the reference version, except, of course, it is a value type.
Perhaps it's because they're item numbers, not indexes? As far as I can tell, C# uses 0-based indexing because most similar languages use 0-based indexing.
I'm probably in the minority, but I'm not really a fan of these new changes. Some are OK, but a lot of them seem likely to be abused more than used appropriately.
p.GetCoordinates(out int x, out int y);
vs
var coordinates = p.GetCoordinates();
out parameters should be deprecated, not enhanced.
Patterns are OK, but switch statement with patterns...why? I'd much rather do something like this:
class ShapeHandler()
{
public void Handle(Circle c)
{
...
}
public void Handle(Rectangle s)
{
...
}
}
The argument for Tuples:
> Custom-built transport type for every method: A lot of code overhead for a type whose purpose is just to temporarily group a few values.
I disagree. Before you know it, that 'temporary group' becomes a first class citizen and deserves its own type. If it's code overhead, I'd rather the IDE/tooling help me with it than it be built into the language.
Overall these changes make the language more expressive which is good. I just fear they will be abused more often than not.
I think C#'s designers make it clear that they don't want you to use out parameters. They're a hack; they were only included at all to make it easier to communicate with C/C++ libraries. But now that they're there, they have to stay because of back-compat - Microsoft definitely does not want a Python 3 situation. They might as well make them as painless as possible for the people stuck with them because of some library. And at the same time, they should offer a compelling alternative to out parameters, which they have finally done with tuple returns.
I mentioned this in another thread, but I wish they'd tell the Visual Studio Team not to use them, then - The SOAP and WCF tools will still happily generate code that requires out parameters.
Your ShapeHandler example above is an example of multiple dispatch[1] - something not very fashionable anymore, but which I'd love to see in a statically typed language. It's a more natural feature for an OO language - but I wonder about the trade offs it has with pattern matching and Algebraic Data Types.
I see your point on out parameters, they are ripe for abuse. You can abuse out parameters right now, just with a little more effort.
var x, y;
p.DoSomething(out x, out y);
Where this becomes useful, I think, are places where you can't avoid using an out parameter. Now, you can choose to throw away or use the out parameter without explicitly declaring it.
Option types are the way to go for something like this:
public static class Parse
{
public static Option<int> TryInt(string str)
{
int value;
return Int32.TryParse(str, out value)
? Some(value)
: None;
}
}
var x = Parse.Int("123").IfNone(0);
var x = Parse.Int("456").Match(
Some: x => x * 2,
None: () => 0
);
Parse.Int("456").Iter(Console.WriteLine);
What I love in C# is, each update the language gets even faster, far more natural to write. Soo different of Javascript, where looks you are fighting against the language first, and then if you win, can develop something useful. I use js why I need use it, but I hope use c# instead, high hopes with webassembly, etc
This is pretty much a terrible language design idea. (Not the "out int x" change, but the whole idea of "out" in an argument list to begin with to indicate values coming out via the arguments.)
The path out of mutable argument bug-hell is not to declare that the values of some argument variables will intentionally get changed by the function in the scope where it is called. It is to make arguments immutable (like they are in the traditional mathy definition of "function"), period, and allow multiple assignment to the function call. What I mean is that, conceptually, ideally, values and state should only flow into the function arguments and only back out of the function call itself.
So for example instead of
> p.GetCoordinates(out int x, out int y);
I think the following would lead to reduced cognitive load and thus fewer bugs:
> int x, int y = p.GetCoordinates;
or even better (color me biased by Erlang/Elixir):
> {x, y} = p.GetCoordinates; # as a pattern match
Instead of a smoothly mentally-traceable flow of values into function arguments and out of function returns, we have this monstrosity of conflating mutable arguments (where values go in and then come back out changed in the scope of the function call) with this "out int x" business which seems to be indicating it intends to "push values upstream", as it were.
Obviously this can be done with the new tuple syntax, but in general I totally agree with everything you've said about 'out'. It is one of the ugliest language features ever, sometimes I wish MS would just say "To hell with backwards compatibility", and throw 'out' on the fire.
// Function definition
(int x, int y) GetCoordinates() =>
(100, 200);
// Invocation
var (x, y) = GetCoordinates();
Well, to be charitable, fortunately you can use a style like you propose where values only flow as I've indicated... but you'd still have to contend with OPC (Other People's Code) and if the language allows it, you just know it will turn up somewhere and ruin your day! ;)
Indeed. Although 'out' is rare, it occasionally does ruin my day. So I have created a set of extension methods [1][2] to remove them from my life (because it does physically enrage me whenever I see the need to use it).
> but you'd still have to contend with OPC (Other People's Code) and if the language allows it, you just know it will turn up somewhere and ruin your day! ;)
Yes, like the standard library's Dictionary.TryGetValue()...
Calling TryGetValue will either return a value or not. Calling ContainsKey, followed by an index read can lead to a race condition that means the value isn't there any more.
If I'm reading the source correctly you could still get the bucket index and before you return true and the value, have that value removed from the dictionary. There is no synchronization going on, so concurrent modifications are just as much a problem with TryGetValue as with other approaches. TryGetValue is not atomic either.
Based on my hazy memory of C#, if id is a struct/value type it is copied, but if it is a class type, there's nothing preventing the method call from mutating it.
> here's nothing preventing the method call from mutating it.
There is, the class could be immutable.
public class Vector
{
public readonly int X;
public readonly int Y;
public Vector(int x, int y)
{
X = x;
Y = y;
}
public Vector With(int? X = null, int? Y = null) =>
new Vector(X ?? this.X, Y ?? this.Y);
}
I believe record-types are proposed for the next release of C#.
This is correct. One of the things I miss coming from C++ is the ability to pass const references. Then you have the advantage of passing a reference instead of copying an object, and the compiler enforces immutability in the function using the reference.
On a similar note, I also really miss the ability to define const class methods (i.e. instance methods which do not modify the instance on which they are invoked). Although, perhaps get-only accessors fill part of that niche in C#.
This language is called C# because you know... C. out variables are there because people were used to coding like this and now that it's there it would just break things to remove it from the language, so you might as well just make it a bit cleaner.
But people should stop coding like this. For the love of all that is good and binary, don't use arguments to mutate values in the same scope. Just return them and reassign them. That way, state flow is always in via the arguments and out via the return value(s). Without this discipline, you will have a hodgepodge of "value flows" and that complexity will kill you when debugging. When new values can be spit out both by function returns and function arguments... Hold on, I have to take an aspirin
I know that a lot of OO/procedural languages permit you to do this (unfortunately). Don't!
Yeah , I get you , this coding style is horrible. I personally try to avoid mutating things as much as possible. I wonder how long we will have these old artifacts around before we decide that things need to move to newer langs like F# instead of tacking new features onto the existing lingua franca of .NET.
Been using c# since the day 1, almost never seen someone designing from the ground up with out parameters for the last 10 years. They're not that common. I guess it looks like a favorite feature in the document because it takes the largest part of it, it's not.
Never used a concurrent dictionary or an IDictionary trying to be sanely efficient using TryGetValue instead of ContainsKey followed by a call to the accessor?
I can't really believe that you started using c# from the day one and you never encountered an hot code path with a TryGetValue.
Of course it gets much worse when you have millions of objects, but even with hundred of thousands it is kind of noticeable.
Unless you don't care about caching at all, but that is a complete different kind of dragons'lair...
I believe it is for interoperability with code in these languages, not just familiarity. That said, the BCL also use out parameters in a few places (the TryParse methods) which arguable set a bad precedent.
Interesting, I've found the reverse is true for me with ES6.
For example, ES6 already had local functions (and a very terse form of that too using lambdas)
class C {
method() {
let localFunction = x => x + 1
function anotherLocal(a) { return a + 1; }
}
}
... arrays are normally used to represent tuples (or freeform objects), and it includes destructuring too:
function f(x) { return [x, x*2] }
let [x, xdoubled] = f(5)
or
function f(y) { return {y, timesTwo: y*2} }
let {y, timesTwo} = f(10)
It almost seemed to me that many of the features listed here were "borrowed" from the liberal style allowed by ES6 and TypeScript (am probably wrong, and both are borrowing from elsewhere).
> (am probably wrong, and both are borrowing from elsewhere).
You're right there. Tuple unpacking has existed in even stronger form (pattern matching) in most functional or functional-ish languages for ages. Python's had unpacking since God knows when. F#, which is sort of related to ML and feeds features to C# somewhat regularly, does this sort of thing as first-class syntax.
It's sort of a trend for people who learn JS first (or only) to look at features that it's had stapled to it and then point out how much other languages are taking from it.
You're incorrect in assuming that I've only/first learnt JS. But its sort of a trend for people to look down on JS programmers, since its considered a "low-status" language ;)
And I'm well aware that the direct inspiration for many of ES6's features is probably Python (and now C# with async/await, which in turn flowed there from F#)
I'm assuming some cross-borrowing is happening here due to developments on the TypeScript team, and due to much higher similarities of the specifics with TypeScript. After all, F# has been around for quite a while, yet we're only seeing this development now - so if F# is the inspiration, why did it not happen much earlier?
Disagree strongly. I don't think looking down on JS programmers is a trend really, it's been happening for a long time now. If anything, that era has been fading with the legitimacy that runtimes like Node and adoption by high-profile companies bring to the JS ecosystem.
As for JS itself, ES6 is a great step in the right direction, and I like it a lot, though I prefer Typescript for pretty much anything when I can use it.
Also - I didn't say that you learned it first or only, just that I see a lot of praise for 'JS features' being adopted by other languages from people who very obviously don't know any better - and this only in the last 3 or so years. So I think it's a trend.
It didn't happen much earlier because the Microsoft languages team is very deliberate and careful about rolling out new features. They have to be. There are something like 1.5 billion machines running some sort of Windows, and (I don't know) on the order of 1/2 - 1 million developers who work with MS languages and tools. Lots of backward compatibility to think about. At this scale even five 9s quality ends up breaking things.
Each release c# get more and more "functional". Previous versions you can use anonymous methods or lambdas to "simulate" local functions, but now its first class citzen.
The problem with JS is you need deal with a lot of hacky legacy things too, you want try new cool things on ES6/ES7, but you need take care about compatibility, 3rd party libraries integration, etc.
IMHO, I hope something like "ES10", where they forget previous versions, create from scratch a new javascript, without worries about polifilling, compatibily, shimming, etc. Then start to evolve from there.
I worked for 6 years on C#, I was C# MVP and I really enjoyed the language.
4 years ago I started to work more with js and then node.js until I stopped working on c#. Js has been for me a gateway to transition to other languages and get paid for that. I learned bash, python, a bit of ruby, go, etc.
If I see c# code today I don't understand what it does. Sure every version has a lot of new very useful stuff but it also introduces noise, "why he used out x instead of the new shiny out var x, he might not know about it, lets send PR".
Along the way I have learned to appreciate simpler languages that does not change that often. Where there are few or just one way to do something.
I think I read an interview to Mitchel Hashimoto (hashicorp) and he said he choose Go over all languages because it was boring.
A boring and simple language allows you to focus on the problem you are solving. A language that doesn't change for years allows people to catch up and master the tool. It also means that you can open a file written by someone else years ago and understand what it does.
Not only that but a lot of very questionable programmers use features just because they're there. C# is becoming like C++ in the sense that it can enable beautiful code from the good coders and truly terrible code from the bad coders.
Go is indeed attractive for this. Although it's a little bit too far to the end of "no extendability" for me. Oberon-07 and Lua are also great examples of making it work.
I agree. After watching the Go developers push back against noisy changes, I'm much more appreciative of determined simplicity in language design.
> If I see c# code today I don't understand what it does.
I am not surprised. The C# team should be more concerned about this. I love C#, but it is getting more complicated and arcane and therefore more unfriendly to newbies. Some of this is probably unavoidable, but some of it could be avoided. The language has to stay attractive to newcomers to survive in the long run.
You're fighting JS more than you fight C# because you don't know JS as well as you know C#.
As someone who has coded in both I won't deny for a second that C# is the better language, but I spend most of my time in JS these days I don't "fight against" it at all. I know how it works, and I use it accordingly.
Javascript has taken a quantum leap with es6, and if you look at what Typescript and Flow are doing, another quantum leap in that dimension. C# is great, but I think the latter, especially Typescript, bring the Javascript community into the same ballpark.
I emphatically disagree with the assertion that WebAssembly is a hack. Maybe asm.js is a hack... but WebAssembly is fairly well thought out.
I don't expect TypeScript to compile easily to WebAssembly. You'd have to write your on GC and do a bunch of other work that you get for free when you target JavaScript... and that means that there are plenty of opportunities do make your runtime worse than your target browser's runtime, at the cost of increased code size to boot.
It's funny you say that, because as someone more experienced in JS, I found myself saying "oh look, C# is coming up to par with ES6!" e.g. Tuple types and destructuring, which are a part of ES6.
I don't see how bringing this up is necessary or relevant. These types of comments seemed to me to be nothing more than a snarky aside. "You're happy about X feature? Well it already existed in Y language."
I brought it up, because the the original post seems to be implying that C# is just copying ES6, and only now "coming up to par". Whereas I think anyone who's not caught in the JS bubble will realise it's very unlikely to be true. There are other .NET languages that have tuples and destructuring, never mind the myraid other languages that have had those features for decades; and ES6 is hardly a panacea when it comes to languages. It's certainly not something that a language designer would be trying to 'come up to'.
Apologies if you thought my comment was snarky, it wasn't my intention.
I don't see why everyone is so defensive about languages, though. C# can achieve parity with ES6 in some ways, and ES6 can achieve parity with C# in others. It doesn't necessarily imply that the developers of one language were cribbing notes from another. It's just a happy thing that some of my favorite features are seeing more widespread adoption between languages.
With my original comment, I was trying to imply that the context in which you read about languages (e.g. which languages you are the most familiar with) can color how you perceive the news. Sadly I feel like everyone read it as an indictment against C# or something.
Anyway, my bad for mistakenly calling you out. It's a bit of a reflex after seeing so many people try to claim that their language is superior.
Out variables can be used for 'while were at it' code - separate concerns that are handy to code in the place where the data is available locally but have no place to be there.
This release also introduces new syntax for tuples (closer to Python) that makes it much more transparent to use them and pretty much thereby introduces multiple return values.
This is now valid and returns a tuple with named values:
public (string city, string state) GetCityAndState()
{
return ("Lake Charles","Louisiana");
}
And you can get the return values without writing "Tuple<" once.
Sure for new code, but I think the concession here is that it provides convenience for dealing with existing code/libraries.
Additionally, it allows restricting the scope of the variable, like in the TryParse examples. The output variable in something like "if (int.TryParse(someString, out var i))" is now scoped to the if block. It cannot be used in the else, nor inadvertently later in the parent scope.
I wish you could somehow define a return type for a function without having to declare a class. Maybe have the function return an anonymous class and then have the compiler infer that.
It's not so much the multiple return as it is losing track of what and where state is being changed. The most common one I see is "populateList(ref myList)", from the callers side you have no idea if a new list is being created or just appended to, you don't know if the list has to be initialized or not, etc. Returning a new list and having the caller specify the assignment is much better.
Just yesterday I fixed a threading bug caused by some semantics around passing by reference and locking.
Yes, it leads to lots of bad procedural code. If you need multiple data items returned from something, they are clearly related and belong in an object. Well written code doesn't use out parameters at all, they are a bad feature and should be removed from the language.
If it's natural for a mathematical function to return a tuple, it should return a tuple; things being objects for the sake of it doesn't constitute an argument. For example: coordinates, swap function, a list partitioning function (returning two lists partitioned based on an element), etc.
A tuple is an object; it's a perfectly proper way to return multiple values from a function, out parameters are not. In fact I'm unsure what your comment has to do at all with anything I said, I'm discussing out parameters and why I don't like them and why it's better to return and object and then you say no return a tuple, which is an object, an instance of the class Tuple. You seem to be trying to disagree with my statement but you've actually supported my point.
Only an object-oriented programmer will say that a tuple is an object. A relational programmer or someone using a logic programming language wouldn't say the same thing.
A tuple doesn't have behaviour, inheritance, encapsulation, or data hiding. Tuples are language-agnostic.
An OO language has little choice but to represent tuples as objects, but to say that tuples are objects is no more true than saying that a user's account is an object, a TCP connection is an object, or a window on screen is an object - it mistakes representation for referent, it confuses the map with the territory.
A tuple is an instance of the class Tuple, an object by definition. It doesn't matter what a relational or logic programmer would prefer to call it, instances of classes are objects. I can add any behavior I like to those instances via extensions. Your tuple might not have any behavior, you might think of it as pure data, but that's a limitation of your view of things, not the reality. The language provides the ability to extend any class, your reality tunnel isn't the same as others.
> ut to say that tuples are objects is no more true than saying that a user's account is an object, a TCP connection is an object, or a window on screen is an object - it mistakes representation for referent, it confuses the map with the territory.
No, it makes the map useful to navigate the territory by accepting the abstraction of objects as a useful thing; there's a reason to say "everything is an object", it's a powerful ability. I'm a Smalltalk'er, everything literally is an object with methods even if/while/for/foreach statements are modeled with objects.
That you find it confusing or meaningless doesn't matter to me, it's my reality tunnel and it works well.
> That you find it confusing or meaningless doesn't matter to me, it's my reality tunnel and it works well.
This conversation, such that it is, is over: simultaneously insulting your co-conversant while explicitly and resolutely staying within your own perspective means there will be no communication, by your will. Good luck with that.
I prefer higher order functional programming, TryGetValue looks ugly to me, I'd rather do...
dictionary.WithValue(aKey, value => DoStuffWith(value));
The dictionary knows whether it has a value or not, I shouldn't be making decisions with if's about a dictionaries data when I can just hand some code to the dictionary and let it do the right thing.
Your other example.
if (TryThing(out res)) {
// Do stuff, use res
}
I'd rather a simple extension to Object enabling this on any value including null...
TryThing().IfPresent(thing => thing.DoStuff());
I'm an old Smalltalk'er, we're accustomed to building such control structures into the class library rather than trying to use an if statement for everything. Once you have a clean syntax for lambdas you have the ability to create a better experience than constantly writing procedural code using the common if/while/for/foreach constructs. In Smalltalk we'd do something like...
dictionary at: aKey ifPresent: [:value | value doStuff ]
That's much better than asking if the key exists with an if, or accessing the dic at a key and doing a null check with an if statement on the value.
That's a matter of opinion, nothing looks worse to me than those out parameters and there's always a way to do things in a cleaner more expressive way than that ugliness. I find many Smalltalk idioms look and work just fine in C# and greatly reduce the amount of code I need to write.
C# still lacks quite a lot in comparison to Smalltalk, but it's slowly getting there year by year.
It's been years and years since I used C# but at the time, ref and out parameters were critical for pinvoke, since pointer arguments are how Win32 functions generally return results.
Oh I'm sure there are valid reasons at the edge to use them, they just make for bad C# code when it's code using entirely the framework; they're overused, usually by programmers who never learned the functional or OO styles and are stuck in the procedural mindset.
Does anyone else just feel underwhelmed by the pattern matching? It seems like syntactic sugar over a standard if(x is Type) that doesn't bring a whole lot to the table other than being able to write more error prone code.
My understanding was this was the first pass with adding patterns to the language with later versions potentially extending the types of patterns and / or where patterns can be used in the language.
Yeah, I was expecting something like what you get in F#.
But maybe it is just the nature of the [C#] language. Still, I think this looks more readable than if-statements.
EDIT: Maybe it is just a bad example of pattern matching, the one they put on that page. I'm betting pattern matching works on the added tuple type. That would be pretty handy.
I'm so stoked for F#. I feel it is SO close. As the user experience with dotnet core smooths out(and ionide no longer needs mono) I suspect it will gain a ton of traction.
F# could have caught on if MS had pushed it as a first class citizen. Instead of pitching it as aimed at really smart people that just need more than C#, they should have sold it as "everything C# can do but better", which is practically true.
Some big-name ivy league around the early-to-mid 2000s notoriously ditched Haskell for Java and that caused quite a stir (isn't that why "Why FP Matters" was written, or re-written?).. so rather they'd have to "get back" to teaching FP.
That alone though may also not suffice though, all that gets the ecosystem is super-generalized hyper-abstract "libraries written by and for PhDs".. not that I'm anti-intellectual I don't think, but if we're talking about "taking off".. programming always took off with "the tinkerers" first and foremost. (Sure, some went on to get hooked on Category Theory but certainly not most!)
I guess FP needs the kind of "OOP summer" hype we got in the mid-90s to mid-2000s. And I kinda feel that's in full swing just not coming into full view just yet.
I have worked with for a while but it seemed very difficult to introduce it to a larger team that doesn't see the point in FP. If there was sample code that clearly showed advantages of F# while using the .Net framework things would be easier. But there is nothing available. C# is the number one language in the .NET world.
C# definitely will remain the number 1, and FP will remain used in a minority of places, until more people get exposed to it earlier in their cursus.
The advantages are in the idioms, immutability by default, null not being legit value by default, emphasis on correctness, advanced type system etc.
The issue is often that people doing C# won't gain enough FP practice to see where F# brings most advantages, try to use it as a OO language for really short time and ditch it because tooling and concepts are not the same as what they are used to.
I'm confident though that adoption is rising and that few years from now most .net shops will get exposure to some amount of F# code, and that people who have been doing C# for so long will eventually pick up any functional language, which in turn will make F# really appealing to them.
I'm happy C# is supporting constructs such as local functions and some basic pattern matching (although type tests are probably the worst use case of pattern matching as seen in ML languages), but I'm also concerned the language is evolving toward more and more complicated syntax and rules (see all the kinds of scoping rules for variables and switch statement) and so little things geared toward correctness (readonly locals, non nil references?).
C# focuses on alleviating developer pain, but sometimes making the choice of enabling to do the wrong thing more readily.
The only way I see FP becoming more popular would be if some popular libraries came up that were purely functional and showed the strength of that approach. I think I understand the benefits of FP but it struggle to see how it would fit into the current library ecosystem. There are not many people who have the luxury of building a codebase from scratch. Most of us need to use other libraries.
> The switch stuff? Without edhaustiveness checking and with inheritance, it's a waste of time.
While this isn't possible in the general case, it might be possible to write a rule in FxCop (or other static analysis tool) to do this kind of checking for e.g. private or internal base types, or to at least check for all the derived types of the current assembly (or solution assemblies.) It also looks slightly less ugly than else if chains, which seems to be a driving factor behind a lot of C#'s newer syntactic sugar.
It actually feels more like taking an antipattern (switching like in their example produces terrible code in the long run) and turning it into a language feature.
It doesn't necessarily lead to terrible code in the long run. It depends on which abstraction axis changes more frequently in your code.
Are you familiar with the expression problem? [1] It's a problem that comes up a lot when you have a bunch of algorithms and a bunch of related values in a data structure, and you want to apply the algorithms to the values. If you have a fixed number of algorithms but keep adding new types of values, it makes sense to use virtual methods for the algorithms; if you have a fixed number of types of values, but keep adding new algorithms, it makes sense to use switch statements (ideally with completeness checking), or pattern matching (if available).
The second case is where the C# feature is useful, and it does not produce terrible code in the long run.
I can't say I agree in any way. There's no instance where a switch statement is preferable to a hash table or pattern matching.
If you have a switch with 3 or fewer cases, use if/else. If you have a switch with more cases, a hash table is going to wind up with far less code, and set you up for polymorphism later if you decide you need to go that route.
In the context of the article (C# patterns), I'm talking about switch statements specifically as a kind of pattern matching.
I disagree that hash tables will end up with less code; the dispatch mechanism for a hash table will be significantly longer than a switch, and the compiler can create a hash table for dispatch (using e.g. a perfect hash function). A switch statement will both be faster and easier to understand and read than storing lambdas in a hash table.
For pure readability, languages with good support for hash literals and lambdas may have the edge, but they'll also encourage dynamism that will hurt both simplicity and performance.
How do you create a hash table where the value is an action that depends on the type of the value? The best you can do is something like Dictionary<Type, Action<object>> and use casting in the action, but that's much worse than C# 7.0 switch.
The real benefit of pattern matching is when the compiler helps you handles the different cases and warns you about one's you've missed—which isn't provided by C# 7.0's version.
Glad to see C# (and ES too in a way) approaching towards F# (& co.) inch by inch with every release. Next and final step, introduce optional "indentation layout" to get rid of braces and semis and I'm a happy camper. FP through the backdoor! =)
I'm wondering why the C# team is so keen on pattern matching - I feel like multiple dispatch would suit the language more and accomplish much the same thing. But C# is a weird beast in some ways - a pure OO language that keeps introducing features to make writing getters and setters more and more convenient.
Maybe I just need to move on with the times. I still see a lot of value in OO, but it's clear it's not at all in vogue. I am glad that functional ideas - particularly immutable data, and anonymous functions - have come into the mainstream. But I don't feel the need to throw the baby out with the bath water.
> I'm wondering why the C# team is so keen on pattern matching
It's kind of a pre-condition (though not in the current initial limited variation) for the introduction of Algebraic Data Types (as F# & co. have them), which I'd still be missing in C# if I had to get working on a C# codebase (might happen again soon, I just don't get any Haskell enquiries in my freelance channels =)
With multiple dispatch, you could already use the existing way of having sum types - class hierarchies - without introducing a second kind.
I just don't see why you want both inheritance and ADTs in the same language. But it's entirely possible I'm missing something, I'm an amateur PLT enthusiast at best.
Would just be syntactic sugar anyway, F# surely compiles its ADTs and parametric polymorphism down to something supported in MSIL bytecode.. but potentially powerfully productive "sugar", any highly expressive language is 80-90% sugar (just the right kind) over a much smaller intermediate core language of way fewer actual primitives
Whitespace-as-syntax is something that I really disagree with (and I don't think I'm the only one). Once you become proficient in a language, the braces, semicolons, and parens become almost invisible structure, involving no cognitive overhead. This is one reason why I've never understood the objections to Lisps with respect to their use of parens.
> Whitespace-as-syntax is something that I really disagree with
That's why I suggested "optional" ;) given how powerful .net tooling is, there'd be a
dotnet --flipformat CodeFile.cs
command that IDEs/editors would invoke from a button/menu.
(I like Haskell's approach here, "layout-by-indentation first" but semis accepted for multiple-things-on-one-line and you can actually selectively have blocks in braces where the default indent-layout is inactive as your blocks are now brace-layouted.)
I was just half-joking with the above, it's just that once you get enough FP sugar in a language to actually be able to effectively write "FP style" that the desire for such syntax evolves, to wit: EcmaScript's fat-arrow functions or C# similar fat-arrow "expression-bodied methods/properties"
As a C/C++ developer, C# feels like unreachable high level heaven. But then again, I prefer my code to have no garbage collector, be portable without any problems and have very high performance. So, C++ it is. If I was writing a Windows-only GUI app with no resemblance of realtime requirements, I would only use C#.
When written with discipline C++ is very portable. I've worked on codebases that spanned devices with ~8mb of memory to full-blown desktop PC and arches(x86/MIPS/ARM/PPC just to name a few).
Writing with discipline is a synonym for writing castrated C++, to avoid touching language features not yet implemented or with slight semantic differences across compilers.
One of the things that attracted me to Java was that I finally could write something where I could use 100% of language features and actually use it everywhere.
C++17 is around the corner, yet most embedded, mainframe and commercial UNIX vendors are between C++11 and C++14, in the few cases where they already support anything from C++14.
Then there are the UB and implementation defined differences across those compilers.
Generally speaking when you are targeting that wide of a range of devices you are targeting a wide range of compilers. It requires some discipline but it's far from the hardest thing in the world assuming you are regularly building and testing for all platforms. I'd say that most major C++ applications or libraries compile in Clang, GCC and MSVC without issue and often build for less common targets as well (icc, nvcc for cuda support, etc.) Things definitely get harder when you move to weirder embedded platforms.
Yup, we targeted GCC, MSVC, plus a few proprietary compilers. As long as you stick to a reasonable set of features(which you should anyway for sanity reasons) it works pretty well.
Having a good CI is a must though but it's not nearly as hard as porting an old codebase backwards.
It's just a configuration problem - at one job, we had a million line code base compiling with clang, gcc (2 versions, can't recall which), on 2 versions of solaris, 2 versions of linux, and linux 32bit and 64bit, plus windows on VS2010, and 2015, so that makes 18 *nix builds and 2 windows builds, so 20 different C++ builds of one code base. All unit tested, and regression tested. Get your CI system of choice working, e.g. TeamCity, fix your makefiles, and you're good to go.
Having done C and C++ across UNIX and Windows, during the late 90's throughout mid-2000's, using the OS vendor's compiler tooling, it was a bit more than just configuration.
For example, back then aCC wasn't even fully C89 compliant.
Of course when one uses the famous trio (gcc, clang, msvc) the world gets simplified a lot.
So when your cloudbleeding, your atleast doing it as fast as possible, right?? ;)
Sure if u write game engines, do it in C/C++. Embedded devices? Probably a good choice.
I work at a startup, and we only have a few devs. I share my C# code-base across the client/server/mobile platform and even cross-compile it to a few other lauinages in between. If i need speed, i just extern out to a C/C++ dll i need and get it (never need to). Or integrate a microservice in eralang.
C# is just like C++, to write fast code, u need to understand the hardware. Its just C#, the hardware includes the garbage collector.
Comments like this appear on HN with frequency, and they betray a complete detachment from reality. Like what an outsider would think looking at the industry.
A very mature language, rapidly evolving, with an enormous volume of well proven libraries and tools, or a cutting edge, barely production level (with a breaking changes language), tiny library new toolset. And you question why someone doesn't just transition? Is that serious?
> barely production level (with a breaking changes language)
Oh no you didn't.
There's an argument to be made in Rust vs C++ but to my knowledge there hasn't been a breaking change in Rust since 1.0 and there's been a ton of work to keep it that way.
There technically have been some small changes, just like in C++.
The key is, as you said, you aren't even sure there were ones. That's how we like to keep it, and that's part of where all that work goes. The rest goes into making sure nothing breaks accidentally :)
Trivial example: shortly after 1.15 was released, a new API was found to have a soundness hole, so a breaking change was made to fix it in 1.15.1.
Because you like the ability to dynamically link to your dependencies so the entire world doesn't need to be rebuilt just to upgrade libxyz.
I love Rust, and I've been trying to get a hobby project written in it - but it really stinks that I can't just rely on my distribution to keep dependencies up-to-date like I can something written in C or C++.
There's a few things Java still has over C# IMO. The biggest one for me is the warnings omitted by the compiler. C# can't seem to tell me about methods that are never called, unless I turn on code lens and look at them all manually.
So are most java people. The difference is in Java it's emitted by the compiler, so you can go through your warnings and nuke them all in one go. Even with Visual Studio though it's situational, you can't get a list of them all at once. only see it in isolation.
Inner classes and objecty enums are still things. Also, anonymous inner classes that implement interfaces - C#'s a anonynous types are fun, but they can't inherit or implement.
Sometimes the "so much more" is the issue with Scala, but yeah, Scala is a great way to make you say "man, I wish I had _" in every other language you use.
Kotlin too. There's even a super nice wrapper over spring-data-jpa [1] so you can do LINQ-to-Entities-esque query building where JPQL queries either aren't staticly-typed enough for you or you need dynamic query generation.
Kind of a noob question. But why would you be happy if C# ran in jvm? Is it just cross-platform compatibility so that you can develop your C# application for Linux?
Man I used to love C# so much - and then I realized what a godsend Maven/Gradle were. I still think C# is the better language and I'm biding my time - is there a decent Maven/Gradle equivalent for C# yet?
"Also there is support for the much more difficult higher-order polymorphic types like Monad<MA, A>. LanguageExt 2.0 provides a fully type-safe and efficient approach to working with higher order types. So yes, you can now write functions that take monads, or functors, or applicatives, and return specialised types (rather than interfaces or dynamic results). So intead of writing a function that takes an option, you can write one that takes any monadic type, bind them, join them, map them, and return the concrete type that you pushed in."
I wouldn't just yet. The platforms that you can reach with Scala, including JS, and soon LLVM, plus all the goodies that are being developed in Dotty, are pretty compelling for me to stay. Scala keeps getting better and better. It is very exciting to see that other languages, like C#, also keep adding excellent features.
I don't like Scala much, a personal preference, but the research behind Dotty is utterly amazing, and when it becomes ready for prime time, it'll be a killer feature.
DOT is some great math, letting them bring simplicity and a ton of high level features to the compiler with very little cost.
For anyone who is disappointed at the lack of exhaustive matching / Discriminated Unions, please try out my library OneOf* (https://github.com/mcintyre321/OneOf). Hopefully something similar will be brought into C# soon, but in the meantime, these libraries provide fairly idiomatic substitutes.
Using static lets you ape that now. You still need to declare a static class, but you don't need to include the class name when calling it if you important the class via "using static".
It'd never pass code review on Hacker News but the classic C# hack for that is just to make a class called Global or whatever and throw your must-be-everywhere functions in there.
Sorry, I didn't mean to confuse the issue. The CLR can do global functions. But no .NET language currently supports it. The example I gave was just a way of achieving visually the effect of global functions (which I assumed was the major issue of the OP, because there's no other cost to using static methods than having the qualify them with the type name).
It's pretty common in languages with pattern matching to use underscore as a catch-all (ML family, Haskell, etc.). I'm not sure how the underscore is a code smell; if you want wildcard patterns without throwing a bunch of unused variables into scope (which can definitely lead to non-obvious bugs), you have to use some symbol.
Mostly like if I submitted some code for review and peppered it with underscores because "I don't care about those variables" I'm pretty sure it'd come back to me with a remark about starting to care.
At the point your writing code you don't care about, something might be wrong.
When working with an object, you don't always care about all of its properties. If it's packed in a certain way (tuple, Optional wrapper, etc.) that is easy to unpack with destructuring, then you might use an underscore to say "this is how it's structured, but I don't care about the particular value it has so please don't bind it to a variable."
If you bound it to a variable and didn't use it, it'd be the same as declaring an unused variable.
Do you ever write an if statement where you don't check one of the fields of an object, or a method call where you ignore a return value? If so, how is this any different?
I do a lot of coding in few different languages regularly (C#, Python, JS mainly) but what I find is that it is the language I feel enjoyable. Although part of that is probably because of tooling (Visual Studio, Visual Studio Code) and also features like LINQ.
A long time ago I tried to use a throw in a ternary expression in C++ (e.g. "return is_good ? value : throw;") and it caused an internal compiler error! Really cool to see that it's now a feature of C#.
Are there any c# free lancers on this thread? Our company is exploring the use of the technology for some data projects. If interested in discussing please reach out: leo at finsight dot com.
Having left C# for iOS development a while ago, it's really interesting to come back and see how many features (tuples, discards, local functions, etc.) have made their way into both languages.
Really liking the extras with Tuples/Destructuring... that was always a pain point imho with dealing with Tuples previously. Would still love a regexp literal though.
> Should tuples be mutable or immutable? The nice thing about them being
> structs is that the user can choose. If a reference to the tuple is
> readonly then the tuple is readonly.
> Now a local variable cannot be readonly, unless we adopt #115 (which is
> likely), but that isn't too big of a deal, because locals are only used
> locally, and so it is easier to stick to an immutable discipline if you
> so choose.
> If tuples are used as fields, then those fields can be readonly if
> desired.
Local methods are really cool, but kind of remind me of GOSUB in QuickBasic from back in the day. It was considered an anti-pattern, if I remember correctly.
Local methods are literally nothing like GOSUB. For starters, GOSUB was originally global, it was only in later structured versions of BASIC (like QB or VB) that you could have functions with local labels, and therefore local GOSUB.
And the reason why GOSUB was an anti-pattern was not because it was local, but because it was so low-level. It was not really a function call - it changed the current instruction pointer to a new statement in the same function (so you didn't get a new execution frame etc), and pushed original instruction pointer onto its own internal stack, from whence you could then return to (effectively, GOTO) it with the RETURN statement. Because it had no execution frame, it also had no provision for passing arguments. And because it was the same code, there were no boundaries - you could flow into the section of code that was meant to be GOSUB'ed into without the use of GOSUB, and you could flow back out without RETURN. E.g.:
foo = 1
IF foo THEN GOSUB bar
PRINT "No GOSUB"
bar:
PRINT "Inside bar"
IF foo THEN foo = 0: RETURN
PRINT "No return"
On the first run, this will do GOSUB, you'll see "Inside bar", then the flag is reset and we return to the point where GOSUB is invoked. But then the natural code flow will pass the "bar" label, and all that code is executed again, except this time it doesn't RETURN, but instead just keeps flowing on.
So, basically, there's an utter lack of structure here. There's no matching of GOSUB and the corresponding RETURN - indeed, there may not even be a corresponding one, or there may be many, and the same RETURN can be reached via GOSUBs through different labels (and will return to wherever the GOSUB came from). If you RETURN without any GOSUB on the return stack, that's a runtime error, not a compile-time one. If you GOSUB without a RETURN, it's not an error, but you will eventually overflow the stack if you keep doing it. And so on.
So, it's a very messy mechanism that dates back to pre-structured days of BASIC. That's the only reason why it was discouraged why BASIC got SUB/FUNCTION.
They remind me of the Delphi / Pascal days, which is no surprise since Anders Hejlsberg was the chief architect behind Turbo Pascal & Delphi and is the father of C#.
public void Test()
{
// Doesn't work
Func<A, string> lam = (A a) => a.ToString();
// Works
string LocalFunc<A>(A a) => a.ToString();
}
Also I think if the local function doesn't close over any variables in the containing method then there's no additional memory allocation, whereas the lambda itself must be allocated.
Out parameters are going to make some things much nicer. I can certainly see local functions being useful as well.
Out of all of it, I think the thing I'm most excited about is pattern matching. Having used F# for a short time, that was the biggest stand-out feature; it really does make some code much more concise and expressive.
I love C# but lately I've been using Python for my quick-and-dirty work because in general I find it to be more expressive. It seems like C# 7 might make me reconsider.