Hacker Timesnew | past | comments | ask | show | jobs | submitlogin

> A few fumbles by Microsoft early on stunted its growth

Microsoft really, _really_ missed out on a huge opportunity to rebrand .NET into something else when they did the Framework -> Core transition. Despite .NET being cross platform for over ten years and winning benchmarks left and right people still see it a the “slow enterprisey framework that only runs on Windows”.



Yes, big time fumble.

I've met a handful of folks who used it in the .NET Framework days and hadn't kept up with the changes in Core (multi-platform, object-functional hybrid, minimal syntax for console and APIs, etc.).


What do you mean by "minimal syntax for console and APIs"?


You no longer need imports, or namespace, class and main method boilerplate to write a basic C# program; there’s now a way to simply write some lines of code in a file with some implicit imports, and compile/run them like it was more of a scripting language.

https://learn.microsoft.com/en-us/dotnet/csharp/tutorials/to...

(If there’s other syntax changes, I don’t know them, AFAIK it’s the same C# you write)


> If there’s other syntax changes, I don’t know them

The new syntaxes that come to my mind are:

* File-scoped namespaces

* "global using"

* "using static"


> What do you mean by "minimal syntax

It's a beginner friendly and "demo mode" set of features to reduce boilerplate for small programs, such that the minimal "hello world" program is literally 1 line of code.

And a working minimal ASP web app with a http endpoint is not much longer.

C# and .NET was from day 1 designed for "programming in the large" so that large codebases can be sensibly organised.

This however causes some overhead, such that a person coming from Python might have looked at the standard C# "hello world" example with using statements, namespace, class and method wrapping the 1-line payload, and conclude that the language is impossibly clunky and cumbersome. My opinion is the opposite; managing e.g. 50K lines of code without those ways of organising code, is going to be impossibly clunky and cumbersome.

However, it is also true that demo mode is great for 1-file demos that get right to the point.


I think the using statements are fine, even for one-file demos. Python, Go and Node don't have implicit imports like C# and it's fine. I'm actually not entirely sold on the implicitness. Forces the reader to look at the .csproj file and the target framework documentation what is implicitly imported.

Most of the verbosity comes from classes and namespaces. Go and Rust have shown it's possible to design a language for "programming in the large" without classes for everything and with less verbose namespaces.

But to be fair, I'm just getting started with C# so my comment above is likely wrong and biased. Happy to be proven wrong :)


C# has several constructs like anonymous types, tuples, named tuples, and records (for structs and classes). Each has different use cases (and sometimes limited scopes like anonymous types) that can serve different contexts for data modelling.

    > with less verbose namespaces
This is, once again, the function of the team and not the language. There is no hard mandate on how namespaces are selected so verbose namespaces is a result of teams preferring it over more concise naming. Part of that might be purely practical. Whereas in JS, you would import a local module by path, C# imports via namespace and convention is to use pathing, but C# will of course allow any namespace convention you like for local modules and does not constrain to strict pathing.


> Most of the verbosity comes from classes and namespaces. Go and Rust have shown it's possible to design a language for "programming in the large" without classes for everything and with less verbose namespaces.

The statement that "C# and .NET was from day 1 designed for programming in the large" is true and factual, supported by design documents that pre-date .NET 1.0, i.e. in the late 1990s

The statement that more-lightweight ways have since been developed of approaching the issue is more subjective. But IMHO it is also largely true, as the programming language world has moved on since then. The C# design has been extended a lot, but is constrained by being backwards-compatible. In some ways it is of its time.

e.g. We might not be "entirely sold on implicit usings" but it was a way to get from existing syntax, to a 1-liner "hello world". I think that global usings are fine, when used very sparingly. e.g. I am happy for a test project to have a global using Xunit because it will be used so widely in the project code. But not many more global usings.


I very much agree with your comment. C# managed to evolve and adopt many “modern” features while maintaining backward compatibility, which is quite impressive.


Minimal web APIs are structured a lot like Express (whereas .NET web APIs are more like Nest.js)

https://learn.microsoft.com/en-us/aspnet/core/fundamentals/m...


Having recently joined a company using C#, and with a background using Go, Python, Node, and similar, I was worried about heavy "enterprise-style" APIs. I was happy to discover the new minimal web API while reading .NET Core documentation.


Probably top level statements and minimal APIs from ASP.Net Core


> Despite .NET being cross platform for over ten years and winning benchmarks left and right people still see it a the “slow enterprisey framework that only runs on Windows”.

Do these people I've never heard of outnumber the people who did upgrade but wouldn't have if it had been branded as a separate product?


I’m definitely one of these people. Maybe I should give .NET a chance.


It's quite nice now. Tooling is way nicer than it was 10 years ago. My team is all Apple silicon Macs and we deploy to AWS Arm64 instances. Unit tests in GH run on Linux workers.


Less than 50% of software engineers ever used .NET for anything, so the answer is almost certainly yes?


I encountered this within the last week...


Yep, I literally only learned it was cross platform last year when I noticed it as a package dependency.

Mind you, I’m not a coder, and more just a Linux homelab hobbyist.


I was going to ask what the multiplatform deployment story was like, it seems like you've partially answered it - it seems like you ship it with .NET Core as a dependency, kinda like JRE for Java programs?

How heavy of a dependency is it?

And is there a dependency hell situation, if different programs require different versions of .NET Core?


There are quite a few knobs there. You can AOT-compile the bytecode, as well, and you can ship the whole thing as a single binary: https://learn.microsoft.com/en-us/dotnet/core/deploying/sing...

Size very much depends on what you actually use in the app, but on the order of tens of megabytes.


Also, one of the major changes in the Framework -> Core (now just .NET) shift was making it legally permissible to redistribute the runtime?

So you can ship .NET code with a .NET runtime all in your installer.

Afaik, Framework was only distributable from Microsoft.


Nope, have always been able to ship the redist installers. Just like VC++. https://www.microsoft.com/en-us/download/details.aspx?id=21 (scroll down to 'Installation Instructions')

After all, not being able to ship the runtime with the software to buyers would have been... Bad. In the early '00s


I think I was getting a few things conflated. Is the following correct?

You can't run .NET Framework applications without a system install of .NET Framework.

You can absolutely run .NET (ex-Core) applications without a system install.


The state of .NET Framework is that it's packaged with Windows so technically it did not require an install - an OS shipped with it.

The state of .NET is something that Java wants to reach in a few years or so. There are basically three ways to deliver an application to the users:

- A single or multiple files containing .NET assemblies and a thin binary launcher (single-file mode controls the exact shipping of this) - this is similar to OpenJDK which requires a runtime to be installed on the system (except OpenJDK does not have the capability to put all assemblies into a single file with a small native section for the launcher).

- A single or multiple files containing .NET assemblies and runtime itself

- A single native executable compiled with NativeAOT

The first two options allow to "merge" assemblies into a single file or ship them separately.

Shipping just .NET assemblies without runtime takes the least amount of space but requires a runtime dependency (it's easy to install on practically any system).

Shipping assemblies + runtime can also be done as a single file where there's a sandwich of native code and .NET assemblies. In order for such executable to not take disproportionate amount of space (65-120+ MiB) it can be trimmed which is recommended - this reduces base binary size down to 10 MiB or less nowadays (and grows as you add dependencies).

And building with NativeAOT relies on the same linker-based trimming but produces a single native statically linked executable. This results in the smallest runtime-independent binaries (they start at about 1-1.2MiB) with the best startup latency but comes with a different performance profile when compared to JIT and is not compatible with features that either rely on JIT or on unbound un-analyzable reflection where ILLink cannot determine the exact scope of code that has to be compiled. The ecosystem has significantly improved since the introduction of this target in .NET 7 to provide users with tools to make their code compatible, if any changes are required at all.


Java has been there for years as well.

AOT compilation has existed for about 20 years, it only happened to be a commercial product, Excelsior JET, Aonix, PTC, Aicas, are some examples.

What GraalVM, OpenJ9 bring to the table is free beer AOT compilers, and in GraalVM's case, a LLVM like compiler framework that doesn't exist at all in .NET land.

They also have the advantage of using agents to gather the required reflection data, instead of forcing an ecosystem split of having to rewrite existing libraries to make them AOT ready.

There was the Phoenix project from Microsoft Research, which had the goal to replace Visual Studio infrastructure with a CLI based compiler toolchain, but unfortunely that project failed to gain traction within Microsoft.

Shipping runtimes, which .NET Core introduced for .NET, has been a thing in Java land since they exist.

There is also the ability to create single executables, coupled with jlink and jpackage.

Besides OpenJDK offerings, there is a richness of JVM implementations, each to those having other capabilities, like OpenJ9 and Azul with their distributed JIT compiler for example.

.NET is great and I prefer .NET to Java consulting projects when given the option, however it is no accident that Microsoft has decided to become again a Java vendor as well.


For .NET Framework, you are indeed correct, but in practice this was treated largely the same way as e.g. C++ runtime libraries - you just bundled the .NET runtime with your installer.

This has been moot for a long time now, though, since Windows has shipped with some version of .NET preinstalled since Vista.


> it seems like you ship it with .NET Core as a dependency, kinda like JRE for Java programs?

Pretty much yes. (there are also other ways to bundle it)

It's not even called ".NET Core" any more, it's just ".NET", which for version >= 5.0 effectively is the successor to cross-platform .NET Core.

.NET 9.0 will be out shortly - The annual release is expected November 2024, likely this week.


Imagine how much better the branding would be if they had just called it:

    > dot
    > dot console apps
    > dot web API
    > dot desktop apps
Simple logo design.

CLI commands would be like:

    > dot new console
    > dot build
    > dot run
    > dot publish
(Yes, I know I can alias)

It's not too late, Microsoft!


It is basically the same as any cross platform language now. They even recommend Docker containers for deployment.


JRE for Java isn't a thing since Java 8, the official way is to use jlink to create a custom runtime, make use of jpackage, or AOT compile.

You may still find some JREs, which are created by some distributions that take the stuff out of the JDK to make classical JRE, though.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: