Hacker News new | past | comments | ask | show | jobs | submit login

More complicated example:

var seniorMales = from c in customer where c.age > 65 && c.Sex == “male” select new {c.FirstName, c.Lastname, c.Age}

foreach(var customer in seniorMales) { Console.WriteLine(customer.Firstname + “ “ + customer.Lastname); }

Why would I create a class/struct for that use case?

Side note: this is why I find ORMs in most languages besides C# useless. Here, “customers” can represent an in memory List, a Sql table or a MongoDB collection and the LINQ expression will be translated appropriately to the underlying query syntax.

The “ORM” is integrated into the language and yes anyone can write a LINQ provider.




This us one of the cases where I would want you to write an explicit type for seniorMales. Reasoning about the LINQ expression is just complex enough that by not constraining its type to your expectations you can easily obscure a mistake in your thinking that would otherwise show up in the data types.


How so? You couldn't pass the anonymous type to another method or return it so the locality would be strong and the anonymous type is just a strongly typed POCO. Creating a class doesn't add anything semantically.

How do you feel about deconstructuring that is available in most languages?


I think the anonymous type is much better. It's type safe, you can easily see how it's defined but you don't pollute the rest of your code with one-off classes that make only sense within the function.

If I had to review the code and saw an explicit type I would recommend an anonymous type.


It is not better. I don't know what type FirstName or Age is. Can Age be negative? Is FirstName an array of char or a string? Can FirstName be more than 10 characters long? It could be a double value for all I can tell from that line of code!


The select statement is projecting the Customer type from either an external data source or an in memory source. That information wouldn’t be encoded into the POCO whether or not it was anonymous.

Changing select new {...} to Select new SeniorPeople {...} wouldn’t give you any more information. At most if I was writing that as part of a repository class I would be sending you back an IEnumerable<SeniorPeople>.

If you were to send me an expression to use in the where clause you would send me an

<Expression<Func<SeniorPeople,bool>>

You have no idea what that expression is going to be translated to until runtime.

Either way, you are just working with non concrete Expression Trees that could be transformed into IL, SQL, a MongoQuery etc. All of the constrainsts would be handled by your data store.

You don’t even know before hand whether you are iterating over an in memory list, or streaming from an external data source.

I could switch out Sql Server for Mongo and you as the client wouldn’t be any the wiser.

And we haven’t even gotten to the complication if the result set was the result of a LINQ grouping operation.


You are comstructing an elaborate strawman that does nothing to work in your favor. If anything, yur essay just makes it clear that it is impossible to glean the data type from the LINQ expression itself.

Yet, any code using its result will contain implicit assumptions about that data. Therefore, in order to maintain type safety, the expected type of the return value must he stated.

That type must also be independent from whatever LINQ does internally to produce that return value. Otherwise, the LINQ providers wouldn't be as exchangeable as you claim.


You also included information about “constraints” like is it a positive or negative number and string length. That wouldn’t be encoded in the type. Why would I go look up the types either way? I’m using a strongly typed language, the IDE would tell me that anyway. While I am writing code, I see a red dot showing me immediately if I’m using the type incorrectly. Any assumptions that were incorrect, I would get immediate feedback.


Not necessarily. Is Age unsigned or not? This constrains the possible range of values. In other contexts, there is a lot more information inferred by the integer type used.


Do you actually work with C#, LINQ and generics?


Yes. I am quite familiar with them.


Then tell me how you can model in C# a type where a property can’t be negative or a certain length.


    class Foo {
      public uint Bar { get; set; }

      private char[] _baz;

      public char[] Baz { get { return _baz;} }

      public Foo() { _baz = new char[5]; }
    }
This is cheating a bit on the array part. But the length of that char array is set in stone and cannot be changed from the outside. However, the Bar property uses a standard C# datatype.


I honestly thing that you haven't done any real work with LINQ or you are imagining problems that don't exist. The char array is not usable as string or we have to go back to 0 terminated strings like C.


I am not imagining problems that don't exist in the application domains I work on.

If your environment is so relaxed that aspects like signedness of an integer don't matter, so be it. But then you are also far removed from a domain where software correctness is non-negotiable.


It’s not aspects “like signednes” that’s the only constraint that you could embed in your defined POCO and still use as a select projection that would survive a LINQ expression that was turned into an expression tree. Your data store would enforce the other constraints. Your C style character array as a string wouldn’t work with either LINQ nor any of the standard library.

Are you really trying to go back to the bad old days with Microsoft C/MFC/WIN32/COM where you had over a dozen ways to represent a string that you had to convert to and from depending on which API you were using?


And your class wouldn’t work as part of the LINQ example. EF for example wouldn’t know how to translate it.


How do you want to model this in C#? Write a full class with all kinds of checking for a single LINQ operation? That will be a very bloated codebase.




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

Search: