As the author of language-ext [1] (functional programming library for C#) -- these suggestions are a big "YES!!!!!" from me. I assume they're doing the first one due to the way they're using static interfaces like traits (which is what I also do to support Functor, Applicative, Monad, etc. traits). Being able to refine the type-checker based on constraints would be a huuuge win. Although, I'd prefer higher-kinds :)
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.
Sorry to go tangential, I was reading your blog posts following the link from your post. The monoid example is possible without static interface methods: you could use the new() constraint and have the empty constructor act as identity element. Kudos on the posts, very nice to read.
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.
I always enjoy reading the language design committee notes (this is the latest one). C# has the most open and collaborative development process I am aware of. Do any other languages progress like this?
The python PEP process is fairly open, most of the discussion ends up happening on public facing boards. I don’t think they have regularly scheduled meetings to consolidate decisions, though
C# is a fantastic language, and with NativeAOT it can become a real alterntive to Go. It "can"; but most likely it won't.
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.
>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.
I never understood people who advocate radical succinctness so typing a program is optimal when most programming time is spent in reading documentation and debugging.
It's not radical succintness. I just like to write pure functions. C# embraces many fp idioms, but in the end makes it hard to use them without a lot of ceremony.
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.
Agreed with this. I happen to work on some Unity projects that do not have namespace and file structure in sync. Unity makes this more likely to some extent.
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.
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.
> Allows me to move directories around, without having to depend on an IDE to keep namespaces in sync.
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
}
> To win in Unix land, C# needs to be editable in a plain text editor.
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
> 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 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.
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.
> When you reorganize files, now references need to be updated in many places.
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.
Or be like me and not care about the Duke structure at all.
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.
When you write 'mod foo;' in a Rust file (say, main.rs), Rust will look for the source code for the module named foo in one of two places: a file named foo.rs in the same directory as the file declaring the module, or a folder named foo/ with a file named mod.rs inside it.
That's great. Something like this is what C# can also aim for, while retaining full backward compatibility.
There has been a lot of people in the C# community that think like you - that want to make the C# syntax more minimalist, the code shorter, so that they their microservice code is as terse as they'd write in node or Go.
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.
Java comes from UNIX vendor, and C# only exists because Microsoft lost against that UNIX vendor.
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 agree with the first example. I wish C# could do “free” floating functions which just lives in the namespace itself. Your second example could do with the extra namespace indentation by doing
I was arguing that the hierarchy is already in your path. The explicit namespace (and even the class name) is redundant if what you want are mostly functions.
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.
not the author but perhaps because of the .net core transition? all code will obviously compile with the framework they are coded for but a significant migration was necessary to switch to core.
I'm mostly doing Go for work these days, but have been curious about C#.
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?
> One problem with Go is the lack of fine-grained control over allocation. In particular, no arena allocation support. How does C# compare?
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.
>> 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.
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:
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).
Great tooling is 50% of what makes C# and F# so damn good. For the love of god don’t write C# in a text-editor. The live debugger gives you over 80% of what people gush about in lisp-interactivity - a live program environment you can poke and introspect.
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.
C# will never attract Go users because async is much less pleasant to use than goroutines. I've never met anyone who'd used both extensively and preferred async. CSP is a theoretically cleaner and easier to reason about approach to concurrency.
I like the type parameter inference from constraints proposal.
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.
As the author of language-ext [1] (functional programming library for C#) -- these suggestions are a big "YES!!!!!" from me. I assume they're doing the first one due to the way they're using static interfaces like traits (which is what I also do to support Functor, Applicative, Monad, etc. traits). Being able to refine the type-checker based on constraints would be a huuuge win. Although, I'd prefer higher-kinds :)
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.
[1] https://github.com/louthy/language-ext/
Sorry to go tangential, I was reading your blog posts following the link from your post. The monoid example is possible without static interface methods: you could use the new() constraint and have the empty constructor act as identity element. Kudos on the posts, very nice to read.
True! (Although that requires an allocation)
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.
The second one seems very similar to the "using static" feature, but less verbose.
I always enjoy reading the language design committee notes (this is the latest one). C# has the most open and collaborative development process I am aware of. Do any other languages progress like this?
Probably they're the only one among mainstream languages
And somehow C# has the most sane programming ecosystem
If we leave out the desktop programming framework schizophrenia from Redmond.
The python PEP process is fairly open, most of the discussion ends up happening on public facing boards. I don’t think they have regularly scheduled meetings to consolidate decisions, though
Java mailing lists since forever, initially JSR process, nowadays JEP.
Go has a repo with all discussions. the discussion about the package file format (go.mod) is very inspiring
Swift
Python, Kotlin
Dart is also absolutely fantastic in this regard.
https://github.com/dart-lang/language
https://github.com/orgs/dart-lang/projects/90/views/1
C# is a fantastic language, and with NativeAOT it can become a real alterntive to Go. It "can"; but most likely it won't.
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.
>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-...
I never understood people who advocate radical succinctness so typing a program is optimal when most programming time is spent in reading documentation and debugging.
It's not radical succintness. I just like to write pure functions. C# embraces many fp idioms, but in the end makes it hard to use them without a lot of ceremony.
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.
> I just like to write pure functions. C# embraces many fp idioms, but in the end makes it hard to use them without a lot of ceremony.
Then... maybe F# would be more your bag?
Agreed with this. I happen to work on some Unity projects that do not have namespace and file structure in sync. Unity makes this more likely to some extent.
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.
I like your phrase. I’ll be borrowing it.
Like all seasoned ICs I say the same thing, but yours is more succinct.
> ridiculous breaking change
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:
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.
> Allows me to move directories around, without having to depend on an IDE to keep namespaces in sync.
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_
How would the caller reference that auto-namespaced class?
> To win in Unix land, C# needs to be editable in a plain text editor.
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
> 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 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.
Hard disagree on path based namespace inference.
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.
> When you reorganize files, now references need to be updated in many places.
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.
> 2. You don't refactor because it's a lot of work.
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.
Or be like me and not care about the Duke structure at all.
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.
> It's not only JS/TS. Python, Go, Rust
Rust allows you to move modules around without you changing using.
When you write 'mod foo;' in a Rust file (say, main.rs), Rust will look for the source code for the module named foo in one of two places: a file named foo.rs in the same directory as the file declaring the module, or a folder named foo/ with a file named mod.rs inside it.
That's great. Something like this is what C# can also aim for, while retaining full backward compatibility.
This would break every codebase in C# where a file lives in a folder where it is NOT in sync with the file system.
This can be opt in, and not break any existing code.
There has been a lot of people in the C# community that think like you - that want to make the C# syntax more minimalist, the code shorter, so that they their microservice code is as terse as they'd write in node or Go.
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.
Java comes from UNIX vendor, and C# only exists because Microsoft lost against that UNIX vendor.
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.
> Pushing these into an IDE is the Windows way of doing things.
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 just want to focus on writing functions. Here's a trivial example.
I would like:
Instead of: Both are callable as:C# allows file-level namespaces so you can write
(one nesting level less). Next, elsewhere you can write Java enforces directory structure to reflect package names, and this feature is not universally popular.I agree with the first example. I wish C# could do “free” floating functions which just lives in the namespace itself. Your second example could do with the extra namespace indentation by doing
namespace math;
But why?
Having to use class/struct instead of free floating funcs tries to force some hierarchy, architecture, etc
Which eventually makes the code better *globally*
I was arguing that the hierarchy is already in your path. The explicit namespace (and even the class name) is redundant if what you want are mostly functions.
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.
Ok, I see
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.
Consider:
Just Linux (not counting other *nix) has a ~63% server market share. [1]
That's a lot of sticks and stones.
[1] https://en.m.wikipedia.org/wiki/Usage_share_of_operating_sys...
Plenty of those servers run Java, which is where C# kind of comes from due to J++ lawsuit.
Server != Dev Workstation
It will never be an alternative to Go because the language itself is already 10x more complicated with tons of changes / feature each releases.
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.
> the code from back then does not compile
Are you to share the code? C# 1 code still compiles today, so I don’t understand this statement at all.
not the author but perhaps because of the .net core transition? all code will obviously compile with the framework they are coded for but a significant migration was necessary to switch to core.
OP specifically said .net 6.
I'm mostly doing Go for work these days, but have been curious about C#.
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?
> One problem with Go is the lack of fine-grained control over allocation. In particular, no arena allocation support. How does C# compare?
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"?
> 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.
[0] https://github.com/golang/go/issues/51317
[1] https://www.nuget.org/
>> 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.
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).
[0] https://www.npgsql.org/doc/index.html
> Pushing these into an IDE is the Windows way of doing things.
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.
Great tooling is 50% of what makes C# and F# so damn good. For the love of god don’t write C# in a text-editor. The live debugger gives you over 80% of what people gush about in lisp-interactivity - a live program environment you can poke and introspect.
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.
> To win in Unix land, C# needs to be editable in a plain text editor.
What do you mean? It's editable in plaintext already. See what "dotnet new" generates.
> given that most projects already have them in sync
What makes you think this? I’d wager that most C# code is not open source.
C# will never attract Go users because async is much less pleasant to use than goroutines. I've never met anyone who'd used both extensively and preferred async. CSP is a theoretically cleaner and easier to reason about approach to concurrency.
This is just a preference. CSP in Go has its warts too, such as idiosyncrasies with channels.
I like the type parameter inference from constraints proposal.
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.
[0] https://github.com/dotnet/csharplang/discussions/198