4 ms·
(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
by 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.