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

I would kill for these languages features in Go


That's what C# offers (except true* Rust-style enums).

The latter will be there in one of the future versions and is in an active design phase, which luckily focuses on tagged-union implementation strategy.

With that said, you can already easily use one of the Option/Result libraries or write your own structure - switching on either is trivial (though you have to sometimes choose between zero-cost-ness and convenience).

It already has struct generics, iterator expressions (LINQ), switch pattern matching, good C interop and easy concurrency primitives (no WaitGroup nonsense, also has Channel<T>). Oh, and also portable SIMD, C pointers and very strong performance in general.

* True as in proper tagged unions with either a tag or another type of discriminant and aliased layout, instead of tag + flattening all constituent parts into a one jumbo struct. Or making it an opaque pointer to a box (like Java does, or C# if you go inheritance/interface route). These don't count. I'm curious about Borgo's lowering strategy for enums, but given Go doesn't have those, I'm not holding my breath and expecting something like F# struct unions at best.


As someone who is "C# curious," but haven't been able to keep up with all the horrific number of rebrands of the "new, open, .net, core, framework", what is the C# equivalent of $(for GOOS in linux darwin; do for GOARCH in amd64 arm64; do dotnet build -o thing_${GOOS}-${GOARCH}; done; done)?


That's spelled `dotnet publish -r ${GOOS}-${GOARCH}` with the new ahead-of-time (branded Native AOT) compilation features installed and enabled.

It isn't without a whole list of caveats if you're used to Go's way of doing things though. See <https://learn.microsoft.com/en-us/dotnet/core/deploying/nati...> for details.


You're very kind, thank you

For others wanting to play along at home:

  $ docker run --name net8 --rm -it mcr.microsoft.com/dotnet/sdk:8.0-jammy-arm64v8 bash -c '
  cd /root
  dotnet new -d -o console0 console
  cd console0
  dotnet publish --nologo --self-contained -v d -r osx-arm64 -o console0-darwin-arm64
  sleep 600
  '
although it didn't shake out

  $ docker cp net8:/root/console0/console0-darwin-arm64/console0 ./console0
  $ ./console0
  Killed: 9
I tried with and without --self-contained and the biggest difference was that self-contained emitted a bazillion .dll files and without just emitted the binary. I case the context isn't obvious, $(dotnet new console) is a skeleton for the infamous WriteLine("Hello, World") without doing crazy whacko stuff


For simple JIT-based but fully self-contained binaries, without adding any properties to .csproj, the command is a bit mouthful and is as follows

    dotnet publish -p:PublishSingleFile=true -p:PublishTrimmed=true -o {folder}
(you can put -p: arguments in .csproj too as XML attrs in <PropertyGroup>...)

This will give you JIT-based "trimmed" binary (other languages call it tree shaking). You don't need to specify RID explicitly unless it's different from the one you are currently using.

For simple applications, publishing as AOT (without opting in the csproj for that) is

    dotnet publish -p:PublishAot=true -o {folder}
Add -p:OptimizationPreference=Speed and -p:IlcInstructionSet=native to taste.

Official docs: https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-p...


You're also very kind, and I realized that it's possible there were a bazillion "watch out"s on the docs and was just trying the <PublishAot>true trick when I saw your comment

However, it seems this brings my docker experiment to an abrupt halt, and is going to be some Holy Fucking Shit to re-implement that $(for GOOS) loop in any hypothetical CI system given the resulting explosion

  /usr/bin/sh: 2: /tmp/MSBuildTemproot/tmp194e0a13157b47889b36abb0ce96cd2d.exec.cmd: xcodebuild: not found


You need an OS for which you are building to be able to compile an AOT binary - it depends on OS-provided tooling (MSVC on Windows, Clang on macOS and Linux, and a system-provided linker from each respective system). In fact, once ILC is done compiling IL to .a or .lib, the native linker will just link together the csharp static lib, a GC, then runtime/PAL/misc and a couple of system dependencies into a final executable (you can also make a native library with this).

Cross-architecture compilation is, however, supported (but requires the same extra dependencies as e.g. Rust).

If you just want to publish for every target from a single docker container (you can't easily do that with e.g. Rust as noted), then you can go with JIT+single-file using the other command.

Keep in mind that Go makes concessions in order for cross-compile to work, and invested extra engineering effort in that, while .NET makes emitting "canonical" native binaries using specific system environment a priority and also cares a lot about JIT instead (there aren't that many people working on .NET compiler infrastructure, so it effectively punches above its weight bypassing Go and Java and matching C++ if optimized).


The sibling comment pretty much sums it up. But if you want more detail, read on:

Generally, there are three publishing options that each make sense depending on scenario:

JIT + host runtime: by definition portable, includes slim launcher executable for convenience, the platform for which can be specified with e.g. -r osx-arm64[0].

JIT + self-contained runtime: this includes IL assemblies and runtime together, either within a single file or otherwise (so it looks like AOT, just one bin/exe). This requires specifying RID, like in the previous option, for cross-compilation.

AOT: statically linked native binary, cross-OS compilation is not supported officially[1] because macOS is painful in general, and Windows<->Linux/FreeBSD is a configuration nightmare - IL AOT Compiler depends on Clang or MSVC and a native linker so it is subject to restrictions of those as a start. But it can be done and there are alternate, more focused toolchains, that offer it, like Bflat[1].

If you just want a hello world AOT application, then the shortest path to that is `dotnet new console --aot && dotnet publish -o {folder}`. Otherwise, the options above are selected based on the needs either via build properties or CLI arguments. I don't know which use case you have - let me know if you have something specific in mind ("Just like in Go" may or may not be optimal choice depending on scenario).

[0] https://learn.microsoft.com/en-us/dotnet/core/rid-catalog

[1] https://github.com/bflattened/bflat (can also build UEFI binaries, lol)


To clarify, my team uses Go and prefers to stick with "idiomatic" Go. So, while we could implement our own types, there would be pushback. As an example I liked lo [0] but my team was resistant because it's not considered idomatic.

If were up to me we'd be using a language with a better type system :)

[0]: https://github.com/samber/lo


It's not the best solution, but an analyzer like [0] covers most of the cases for reference types. For enums and struct DUs in general we'll have to wait for language (or even runtime) support.

[0] https://github.com/shuebner/ClosedTypeHierarchyDiagnosticSup...




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

Search: