Re: random sorting a collection
- From: "Peter Duniho" <NpOeStPeAdM@xxxxxxxxxxxxxxxx>
- Date: Fri, 30 May 2008 00:08:57 -0700
On Thu, 29 May 2008 23:23:39 -0700, Jon Skeet [C# MVP] <skeet@xxxxxxxxx> wrote:
[...]While the compiler is complaining about not being able to perform
inference on the type, it's my opinion that the expression "(int iElement)
=> return rnd.Next(integers.Count);" needs no additional information.
It does. That expression in itself doesn't have a known type. It can
be converted to a delegate type in itself.
Well, I understand the language doesn't support it. But it's what I was talking about toward the end of my previous post. The expression has enough information that it _could_ be converted into a type (that the compiler makes up).
This is borne out by the fact that using that directly in the OrderBy()
method works fine. (Note: I realize this isn't actually true...it's just
how I think it _ought_ to be...see below).
The reason it works for OrderBy is that OrderBy's parameter is a
Func<TSource,TKey>
I think the way I wrote my paragraph might have miscommunicated my point.. I understand in the context of OrderBy() that things work. The "this isn't actually true" that I was referring to was the question of whether the compiler can just make up a type for the purpose of inference.
Having successfully used OrderBy() to allow the inference to work (see my previous post where that was the one way I got things to work :) ), I am definitely aware that _that_ approach does work. :)
[...] However, when you put in an
extra level of lambda expressions, it won't manage it - if you call
OrderBy(first => (second => "foo"))
you'll get the same type inference problem - it can't infer the TKey
type.
Right. That was my point when I that it's not really a type inference problem per se, but rather than the "search and replace" nature of the "orderby" statement creates a type inference problem. While the lambda expression I wrote itself contains enough information for _it_ to be converted to a type by inference, once it's wrapped in yet another lambda expression, that information isn't available/relevant to the compiler.
(It's possible you understood all of this bit already - just thought
I'd restate it for clarity.)
It seems to me that the real issue here is how the expansion works, in
that it's a straight "search and replace" sort of expansion in which a
lambda expression is simply not an appropriate input.
It's not an appropriate input when the compiler needs to do type
inference.
I thought that's what I wrote. :)
If you wrote a type with the appropriate LINQ operators
where OrderBy was declared to accept a
Func<TSource,Func<TSource,TKey>> instead, I think it would cope just
fine.
How would that work? As you wrote before (maybe not in so many words, but I think it was basically the same thing), there's the issue of being able to use a Func<TSource, TKey> as a comparison object. Unless Func<TSource, TKey> implemented IComparable (or whatever the "orderby" requirement happens to be), would that actually work? (Actually, now that I've played with the casting variations -- see below -- I think it wouldn't, or else I misunderstand what you're saying).
I (think) I get why the compiler says what it says. Different parts of
the compiler are probably responsible for different parts of the process;
there's effectively a pre-processor doing the "search and replace" part,
and by the time that then is tried to be compiled into IL, it's not only
just plain wrong, there's no enough type information for any inference to
be done. Hence the actual error message.
Sort of. The query expression expansion part is indeed relatively
plain. But I don't think that's the root cause - the root cause is the
inability to infer a whole type directly from a lambda expression (as
opposed to inferring some of the parameter types or the return type,
based on knowledge of the general shape of what it's meant to be
converted to).
I guess we just differ on what we consider "the root cause". :) The way I'm looking at it, the lambda expression I originally tried has enough type information to be inferred, _if_ the context would match that type. But since the "search and replace" of the "orderby" statement causes the context to be something else, where the type information is no longer available, _that_'s the root cause. The act of incorporating my lambda expression into another one is the sequentially initial cause of the problem.
I won't put words into your mouth, but my impression is that you're looking at the issue more from the point of the final compiler error, and why _that_ happens. To me, a "root cause" would be the "original point of failure", and to me that point of failure is the first point at which the type inference information is lost. It seems to me that to you, the "root" point of failure is found approaching the question from the other end: the compiler goes to try to match the arguments for OrderBy() and can't get past the lack of type information on the given lambda expression (the one generated by the "orderby" statement).
It reminds me of the blackberry bushes I keep trying to whack back. They send out these leaders that burrow into the ground and create new root systems. At that point, which end is the "root" depends a lot on which direction you look. :)
So, sure...the cast is required...but the real gimmick in the code you
posted is the final "()" that actually _calls_ the delegate. That changes
the lambda expression, after casting, into something that can then be
inserted into yet another lambda expression for actual evaluation. Even
with a cast, a lambda expression by itself wouldn't work.
It wouldn't actually *work*, but I think it would compile.
Exactly right. :) I tried it. With the cast, the compiler decided it had enough type information to match the outer lambda expression and compiled fine. Of course, what it was returning was the delegate itself, not the evaluation of the delegate, and of course the delegate isn't comparable, so BOOM! :)
[...]
Just to be clear for any other readers - it's not "var" that creates
anonymous types, it's expressions of the form new { Property =
Value }.
Thanks for the clarification. I understand where the anonymous type comes from, but I certainly didn't express myself very well.
[...]
However, yes, it would be possible for the compiler to create a new
delegate type for you - or try to use one of the existing generic
ones, as mentioned before. Personally I don't think the extra
complexity in the language (particularly with respect to overloading -
there are a few nasty cases I can think of off-hand) but I would
imagine it would be doable.
Before anonymous types, I would have said "sure, keep the language simple". But C# is getting much more complicated with each revision. If other people get their pet features, why not me? :)
Pete
.
- Follow-Ups:
- Re: random sorting a collection
- From: Jon Skeet [C# MVP]
- Re: random sorting a collection
- References:
- random sorting a collection
- From: Adam Sandler
- Re: random sorting a collection
- From: Chris Dunaway
- Re: random sorting a collection
- From: Peter Duniho
- Re: random sorting a collection
- From: Chris Dunaway
- Re: random sorting a collection
- From: Peter Duniho
- Re: random sorting a collection
- From: Jon Skeet [C# MVP]
- Re: random sorting a collection
- From: Peter Duniho
- Re: random sorting a collection
- From: Jon Skeet [C# MVP]
- Re: random sorting a collection
- From: Peter Duniho
- Re: random sorting a collection
- From: Jon Skeet [C# MVP]
- Re: random sorting a collection
- From: Peter Duniho
- Re: random sorting a collection
- From: Jon Skeet [C# MVP]
- Re: random sorting a collection
- From: Peter Duniho
- Re: random sorting a collection
- From: Jon Skeet [C# MVP]
- random sorting a collection
- Prev by Date: Re: random sorting a collection
- Next by Date: Memory mapping
- Previous by thread: Re: random sorting a collection
- Next by thread: Re: random sorting a collection
- Index(es):
Relevant Pages
|