1. 9
  1.  

  2. 4

    It’s interesting that they mention tooling because as far as my experience goes Java has the best tooling beating any other language. It’s mainly because it’s so old but still for each problem Java ecosystem has numerous solutions. Most of them, of course, stem from innate Java’s flaws (modules and OSGi) but still…

    Personally I think C# and .NET are better as a language and runtime but this is no surprise as they were designed later than Java and thus had an advantage (there are things I wish Anders and team would not copy from Java…)

    1. 4

      I strongly agree with this list, though I’d note that Kotlin is doing a really good job bringing literally all of these except value types to the JVM, in a fairly lightweight syntax to boot. (Properly doing value types would require changes to the JVM, though Kotlin immutable data classes by default behave similarly to value types, which can be useful in many situations.)

      That said, this post inadvertently reminded me of how few people actually get what C# async and await do. If you look at the sample output in that example, the astute reader will realize that nothing happens in the asynchronous task until .Wait() is called. That’s because Main() is not itself an asynchronous method, and the author never set up a task runner, so this program actually runs entirely in a single thread. I suspect what the author wanted to do would be closer to something like

      TaskAwaiter david = Task.Run(ThinkAboutIt).GetAwaiter();
      ...
      int result = david.GetResult();
      

      which would actually have David read in the background.

      1. 2

        That said, this post inadvertently reminded me of how few people actually get what C# async and await do. If you look at the sample output in that example, the astute reader will realize that nothing happens in the asynchronous task until .Wait() is called. That’s because Main() is not itself an asynchronous method, and the author never set up a task runner, so this program actually runs entirely in a single thread.

        This is largely inaccurate. ThinkAboutIt doesn’t run when Wait is called, it will immediately begin running on Main’s thread until it hits the first await (the one inside ReadTheManual), at which point control returns to Main, and the rest of the logical thread of control will be on a background thread (not on the initial thread).

        You can verify this yourself by inserting a few prints of Thread.CurrentThread.ManagedThreadId.

        1. 1

          Huh, I apologize; you’re correct. That said, I’m now very confused. When async/await was first introduced, I remember Microsoft screaming about how you needed to be in an event loop for it to work properly, and I remember having to lean on third-party runloops (e.g. Nito.AsyncEx) to get the behavior that’s going on here. (In fact, IIRC, the behavior of await was to return immediately to the parent thread—which, since it was called directly from Main here, would be the OS, which resulted in the program terminating.)

          Did the implementation change, or is there now an implicit run-loop, or maybe I’m conflating this behavior with having Main itself be async (which I think they’re going to allow in the next C# revision anyway)? Any idea what I’m remembering here?

          1. 1

            Maybe the very early CTPs did that? The F# version uses ‘cold’ tasks but C# has been hot since I’ve been using it…

            1. 1

              To my knowledge, await has always ran its target on the current thread until an actually asynchronous operation takes place. This could be something like waiting for a thread to complete, or async IO to finish.

              if you have an async method that skips doing any real async work (maybe you have a cache or something?), you don’t want to have to launch a new thread for that method.