C# design team is/was unparalleled
C# design team is/was unparalleled
https://devblogs.microsoft.com/dotnet/performance-improvemen...
(for some reason HN would not allow to resubmit it, and the post was left by wayside not reaching frontpage)
It's pretty well put together but it was very hard to work out the patterns of what it was doing underneath e.g. I could not tell you now how to implement a custom IQueryable (I know where to look but couldn't tell you the rhythms of it) for some database and I am the type of person who usually does go and find that kind of thing out before using something for a "serious" project.
Maybe it's just a microcosm for C# as a whole - very productive language, good design team, quite hobbled by it's weird/philistine upbringings: Bjarne said within C++ there is a simple language trying to escape, in C# you basically have a simple language buried in nouns.
Basically allowing for a uniform way to query data which is reminiscent of a more modern version of SQL (in my optics anyway). Does anything library wise come close to this within the Golang ecosystem?
There is also relinq library which transforms linq expressions into expressions which are easier to understand/use.
There's a lot hidden in there, but basically they expect you to use EF. Writing an IQueryable is a similar amount of work to writing a SQL query planner. You get passed a tree of Expression objects.
https://learn.microsoft.com/en-us/archive/blogs/mattwar/linq...
* Not understanding when something is evaluated.
* Not understanding the computational complexity of multiple chained operations/aggregates.
* Not understanding the expectation that Single() requires exactly one of something.
* Not understanding how damn hard it is to test LINQ stuff.
Java: https://www.jooq.org/
Kotlin: https://www.ktorm.org
Pretty much. There's the "language integrated" version which looks a lot like SQL:
var foo = new List<int> { 1, 2, 3, };
var response = from x in foo where x > 1 select x.ToString();
But that just translates to the method-orientated one which many people prefer response = foo.Where(x => x > 1).Select(x => x.ToString());
If instead of querying a List or Dictionary you query a database, using an ORM (usually Entity Framework), that will actually get converted to SQL and run on the DB.Sorry, but idk how it is footgun of LINQ. It is like complaining about 0 or 1 based indexing
>Not understanding how damn hard it is to test LINQ stuff.
Any examples? Because I struggle to see such
The F# compiler is slower than the C# compiler, but it's still more than fast enough for building large applications.
Rust has combinators, which is the same thing.
Most new languages are recognizing that functional support (even if they don't consider themselves FP languages) is necessary.
> Not understanding how damn hard it is to test LINQ stuff.
I disagree with this. Just run the LINQ query on a compatible iterable.
yes thats what linq is?
https://learn.microsoft.com/en-us/dotnet/csharp/linq/
"Language-Integrated Query (LINQ) is the name for a set of technologies based on the integration of query capabilities directly into the C# language." With LINQ, a query is a first-class language construct, just like classes, methods, and events.
doing this in java is not LINQ imo
List<Integer> lowNums = filter(toList(numbers), new
Predicate<Integer>() {
@Override
public boolean apply(Integer n) {
return n < 5;
}
});
It's more general and reusable than SQL, so you can map a subset of it to SQL, which is what some object-relational mappers do.
Books: C# 12 and .NET 8 - Modern Cross-Platform Development Fundamentals - Eighth Edition: Start building websites and services with ASP.NET Core 8, Blazor, and EF Core 8 by Mark J Price
Web API Development with ASP.NET Core 8: Learn techniques, patterns, and tools for building high-performance, robust, and scalable web APIs by Xiaodi Yan
Turorials: series of tutorials on YouTube by IAmTimCorey and Shawn Wildermuth.
Doing web dev in .NET nowadays for me is mostly creating HTTP/JSON/REST APIs and using whatever FE framework you like to interface it (for me that is React or NextJS). The keyword you want to search for is "ASP.NET WebApi" or - more modern - "ASP.NET minimal API".
You could still do .NET MVC server-side rendering using "Razor" (the markup language in ASP.NET MVC - search for "ASP.NET MVC Razor".
This Expression AST is constructed by the compiler, not something that can be tacked on by a library later.
Anyway, I came across a podcast featuring the author of "ASP.NET Core in Action", Andrew Lock, and he seems to know his stuff. I haven't read the book yet, but maybe this is the book you are looking for.
--
1: https://dotnetcore.show/season-6/navigating-the-aspnet-core-...
2: https://www.manning.com/books/asp-net-core-in-action-third-e...
IEnumerable<> is regular in-memory lambdas/streams, same what you find in many places.
IQueryable<> relies on the LINQ expressions, those CAN be JIT compiled for direct execution, but the fact that they are data-objects is what allows the translation to SQL and execution on the server rather than locally and can give massive gains since processing can be done where the data lives.
The post I submitted refers mostly to optimizations to those extension methods.
This clicked for me after having learned Haskell. It also shares some of Haskell's features/pitfalls, such as laziness.
There are pitfalls, sure, and honestly I wouldn't advise a team having no one somewhat experienced with basic functional idioms (including laziness) to use it. It can lead to obtuse and slow code if used indiscriminately. I try to lead by example myself.
This is really the thing with the entire .NET stack that’s very hard to communicate. The standard library and framework design are so well thought out relative to anything else out there. More than that, the support within VS is beyond any other dev tool that exists for any other language - it’s not even particularly close. Edit-and-continue comes to mind, which despite how many times people confuse the two is not hot reload, and is wildly more productive and useful.
I remember back close to 20 years ago DHH was espousing Ruby/Rails and that the concept of types at all were a code smell, and thinking “you’re just very wrong, and clearly aren’t familiar with what else is out there”. Eventually a lot of that crowd moved to Node, then to typescript, and came around.
VS Enterprise (expensive as it is) had features 15 years ago that still seem magical when I show them to JS/TS folks now. IntelliTrace is one that comes to mind - there’s nothing remotely close to it’s snapshot debugging that I’ve seen anywhere else, and I’ve really looked.
The big problems with the ecosystem are that the docs are exhaustive but terribly boring, and not well explained from a learning-something-for-the-first-time perspective. They also really expect that everything you do is the Microsoft way, so if you’re trying to interface your code with something like an Avalonia UI, you’re on your own.
The language is absolutely wonderful though, even when used with Rider. The productivity relative to node/typescript is better enough that it crushes my soul having to go back to wrestling tsconfig and imports after working with .NET references for even small changes. So many of the little things I used to take for granted really just work, and work well. It’s just a wonderful piece of work executed over decades, held back by poor community outreach and badly written documentation.
With scripting languages, it's all JIT :)
The C# teams progress on this has been slow. Keep in mind the CIL bytecode has had such capabilities for at least 20 years now and only in the past like decade are we seeing more features and optimizations around LINQ and System.Reflection.Emit.
Dynamics were extremely slow in C# and if you look at the CIL generated you see why. It's possible for example to use something like a Haxe anonymous types[1] to optimize Dynamics so that CallSite caching is way more performant.
I am pretty sure in C# the only way to accept an anonymous type is as a dynamic value, so even though the type of the structure is well-defined at compile-time, it will still rely heavily on runtime reflection/DLR with no additional caching beyond what DLR does for any other dynamic type.
Anyways, this leads to niche libraries being built for handling dynamic data like JSON performantly.
Which leads to annoying things like .NET libraries/apps being incompatible (without some adapter) if they use for example, different JSON libraries under the hood. (See [2]).
Problems like these (the lack of actually good JIT/dynamic code support) in my opinion significantly slow down the .NET ecosystems development, that's why it always feels like .NET is just catching up with features other popular languages have.
To be fair though, much of C#'s lag is owed to Microsoft's contribution to .NET being mostly technical debt. Almost everything good that came out of .NET came from open source/non MS teams (like Mono).
[1] - https://haxe.org/manual/types-anonymous-structure.html
[2] - https://learn.microsoft.com/en-us/dotnet/standard/serializat...
Regular transform code in JS (Like IEnumerable)
const ids = users.filter(user => user.age<18).map(user => user.id);
IQueryable like to be transformed to the server:
const ids = users.filter(user => user.age.lt(18)).map(user => user.id);
In C# it'd look identical, but in JS or Java this would be achieved via proxy-object hacks (the .lt() function in the filter instead of the < operator and the .id property getter for the user map to send a flag under the hood for the mapping function).
var lowNums = Arrays.stream(numbers).filter(n -> n < 5).toList();
2024's Java is also quite a bit better than 2013's Java.Which still isn't as nice as LINQ, but this way we've painted the alternative in its best light, not in the light that makes C# look the best.
Developer experience is far ahead any other technology out there.
Std lib and its API design is world class, I wish cpp had as good stdlib. Tooling is strong, especially debugger
A practical example of using this: https://chrlschn.dev/blog/2024/07/csharp-discriminated-union...
So what? I see LINQ used all the time, and it is almost entirely (extension) methods IEnumerable<T>
Could I implement IEnumerable<T>? I think I did once, as an exercise. It's not that complex. Not that interesting to be able to do it either.
LINQ is useful without EF. LINQ is not EF and EF is not LINQ.
I don't agree. I don't feel any expectation to use EF. It would not be relevant anyway to our code.
LINQ is not EF and EF is not LINQ. EF uses LINQ but not vice versa. LINQ is useful without EF.
The LINQ extension methods that we use constantly are on IEnumerable<T> so EF and IQueryable is of no importance to us, but LINQ is used everywhere.
Is it the SQL-like query syntax? LINQ to objects? LINQ to SQL? Expression trees in general?
Expression trees and LINQ to SQL/EF/etc. are hard to find elsewhere. The query syntax often doesn't seem to be that big of a deal, especially since not all methods are available there, so pure query syntax often doesn't work anyway.
There isn't a seamless way to do what LINQ does in any of those languages. But if the runtime supports a LISP then you can do more than what LINQ does (Clojure for the JVM, something like zygomys for Go, Hy for Python, and ... well, Ruby for Ruby).
As useful as that might be, we should really be writing better code. This is interesting for dynamically generated chains, I suppose. But if these operations are done on bespoke code, this is kind of perverse positive reinforcement. The library itself is recognizing a sub-optimal pattern and correcting for it. I hope there's feedback, at least, that suggests improvements to the underlying code.
If it's scripted you can typically just get a string representation of the function.
If it's Java, JAR inspection/dynamics have been a thing for a long time. And in other languages, they usually directly support metaprogramming (like Rust) and plugging code into the compilation logic.
Linq is lazy. .ToList() reifies. there, that's the gist of what you need to know. Not hard.
> Not understanding the expectation that Single() requires exactly one of something.
eh? There are a bunch of these methods, Single, SingleOrDefault, First, FirstOrDefault, Last, LastOrDefault and you can look up and grasp how they differ. It's fairly simple. I don't know what the problem is, outside of learning it.
> Not understanding how damn hard it is to test LINQ stuff.
Hard disagree. LInq chains can be unit tested, unless your Db access is mixed in, which is not a LINQ issue at all, it is a database query testing issue. LINQ code, in itself, is easily unit testable.
Giant majority of ppl refers to this when talking about LINQ.
But yea, it is LINQ method chaining.
SQL like syntax is LINQ query syntax
> Enumerable.Single Method - Returns a single, specific element of a sequence.
Some overload descriptions:
- Returns the only element of a sequence that satisfies a specified condition, and throws an exception if more than one such element exists.
- Returns the only element of a sequence, and throws an exception if there is not exactly one element in the sequence.
https://learn.microsoft.com/en-us/dotnet/api/system.linq.enu...
> Enumerable.FirstOrDefault Method - Returns the first element of a sequence, or a default value if no element is found.
https://learn.microsoft.com/en-us/dotnet/api/system.linq.enu...
When everything just works, you have a lot more time to focus on your problem. Once you can focus on your problem, you may quickly find out you don't actually care about it. Focusing on tools is a great way to hide from this reality.
The link that you gave says "LINQ is the name for a set of technologies" which includes the "SQL like syntax".
Includes is not the same as "is".
It isn't the most often used part of LINQ.
You can write hard to read code with any framework. Yes it takes effort sometimes to make linq code clear, but you should not give up on it.
You mean like fluent interface? https://en.wikipedia.org/wiki/Fluent_interface
What does this have to do with LINQ or C#. I remember doing 'method chaining' in 1990s .
I love LINQ, I love having a typesafe ORM as a standard feature of C#, but the convenience of being able to reuse my Pocos and some expressions for both in-memory and in-SQL don't outweigh the downsides.
If I were designing SQL/LINQ today, I'd keep the in-memory record classes and in-database record classes distinct and use some kind of codegen/automapping framework for keeping them synched up. Maybe allow predicate operators to return things other than booleans so we could make `a == b` return some kind of expression tree node.
For ad-hoc queries using anonymous classes? Support defining an interface inline in a generic so you can say
public T MyQuery<interface {string Firstname{get;set;}; string Lastname{get;set:}} T>();
Like, to elaborate, if you were doing some kind of JSON-based codegen (alternately you could do something where you have a separate hand-written POCO Model assembly and use reflection against it to generate your DbModel classes so it's still Code First). Yes, I know MS tried and abandoned this approach, I used LinqToSQL and EF3.5 and whatnot and suffered all that pain.like, your master datatable file would be something like
```json
"tables" : [
"persons" : {
"dataRecordClass" : "DataRecordsNamespace.DbPerson",
"objectClass" : "PocosNamespace.Person"
},
"columns : {
"PKID" : {
"type" = "integer",
"isPrimaryKey" = true,
"isAutoGenerated" = true,
}
"firstName" : {
"type" : "nvarchar(255)",
"allowNull" : true,
}
"lastName" : {
"type" : "nvarchar(255)"
"allowNull" : false
}
}
]
```
which would generates something like ```cs
public class DataRecordsNamespace.DbPerson : DbRecord {
public DbPerson() { throw ThisIsAFakeClassException(); }
public DbInt PKID{
get => throw ThisIsAFakeClassException();
set => throw ThisIsAFakeClassException();
}
public DbNVarChar {
get => throw ThisIsAFakeClassException();
set => throw ThisIsAFakeClassException();
}
}
public partial class PocosNamespace.Person {
public AutoGenerated<int> PKID{ get; init; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class MyDbModel : DbModel {
public DbTable<DbPerson> Persons => DoSomeLazyStuff();
}
public static class MyDbContextExtensions {
public static List<Person> Resolve(this DbQuery<DbPerson> dbPersons)
{
//call code to execute the actual query.
}
}
```
Am I making sense? Then you wouldn't have the problem of "oops I used an untranslateable method or member of Person", because MyDbModel can't have any of those. You'd lose the ability to to switch from whether a query is in-memory or in-database just by removing the ToList(), but I'd argue that's a misfeature, and better-handled by having some kind of InMemory implementation. Like, having DbQuery have a simple `.ToLocalMemory()` function that is a hint that the next part should be done locally instead of in the database would be a better way to do that. Then you could still do ```cs
List<Person> myPersons = connection.MyDbModel
.Persons
.DoSomeInDatabaseQueryStuff()
.ToLocalMemory()
.DoSomeLocalMemoryStuffToOffloadItFromDatabase()
.Resolve()
.DoSomeDotNetStuff()
.ToList();
```
edits: fix some of the HN pseudomarkdownSource code of the function means you have to implement the parser/lexer to convert it into a usable AST which is bad for both runtime performance and library size.
Very much doubt this is available in Java, which Java ORM lets you use native Java language expression syntax to query a database?
Various names, same concept.
"fluent interface is an object-oriented API whose design relies extensively on method chaining."
>What does this have to do with LINQ or C#.
Check the name of the namespace where all those APIs like Where, GroupBy, etc. are implemented, it is "System.Linq"
So thats why majority of ppl think about them when talking about LINQ.
Query syntax has like less than 1% of the "market share" versus method chaining style
(Hybrid Blazor where you use both server and client possibly in the exact same assembly/project is where most of the worst Blazor mistakes lie, but those aren't the mistakes of Silverlight, those are the mistakes of ASP Classic before .NET where you can be easily confused by new versions of the which bit of this is `runat="server"` and which bit is `runat="client"` and easily and accidentally create wild RPC ravioli/spaghetti code.)
No. When it was release (circa 2007), very few mainstream languages embraced "Code as Data" the way C# did. In Java, there was no way to pass an expression (as an AST) to an SQL library. Which is why LINQ is so much more ergonomic than Hibernate. In C#, you could use language features you're already familiar with (such as "order.id > 100 && order.id < 200") in your queries, whereas Hibernate made you learn the framework's specific patterns (add Criteria etc etc, I don't recall now). Java just wasn't expressive enough for this.
In fact, you couldn't do this even today in a language like say Python or JS. I mean, not without running it through something like babel to get an AST, and having arbitrary rules on what's code and what's data. C# had this in the spec; based on whether it was IQueryable.
> Almost everything good that came out of .NET came from open source/non MS teams (like Mono).
My team adopted Mono very early - like in 2005. Your statement is not true at all. C# and the Framework was a very good spec irrespective of what Open Source / Mono did, and while Mono existing might have accelerated .Net's transition into Open Source, it would have happened anyway due to the definitive swing towards Open Source in the 2000s. Linq-to-SQL, Asp.Net MVC, EF etc didn't come out of Mono.
For example, the ReadOnlySpan type is a recent addition to the runtime and it will allow faster iterations when used. They simply enabled Linq to use it now.
Here's how you'd do something similar in our OrmLite ORM [1]:
public class Person
{
[AutoIncrement]
public int Id { get; set; }
public string? FirstName { get; set; }
[Required]
public string LastName { get; set; }
}
Create Table: var db = dbFactory.Open(); // Resolve ADO.NET IDbConnection
db.CreateTable<Person>(); // Create RDBMS Table from POCO definition
Execute Query: // Performs SQL Query on Server that's returned in a List<Person>
var results = db.Select<Person>(x => x.FirstName.StartsWith("A") && x.LastName == "B");
// Use LINQ to further transform an In Memory collection
var to = results.Where(MemoryFilter).OrderBy(MemorySort).ToList();
Everything works off the POCO, no other external tools, manual configuration mapping, or code gen needed.For .NET Backend/JS Frontend, look for resources that uses minimal APIs. MVC is also good but has a lot of backwards compatibility baggage that led to the creation of minimal APIs.
On the server you can run ASP.Net using Giraffe, which is a Functional Programming layer with comparable performance to C#.
On the front-end, you can write React in an true Functional Programming language.
And of course you can share F# code between frontend and backend.
db.Select<Person>(x => Regex.IsMatch(x.FirstName, "^A.*"));
This would fail at run-time instead of compile-time.That's why I'd rather see the DB classes auto-generated with a mapper to convert them. Having the "master" be POCOs instead of JSON/XML/YAML/whatever isn't something I'm convinced on in either direction, but imho the in-database classes being not real POCOs is the important part because it reduces the the problem of somebody writing Person.MyMethod() and then blowing up because it's not a SQL function.
Not that I use this, I am a myBatis person in what concerns database access in Java, and Dapper in .NET for that matter, not a big ORM fan.
And case in point most people use LINQ for in-memory datastructures, not the database part.
How would you perform this regex query with your code generated solution? What would have to be code generated and what would the developer have to write?
As there's a lot more features available in different RDBMS's than what's available in C# expression syntax, you can use SQL Fragments whenever you need to:
var results = db.Select(db.From<Person>()
.Where(x => x.LastName == "B")
.And("FirstName ~ '^A.*'"));
create.select(BOOK.TITLE)
.from(BOOK)
.where(BOOK.PUBLISHED_IN.eq(2011))
.orderBy(BOOK.TITLE)
If Java supported LINQ you'd be able to use a more intuitive and natural Java expression syntax instead: create.from<Book>()
.where(x -> x.publishedIn == 2011)
.orderBy(x -> x.title)
.select(x -> x.title);
If you insist in telling LINQ === EF, well that isn't what most folks in .NET use System.Linq for.
And back to the ORM thing, jOOQ is one way, there are others, and even if it isn't 1:1 to "from x select whatever" the approach exists.
I don't use EF, nor have I ever mentioned it.
You're replying to a thread about what it takes to implement a LINQ provider, which was dismissed as every high level language implements it with iterables, then proceed to give non-equivalent examples.
That's why I guess today I work in Clojure :)
It’s part of the design philosophy of Go though. They don’t want any magic. It’s similar to why they enforce explicit error handling instead of allowing you to chose between explicit and implicit. They want you to write everything near where it happens and not rely on things you can’t see.
It’s probably the primary reason that Go is either hated or loved. I think it’s philosophy is great, a lot of people don’t. I have written a lot of C# over the years, so I’m a little atypical in that regard, I think most C# developers think Go is fairly inferior and in many regards they are correct. Just not in the ones that matter (come at me!). To elaborate a little on that, Go protects developers from themselves. C# is awesome when it’s written by people who know how it works, when it’s not you’ll get LINQ that runs in memory when it really shouldn’t and so on.
It's time to have value-type local lambdas, or a strategy that doesn't make lambda allocation the overhead that it is. And also there really should be wildcard support (`_`) for LINQ variables by now. Which was been completely ignored when they were brought in for lambdas. It should also be possible to use a lifted-type (like IEnumerable<T>, Option<T>, etc.) as the final item in a LINQ expression, rather than `select ...`. The select adds overhead that isn't needed for certain use-cases and limits things like tail-recursive LINQ expressions.
Libraries like mine that go all-in on LINQ [1], but aren't using `IEnumerable` or `IQueryable`, or any of the LINQ extensions, continually get ignored because MS are focusing purely on improving the performance of their own projects.
A good example is the improved lambda inference. It was only brought forward because ASP.NET Core needed it for its minimal API. It seems like many of the features of the language/framework are driven by their own needs rather than those of the community. The absolute worst thing is the ever expanding set of 'magic methods' (like the LINQ extensions Select, SelectMany, and Where, but also GetAwaiter, and the rest). MS are adding capabilities for themselves (the compiler mostly) rather than do what is really needed and add proper higher-kinded traits to resolve the magic. So everything is weakly typed and only vaguely discoverable by the compiler :/
LINQ is one of those key differentiators between languages, yet it's been wallowing, pretty much untouched since C# 3. I think it's a crying shame that it has basically been ignored since then and, even now, they think LINQ is only useful for iterating lists. And primarily only their own list implementations.
/rant
Don't get me wrong, I appreciate all performance improvements, I'm sure it will help plenty of users. But the focus always seems to be narrowly targeted, which limits the potential.
Well, better late than never.
my point was that laguange support for sql like sytax is part of what makes LINQ linq. Java niceties is not relevant.
I was discussing IQueryable with someone else to whom it was important. In reply to
> I could not tell you now how to implement a custom IQueryable (I know where to look but couldn't tell you the rhythms of it) for some database
And "for some database" the default answer is "use EF" as the intermediary between LINQ queries and the database itself, rather than delving into IQueryable.
LINQ-to-objects is very important and useful but I was talking about something else.
This means that you can have a team of C# developers writing in a language they are familiar with, a team of node/TS developers writing React and a team of F# developers working on a pure functional core with all of the business logic. Write your validators in F# can you can share the same logic for a form in the UI and an API endpoint on the backend.
In my opinion having type inference, discriminated unions, computation expressions, et al., makes for a very concise and expressive way to model the core logic of an application.
We're quite accustomed to writing our own SQL select statements and would like to continue doing that to have known performance, but the update, insert and delete statements are a chore to do manually, especially for once you're 4-5 parent child levels deep.
I'm certainly guilty of this! What's the difference?
(I don't mind outdated for .NET stuff, nearly everything from enterprise vendors looks like it just jumped out of WinXP anyway.)
That said, you would never get a PR through me that does this in the actual business logic. You can use things like AspNetCore without touching a single attribute if you really don't want to.
I think the main reason why C# didn't have this (and other low-level features like plain function pointers) for so long is because the original vision for .NET was that you'd mix and match different languages in your project as needed. So if you needed that kind of stuff, you'd reach out for managed C++ (and later, C++/CLI), while C# was kept deliberately more high-level.
And so once that approach was abandoned, C# needed to catch up to be able to play the "one language that can do it all" role.
That said, C# / .NET shops did have a tendency to mindlessly buy into all sorts of terrible Microsoft enterprisey stuff. That drove me crazy and ultimately is what made me head out for greener pastures.
On the other hand, Client Blazor has huge initial overhead (it compiles a form of the entire .NET platform in WASM; you can golf it down a bit, but it's still an entire runtime and GC and most of a standard lib depending on what your app does, and its dependencies), but once it is loaded it can be as performant as just about any other Virtual DOM-like (modulo the overhead between DOM/JS and WASM, but that overhead is surprisingly small in current browsers and seems to only get smaller as browsers continue to optimize WASM scenarios).
I don't think I'd recommend it for most consumer-facing websites any time soon, but in my experience Client Blazor is still much better than Angular for performance in an Enterprise/Internal App scenario.
There were definitely some quirks and issues early on but they've done a pretty good job at smoothing that stuff out since it's gone through two LTS version of .NET.
The pipeline for something like that is click->js/wasm websocket->server code->websocket->ui updates. If you're doing something absurd on the back end when a checkbox is clicked, sure 1-2 seconds but that's a developer problem, not a Blazor problem. If you put me in front of a React app, I'd probably do something stupid like that too because I don't have much experience with it.
I suspect your complaint is more related to .NET/Blazor making it easier for less experienced developers to develop a working site/page with a lot of spaghetti where that same developer would struggle to create the same page in another ecosystem. If you compare to equally senior/experienced developers in different frameworks, I suspect you'd see the same basic performance from the two platforms up until a scale that very few of us are actually working in. Blazor can be quite fast if you don't write bad code.
I find a lot of the complaints about .NET to be that it enables developers who write bad code to get things done inefficiently instead of not being productive at all. IMO, having senior developers doing code reviews is pretty essential if you have junior developers on a team but the ability to build something, even if poor, can really accelerate the learning process when a senior person can look at a complete project, point out the issues and show the difference that the corrections make.
Sorry for the rant and sorry if this doesn't really apply to you specifically.
I'm looking for something that will make me "wow, Blazor can be used to build great apps!" or "ok has advantages over the React/Vue etc. equivalent".
Because if there aren't any, in similar thinking with parent, I'm afraid that it won't catch up and it'll go the way of silverlight, so I refuse to invest any time.
Also, I too, use Clojure today - it is very nice.
There is a difference: Silverlight was not open-source, whereas Blazor is open-source on both server-side and WebAssembly (WASM).
ASP.net MVC has reached maturity and is notably used in project like NopCommerce.
Of course, C# projects tend to have a level of abstractions that are simply absurd to work with. "Enterprise" development makes my cringe more often than not.
I also think wasm Blazor is a non-starter as well until WASM GC integration in the browsers gets fully integrated for C# targets.
if "Person.FirstName" is a string, then that encourages users to use string-operations against it, which will fail if this expression is being translated to SQL for executing in the DB.
if "Person.FirstName" is some other type with no meaningful operations supported on it (which will get converted into a string when the query is executed) then it prevents many many classes of logic errors.
C# has nothing like that, xml comments and raw documentation that has no value
I’ll look for an opportunity to give client Blazor a try.
Modern C# is probably the best general purpose language out there with the best tooling along with the dotnet framework. Too bad the guides and public information all align with the latest trends Microsoft are pushing to appear relevant. Blazor, MAUI, Aspire e.t.c. are all distractions to maintain the appearance of being modern. None of which are production ready or actually good for that matter.
Back to my original point. If you want to create a new web app then you're REALLY pushed to use Blazor, which is confusing, has many flaws, is basically alpha and is just a bad idea in general. For some reason you're shown a laughably simple guide spread over eight pages which could be a single page. You finish the "guide" and so you go to the "documentation". That documentation page is full of buzzwords that confuses new developers and belittles old developers. The end of this page links back to the pathetic guide. It's seriously like this for everything they do. There's tiny little nuggets of information scattered over thousands of useless pages.
I may sound blunt but it's a fantastic technology ruined by terrible management, poor communication and clearly the worst developer relations team any tech company has ever assembled. How can any company with this much money, this much recognition and this great of a technology fumble it so badly. Well... I actually do know why and it's obvious to anyone capable of critical thinking.
// Method syntax
var evenNumbers = numbers.Where(num => num % 2 == 0).OrderBy(n => n);
// Query syntax
var evenNumbers = from num in numbers
where num % 2 == 0
orderby num
select num;
Method syntax and query syntax are both part of LINQ (query syntax is syntactic sugar). .Net developers tend to overwhelmingly prefer method syntax.[1]: https://github.com/acple/ParsecSharp/blob/da8d0cb9ec39e28dd9...
If you look at how a LINQ query gets translated to a method chain (e.g. via SharpLab or let Rider/ReSharper rewrite them) you'll notice that multiple `from`s or `let`s can become quite ugly.
For more junior devs using LINQ, setting them up with a profiler and the debugger I believe helps makes more sense about what is going on behind the scenes. Sometimes it's helpful to have them code using for-loops and standard C# logic, and then compare to how you'd implement in LINQ, to see the positive and negative of both approaches.
3 years ago: https://github.com/dotnet/csharplang/blob/main/meetings/2021...
I've given up submitting to csharplang now. It seemed like a positive when it was first open-sourced, but the proposals/issues are often just circular discussions that go nowhere. It doesn't feel like (at least from the outside) any proposal by a non-MS employee would make it thru the process unless MS needed it themselves. Which is what I was alluding to in my original post.
I may well be wrong and maybe some proposals have made it through, but it feels like an illusion of community collaboration rather than actual community collaboration imho. I don't expect preferential treatment or anything like that, but it would be good if one of the most standout features of C# got some proper attention after a decade of neglect.
There has been a lot of effort on performance in many areas of the framework and the language. Leveraging that work for LINQ (the language feature) would be very welcome.
.Select(x => new Employee { Name = x.Name, DepartmentName = x.Department.Name }).ToList();
Some of these features are provided by tools like Resharper, and I wonder if there isn't some kind of agreement (whether written or unspoken) where they don't step on each other's toes. To be honest, most documentation I have seen written in C# projects still makes me reach for the source code due to poor quality. Having lots of autocompleted tooling doesn't help when it comes to reading, only writing, in my experience.
In dotnet, it seems everyone uses the Microsoft "blessed" framework, until Microsoft does a full rewrite or loses interest - then everyone has to rewrite their stuff too.
There's no way Microsoft are the only ones capable of producing good library/framework ideas - so what gives?
ReadOnlySpan is so powerful because it can be used generically and has implicit conversions that allow you to improve the speed of existing methods without breaking backwards compatibility.
It's well designed and that takes thought and time.
(Whether I recommend it, not sure! I did it and then undid it, with suspicion that tests were taking longer due to, perhaps, worse caching of build artifacts.)
We were planning on sticking with this, it has worked well so far, but good to know to avoid getting tempted by the alternative.
Edit-and-continue allows for changing the code and then updating the output directly in memory without re-compilation or restarting the execution. It sounds similar but in practice it allows for much more rapid iteration and is profoundly more useful. If you’re pretty deep into an application or web app for example (e.g. added to basket -> checkout -> process payment) and are 30 or 40 calls deep in a stack and realise you’ve a simple bug or change to make, you can edit the code in memory, drag the debugger back to the line, re-execute it and move to the next statement. The benefits of this compound really quickly for anything more than trivial scenarios, so much so that I’ll often code directly in a debugging session as it’s just handier to have a full rewindable call stack right there for simple cases where I’ve forgotten a property name or need to correct and XPath or something.
The surprising thing is that this isn’t even new, VS has had this for at least 20 years (and I think 25 or more as i know VB6 had it. Yes I’m old.)
Edit: 27 years ago in VC++5 (1997).
The docs are clearly not written by engineers and it really shows.
It’s a shame too - MAUI should be excellent. Best-in-class even. They’ve had the most resources and best tech to throw at the problem and are a distant second at best to React Native. (It might see less use than Flutter these days I’ve no idea).
Also having the C# dev kit for VS Code be non-free is just insane. They’re actively giving the market over to node.
From what I've heard - there is an awareness that the current cost of delegates, while not that problematic anymore, can be improved. Whether this happens via explicit syntax to enable (ref) struct closures and value delegate pattern implementations or via object escape analysis and better devirtualization remains to be seen.
p.s.: I really wish that instead of LanguageExt, companies would have adopted F# instead.
You'd be right to point out that confusing README of these two does not do .NET any justice however.
Ah the standard "why don't you just use F#" line. I have a standard response to that now ;)
https://github.com/louthy/language-ext/wiki/%22Why-don't-you...
The Nx elements figure is a speedup you would expect if you introduce a shortcut to any algorithm that can bypass doing full iteration, and >100x speed-up is what you would expect from going from interface dispatch per element (even if devirtualized behind a guard) to a bespoke vectorized implementation.
Even if you happen to have irrational dislike of .NET, this is still useful learning material and perfectly applies to other languages that expose similar functionality (provided they have sufficiently good type system and generics).
But it is slightly more expressively powerful than SQL and way easier to follow, if you need it, than the method syntax.
They are compile-time type information with no runtime overhead. So if you're using a lot of interrelated arrays, you can make a unit of measure for indices into just a specific type of array. This allows type-level enforcement of never using the wrong index for the wrong array.
Anywhere you might want to keep categories (not category theory) of numeric values distinct from one another without intermixing, units of measure in F# can cover you.
If project goes belly up no one can pin it on you choosing something non standard.
So it is a feature of dotnet ecosystem not a bug “doing stuff the MSFT way”
ASP.NET Core is strong and overall better option when compared to FastAPI, RoR, Spring or Node.js with Express/Nest.js. EF Core with LINQ and safe SQL interpolation is one of if not the best ORMs that exist on the market across all programming languages.
This results in much weaker demand for alternatives, and combined with community that historically erred on the side of "out of box" choices, it's no surprise that there aren't really big viable alternatives to ASP.NET Core. There are for EF Core though - Dapper/DapperAOT and Linq2Db. Aside from that, most community libraries, both C# and F#, instead usually opt to build on top of them, like Fast-Endpoints or Giraffe/Oxpecker.
.NET could use a framework that is what Vert.X is to Spring, but even existing landscape is so much better than almost every other alternative, that it's difficult to complain, except, I suppose, when it comes to Identity and Authn/Authz in general that are more complex than ideal.
p.s.: I'm not saying that all "first-party" libraries are good. ASP.NET Core and EF Core, especially their "core" functionality are great. The surrounding selection of packages however can be hit or miss, and it's where a productive choice is to look for community libraries instead. It's an area that is slowly getting better.
You do mention these things in your README, and I appreciate it, as most are set on "selling" their library instead of actually listing what it exceeds at and the purpose. Your comment on being non-idiomatic is another issue that I see (again, talking about people learning and getting used to C#/.NET). Only in my opinion, I feel like Microsoft want to keep their tools and languages following certain practices, and I get that your naming follows more functional programming practices to make them natural to FP. I feel like often, little issues like this are very large to Microsoft when it comes to looking into improvements.
I starred your repo, and am very interested in what you've put together here. On the last few major applications I've built (I normally build content management systems that are highly customized, that I tend to not call apps), I've used a Result<T> type that seems to be roughly the same as Option<T>. I wrote that sentence, and then went back to look at your library, and as much as I thought I knew about FP, I really don't. I think I'm really decent at C# and doing some complex things with it (I mainly use Umbraco CMS, and I've gotten my code to run websites under the minimal recommended requirements of the base Umbraco software). With that said, I read a lot about FP, but still have tons of issues picking it up. F# For Fun And Profit is the closest it's made sense to me. In the end, all this is to say that it's nothing that you're doing wrong. Microsoft is going to target the average or beginner developer, because that is the vast majority of developers that they have in their environment.
I hope that you library can gain some internal improvements, because it looks like you've spent an enormous amount of time on this, and you have enough stars on GitHub to at least indicate that people are actively using your library and getting benefit from it. I apologize if any of this came off as dismissive, I think what you've done here is exciting, and feel like you've set up enough documentation where I can slowly pick up concepts that I'm unfamiliar with.
.Select(x => new { Name = x.Name, DepartmentName = x.Department.Name }).ToList();
Same code as I wrote, except capture in an anonymous type. The documentation practically encourages this.As for source for nuget packages, it's easy to enable source link to make that happen too, it's just that this is all pretty new so not every package is doing it.
(I first learned FP with Scala, so the names from there feel the most natural to me, tbh)
Edit: it just occurred to me it has to be SQL inspired or something like that.
If it is F# that is pushing a lot of innovation in the .NET ecosystem and many years in features ahead (at least it was a few years back) why not reward that effort through its use? We should encourage the behavior we want out of these language development teams after all by voting with our feet. Worked with the Java ecosystem for example - even Java now is improving. It would create a positive feedback loop (like most other innovative tech) where more market would create more engineering effort on it as well.
Reading these forum's over the years it feels like many C# people really want to stick in their camp and wait "just because" - it almost feels "tribal" and their team is "C#". I just don't see this culture in some other language ecosystems - makes me think if F# was in any other ecosystem than .NET it would of thrived a long time ago. That's just my impression though.
Because we don't really make choices and the C-level executives think that only C# or Java are worth using since they are the behemoths of the industry.
And I am quite content we don't have to use Java with all that object everything, factory factory factory and plainly insane "design patterns".
And when languages imitate features of a different language, they tend to go for the features that people like and use. No-one is going to add "similar capabilities" to the feature that no-one wants in the first place. People who say "C#'s LINQ is awesome!" just aren't talking about "sql like syntax", and people who say "without sql like syntax it's just not on the same level as LINQ" are misguided.
Yes, I understand that implementing IQueryable is a beast, but let's not pretend that writing a database connectivity layer was a trivial, everyday activity before IQueryable. It's a specialised, tricky task. IQueryable may not make it easier, but it never was "easy" per se. Nor common, or usually necessary. Or something to do as an exercise "before using something for a serious project" as the grandparent post suggests.
YMMV as to how important IQueryable is to your code.
On the other hand, if you can write extension methods over "this IEnumerable<T> source" you can extend LINQ. IQueryable being complex is no barrier to that, in any way.
Anyway, EF is cool, but probably every .NET dev has an EF/LINQ performance related horror story (the generated queries are ridiculous).
A self compiling language is more impressive to me than ASP.NET MVC.
And C# is just lacking for what is actually capable in CIL bytecode. Or _was_ when I last used.
There have definitely been improvements, but in my opinion, they have just been kind of slow.
When I think of Microsoft's impact on .NET and it's culture, I think of stuff like SOAP, the SmtpClient, breaking changes in APIs every year and the technical debt left by it, the dogmatic fanboys, etc...
Quoting from the docs (emphasis mine): > .NET Hot Reload applies code changes, including changes to stylesheets, to a running app without restarting the app and *without losing app state*
That sounds more like how you described edit-and-continue to me.
Across the Internet, it's still quite fast if you use Azure SignalR service, which is effectively a globally distributed CDN. Most commercial apps use this service.
Blazor WASM is better than I thought it would be. My company has built a healthcare SaaS app that has ~5k daily users on it and no one has complained about the initial rendering and download time to pull down 25MB on the initial load. This sounds like a lot but with modern broadband, 5G, and CDNs, this takes about a second or two.
Also
https://news.ycombinator.com/item?id=41884187
https://news.ycombinator.com/item?id=41809351
using LanguageExt;
using static LanguageExt.Prelude;
I list all of the others so that people can easily add them to their global-usings. The key is `using static LanguageExt.Prelude`, because static-usings aren't flagged by tooling.It's a conscious choice not to pander, I don't mind if the C# FP community doesn't include everybody in the C# community, I'm simply presenting an opinionated approach that is close to the 'norms' of FP languages/frameworks rather than trying to fit into the C# conventions. It's intentionally going 'all in' rather than just trying to augment the existing approach with types like Result or LINQ (the extensions). Most of the benefits of pure-FP come from a complete change of approach; I'm saying "leave the previous C# world behind and let's try a different way". Some people really won't like it and that's fine. In a company it needs an advocate that pushes the narrative, if that isn't there, then most won't get past the use of Option, or simple stuff that doesn't move the needle much.
I've been a CTO for 20 years and have mentored many juniors in my time, including in FP. A willing junior with a good mentor will find FP easier than OO once they grok it, because pure FP becomes more intuitive eventually (as it's based on maths, so you get to a point where - if your code compiles - you feel like it must be right, which is very powerful reinforcement for everyone, but especially for juniors).
> probably every .NET dev has an EF/LINQ performance related horror story (the generated queries are ridiculous)
> There have definitely been improvements, but in my opinion, they have just been kind of slow.
> much of C#'s lag is owed to Microsoft's contribution to .NET being mostly technical debt. Almost everything good that came out of .NET came from open source/non MS teams (like Mono).
Do you actively use .NET (any modern target in the last, say, 3-4 years or so)?