3 ms·
There are real advanced issues here, not just syntax issues. I'd summarize the first four items like this: A. (1,4) C# immutable collection support is a step-c
by yyyk 6y ago
There are real advanced issues here, not just syntax issues. I'd summarize the first four items like this:
A. (1,4) C# immutable collection support is a step-child, without full support for the required behaviours around it from the compiler and the community. That's why VS allows "immutableList.Add(item)" as if it were mutable, when it should be an error.
Yea, C# isn't just a functional language, but if there's support for immutable collections it should be done right.
B. (2,3) There is "no way to implement interfaces or abstract classes using an expression". The author's example is simple, but one could imagine a comparison involving captured variables where the separate class complicates things, because any captured variable needs to be shoved in a constructor.
I've hit 1 and 2 directly, 3 comes naturally from 2 (when you can define an object expression, you want a simple syntax for the constructor), as well as 4 from 1. I've had sufficient annoyances with 1 I've decided to not use immutable collections until support is improved.
As for dynamic, it's good for what it does, people who use it know the risks. Instead, I'd complain about nuget, when it's too easy to use outdated/obsolete packages and keep them that way. npm actually has better package management options. The saving grace is that the typical C# solution has far less dependencies than the JS/TS projects, but it's best to act prophylactically, and help the programmer to keep dependencies updated.
- rndgermandude 6y ago(1) I discussed here and I do not even know what's going on there: https://news.ycombinator.com/item?id=24168274 https://news.ycombinator.com/item?id=24168274 Tho, your own example of immutable collections is actually a good one. Rather specific, but still good. Immutable collections really could profit from compuiler-level warnings or even errors. It would be an easy enough fix for the language/compiler team: have some attribute that you/the immutable library authors would decorate functions with, something like [NoDiscardReturn] and the compiler would check that and emit warnings/errors. (2) Implementing something like IComparer<> is something you rarely do, and more or less never the way the author does. var enumerator = array.OrderBy(e => e.Foo).ThenBy(e => something.CheckProperty(e.Bar)).ThenByDescending(e => e.Name, StringComparer.OridinalIgnoreCase); array = enumerator.ToArray(); // Tho you often do not need to call .ToArray() if you're only gonna traverse the enumerator once Using Linq like this is more idiomatic and also kinda "functional", which appears to be what the author is after. Now, this was specific to the comparer stuff, but in general a sane API these days would use Func<> or Action<> instead of single-method interfaces. There are still some leftovers in the C# stdlib (and probably more in third party libraries) but again, you can write a wrapper once - not the horrible mess the author proposed either, but an interface implementation that would use single Func<> parameter in the constructor and then call that in the method implementation. internal class Foo { public string Bar; public int Baz; public override string ToString() => $"{Bar}: {Baz}"; } internal class DontAnnoyMeComparer<T> : IComparer<T> { private readonly Func<T, T, int> cmpFunc; internal DontAnnoyMeComparer(Func<T, T, int> cmpFunc) { this.cmpFunc = cmpFunc; } public int Compare(T x, T y) => cmpFunc(x, y); } static void Main(string[] args) { var foos = new[] { new Foo { Bar = "World", Baz = 1 }, new Foo { Bar = "Hello", Baz = 2 }, new Foo { Bar = "Hello", Baz = 1 }, }; // First with some ideomatic Linq Console.WriteLine(string.Join(", ", foos.OrderBy(f => f.Bar).ThenBy(f => f.Baz))); // Then with our helper interface implementation Array.Sort(foos, new DontAnnoyMeComparer<Foo>((x, y) => { var res = x.Bar.CompareTo(y.Bar); return res != 0 ? res : x.Baz.CompareTo(y.Baz); })); Console.WriteLine(string.Join(", ", (object[])foos)); } // Output // Hello: 1, Hello: 2, World: 1 // Hello: 1, Hello: 2, World: 1 (3) related directly to (2). The only real reason this is a real-world problem for the author is that they do not actually write idiomatic code. (4) Sure, something like that would be nice sometimes. But the lack of it is hardly the end of the world. Tho on the flipside, in my opinion languages that offer such pseudo-DSLs or even real embdeddable DSLs quite often suffer from people writing DSLs for every freaking thing, thus reducing readability of their code. (5) dynamic is hell for robust code, that's why you avoid it. I only ever used it when I was too lazy to do the extra typing to create proper types in run-once code dealing with JSON. And even then I should have probably just: class MyType { [DataMemeber] public int Foo; [DataMemeber(Name="baz")] public int Baz; }
- yyyk 6y ago1) Immutable collections is a bit of a pain in C# right now. No LINQ To() methods, some nugets don't actually work with them, constructor methods can be nicer... His item 4 is to some extent a result of the limited immutable support (he mentions "a lightweight way of building immutable list/collection expression"). Fix that support and 1,4 out of his list are not much of a problem anymore or at least ameliorated. 2) I would be glad to never need hear of IComparer or IEqualityComparer again, which I only need due to the stdlib leftovers... Admittedly not much, but enough to be annoying. His solution is more general, but your idea is very nice. Why didn't I think of that? 5) Dynamic is there for the Dynamic Language Runtime and for dynamic code far more general than your example. It should be kept in that silo, but it does do its job there. IMHO, the author tries to write C# with the current trend of functional+immutable, and that's why he ended up hitting these issues. It's true that the OOP way isn't bad (at least with those examples), but it's also true C# could offer better support for doing things the other way without much effort.
- rndgermandude 6y agoI thought about creating a small library that would expose a static IComparer<T> ToComparer<T>(this Func<T, T, int>) extension method (and a similar one for IEqualityComparer<T>). But I so far just was too lazy. If somebody from the C# API team reads this tho.... :P And while you're at it dear C# team, add .Distinct<TSource, TDest>(Func<TSource, TDest>, IEqualityComparer<TDest>) similar to OrderBy and friends, and various constructors to the generic collection types taking Func<T, T, int> instead of IComparer<T>. Yeah, API bloat, but good one in this case IMHO. C# and the .NET runtime and the compiler(s) are still evolving indeed, and I would guess a lot of issues will be addressed and fixed in the future. PS: the most annoying bit to me about the immutable collection library is that they are dead slow whenever I tried them.
- moomin 6y agoJust to pick on your response to 2: there’s plenty more complex interfaces than Func possible that have single-use implementations. The fact that they’re rare in C# is precisely because they’re too painful.to the extent that C# developers will instinctively attack the problem a different way to avoid the painful syntax.
- zmj 6y agoThese days I would use ReadOnlyMemory<T> to express an immutable view of a collection. If you need LINQ on it, there's MemoryMarshal.ToEnumerable.