[HN Gopher] Net 9.0 LINQ Performance Improvements
       ___________________________________________________________________
        
       Net 9.0 LINQ Performance Improvements
        
       Author : olvy0
       Score  : 171 points
       Date   : 2024-10-18 10:39 UTC (12 hours ago)
        
 (HTM) web link (blog.ndepend.com)
 (TXT) w3m dump (blog.ndepend.com)
        
       | high_na_euv wrote:
       | LINQ is so fucking useful and well designed feature of .NET
       | ecosystem that it is unreal when you gotta use lang which doesnt
       | have such a thing.
       | 
       | C# design team is/was unparalleled
        
         | pjmlp wrote:
         | LINQ is largely based on FP stuff, also how Smalltalk
         | collections work.
         | 
         | It is relatively easy to find similar capabilities in most
         | languages nowadays, unless one is stuck on Go, C and similar.
        
           | sanex wrote:
           | Do you know an equivalent for Linw to EF in kotlin or Java
           | because I have not found it.
        
             | stanac wrote:
             | Those are linq expressions. They are indeed wonderful. You
             | get an abstract tree from which you can create SQL or API
             | commands to access the data source. I remember in the early
             | days (.NET 3.5?) there were multiple examples of LINQ2X
             | like Linq2Csv, Linq2Rss Linq2Drobox (I'm paraphrasing, I
             | don't remember actual examples, but it was wild).
             | 
             | There is also relinq library which transforms linq
             | expressions into expressions which are easier to
             | understand/use.
        
             | pjmlp wrote:
             | Rather quick search, as I am more of a myBatis person,
             | 
             | Java: https://www.jooq.org/
             | 
             | Kotlin: https://www.ktorm.org
        
           | kumarvvr wrote:
           | Any pointers to such libraries in python?
        
             | pjmlp wrote:
             | itertools would be the starting point, unfortunelly Python
             | is rather limited due to the way it only supports one line
             | lambdas.
        
           | apwell23 wrote:
           | No it isn't easy to find similar capabitites in java, go,
           | python, ruby.
           | 
           | Maybe you do simulate some of this using meta programming in
           | ruby but its certainly not 'easy to find'.
        
             | pjmlp wrote:
             | It certainly is, unless you are talking about SQL like
             | syntax, which is basically syntax sugar for classical FP.
             | 
             | And I explicitly left Go out of my list.
        
               | apwell23 wrote:
               | >unless you are talking about SQL like syntax
               | 
               | 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;             }         });
        
               | high_na_euv wrote:
               | To be fair, 99% of linq usage is method chaining syntax,
               | not query syntax
        
               | apwell23 wrote:
               | LINQ = Language Integrated Query
               | 
               | Its even in the name. What do you mean by "method
               | chaining is linq" ?
        
               | ygra wrote:
               | Considering the methods live in the System.Linq
               | namespace, I think the extension methods may also be
               | called LINQ.
        
               | high_na_euv wrote:
               | "var results = list.Where(x => x.Salary > 12345).Select(x
               | => x.Name).ToList())"
               | 
               | 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
        
               | apwell23 wrote:
               | > But yea, it is LINQ method chaining.
               | 
               | 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 .
        
               | high_na_euv wrote:
               | >fluent interface
               | 
               | 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
        
               | Merad wrote:
               | LINQ is the name for the overall system. LINQ can be
               | written using two different styles:                   //
               | 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.
        
               | svieira wrote:
               | These days it would be                   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.
        
               | Rohansi wrote:
               | One of the unfortunate pieces missing from Java's streams
               | is the ability to easily extend them with additional
               | operators. In C# they are all extension methods for the
               | IEnumerable interface so you can add your own methods
               | into the chain but that's not possible in Java.
        
               | pjmlp wrote:
               | It is coming, it is called Gatherers, another approach,
               | same result.
        
               | svieira wrote:
               | I'm a huge fan of Gatherers, lovely API!
        
               | apwell23 wrote:
               | i posted that example from a comment that linked to this
               | repo https://github.com/mythz/clojure-linq-examples
               | 
               | my point was that laguange support for sql like sytax is
               | part of what makes LINQ linq. Java niceties is not
               | relevant.
        
               | ygra wrote:
               | I guess the very fact that LINQ is so many things makes
               | such discussions a bit annoying at times because everyone
               | refers to a different set of features.
               | 
               | 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.
        
               | SideburnsOfDoom wrote:
               | > yes thats what linq is?
               | 
               | 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.
        
               | apwell23 wrote:
               | sure but you cannot just remove 'sql like syntax' and
               | claim you can do linq in any language.
        
               | pjmlp wrote:
               | I discovered someone stuff in Java pre-history days.
               | 
               | Because I am feeling nice,
               | Arrays.stream(new int[]{1, 2, 3, 4, 5, 6, 10, 23,
               | 45}).filter(n -> n < 5).forEach(System.out::println)
        
             | svieira wrote:
             | There are easy ways to do some subset of what LINQ does in
             | Java (using annotation processors), in Go (using
             | generators), in Python (using double-underscore methods to
             | capture all the operations the expression is working with
             | at runtime, see SQLAlchemy) and in Ruby.
             | 
             | 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).
        
           | blackoil wrote:
           | One difference with LINQ is its ubiquity. It works with
           | database, in memory data structures, on disk files. You can
           | use your skills/code across all the system.
        
             | John23832 wrote:
             | It's just built on top of anything that is Iterable. If a
             | language has first class iterator support, they could do
             | something similar.
        
               | naasking wrote:
               | Mainly first-class functions I think. If you have those,
               | you can just use fold in the core combinators.
        
               | mythz wrote:
               | Takes a lot more than that, LINQ providers work by
               | accepting a LINQ Expression Syntax tree instead of an
               | opaque function, which allows providers to inspect and
               | traverse the Expression's AST and translate it into the
               | data source it's implementing.
               | 
               | This Expression AST is constructed by the compiler, not
               | something that can be tacked on by a library later.
        
               | megadal wrote:
               | Yes, but I think the point is practically every high
               | level language can already do this pretty trivially.
               | 
               | 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.
        
               | mythz wrote:
               | If it were trivial you'd see LINQ-like providers
               | implemented in "practically every high level language".
               | 
               | Source 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?
        
               | pjmlp wrote:
               | jOOQ would be one such example, https://www.jooq.org/
               | 
               | 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.
        
               | mythz wrote:
               | This is a custom expression language to work within the
               | expressive limitations of the language:
               | 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);
        
               | pjmlp wrote:
               | Java streams are what you're looking for.
               | 
               | 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.
        
               | mythz wrote:
               | > If you insist in telling LINQ === EF
               | 
               | 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.
        
               | recursive wrote:
               | IQueryable<> manipulation has other tools available to it
               | than brute-force iteration, like streams do. Streams may
               | be the closest thing java has, but it's still a
               | fundamentally different thing.
        
               | eknkc wrote:
               | Wait what? Am I gonna include a source code parser and
               | AST analyser to my JavaScript library for example, to
               | examine the provided expression source and do this? This
               | reads like the infamous Dropbox comment from when it
               | first got released.
        
               | jayd16 wrote:
               | Not that I agree it's trivial but even if it was, so
               | what?
               | 
               | This just feels like sour grapes.
        
               | Pxtl wrote:
               | Having used it since its inception, I've come to the
               | conclusion that the SQL translator is kind of a
               | misfeature. It creates so many weird bugs and edge-cases
               | and tedium.
               | 
               | 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 pseudomarkdown
        
               | mythz wrote:
               | Guess everyone has their preferred style, I personally
               | avoid code-gen data models like the plague and much
               | prefer code-first libraries.
               | 
               | 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.
               | 
               | [1] https://docs.servicestack.net/ormlite/
        
               | Pxtl wrote:
               | My problem with this approach is that this falls apart if
               | you write:                   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.
        
               | mythz wrote:
               | Isn't this just `.StartsWith("A")`?
               | 
               | 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.*'"));
        
               | Pxtl wrote:
               | Yes, it's a trivial example. I'm not looking to support
               | it, I'm looking to catch it at compile-time.
               | 
               | 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.
        
               | magicalhippo wrote:
               | Saw EF now supports custom SQL queries, so been
               | considering that once we've moved to MSSQL (old db server
               | isn't supported by EF).
               | 
               | 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.
        
               | Pxtl wrote:
               | Quick word of advice when dealing with deep parent/child
               | reloationships:
               | 
               | Do not use lazy loading feature. That way lies madness.
        
               | magicalhippo wrote:
               | We're not doing that where we come from. All child tables
               | have the main id so we can load the data for all child
               | rows with just one query per child table, and we load
               | everything at once.
               | 
               | We were planning on sticking with this, it has worked
               | well so far, but good to know to avoid getting tempted by
               | the alternative.
        
           | jiehong wrote:
           | I've found [0] for clojure, which maps the best IMO, but it
           | also contains links to the same LINQ examples in other
           | languages (java, kotlin, swift, elixir, python, ...).
           | 
           | [0]: https://github.com/mythz/clojure-linq-examples
        
             | nightski wrote:
             | The difference is many of those are dynamically typed
             | languages. It's still useful, but a lot of the a beauty of
             | LINQ comes from the fact that it is within a statically
             | typed language.
        
           | John23832 wrote:
           | It's surprising that Go didn't ship with it, but given that
           | they just added iterators, it's coming.
           | 
           | 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.
        
             | rw_panic0_0 wrote:
             | nah it's not coming, functions like maps and filters won't
             | come to go by design, iterators are not only about FP stuff
        
             | pjmlp wrote:
             | Go culture is quite clearly against this kind of niceties.
        
             | devjab wrote:
             | You can do functionality similar to LINQ with chaining as
             | long as you don't need to call a method with a generic
             | different from the one defined. If you do need that, you're
             | going to have to do it without chaining. You can still do
             | something similar but it'll be a lot less elegant than how
             | C# does it.
             | 
             | 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.
        
           | whizzter wrote:
           | Yes and no, the LINQ syntax being coherent between
           | IEnumerable<> and IQueryable<> hides a lot of good magic.
           | 
           | 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.
        
             | whizzter wrote:
             | For reference, to achieve what IQueryable does with 100%
             | normal code in JavaScript you need something like Qustar
             | that was posted here a month ago.
             | 
             | 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).
             | 
             | https://github.com/tilyupo/qustar
        
         | munchler wrote:
         | If you like LINQ, you should really give F# a try.
        
           | neonsunset wrote:
           | F# is even better. I only wish performance wasn't hit or miss
           | around sequences/iterator expressions. Hopefully one day it
           | will reach parity with C# through compiler improvements
           | and/or detaching FSharp.Core from conservatively targeting
           | NS2.0 and modernizing it.
        
             | emn13 wrote:
             | I never really got over the order-dependent and fairly slow
             | compile times, but it's been like 10 years since I used it
             | for anything even slightly complex. Is F# better in this
             | regard now, or are there accessible patterns to help deal
             | with that?
        
               | munchler wrote:
               | Order-dependency is a feature, not a bug, but it does
               | take some getting used to. If you really want to avoid
               | it, you can now declare all functions in a module to be
               | mutually recursive, so you can put them in any order.
               | Cyclic dependencies between files are still prohibited,
               | for good reason. See
               | https://fsharpforfunandprofit.com/posts/cyclic-
               | dependencies/.
               | 
               | The F# compiler is slower than the C# compiler, but it's
               | still more than fast enough for building large
               | applications.
        
         | mhh__ wrote:
         | Maybe you've been unlucky but LINQ didn't really seem all that
         | interesting to me using it.
         | 
         | 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.
        
           | pjc50 wrote:
           | > 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
           | 
           | 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...
        
             | SideburnsOfDoom wrote:
             | > basically they expect you to use EF. Writing an
             | IQueryable...
             | 
             | 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.
        
               | pjc50 wrote:
               | > IQueryable is of no importance to us
               | 
               | 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.
        
             | christophilus wrote:
             | Back when I was primarily a C# dev, I used OSS lightweight
             | ORMs which had LINQ interfaces. I also frequently used LINQ
             | on in-memory structures. It's fantastic, and I never felt
             | any need to use EF.
             | 
             | 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.
        
           | bazoom42 wrote:
           | It is not rocket science to implement IQueryable but it is
           | not trivial either since the API is optimized towards ease of
           | use rather then ease of implementation. The Select and Where
           | methods support arbitrary C# expression trees, so the
           | implementation have to traverse the tree and throw errors if
           | some expression cannot be translated to the underlying
           | engine.
        
           | justin66 wrote:
           | > Maybe you've been unlucky but LINQ didn't really seem all
           | that interesting to me using it.
           | 
           | Getting good use out of a tool you do not find interesting
           | would mean a person was... unlucky?
        
             | mhh__ wrote:
             | Unlucky as in forced to write COBOL prior to C# or whatever
        
           | SideburnsOfDoom wrote:
           | > I could not tell you now how to implement a custom
           | IQueryable
           | 
           | 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.
        
         | hggigg wrote:
         | LINQ is a veritable footgun in any large team I find. While
         | it's extremely powerful and really nice, it's so so so easy to
         | blow your toes off if you don't know what you are doing. Some
         | of my favourite screw ups I saw:
         | 
         | * 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.
        
           | high_na_euv wrote:
           | >Not understanding the expectation that Single() requires
           | exactly one of something.
           | 
           | 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
        
           | pjc50 wrote:
           | How much of that is LINQ-specific and how much is just the
           | cost of using an ORM to build queries rather than typing them
           | out as SQL?
           | 
           | I've never encountered testing problems with LINQ-to-objects.
        
           | John23832 wrote:
           | I sort of agree. I recently had to code splunk a bug with 3
           | other engineers and we all got to a relatively complex LINQ
           | and of the 4 of us, we all had 4 different interpretations
           | when visually inspecting.
           | 
           | > Not understanding how damn hard it is to test LINQ stuff.
           | 
           | I disagree with this. Just run the LINQ query on a compatible
           | iterable.
        
             | hggigg wrote:
             | Regarding the testing, it's more the sheer multiplicative
             | number of cases you have to consider on a LINQ expression.
        
             | SideburnsOfDoom wrote:
             | > I recently had to code splunk a bug with 3 other
             | engineers and we all got to a relatively complex LINQ and
             | of the 4 of us, we all had 4 different interpretations when
             | visually inspecting.
             | 
             | 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.
        
           | SideburnsOfDoom wrote:
           | > * Not understanding when something is evaluated.
           | 
           | 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.
        
           | jve wrote:
           | Single gives you some guarantees about the returned value.
           | Use First/FirstOrDefault if you don't need those guarantees.
           | You can also provide predicate for FirstOrDefault to select
           | First element that matches your predicate.
           | 
           | > 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...
        
         | highwaylights wrote:
         | I'll get started then end up on a rant but..
         | 
         | 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.
        
           | high_na_euv wrote:
           | Your experiences are coherent with mine.
           | 
           | 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
        
           | bob1029 wrote:
           | Agree with all of this. I think the biggest problem with
           | popularity around these tools is that they're _too_ good.
           | 
           | 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.
        
           | Nullabillity wrote:
           | > 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.
           | 
           | https://rr-project.org/
        
           | martindevans wrote:
           | > Edit-and-continue comes to mind, which despite how many
           | times people confuse the two is not hot reload
           | 
           | I'm certainly guilty of this! What's the difference?
        
             | highwaylights wrote:
             | I'm simplifying this for brevity but: Hot reload is a
             | concept whereby changes will be saved, if necessary
             | compiled (in the case of compiled/JIT-ed languages), then
             | whatever is pointing at the original source is run again
             | automatically (a web page/an app screen/whatever).
             | 
             | 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).
        
           | MainlyMortal wrote:
           | Your comment about the docs is the real reason .NET/C#/F#
           | isn't gaining any new users. The dotnet team should actually
           | be embarrassed about this but it's clear they don't care so
           | neither will anyone else. It's 100% quantity (slop) over
           | quality for Microsoft. Their website and guides are terrible
           | and irrelevant for both new and experienced devs.
           | 
           | 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.
        
             | highwaylights wrote:
             | This really seems to be the problem - the developer
             | relations seems to be comprised of non-developers.
             | 
             | 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.
        
               | neonsunset wrote:
               | As I keep having to repeat here ad-nauseam, DevKit is
               | optional, you only really need base C# extension which is
               | what provides language server, debugger and code
               | completion capabilities. For VSCodium and non VSC-based
               | distrubutions there's also a fork that packages Samsung's
               | NetCoreDbg component instead of vsdbg.
        
         | megadal wrote:
         | It's just an API for JIT, basically metaprogramming. It's cool
         | but you can definitely do a similar thing in pretty much every
         | high level language.
         | 
         | 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...
        
           | jeswin wrote:
           | > It's cool but you can definitely do a similar thing in
           | pretty much every high level language.
           | 
           | 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.
        
           | int_19h wrote:
           | C# generics will handle anonymous types just fine. That's
           | what lets you write stuff like `from ... select new { ... }
           | where ...`.
        
       | neonsunset wrote:
       | Relevant section in the annual book-sized post on all performance
       | improvements in .NET 9:
       | 
       | 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)
        
       | dingdingdang wrote:
       | OK, so since I've never actually bothered to look at what LINQ
       | actually is.. there may be others in the same boat: "LINQ allows
       | you to query any enumerable collections such as List<T>, Array,
       | or Dictionary<TKey,TValue>.". Got to admit I still find the LINQ
       | to DB passtru rather opaque even after reading up on it:
       | https://stackoverflow.com/questions/30716776/passing-a-query...
       | 
       | 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?
        
         | caseymarquis wrote:
         | While LINQ does include a library of extension methods for
         | functional programming with .NET collections (which is great),
         | it also includes "Expression Classes". In a nutshell, this
         | allows a user to pass a single expression lambda to a function,
         | and the function implementor receives the abstract syntax tree
         | for the lambda, not the lambda itself. You can then not only
         | receive and analyze these trees, you can also manually build
         | and compile them. This effectively allows a limited set of
         | runtime macros within .NET.
        
         | pjc50 wrote:
         | > Basically allowing for a uniform way to query data which is
         | reminiscent of a more modern version of SQL.
         | 
         | 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.
        
         | naasking wrote:
         | > Basically allowing for a uniform way to query data which is
         | reminiscent of a more modern version of SQL (in my optics
         | anyway)
         | 
         | 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.
        
       | blackoil wrote:
       | Anyone knows of a comprehensive book/tutorial to learn end to end
       | web development in dotnet. Most I have found are elementary,
       | outdated or poor quality.
        
         | DeathArrow wrote:
         | I've learned by doing, but here you go.
         | 
         | 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.
        
         | littlecranky67 wrote:
         | That is because all the hot-and-new in .NET web development is
         | Blazor, and it is not really popular outside of Microsoft's
         | Blogosphere (and IMHO never will be and go down the same way as
         | Silverlight did). The "venerable" technologies are still
         | present in .NET 9 and still work, get maintained etc.
         | 
         | 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".
        
           | WorldMaker wrote:
           | Blazor for better and worse can't have the same ending as
           | Silverlight did. In Server Mode it is just Razor + SignalR
           | for HTMX-style frontends that sort of live update/"magic
           | RPC". In Client Mode it is just Razor as a virtual DOM-ish
           | framework running directly in Web Assembly (wasm) in the
           | Browser. At the end of the day Client Blazor is much more
           | like writing front end websites with Elm than writing
           | websites for the Silverlight plugin.
           | 
           | (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.)
        
             | hakanderyal wrote:
             | Do you know of any performant, quality examples of Blazor
             | out in the wild? All the examples I've seen have
             | unacceptable UX by modern standards.
        
               | m_fayer wrote:
               | https://github.com/Webreaper/Damselfly
        
               | parineum wrote:
               | > All the examples I've seen have unacceptable UX by
               | modern standards.
               | 
               | What does that have to do with Blazor?
               | 
               | One could easily write outdated UX in React if they so
               | choose.
        
               | hakanderyal wrote:
               | It's the slowness/sluggishness, not the looks. Most of
               | the time even a simple interaction like clicking a
               | checkbox takes ~1-2 seconds, which probably comes from
               | tracking the state on server.
               | 
               | (I don't mind outdated for .NET stuff, nearly everything
               | from enterprise vendors looks like it just jumped out of
               | WinXP anyway.)
        
               | parineum wrote:
               | I've never seen that behavior, even in the preview/beta
               | versions. That example is less complicated than the
               | sample project that you get when you create a brand new
               | project from the visual studio template (it's something
               | like increment a counter on the server side via button
               | clicks iirc).
               | 
               | 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.
        
               | hakanderyal wrote:
               | I get where you are coming from, and I'm on the same
               | page. I'm not complaining about Blazor, I'm complaining
               | about not finding any good examples. That's why I'm
               | asking around.
               | 
               | 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.
        
               | CrimsonCape wrote:
               | The best Blazor app i've seen is nodexr.
               | 
               | https://www.nodexr.net/
               | 
               | https://github.com/Jcparkyn/nodexr
        
               | hakanderyal wrote:
               | That's what I was looking for, thanks!
        
               | aksss wrote:
               | > 1-2 seconds
               | 
               | Something is wrong there, probably someone is screwing up
               | form validation in their component framework or
               | something, but IME that's not a Blazor thing.
        
               | WorldMaker wrote:
               | Certainly I also can't imagine how you would get strong
               | performance out of Server Blazor in real world/Enterprise
               | conditions. RPC busses are going to RPC and roundtrips
               | are still roundtrips even when SignalR-backed web
               | sockets. Flooding UDP web sockets with HTML chunks isn't
               | necessarily a great idea, even if HTTP3 (QUIC) kind
               | of/mostly succeeds at it, but SignalR as good as it is
               | certainly isn't HTTP3.
               | 
               | 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.
        
               | hakanderyal wrote:
               | Thanks, that confirms my initial findings.
               | 
               | I'll look for an opportunity to give client Blazor a try.
        
           | MangoCoffee wrote:
           | >IMHO never will be and go down the same way as Silverlight
           | did
           | 
           | 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.
        
           | tracker1 wrote:
           | Also worth looking into are some of the extensions for
           | Razor/HTMX views, which IMO is a way better approach than
           | server-managed Blazor. Jetbrains has a few good videos and
           | really nice dev extensions for this approach.
           | 
           | I also think wasm Blazor is a non-starter as well until WASM
           | GC integration in the browsers gets fully integrated for C#
           | targets.
           | 
           | https://www.youtube.com/watch?v=uS6m37jhdqM
        
           | Alupis wrote:
           | Why is this still a problem within the dotnet world? Why
           | aren't there a dozen popular application frameworks to choose
           | from like there is for Java and most other languages?
           | 
           | 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?
        
         | emmanueloga_ wrote:
         | I've recently taken an interest in web development using C#. It
         | seems to me that ASP.NET is THE way for creating web
         | applications in .NET, for better or worse ("for worse" since
         | lack of alternatives sounds a bit suspicious to me...).
         | 
         | 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...
        
           | WorldMaker wrote:
           | There are alternatives, but most of them have been "consumed"
           | in that ASP.NET does what they do better (most recently
           | "ASP.NET Minimal API" removed a lot of the appeal for many of
           | the smaller alternatives), or "consumed" because "ASP.NET"
           | the brand also includes the low level HTTP machinery at this
           | point and alternatives are increasingly "ASP.NET + some extra
           | framework" which doesn't sound like an alternative, or are
           | focused on small niches and other languages. There's a lot of
           | fun alternatives in F# (Giraffe is the first one to my mind),
           | but obviously that is no longer web development in C#.
        
             | DonnyV wrote:
             | Modern Asp.net stole a lot from a little web framework
             | called NancyFx. It really shaped what Asp.net Core is
             | today.
        
               | WorldMaker wrote:
               | I agree, "Minimal API" owes a lot to Nancy, specifically.
               | There were a few others in that space, but Nancy was
               | definitely the big one that pushed ASP.NET the most.
        
             | nickpeterson wrote:
             | I really wish suave wasn't abandoned. We could have such
             | nice things in F#-land but all of our the cool stuff gets
             | dropped in favor of veneers over ms frameworks.
        
               | fire_lake wrote:
               | Suave isn't dead - it's more "complete"
               | 
               | What is missing? I might make a PR :)
        
         | hakanderyal wrote:
         | For server-rendered UI, look for resources that uses Razor,
         | ignore Blazor stuff at the beginning.
         | 
         | 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.
        
         | greener_grass wrote:
         | A bit of the beaten path, but F# with Fable is a very powerful
         | combination.
         | 
         | 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.
        
           | williamcotton wrote:
           | An architecture I've been using lately is writing a
           | functional core in F# and importing the library in both C#
           | API backends as well as React frontends. As you know, Fable
           | can compile to TS which you can import into your node
           | application.
           | 
           | 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.
        
       | DeathArrow wrote:
       | The more C# borrows from F#, the happier I am. I am awaiting for
       | discriminated unions to finally reach C# so I can do domain
       | modelling like a boss. :)
        
         | CharlieDigital wrote:
         | You can largely already pretty easily incorporate DUs using
         | OneOf[0] and Dunet[1].
         | 
         | A practical example of using this:
         | https://chrlschn.dev/blog/2024/07/csharp-discriminated-union...
         | 
         | [0] https://github.com/mcintyre321/OneOf
         | 
         | [1] https://github.com/domn1995/dunet
        
         | stult wrote:
         | I'd kill for units of measure too. It makes maintaining any
         | kind of engineering or scientific code so much easier.
        
           | fuzzy2 wrote:
           | In a past project, we used Units.NET. It worked pretty well
           | as far as I could tell. (I was not involved with the gritty
           | domain details.) My colleagues even extended the library
           | where units were missing.
        
           | Jordanpomeroy wrote:
           | In my experience units of measure in technical apps is only
           | interesting in the UI layer as most apps I've worked on have
           | a "base" system of units that all calcs are expecting. What
           | alternate experience have you seen?
        
       | olvy0 wrote:
       | For me, the most useful part of LINQ is neither the IQueryable
       | syntax tree based extension mechanism, nor the language
       | integrated part (which I dislike), but simply the IEnumerable
       | extensions. Originally known somewhat confusingly as linq to
       | objects. Those allow me to write c# in functional style, keeping
       | the code concise.
       | 
       | 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.
        
         | osigurdson wrote:
         | C# has quite a few easy to use things that take a while to
         | understand. In some ways it is a bit of an "experts only"
         | language.
        
           | aksss wrote:
           | It's hard to forget what you know and see through eyes of a
           | beginner, but I definitely find C# to be a very "rich"
           | language, in the sense of finding new features and ways of
           | doing things the more I use it and as the incessant releases
           | roll out. I like to think it's still pretty easy to start
           | with though if one is focused on the fundamentals. Lots of
           | head room for progressively expert use, I guess.
        
         | jasonthorsness wrote:
         | This is how I use LINQ as well. With some non-standard names,
         | it has everything you need! Eric Lippert wrote a great series
         | on monads tying it to LINQ:
         | 
         | https://ericlippert.com/2013/04/02/monads-part-twelve/
        
         | tracker1 wrote:
         | This is my preference as well, I love the functional aspects of
         | the LINQ extensions for IEnumerable (and IQueryable)... Just
         | easier to reason with IMO. Not always the most performant
         | option(s) in for example (Entity Framework), but usually a
         | pretty good option most of the time. I also like to use Dapper
         | over EF.
         | 
         | 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.
        
         | sedatk wrote:
         | Totally. I couldn't care less if the LINQ syntax had gone
         | tomorrow, but functional composition is so powerful, and easier
         | to maintain too.
        
           | recursive wrote:
           | I would miss it for `let`, and for multiple `from` clauses.
           | These are things that can be done with extension methods and
           | callbacks, just not as elegantly.
        
             | sedatk wrote:
             | `let` is just a .Select(), isn't it?
        
               | brewmarche wrote:
               | A `Select` to a tuple or anonymous class which you have
               | to carry around all the way.
               | 
               | 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.
        
               | progmetaldev wrote:
               | To add on to what you wrote, it amazes me the number of
               | developers that don't understand you can use .Select() to
               | construct named object instances. I'm probably using bad
               | terminology, but something like:
               | .Select(x => new Employee { Name = x.Name, DepartmentName
               | = x.Department.Name }).ToList();
        
               | recursive wrote:
               | How do these developers use .Select() then?
        
               | sedatk wrote:
               | Oh that's convenient, that's for sure.
        
         | recursive wrote:
         | If you like haskell, you might* like some of the other
         | applications of linq's query syntax, like combinatoric parser
         | construction. [1] The query syntax isn't hard-coded to do stuff
         | with IEnumerable, that's just what it does by default. It can
         | be used for pretty much anything. It works a bit like operator
         | overloading.
         | 
         | [1]:
         | https://github.com/acple/ParsecSharp/blob/da8d0cb9ec39e28dd9...
        
         | progmetaldev wrote:
         | I've only ever used the method syntax for LINQ. I'm not a fan
         | of having another "embedded" language inside my host language,
         | especially since what is returned eventually needs to go back
         | to C#. When I'm not using an ORM like Entity Framework or
         | Dapper, I still prefer to place my data access logic with SQL
         | into a separate abstracted project so it doesn't spill across
         | my application (and can be replaced if I were to require a
         | different RDBMS, although this has only happened to me once in
         | 20 years).
         | 
         | 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.
        
       | nightski wrote:
       | Whenever I work in other languages/ecosystems LINQ is the one
       | thing that I really miss. It's just such a nice capability to
       | have available in the standard library. Beautifully designed
       | given the constraints it had to work within.
        
       | EVa5I7bHFq9mnYK wrote:
       | It's a shame, actually, that .NET performance improvements of up
       | to x1000 could still be found after two decades and hundreds of
       | millions spent on development.
        
         | eknkc wrote:
         | Most of the time, it is not because there were too many slow
         | things to be improved, it is mostly because they are adding
         | more facilities to the runtime, enabling other performance
         | improvements.
         | 
         | 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.
        
           | EVa5I7bHFq9mnYK wrote:
           | ReadOnlySpan is a breakthrough innovative data structure,
           | consisting of a pointer and a _length, that took Microsoft
           | Corporation two decades to invent.
           | 
           | Well, better late than never.
        
             | neonsunset wrote:
             | other languages do not have special pointers that can point
             | to GC object interiors, be transparently addressed with
             | arithmetics and cooperatively updated by GC without
             | pinning, while also allowing to point to stack and
             | unmanaged memory
        
               | EVa5I7bHFq9mnYK wrote:
               | I see, thanks. Still, x1000 performance improvement is
               | called a bug fix.
        
               | int_19h wrote:
               | But those pointers were around since .NET 1.0. Not only
               | that, but things like e.g. ArgIterator were also there!
               | Span could have been there too; it was really a matter of
               | design rather than technical capability.
               | 
               | 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.
        
               | neonsunset wrote:
               | 'ret T's aka byref pointers aka managed references in
               | their _current_ form is a relatively recent addition. I
               | can 't seem to find which exact version but if my memory
               | is correct - around .NET 5 or so, before that e.g. Spans
               | had to use a specially annotated field with [ByRefLike]
               | attribute. There wasn't really such a forefront support
               | in both the language and the runtime to enable the user
               | scenarios and even, if limited, ref escape analysis that
               | are possible today. .NET 9 goes further and allows types
               | that hold byrefs to be generic arguments, so you can now
               | handroll your own "true" span-based LINQ-like code as
               | well.
        
             | koyote wrote:
             | Given that it took C++ a similar amount of time to invent
             | the string specific string_view I don't think it's as
             | simple as you're making it out.
             | 
             | 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.
        
       | ibejoeb wrote:
       | > Some more optimizations can happen when the chain ends up with
       | methods like Count(), First(), Last(), ElementAt() or Sum(). For
       | instance, OrderBy(criteria).First() can be optimized to execute
       | as Min(criteria).
       | 
       | 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.
        
       | stonethrowaway wrote:
       | C# is Pragmatic [0].
       | 
       | [0] https://news.ycombinator.com/item?id=41761346
        
       | hakanderyal wrote:
       | Beware, once you get used to using LINQ and usually work in a
       | domain that it shines, you won't want to go back to using
       | anything else.
        
         | jayd16 wrote:
         | Do not, my friends, become addicted to LINQ. It will take hold
         | of you, and you will resent its absence.
        
       | mannycalavera42 wrote:
       | I have fond memories of using LINQPad
       | 
       | That's why I guess today I work in Clojure :)
        
         | m_fayer wrote:
         | It's been consistently one of my favorite tools for a good
         | decade. I don't know how much Microsoft is paying them to keep
         | it Windows-only because that's the only reason I keep windows
         | around, and I'm sure that goes for a number of important
         | developers.
        
           | stuartd wrote:
           | There's a Mac version coming (very exciting!)
           | 
           | https://x.com/linqpad/status/1820379112651026587
        
         | iLemming wrote:
         | I can relate. I used .Net at the beginning of my career, and
         | that one was one of the few nice things. I enjoyed building in
         | C#, until one day I realized that MSFT is more like a mental
         | prison (apologies for the strong negative word) - mind that
         | it's my personal feeling at that time, many things have changed
         | positively since then, although I moved on already.
         | 
         | Also, I too, use Clojure today - it is very nice.
        
       | louthy wrote:
       | "LINQ Performance improvements" really should read: "our own
       | List<T> implementation performance improvements". Microsoft seem
       | to spend their time improving what they need, rather than
       | spending time on general improvements. LINQ (the syntax, not the
       | method extensions) needs investment. Primarily around lambda
       | allocation and potentially on compile-time reduction of lambdas.
       | 
       | 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.
       | 
       | [1] https://github.com/louthy/language-ext/
        
         | neonsunset wrote:
         | If you do have useful feedback, please submit an issue or
         | contribute a PR to dotnet/runtime. That's how many performance
         | improvements in LINQ come to be, that the post discusses.
        
           | louthy wrote:
           | 7 years ago: https://github.com/dotnet/csharplang/issues/1060
           | 
           | 3 years ago: https://github.com/dotnet/csharplang/blob/main/m
           | eetings/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.
        
             | neonsunset wrote:
             | C# is already big enough language. This is more about .NET
             | in general and less about C# specifically.
             | 
             | 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.
        
               | louthy wrote:
               | > p.s.: I really wish that instead of LanguageExt,
               | companies would have adopted F# instead.
               | 
               | 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...
        
       | Culonavirus wrote:
       | There has to be a better way to do things than this annotation
       | noodle soup. My eyes are bleeding every time I look at modern Net
       | code.
        
         | bob1029 wrote:
         | Those attributes correspond to the benchmarking library used in
         | the article. Unit testing & benchmarking code does typically
         | look kind of like a plate of spaghetti.
         | 
         | 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.
        
         | recursive wrote:
         | What .net code are you looking at? I rarely use attributes at
         | all.
        
       | zija wrote:
       | I don't understand why the dotnet team doesn't invest more
       | resources and time into tools: doctests and documentation
       | generation, better and faster unit tests that I can write next to
       | the actual code, easy access to the source code, no need to
       | decompile a Dll to see it after pressing F12, a central place for
       | packages and documentation like in pkg.go.dev or docs.rs . Most
       | packages in nuget have no documentation at all, or only in readme
       | format on GitHub, or a short Wiki on this page. Other
       | environments like Rust, Golang, Java, Python are light years
       | ahead when it comes to these aspects.
        
         | sibit wrote:
         | A part of me jokes that Micro$oft only invested in OpenAI
         | because it's the only sensible way to browse .NET/Nuget
         | package(s) documentation. The other part knows it's dreadfully
         | true.
        
           | zija wrote:
           | Small F# community have
           | https://fsprojects.github.io/FSharp.Formatting/ that is a lot
           | better than docfx, it has markdown support, notebook suport,
           | script output embedding.
           | 
           | C# has nothing like that, xml comments and raw documentation
           | that has no value
        
         | Merad wrote:
         | Sandcastle Helper File Builder has been around forever and
         | started as an internal MS project IIRC, but for some reason few
         | libraries use it.
         | 
         | https://github.com/EWSoftware/SHFB
        
           | progmetaldev wrote:
           | I used to use this quite a bit after it was introduced, but
           | CHM files are a bit unwieldy for documentation, at least for
           | myself. Having integrated search is nice, but the windowed
           | interface, and being tied to Windows (AFAIK, maybe there are
           | readers for other operating systems) I believe will keep this
           | project from being used. I always found it to be decent for
           | more advanced developers, but felt there was something
           | missing for more junior developers that needed documentation.
        
         | progmetaldev wrote:
         | I agree with you, but I think this is most likely due to how
         | relatively new open source C# is. I'd hazard that most C# being
         | written is still done by enterprises/companies as closed
         | source. I feel this will improve over time, as long as
         | Microsoft continues down the road of being open, and doesn't
         | pull back what they've been doing in the last few recent years.
         | 
         | 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.
        
         | mwsherman wrote:
         | Here's a way to write tests next to the code:
         | https://clipperhouse.com/go-test-csharp/
         | 
         | (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.)
        
       ___________________________________________________________________
       (page generated 2024-10-18 23:01 UTC)