Hopefully it will see a renaissance when people realise that with ASP.Net Core they can write code that looks broadly similar to Rails/Laravel/Django code, and get much better performance more or less for free. There are definitely some rough edges around the ecosystem though. Entity Framework isn't nearly nice as Laravel's Eloquent ORM, and it's pretty jarring looking at a promising library, only to realise that it's a commercial offering (don't get that with PHP!).
I've used F# in a few professional projects before and that language is certainly underrated. I used to work in Microsoft's DevDiv and everyone knew it was criminally underfunded. I think if it had OCaml-style modules and Microsoft threw more weight behind it could take off big time.
In addition, there was the question what not to implement. A notable omission from the design was the functorial module system of OCaml. Functors were a key part of Standard ML and a modified form of the feature was included with OCaml, a source of ongoing controversy amongst theoreticians. The author was positively disposed towards functors as a “gold standard” in what parameterization could be in a programming language but was wary of their theoretical complexities. Furthermore, at the time there were relatively few places where functors were used by practicing OCaml programmers. One part of the OCaml module system – nested module definitions – was eventually included in the design of F#. However, functors were perceived to be awkward to implement in a direct way on .NET and it was hard to justify their inclusion in a language design alongside .NET object programming.
The Early History of F# https://fsharp.org/history/hopl-draft-1.pdf
Yes, you do end up writing some code that a great ORM would just give you for free, but honestly I haven’t felt pain from doing this as it makes me actually think about and set in stone what relationships and models I intend to support in my data layer.
ORM's like Eloquent (PHP) are super nice, because they let you lean on them completely for simply queries, and then give you layers of opt-outs. For example, inserting a row is just obj->save(). For slightly tricky selects you can use the whereRaw method to interpolate raw SQL into just a where clause of the query, or you can use DB::query() to write a full raw SQL query if you have some queries that are particularly complex.
I guess I could give Dapper a go though. SQL is... fine.
But from what I can see, EF is trying to provide an abstraction layer that pretends that I am just working with collections of objects, which I don't like at all because it makes it harder to control which queries actually get executed and when!
On the other hand, Eloquent provides an abstraction for generating queries, but this maps pretty closely to SQL, and it otherwise largely stays out of the way...
The type safety is nice, and of course you don't get that in PHP. But IMO that's more about the language than the library.
There are a lot of add-ons for it that simplifies all the generics for you.
There are ways to mitigate this [1]. You write your queries in .sql files in Visual Studio, so you get intellisense and syntax highlighting, and you can even add these to your automated test suite to ensure they run correctly.
I think the link is pretty clear: it combines and batches queries while providing a type-safe interface for the returned results. It further provides intellisense and unit testing features that are tedious and error-prone to achieve in other ways.
Of course you can do this all by hand, or manually batch your queries to avoid round trips, but why would you want to?
The flexibility and performance of full SQL, without having to write all the mapping boilerplate by hand.
The eco system still seems wonky, but NuGet probably isnt more weird than that of Golang.
NuGet, I'm still not sure of either, but at least it mostly works transparently. Though I haven't actually tried publishing anything to it, only consumed. npm seems to have the least resistance imho, for good and bad results alike.
The language is really good - it's one of my favourites. It's almost 2 decades old, but it's evolved naturally and is still a modern language.
Unfortunately, it's the shit around it that let it down... MSBuild, NuGet, VS - they're full featured, but very slow and clunky and hard to work with. Only popular because there's been no viable alternative.
Now, with dotnet core, there's no more reliance on Windows (for both dev and production). I can develop and deploy on my preferred OS, and there's a choice of IDE (Rider and VS Code).
> Paket is a dependency manager for .NET and mono projects, which is designed to work well with NuGet packages and also enables referencing files directly from Git repositories or any HTTP resource. It enables precise and predictable control over what packages the projects within your application reference.
The big change is solution-level dependency management instead of the nuget-default project-level management, so you always have the same versions of dependencies across all projects in a solution. It also uses a lockfile for these versions so that restores are idempotent. It also allows for fetching independent files from HTTP-accessible locations or git repos, which is nice in F# because the language is succinct and enables you to reuse modules without going through the rigamarole of making and publishing nuget packages.
It is very uncommon in stand-alone software development of all sorts (shrink-wrapped, service development, commercial web apps, etc) for very obvious reasons. That doesn't make it underrated, there just happens to be a lot of other great platforms.
It seems like a good language with very good tooling if object oriented programming (in the Java and C# sense) is your posion of choice. Now with .Net Core and other good iniatives from Microsoft it might be a more relevant language than ever.
Migrating large projects to dot net core piece by piece is fraught with tooling bugs and issues (you pretty much need to migrate everything to SDK-style projects before you do anything else, for example, otherwise you get strange interactions between net461 and netstandard projects around auto-generated binding redirects). There's still DLL hell. Default "copy local" results in crazy n log n file copies in large solutions that totally kills build performance (you can tweak this to use hard links in an effort to improve things, but not within Visual Studio which is where I really want cycle times to be low, or do mad hacks with shared output folders, but that can give you nondeterministic builds).
So it's far from all roses - check out their bug trackers on github and there are a number of surprising issues. There are also a lot of missing things on Linux still (e.g. Out-of-the-box support for kerberos auth in ASP.NET core/WebAPI things on Linux). Quite a number of APIs pretend they are there in netstandard but throw at runtime on Linux machines, and yet other things are annoyingly half-hearted, like mapping some Linux syscall return codes to Windows HResults, but not all of them and not consistently across all APIs.
It's getting there, but the surrounding ecosystem has a lot of catching up to do compared to Java, IMO.
The language is nice, though. F# also.
I understand that's changing of course, now that Microsoft has open-sourced the core of the language and started pushing to get support onto Linux and other platforms, but they are still making up an almost 2-decade deficit here.
But yeah, Visual Studio beats the pants off Netbeans and Eclipse, while functional, is very clearly what happens when you let an engineer design a UI, everything is possible and nothing is easy.
NuGet does have some rough edges, and compile time for even my small .NET Core projects tends to be on the order of seconds, which is surprising for a mature compiler and stripped-down framework.
IMO the investment in VS Code basically signals VS has become too bloated and complex to innovate on so they're better off creating a new IDE from scratch with better plugin extensibility and ecosystem that's innovating and delivering features significantly faster than VS which comparatively looks like it's stalled.
Anything outside of that is average, if anything.
So when you look at VS from the perspective of someone who's used to typical Unix or JS tooling, it's comprehensive. If you look it from the perspective of an old time Java developer, it's lagging behind.
Maybe C# is really only fantastic on Windows with Visual Studio?
RIDER from JetBrains is fantastic IDE on all platforms.
VSCode is a good editor, when you want to write smaller (single file) C#/F# programs.
LinqPad is only for Windows but is nice companion editor to riff off small methods/functions or probing LINQ etc.
/p:CreateHardLinksForCopyFilesToOutputDirectoryIfPossible=true /p:CreateHardLinksForCopyAdditionalFilesIfPossible=true /p:CreateHardLinksForCopyLocalIfPossible=true /p:CreateHardLinksForPublishFilesIfPossible=true
It will give you a considerable speed-up for very large solutions, especially if there are lots of common project dependencies, as it will make hard links instead of copying entire files. This could save you gigabytes of file copying in very large solutions. Google for "hard link" if you don't get what I mean by that.
Note that dotnet core works differently and doesn't do copy local at every stage up the dependency tree when you build, instead copying dependencies directly into your top level application project only when you run the publish target, which is obviously cheaper than either approach.
I've not seen any thread on HN bashing MS without reason. However, the only guys who claim to use C# either work with big companies or freelance.
Some context has shifted, the Microsoft takes over Github part has shown sentiment shift also ( not everyone of course)
Beyond that, MS does deserve the skepticism it gets, and I'm not a fan of the "M$" references or similar. Leadership at MS has changed and it does show. I do wish they'd stop doing sleazy things with windows though. I've been using more Linux and Mac as a result.
i.e. its been fully open source for 4 years https://mattwarren.org/2018/12/04/Open-Source-.Net-4-years-l... and is under the .NET Foundation rather than Microsoft https://dotnetfoundation.org/
According to the comments on the issue tracker, it was supposed to be OK because it was anonymized – but oops, there was a bug, so it wasn't totally anonymized. But it's OK because you can disable it if you happen to know about it – but oops, the disabling mechanism had a bug.
Things that are important to many free software users are not important to Microsoft. I was excited about .NET Core until I became aware of this stark misalignment of goals and priorities.
I'd say it's only really in this last year that it's really started escaping its legacy and started really making sense as a non-microsoft stack.
inb4 "but EEE was only the 90s!"
http://computer-programming-forum.com/29-pascal/c1ccf8167920...
I don't remember Turbo Pascal ever having similar to coroutines and I used all versions up to Turbo Pascal for Windows.
The async/await implementation will never fall back to thread pool by itself. Tasks are "futures", and in that sense a thread/task pool may be used in async/await when you need to run tasks in parallel. But when a thread pool is used is always under the control of the programmer.
Task is a more basic concept than threads. Tasks are about asynchronous execution, thread about parallel execution. Parallel execution is inherently asynchronous, but asynchronous execution is not parallel.
Indeed, that it the whole idea behind async/await: Enable the asynchronous model without the overhead of multiple threads.
It does use a threadpool scheduler by default for a console app. Yes, I could override that if I wanted to.
For UI threads (WPF, WinForms) it is essential that the code continues on the original thread. This the synch context used in WPF/WinForms will post the continuation on the original thread once it becomes available (thrugh the big message loop).
For ASP.NET threads, requests are processed from a thread pool. The ASP.NET synch context IIRC will schedule continuation on any ASP.NET managed thread.
So yes, you may see your code (esp. in console apps) executing on another thread after an async call, but that does not mean that .NET schedules your tasks on a thread pool. There is still only a single thread of execution at any one time, until you explicitly use a thread pool (e.g. Task.Run)
for (var i = 0; i < 1000000; i++) {
var unused_task_var = RunTaskAsync();
}
await RunMainMonitoringTaskAsync();
And I purposefully wasn't calling await on "unused_task_var". And this was doing what I wanted, running all those tasks on multiple background threads in the pool, as long as RunTaskAsync method itself yielded once early on in its function (to return control back to the for loop).tl;dr If you call an async method and don't await on it, it will be parallelized - for a console app, at least.
Honestly, I don't find the MS docs on this to be that great. Not 100% sure I'm even doing it the right way here. Everybody says use Task.Run but that is for CPU bound tasks. I want to run a ton of IO waiting tasks.
edit: looks like I'm doing it right. See "Async Composition" @ https://blog.stephencleary.com/2012/02/async-and-await.html
In general it works pretty well until you need more than the defaults offer, then it becomes almost an exercise in frustration.
Async/await makes concurrency bubble up. This is a great article that explains this issue: http://journal.stuffwithstuff.com/2015/02/01/what-color-is-y...
It's also why I tried Golang. Once you use goroutines it's hard to go back, since the code is synchronous code.
(I use JavaScript with async/await in my day job)
The nice thing about async/await is that it's just a wrapper around futures, which are themselves a composable wrapper around callbacks (semantically; the implementation can be more efficient, of course). So any language that can express function callbacks as first-class values can represent a future, and any language that can represent a future can interop with the async/await world. Which is why you can have JS code doing await on C# code doing await on C++ code in a Win10 UWP application, and it all works. And you can take existing libraries and frameworks that use explicit callbacks (often written in C), and wrap that into futures such that it's all usable with await.
I'd say the more important concern with c# is to be careful you're not accidentally calling a "really blocking" function from an async method, or you will lose scalability. The lesser issue is the mundane task of changing all your function signatures in the chain to async.
I too would use Go if it didn't regress in every single area for me, other than concurrency, and make me sad.
This is a spot-on. The only language I know that did this all right is Haskell, where most of your code doesn't need any thinking of async operations (either runtime gets you covered, or function takes a callback as a parameter, instead of any await magic), and when you need them -- you have `async` library that gets all you need.
Laziness is not Async.
You explicitly provide instructions which expressions get turned into async expressions in Haskell.
- either Haskell gives you API which is done "right", without any Async types. For example, `bracket` function
- or runtime gives you lightweight threads by default, so you can just `fork myComputation` and it'll run in a lightweight thread which "just works"
- or finally, in rare situations of interleaving different computations with complex dependencies, you just use the `async` library, which is not a special language construct but a library, which lets you "await" and all that
It's easy enough to wrap a non async library with promises so I can use it with async and await.
I've sometimes done the same thing with non-async libraries in C# by wrapping them with Tasks.
I usually only do this when I'm pretty sure I'll have to farm out the functionality to a separate service in the very near future. I just start with an async facade around the library, and then swap in an async wrapper around the web service when the time comes. Then I can just drop it in without needing to make any changes aside from changing the interface binding in the DI container initialization.
I suppose this might violate YAGNI. But I really don't do it often at all. I only doing it when I'm following the principle of PSIGNIS (Pretty sure I'm going to need it soon). Maybe it's better to just use the library synchronously and then refactor when it's time to move the functionality to a separate service. I don't think the amount of dev time spent is hugely different either way.
Wait until you try goroutines :)
Could even use the return `await Task.WhenAny` to tell you the specific one to check. Shouldn't be a very hard construct to make; to make it more select like.
It has the benefit that any number of tasks can be selected, but the efficiency is not good as hard-coded select blocks.
But it looks C# Task.WhenAny has much less use case variants than Go select block.
The holy grail is cooperative multitasking and always-on, opt-out async [0] if you ask me.
Such as?
Indeed, phantom types are wildly underappreciated. Long ago, I created an library [1] that ensures the type safety of any runtime generated programs you create using it. It does this by typing the various stacks that are in play at any given time, but every new generic type on the CLR ends up creating new type descriptors in global data structures (which aren't GC'd), so complex programs with deep stacks end up generating a lot of static, uncollectable data that just hangs around forever.
[1] http://higherlogics.blogspot.com/2008/11/embedded-stack-lang...
Haven’t touched java since version 7 i think. But was pretty convinced they both have comparable type inference capabilities when it comes to parametric polymorphism.
The big difference between C# and java is the reification of the parameter values, inferred or not.
And the reification method choosen for C# gives you some extra metaprogramming capabilities, especially when combined with reflection.
My argument was that this can be provided design time instead (inference too) while retaining the extra safety of having theorems for free
Typescript (and normal Javascript) both support async/await very well as long as you use Babel to compile your code.
Infact, you don't even need to use Babel to compile your code because a large portion of browsers natively support async/await: https://caniuse.com/#search=async
I'm not sure why people say you need libraries that support async/await. In JS/TS, async/await are built into the language itself and most libraries utilize the Promise API, which means they also support async/await (since async/await is built on top of promises).
Example taken from here: https://mariusschulz.com/blog/typescript-2-1-async-await-for...
And .NET is still very much Microsoft’s baby. Unlike an independent language like C or JS or Rust, MS could pull the rug out at any time.
Yes, Mono. But Mono is an unofficial port of a moving target. They have no control over the direction of .NET.
With open membership https://dotnetfoundation.org/blog/2018/12/04/announcing-net-... and election of its board https://dotnetfoundation.org/blog/2019/01/23/why-you-should-...
Maybe MS will in future cede all control over the language. Maybe in future 99% of code contributions won’t come from Microsoft employees.
But even then it would take years for the language to become more widely adopted outside Windows.
What you mean? C# is open source. And, here is the location - https://github.com/dotnet/csharplang
So in practice, 'pulling the rug out from under' Mono (or .NET Core) users would be pulling the rug out from under paying customers.
Unrelated, anyone know how I can get my Windows 10 Mobile phone to sync Zune songs to my Windows Media Center? My Xbox360 stopped working smoothly after the last few forced updates
Part of it is not necessarily the design F# took but that the TPL is incompatible enough that the mixing of TPL-centric .Net libraries becomes a problem. It might be wise for F# to support the TPL via computation expressions with something like `task { ... }` (there are a few implementations out there but a compiler supported state machine generator would be more ideal).
I'm not clear if you absolutely have to use TPL but CML is likely just a better model for tackling concurrency and Hopac is orders of magnitude more efficient than F#'s async.
Since I have mostly been around enterprises, I can say it is pretty much appreciated.
This are however the kind of customers that will happily have WebSphere, SAP, cluster management with AD, SQL Server OLAP and so on.
There won't be any projects being published on github and getting software into the projects always requires some kind of change request.
Not the kind of shop many HNers like to talk about.
Regarding Java, as someone that works on both platforms, I still look forward that Valhalla comes to fruition.
Which is why I am usually against the "I rewrote X in Y", unless it holds a good business value story going for it.
Other than that, I do agree, I really like C# a lot and am glad the effort that's been put into making sure Core works cross platform. I still shutter every time I have to work in VS (not Code) though.
Something I'm curious about, how does C# handle parallelizing async code? Is it hard? Easy? How do you do it?
Have you tried Python's asyncio?
This applies just as much to Python asyncio so I'm not sure it's a good suggestion from that perspective. You can use an executor to wrap things that don't support asyncio but that doesn't really qualify as good asyncio/await imo.
async/await - C# is the ONLY language which gets this right. Javascript has it now but you need to be use libraries which support it too, which are hard to find. Kotlin has coroutines but Java base library doesn't have support for coroutines so you can't use it all the way through and create a chain of all async functions. Once you use async/await it's hard to go back, since the code is as easy to write as synchronous code.
Then you have proper support for generics(unlike Java which has type erasure), LINQ queries and an amazing IDE which is visual studio.