Wherefore `from` in LINQ?
-
@Dreikin I have seen and have committed atrocities using Linq.
If you can, it is better to look at the Linq method and see if it assumes an implementation in the Class of a particular Interface.
e.g. Distinct assumes IEquatable is implemented if you don't supply a lambda query to the Distinct Linq query.
Can't find a good example but this stack overflow should give you a good idea
-
@lucas1 said in Wherefore `from` in LINQ?:
@Dreikin I have seen and have committed atrocities using Linq.
If you can, it is better to look at the Linq method and see if it assumes an implementation in the Class of a particular Interface.
e.g. Distinct assumes IEquatable is implemented if you don't supply a lambda query to the Distinct Linq query.
Can't find a good example but this stack overflow should give you a good idea
Yep, I do believe something like that would've got me, expecting the language to do more work than it says it will.
-
@Captain said in Wherefore `from` in LINQ?:
Eric Lippert (the C# and Haskell poobah)
Haskell? Were you thinking of Erik Meijer?
Judging by more recent blog posts, Lippert is now an O'Caml enthusiast.
-
@Bort I'm not sure. I seem to remember Lippert hanging out with SPJ and Meijer when he worked at Microsoft on C# but I could be confused.
-
@Dreikin it worth looking at how things were done pre Linq. Because that is probably what linq is doing in the background.
-
@Captain They're both Eri[c|k]s?
He did a series on monads in which he regularly refers to Haskell, but he never struck me as one of the Haskell people.
-
@Bort argh I remember reading that a while ago
-
@Bort Yes, I'm presumably confused because they're both C# poobahs named Eri(c|k).
Also, Lippert looks like Ted Cruz...
-
@Captain I think he looks more like the Zodiac killer.
-
@lucas1 new language spec for C#
-
@Captain said in Wherefore `from` in LINQ?:
Also, Lippert looks like Ted Cruz...
@lucas1 said in Wherefore `from` in LINQ?:
I think he looks more like the Zodiac killer.
-
@Bort That was kinda the intention. I am normally thinking a few steps ahead.
-
@lucas1 said in Wherefore `from` in LINQ?:
@Bort That was kinda the intention. I am normally thinking a few steps ahead.
ooooohhhh... Checkmate.
-
@Bort I am playing 4d chess everyday. :D
-
@RaceProUK said in Wherefore `from` in LINQ?:
@dkf I'd expect people to pretty quickly figure out that
for (;;) {}
andvar q = for x in y
are very different statements :Pforeach (var thing in for x in y select x.foo){}
TBF, that's pretty horrible whether you use
for
orfrom
-
@Jaloopa I'm gonna pretend I've never written code like that >_>
-
@accalia said in Wherefore `from` in LINQ?:
@Dreikin said in Wherefore `from` in LINQ?:
I'd think that depends on the type of context, no?
tell you what. dake "COS-347 Compiler Architecture and Design" and ask that question again after the final. ;-)
once you know how compilers actually work you'll understand why talk of contextual kewords make the people who know compilers shit their pants.
Or simply build a parser for a serious language, and you'll find that contextual keywords can be done, but they're tricky because you have to be very aware of possibilities for ambiguity. (Fun factoid: this is why C# has the awkward-looking
yield return
statement: generators were added in after the creation of the C# language, and it was quite conceivable that someone would have used the wordyield
as an identifier, such as in financial calculations. Turning it into a keyword would have broken existing code, but because there was no context in which<identifier> return
is valid, they could safely make it a contextual keyword that way.)
-
@PleegWat said in Wherefore `from` in LINQ?:
@Dreikin I think the difference lies in the return value. A
for
loop doesn't have a return value, while afrom
construct doesn't actually get evaluated until the iterator it returns is iterated or flattened. Or am I confusing concepts?It's a bit trickier than that. The
from
expression does get evaluated immediately, and it immediately returns an enumerator. The sequence produced by the enumerator does not get evaluated immediately, though.
-
@masonwheeler said in Wherefore `from` in LINQ?:
Fun factoid
Fun fact, a factiod isn't what people think it is. A factoid is something widely believed but easily proved false. The etymology is "fact like", not "small fact".
Technically, the widely understood definition of Factoid is itself a factoid
-
@masonwheeler said in Wherefore `from` in LINQ?:
@accalia said in Wherefore `from` in LINQ?:
@Dreikin said in Wherefore `from` in LINQ?:
I'd think that depends on the type of context, no?
tell you what. dake "COS-347 Compiler Architecture and Design" and ask that question again after the final. ;-)
once you know how compilers actually work you'll understand why talk of contextual kewords make the people who know compilers shit their pants.
Or simply build a parser for a serious language, and you'll find that contextual keywords can be done, but they're tricky because you have to be very aware of possibilities for ambiguity. (Fun factoid: this is why C# has the awkward-looking
yield return
statement: generators were added in after the creation of the C# language, and it was quite conceivable that someone would have used the wordyield
as an identifier, such as in financial calculations. Turning it into a keyword would have broken existing code, but because there was no context in which<identifier> return
is valid, they could safely make it a contextual keyword that way.)I hope to. I've been taking notes on stuff I'd like to do, but am still on the 'what should it look like?' stage.
Look, I'm not arguing contextual keywords are not hard. I'm not gonna argue that any compiler stuff isn't hard, because I haven't done any of it yet. I'm saying:
- the C# people seem to have so little problem with it that they started with them on the first release, and
- I'm not yet able to find a reason they couldn't have used a different keyword that flows better, or better yet reuse
foreach
to begin LINQ expressions as well.
I'd be interested in hearing something more substantial than "programming things is hard" for why it couldn't be done that way.
For a particular example, is there a reason
@Jaloopa said in Wherefore `from` in LINQ?:
foreach (var thing in for x in y select x.foo){}
couldn't be something like
foreach (var thing in y select thing.foo) {}
-
@Dreikin I think it's because LINQ is implemented (partially) by syntactic translation to lambda expressions, and the
thing
variable isn't in scope of the lambda term doing themapselect. Changing that so that what you want is possible could perhaps be done, but would violate some principles of least surprise elsewhere. It'd also make for more headaches with the implementation, I bet.
-
@Dreikin said in Wherefore `from` in LINQ?:
foreach (var thing in y select thing.foo) {}
That doesn't' seem to make sense. What's your loop variable in the scope of foreach? You're selecting
thing.foo
, but you have no way to refer to it, since you're not assigning it to any variable.Quick exercise:
public class ThingClass { public int foo; } var y = new List<ThingClass> { new ThingClass() { foo = 1 } }; foreach (var thing in y select thing.foo) { //how to get the value of foo here? }
-
@Maciejasjmj said in Wherefore `from` in LINQ?:
@Dreikin said in Wherefore `from` in LINQ?:
foreach (var thing in y select thing.foo) {}
That doesn't' seem to make sense. What's your loop variable in the scope of foreach? You're selecting
thing.foo
, but you have no way to refer to it, since you're not assigning it to any variable.Quick exercise:
public class ThingClass { public int foo; } var y = new List<ThingClass> { new ThingClass() { foo = 1 } }; foreach (var thing in y select thing.foo) { //how to get the value of foo here? }
I was thinking the compiler could reuse
thing
, but yeah, that might not work as well for everyone else as I thought. Hm.select thing.foo as var foo
could work. Tricky sinceas <type>
would be valid, but not, AFAIK,as <type> <name>
. Perhapsas new <type> <name>
, if I wanted to be wordy.Might also make sense for
select
s to only be used for assignment, and loops would leave the projecting to the loop body (i.e, the linq in the loop would be for filtering).Nice point. I think I need to give that particular example more thought.
-
@Dreikin said in Wherefore `from` in LINQ?:
I was thinking the compiler could reuse thing, but yeah, that might not work as well for everyone else as I thought.
So in the loop body
thing
is an integer, but in the select clausething
is aThingClass
by design? That would make for very awkward real-life code:foreach (var index in objectsWithIndices select /*wtf? my index has an index?*/ index.index)
@Dreikin said in Wherefore `from` in LINQ?:
select thing.foo as var foo could work.
foreach (var obj in objectsWithIndices select obj.index as var index)
Hm... it doesn't look right. In "standard" foreach the first declaration from the left is the iteration variable, but in this syntax it's a lambda parameter.
-
@Maciejasjmj said in Wherefore `from` in LINQ?:
@Dreikin said in Wherefore `from` in LINQ?:
I was thinking the compiler could reuse thing, but yeah, that might not work as well for everyone else as I thought.
So in the loop body
thing
is an integer, but in the select clausething
is aThingClass
by design? That would make for very awkward real-life code:foreach (var index in objectsWithIndices select /*wtf? my index has an index?*/ index.index)
@Dreikin said in Wherefore `from` in LINQ?:
select thing.foo as var foo could work.
foreach (var obj in objectsWithIndices select obj.index as var index)
Hm... it doesn't look right. In "standard" foreach the first declaration from the left is the iteration variable, but in this syntax it's a lambda parameter.
linq doesn't require
var
for the firstthing
. That could solve the "first declaration from the left" thing, but only in terms.This is why I'm thinking that having
foreach
loops look more likeforeach (thing in y where thing.foo > 10) { // select-like ops here. }
might be better*, with assignment still as
var z = foreach thing in y select thing.foo;
do
is a keyword, but it starts ado...while()
loop, so I'm not sure whether this would also be possible:foreach thing in y where thing.foo > 10 do { // select-like ops here }
I'm thinking
do
can't occur in that position currently, but I'd have to check the spec to be sure.It separates pretty well. There's a core section (
foreach ...
) that is then used for assignment viaselect
, or looping viado
.Interesting..
*: I'm assuming there's other stuff in the loop that justifies not just using
select
in the first place.
-
@accalia said in Wherefore `from` in LINQ?:
Contextually relevant keywords are hell for compilers.
Uncontextually irrelevant keywords: https://github.com/golang/go/blob/go1.7.3/src/cmd/compile/internal/gc/lex.go#L610-L615
-
@Dreikin I think I'd prefer something like
for obj in objects select obj.name using name { ... }
-
@PleegWat said in Wherefore `from` in LINQ?:
@Dreikin I think I'd prefer something like
for obj in objects select obj.name using name { ... }
Ooh, I like that one.
-
@PleegWat Kinda looks like keyword soup to me. But then LINQ query comprehension syntax tends to look like that anyway.
-
@RaceProUK said in Wherefore `from` in LINQ?:
But then
LINQquery comprehension syntax tends to look like that anyway.The problem is people trying to graft things in without saying either that they'll stay with the syntax that they're starting with, or going to a wholly new syntax that they're embedding. Because it's a frankenlanguage, there's a few places where the bolt in its neck insists on showing through…
-
@dkf said in Wherefore `from` in LINQ?:
Because it's a frankenlanguage, there's a few places where the bolt in its neck insists on showing through…
Some languages don't really try to hide it (<cough>C++</cough>).
-
@dkf Yeah, I'm not fond of it either, conceptually. The closest I get is running SQL statements from my C code, so I probably don't have right to talk, but I'd prefer the approach that still looks like function invocation because the interplay with 'normal' code is much clearer.
-
@PleegWat said in Wherefore `from` in LINQ?:
I'd prefer the approach that still looks like function invocation because the interplay with 'normal' code is much clearer.
I'm quite fond of outright embedding of another language. It does require being able to read both, but it lets you use each language for the things that it does best. It's not just SQL that can benefit from this; specialist mathematical languages can also be very good candidates for this sort of thing. Even in C you've got embedding of assembler for doing the particularly tricky bits.
-
@dkf There's that. One of the things that frustrates me in SQL is that you're saying what you want done, not how, and oracle isn't too good at finding the best way to get you your results.
-
@PleegWat said in Wherefore `from` in LINQ?:
oracle
-
@dkf Well, nothing to be done about that. And we started out on mysql before the acquisition and that had its own problems.
-
@RaceProUK said in Wherefore `from` in LINQ?:
you can't mutate a collection being iterated
Seems like a pretty easy thing for the compiler to magic away.
-
@xaade said in Wherefore `from` in LINQ?:
Seems like a pretty easy thing for the compiler to magic away.
In what sense? It's semantically complicated to say the least, depending on the underlying model of what is being iterated over (linked lists are different to hash tables and both are different to balanced trees) and after a lot of hard-won experience, compilers now only do relatively safe optimisations. Iterators are simply non-trivial from the perspective of the compiler, though a particular iterator of a particular collection might be fairly simple…
-
@dkf said in Wherefore `from` in LINQ?:
@xaade said in Wherefore `from` in LINQ?:
Seems like a pretty easy thing for the compiler to magic away.
In what sense? It's semantically complicated to say the least, depending on the underlying model of what is being iterated over (linked lists are different to hash tables and both are different to balanced trees) and after a lot of hard-won experience, compilers now only do relatively safe optimisations. Iterators are simply non-trivial from the perspective of the compiler, though a particular iterator of a particular collection might be fairly simple…
Something like copy-on-write semantics, I think was the gist of the suggestion. I suppose if you define the language or library right, that could work even when more than just the local area has a reference to the structure. As one example:
- Iterate over original collection generating a copy as you go if something tries to mutate the original.
- Replace internal/private reference in original collection with new structure when finished.
...assuming you could prove there were no undesired/potentially-problematic side-effects to doing that. Other ways could include doing basically the same thing, but returning the reference rather than reassigning an internal/private collection property, and automatically creating a new variable to hold it and take the place of the original token from that point on.
E.g.,
var collection = new HashSet<string> { "hello", "world", "!" }; foreach (var token in collection) { collection.Remove(token); collection.Add(token.ToUpper()); } return collection;
Could translate to
var collection = new HashSet<string> { "hello", "world", "!"}; var new_collection = new HashSet<string>(); foreach (var token in collection) { new_collection.Add(token.ToUpper()); } collection = new_collection;
-
@Dreikin said in Wherefore `from` in LINQ?:
copy-on-write semantics
It makes the implementation rather more complicated though, since pure copy-on-write is actually quite expensive in terms of memory allocations (which are usually the most expensive operations in a program short of talking to the OS). I know this because I've implemented CoW data structures; the costs of a copy are non-trivial and need to be avoided where possible…
-
@dkf said in Wherefore `from` in LINQ?:
I'm quite fond of outright embedding of another language.
This way madness and Boost::Spirit lies.
-
@Dreikin said in Wherefore `from` in LINQ?:
Iterate over original collection generating a copy as you go if something tries to mutate the original.
Replace internal/private reference in original collection with new structure when finished.But the point of modifying the collection in the
foreach
is generally to have access to the modified collection in theforeach
. I struggle to find a good example that can't be rewritten into something that a) doesn't require the magic, and b) is much more obvious as to what's actually happening.Yours is much better expressed as:
var collection = new HashSet<string> { "hello", "world", "!" }; collection = new HashSet<string>(collection.Select(token => token.ToUpper()));
-
@Maciejasjmj That's just what he's doing. There's some missing information on why he's doing it (I know, I know, it's an example). Why are we taking one in-memory data set and converting it into a different one in the first place?
-
@PleegWat said in Wherefore `from` in LINQ?:
Why are we taking one in-memory data set and converting it into a different one in the first place?
In a real example, it's because the creation and modification are actually separated by quite a lot of other code.
-
Something to consider:
-
@lucas1 said in Wherefore `from` in LINQ?:
Something to consider:
They should've still thrown it in, if only to prevent
Select()
being abused in strange ways to achieve something similar.
-
@Maciejasjmj I seen the same in JS. Is is shit code is the job gets done?
-
@lucas1 said in Wherefore `from` in LINQ?:
Is is shit code is the job gets done?
Is the code not shit just because it works?
-
@Maciejasjmj If it fulfils requirements than no.
I am sure I've got a book packed away that addresses this. Btw written by my lecturer.
-
@lucas1 said in Wherefore `from` in LINQ?:
@Maciejasjmj If it fulfils requirements than no.
I am sure I've got a book packed away that addresses this. Btw written by my lecturer.
A good mindset to get yourself a front page feature, that's for sure.