The problem with C# is that its design decisions won't attract any new users who are considering or using Go (or in some cases Rust). That's a consequence perhaps of listening to its users, who are mostly Windows-based and have rigid preferences. And then on the other hand, C# goes on to introduce excellent functional-style abilities - while at the same time handicapping them in some way.
Recently, on one of their GH issues I was arguing that it's a good idea to reduce typing and allow namespace inference from directory structures/paths - given that most projects already have them in sync (and it can be done in a non-breaking way). In general, I felt that the community feels that it should be solved with "IDE features". Pushing these into an IDE is the Windows way of doing things.
To win in Unix land, C# needs to be editable in a plain text editor. It requires succinctness. But with the current community, I'm afraid they'll never figure this out.
I hope that remains the case. File structure inferred namespacing to save one line per file seems like a ridiculous breaking change. If you're looking for succinctness to the level that something like that matters in your line/character count, use Perl or something.
If you're looking for something like scripting without a lot of fanfare, just look at https://devblogs.microsoft.com/dotnet/announcing-dotnet-run-...
So what I see is a very capable language, with generics far ahead of golang, but a pain to write because I need to nest them inside namespaces and classes. If you take the HN crowd for instance (which is what a lot of startups are like), nobody wants to write Java-style OOP. C# can simplify it quite a bit (retaining full backward compat), but likely won't.
Then... maybe F# would be more your bag?
Features like this just cause more unexpected and surprising things to happen.
I always tell folks I work with to have a “reader bias” when writing code. People bend backwards to add fancy reflection and magic to automatically save 3 lines of code then spend days of headache debugging it when it causes a problem.
Like all seasoned ICs I say the same thing, but yours is more succinct.
Not at all. This can be done without breaking code. The important part isn't typing the namespace - rather, the freedom to move files around without having to change namespaces.
Even if it were something like:
auto namespace; // for example
it's good enough. Allows me to move directories around, without having to depend on an IDE to keep namespaces in sync. IDEs anyway can only take a good guess at this, if namespace doesn't match the dir name.> just look at https://devblogs.microsoft.com/dotnet/announcing-dotnet-run-...
I am not looking for a scripting solution. C# is a misfit for it. I want all of C#, with terseness and not forcing OOP.
So... without and IDE, you'd move code around, let the NS be changed due to being placed in a different directory structure, and then fix namespaces on use-sites manually?
> I want all of C#, with terseness and not forcing OOP.
C# does not force OOP on you. You can have a single namespace, single static partial class and spread its members across as many files as you want. So the "ceremony" consists of the following snippet _per file_
namespace NS;
static partial class C {
// Your methods here
}s/Windows/modern/
> To win in Unix land, C# needs to be editable in a plain text editor.
I guess hard-core unix users still use sticks and stones to make fire.
I would like:
// math/adder.cs
public static add(int x, int y) : int {
return x + y;
}
Instead of: // math/adder.cs
namespace math {
class adder {
public static add(int x, int y) : int {
return x + y;
}
}
}
Both are callable as: math.adder.add(10, 20); // math/adder.cs
package math;
…code…namespace math;
Having to use class/struct instead of free floating funcs tries to force some hierarchy, architecture, etc
Which eventually makes the code better *globally*
Currently, you're forced to define the hierarchy in the directory structure, and then again with namespaces. There should be a way to opt out of this.
As of now you can opt out of physical hierarchy (file patches)
I think logical hierarchy is better because you avoid stupid things like moving file to other folder causing compilation errors.
I've witnessed too much of such issues in C++/cmake world to want it.
namespace Math;
static class Adder {
public static int Add(...) { ... }
}
(one nesting level less). Next, elsewhere you can write namespace Whatever;
using static Math.Adder;
class CC {
void M() {
var z = Add(10, 20); // no NS qualification needed due to using static above
}
}
Java enforces directory structure to reflect package names, and this feature is not universally popular.That's a lot of sticks and stones.
[1] https://en.m.wikipedia.org/wiki/Usage_share_of_operating_sys...
I used to think in this idealistic way - if I can't reasonably use the language in VIM (without plugins of course!) the language is flawed, etc.
Lately I've come to embrace the viewpoint that a mixture of language features and great editor support are what enable productivity and creativity.
Being able to observe a live program in a debugger is so much more powerfull technique. I know there are people out there who can architect anyhting from first principles and deduction - but unless you are really strong it that way live IDE wins.
It's a pain to couple these two and you end up with giant stacks of `import`s in "modern" JS.
When you reorganize files, now references need to be updated in many places. The editor slows to a crawl as the files are updated and the LSP has to process the changes.
Big yikes. I hate it in TS/JS because its a paper cut that doesn't need to exist. Namespaces make refactoring organization structure way less jarring and at least I do that very frequently in certain lifecycles of code.
This is exactly why directory based namespaces are a good idea.
Otherwise:
1. You refactor. But namespaces which were formerly in sync with dir structure, but now aren't because you decided to move directories around to manage code better.
2. You don't refactor because it's a lot of work.
> I hate it in TS/JS
It's not only JS/TS. Python, Go, Rust ....
C#'s approach here is redundant, and due to copying whatever Java was doing.
Rust allows you to move modules around without you changing using.
That's great. Something like this is what C# can also aim for, while retaining full backward compatibility.
Why? It's free is you use an IDE and otherwise mostly doable with search and replace + a few manual fixes where the compilation fails.
I don't sync my namespaces to file paths and instead only use namespaces to logically group imports. That let's me organize the visual structure of the tree independently of the logical structure.
Every IDE now has great navigation utilities that doesn't require click based navigation so I don't see the infatuation some folks have with syncing these.
In JS, end up creating stupid barrel files all over the place.
I was using net core 6 years ago, 6 years is not much but the code from back then does not compile anymore and the ecosystem changed a lot.
Are you to share the code? C# 1 code still compiles today, so I don’t understand this statement at all.
What do you mean? It's editable in plaintext already. See what "dotnet new" generates.
This isn’t a C# issue, it’s dynamic vs static typing issue. You can edit C# in any text editor (obviously) but you don’t get all benefits a good IDE gives you. Statically typed languages in general allow IDEs to provide a wealth of benefits that make writing and maintaining code much easier. With the IDE one can be much more productive.
This is also possible for dynamically typed languages but in practice they’re not at the same level.
So yeah write your little dynamically typed language scripts in vim. The first thing I’m doing for a large C++ project is put it in an IDE. Not to build it but to explore it and understand it, ymmv
What makes you think this? I’d wager that most C# code is not open source.
One problem with Go is the lack of fine-grained control over allocation. In particular, no arena allocation support. How does C# compare?
Another problem is relatively high cost of FFI interop with C. It's gotten better, but Go still needs to switch stacks, etc. How is C#?
How does C# compilation speed compare?
Does the compiler optimize more aggressively than Go (which does very little optimization)? I've heard the C# AOT compiler is lacking, but it's not clear in what way.
Does C# have the equivalent of "go run"?
What's the package management situation like?
Can you use LINQ against databases like Postgres on Linux, without having to buy into a lot of Microsoft/.NET stuff?
Go has an experimental arena package [0], but the proposal is on hold and the code may be removed in the future.
C# does not support arenas. But it does provide the stackalloc keyword, whereas in Go you kind of need the compiler's blessing for avoiding heap allocations.
> Another problem is relatively high cost of FFI interop with C. It's gotten better, but Go still needs to switch stacks, etc. How is C#?
Async in C# is implemented as stackless coroutines. Calling into FFI is cheap.
> How does C# compilation speed compare?
In my experience, release builds are a bit slower than Go.
> Does the compiler optimize more aggressively than Go (which does very little optimization)? I've heard the C# AOT compiler is lacking, but it's not clear in what way.
Not much to say on this, but with each new .NET release, a core .NET team member posts a blog post about performance improvements in the new release. The most recent one: https://devblogs.microsoft.com/dotnet/performance-improvemen...
> Does C# have the equivalent of "go run"?
dotnet run
> What's the package management situation like?NuGet Gallery [1] is like a centralized DLL registry. Definitely not as good as Go.
> Can you use LINQ against databases like Postgres on Linux, without having to buy into a lot of Microsoft/.NET stuff?
Probably not. This is usually done with EF Core and the Postgres provider.
>Probably not. This is usually done with EF Core and the Postgres provider.
You can use Npgsql[0] alone or with non-EF Core interfaces, since it's just a ADO.NET Data Provider (for others: the common interface for database access in dotnet).
The GP question is interesting because it asks about using LINQ with databases "without having to buy into a lot of Microsoft/.NET stuff". I'm going to assume they mean "without using all-microsoft-sourced libraries and frameworks like Entity Framework" (since LINQ is a .NET library interface thing anways).
A couple of example of alternatives that support utilizing Npgsql for database access:
1. Linq2DB: https://linq2db.github.io
2. Dapper: https://github.com/DapperLib/Dapper?tab=readme-ov-file#will-...
3. SqlHydra: https://github.com/JordanMarr/SqlHydra?tab=readme-ov-file#co...
There are a number of other libraries, some more or less complete/maintained than others. EF and Dapper are by far the most popular libraries folks are using on top of Postgres, but there are alternatives, and using the ADO interface on its own works fine (I've done this in very small projects to limit dependencies).
I couldn't disagree more strongly. This has nothing to do with Windows/Unix and everything to do with language philosophy. I also think that languages that understand that understand they are targeting (text, IDE) rather than just (text) accomplish things that those that only target text never will.
I think the changes they implemented were a mixed bag. True, they did a lot to clean up the corporatey 'design-pattern' mindset of the API, and some of the syntax is nice.
But there's a lot of stuff I dislike - top level statements are nightmare to use, as they interact weirdly with the rest of the language, implicit usings are just straight up magic in a bad way.
If you're comfortable with the IDE workflow (what's an IDE anyways? everyone's using VS Code/forks and AI nowadays), then it takes care of the boilerplate for you, and it's not an impediment when reading, as your eyes just skip over it.
C# is 25ish years old, and it's a testament to how well-designed it is that it's still used in almost every domain.
Go is an awesome language, but part of its awesomeness comes from the really small feature set, and trying to retrofit Go-like syntax into C# makes the language worse in many ways.
Many Linux folks also like to path themselves on the back that Android is Linux, thus UNIX land as well.
Swift and Objective-C also come from UNIX land vendors.
IDEs were invented at Xerox PARC, and companies exploring Lisp Machines.
All 1990's systems, with exception of classical UNIX werr adopting IDEs.
Mac OS, OS/2, BeOS, Solaris, NeXTSTEP, Oberon, Plan 9/Inferno ACME,...
It isn't a Windows only thingy, rather progress.
As someone that was around as UNIX was becoming mainstream, it looks like there is too many idealism going around about what UNIX as OS, and related vendors were all about, before the widespread adoption of GNU/Linux.
I've been adopting these new approaches into my code gradually over time by way of intellisense suggestions. Sometimes I'll see the little ... in front and think "what the hell, let's see". If it looks ugly, it's easy enough to back out. Some things took a while to grow on me.
So far the only newish thing I haven't preferred much is the range operator syntax [0]. Every time I accept that one its a quick revert to the more verbose indexing operators.
The second one has been a big ballache when using pattern-matching. I think the leading `.` on the patterns isn't pretty, but I'd take it over handwriting the full type name every time.
The technique works best for encoding higher-kinded traits and, as you say, Monoid doesn’t need any of that, but it was an easy way to introduce the ideas.
jasonthorsness•6mo ago
tester756•6mo ago
And somehow C# has the most sane programming ecosystem
pjmlp•6mo ago
mdhb•6mo ago
https://github.com/dart-lang/language
https://github.com/orgs/dart-lang/projects/90/views/1
sakesun•6mo ago
legobmw99•6mo ago
monocularvision•6mo ago
brainzap•6mo ago
pjmlp•6mo ago