
Java LINQ – C# LINQ examples running on Android - mythz
https://github.com/mythz/java-linq-examples/blob/master/README.md
======
mythz
Something that stands out here is Java's reluctance to add proper Type
Inference, which particularly stands out in linq43:

[https://gist.github.com/mythz/7e263820332a0fcea766](https://gist.github.com/mythz/7e263820332a0fcea766)

What's interesting was that Type Inference was actually considered and
rejected because it was considered "un-Java Like"
[http://programmers.stackexchange.com/a/184183/14025](http://programmers.stackexchange.com/a/184183/14025):

> Humans benefit from the redundancy of the type declaration in two ways.
> First, the redundant type serves as valuable documentation - readers do not
> have to search for the declaration of getMap() to find out what type it
> returns. Second, the redundancy allows the programmer to declare the
> intended type, and thereby benefit from a cross check performed by the
> compiler.

With "Humans Benefit" cited as the rationale, which seems to contradict the
behavior in IntelliJ IDE's which _automatically collapses_ boiler-plate code
into a "typeless lambda format" of what the source code would've looked like
if Java had lambdas.

~~~
benjiweber
To be fair a lot more type inference is done in Java 8 (it's not just
lambdas), it's just not available for Android.

And Java tends to do type inference on the right hand side instead of the left
hand side, so things look a lot cleaner if you chain them instead of assigning
them to intermediate variables.

~~~
mythz
> And Java tends to do type inference on the right hand side instead of the
> left hand side, so things look a lot cleaner if you chain them instead of
> assigning them to intermediate variables.

This example _is_ chained, i.e. there are no intermediate variables.

~~~
benjiweber
The customers and customerOrderGroups are intermediate.

I would expect in reality to do something like this in Java 8 (Disclaimer
probably not exactly correct syntax, not near a Java compiler)

    
    
      getCustomerList()
        .map(c -> tuple(
          c.companyName,
          c.orders.stream()
            .collect(groupingBy(order -> order.orderDate.year)).entrySet().stream()
            .map(yearGroup -> tuple(
              yearGroup.key, 
              yearGroup.items.stream().collect(
                groupingBy(order -> order.orderDate.getMonth() + 1)
              )
            ))
        .forEach(Log::print)
    
    

Further it looks like we should probably have domain types for
MonthGroup/OrderGroup etc instead of tuples, which would make it still cleaner

~~~
mythz
> The customers and customerOrderGroups are intermediate.

The `customers` and `customerOrderGroups` are variables in _each of the
examples_. Which is the point of a close 1:1 translation between different
languages. linq43 groups Customer Orders in a _single expression_ by
Year/Month into an anonymous structure. This just doesn't translate very well
to Java 7 which lacks many of the language features to make it more readable.

Of course it can be rewritten using Java 8 streams which is much better suited
for functional programming courtesy of lambda's (which is the primary cause
for much of the boiler-plate). But until it's supported in Android we have to
make do with what we have.

\----

Should also give a shout-out to RetroLambda which I just discovered in the
comments:
[https://github.com/orfjackal/retrolambda](https://github.com/orfjackal/retrolambda)

Which looks like it's a post-build Maven and Gradle plugin to back port Java 8
features to be able to run on Java 7 Android and JVM runtime. Not sure if
there are any disadvantages with this approach (debugging?) but it's an
interesting alternative.

Another option would be to just use a different JVM language, Kotlin looks the
most appealing to me which supports Android and has good Java
interoperability: [http://kotlinlang.org/docs/tutorials/kotlin-
android.html](http://kotlinlang.org/docs/tutorials/kotlin-android.html)

~~~
benjiweber
Yes Kotlin seems like a very nice option for Android.

One could also go for implementing a more Linq-esq style in Java. Something
like [http://benjiweber.co.uk/blog/2013/12/28/typesafe-database-
in...](http://benjiweber.co.uk/blog/2013/12/28/typesafe-database-interaction-
with-java-8/) could be implemented on top of collections as well as databases.

------
inglor
Just because they can translate doesn't mean it's good. If you check out this
example: [https://github.com/mythz/java-linq-
examples/blob/master/READ...](https://github.com/mythz/java-linq-
examples/blob/master/README.md#linq19-selectmany---indexed) it converts 6
lines of readable C# to 20 lines of bad formed Java. It would be a lot nicer
to see a Java 8 translation - a lot more comparable.

~~~
mythz
Right, but Java 8's not available on Android which is a constraint for this
library.

If that's "bad-formed Java" what's a better functional form? Or do you mean
for Java it's better to use an imperative-style with mutating collections?

~~~
jameshart
It's better to write code that is amenable to being understood when read.
These Java forms accomplish things 'the LINQ way' but at the expense of
completely obscuring the intent of the code. LINQ makes sense in C# because
the syntax supports a mapping from a declarative query to stream-oriented
operations. Without the syntactic support, it becomes unreadable.

~~~
tracker1
I usually prefer the chaining method extensions for collections myself... Even
then it's far easier to follow than the Java examples, or even the Java8
comments... but that's mostly personal preference. I'm also not sure how/if
this has an IQueryable interface equivalent, which is pretty cool as well.

------
tracker1
Wow, that just looks hideous... at first I was hoping this was some kind of
Java preprocessor for linq constructs... but it's just plain ugly.. it's even
worse than the method chaining you can do in C# with lambdas, which I prefer
over linq syntax...

    
    
        var result = someEnumerable.Select(x => x.Bar < 5).ToList()
    

Still a lot cleaner than the type specific mess in the examples... I think
sticking to for-loops is probably cleaner than that mess.

I don't mean to be critical here, it's just I don't think it's really any
better than without the "LINQ" for Java in this case.

------
vtman2002
this has a nicer syntax IMHO:
[https://github.com/keredson/DKO](https://github.com/keredson/DKO)

~~~
tracker1
Thank you.. that definitely is a much nicer syntax, and closer to C#'s method
chaining.

------
otis_inf
> linq102: Cross Join

I think it's an inner join, not a cross join. SelectMany() produces a cross
join.

------
revelation
Yes, it's all perfectly Turing compatible, of course we can also do that on
Android.

That is also totally not the point.

~~~
mythz
Most Developers don't care if an academic turing-complete brainfuck can be
made to run on Android, they care if they're able to be more productive and
create more readable and maintainable code.

Running on Android was a constraint for this library, the natural approach to
functional programming in Java 8 would've been to use Java 8's new stream API,
but as that's not available on Android we fallback to using what currently
does work on Android - which _is_ the point of this library.

------
gosukiwi
Java is such a boring not-elegant language.

~~~
616c
$LANGUAGE_I_HATE is $CRITIQUE_1 and CRITIQUE_2.

And I know, I know, bash is even less elegant and more boring. Haha.

~~~
616c
You know, I am pretty impressed I got down-voted. Every time I see someone
mock Java or PHP around here, people are quick to point out no language is
perfect and personal biases are not great for reasoned discussioned. I thought
there was no perfect language?

C is also boring, but I assumed mocking it here would be asking for free kicks
to the face. Apparently, I was wrong.

------
batou
Not a great fan of LINQ if I'm honest. Sure it's terse and powerful but with
it comes great responsibility and a relatively large pile of tasty landmines.
Three regular problems I see:

FirstOrDefault being passed 2 rows = non-determinism. This one is always fun
when your SQL server doesn't guarantee the order of rows returned so every
time you hit .FirstOrDefault you get a different item. Never happens in dev
due to the tiny datasets fitting in a single page.

There's also Single being passed 2 rows = crash. SingleOrDefault being passed
>1 rows = crash.

And when it does crash it's entirely not helpful because the lambda block
reports no state information in the stack. Inevitably this leads to adding
precondition checks to avoid "Hey everyone, one of the 20 LINQ expressions in
this method blew with more than one element in the sequence".

Then there's the fact that you don't know the size of the set of data nor
really think about it. So if someone passes in a collection of 10 rows in dev
and it works out that it's O(N^2) and has a random .ToList() in it then you're
up shit creek in the memory and time departments when that 10000 items
collection appears in production.

None of this unique to LINQ but it hides a lot of problems behind a wall of
pain.

From extensive experience; there be dragons.

~~~
curveship
With all respect, it doesn't sound like you've taken the time to understand
LINQ:

\- Single and SingleOrDefault crashing with >1 row is a feature, not a bug. It
means that your expectation that your filter is unique was incorrect. In that
scenario, a crash is what you want. It's like when we use asserts. Similarly
..

\- First and FirstOrDefault are only really appropriate after an OrderBy, i.e.
to get the top item of a particular ranking. Using them anywhere else is
almost always incorrect, and in the very few cases where it isn't, needs a
comment to explain why, or I'll bounce your code back to you in review :).

LINQ is very expressive (you can do a lot with a little bit of code),
especially with the embedded (non-fluent) syntax. That means that, yes, you
can write some non-optimal code without realizing it, because it's only a few
lines. On the flip side, you can also refactor that code quickly into more
optimal patterns. By comparison, old-school iterating through collections is
often much more difficult to refactor.

~~~
batou
I understand LINQ very well (right down to code generation and expression
trees) but unfortunately I work with a lot of other people's code.

Perhaps that is the problem? :-)

More seriously, the thing has really leaky abstraction boundaries which is a
main pain point. I have to write and manage a lot of boring enterprise code
and creativity and expressiveness go a long way to introducing a lot of
additional work.

~~~
nlawalker
LINQ is not where the leaky abstraction is, IEnumerable is. IEnumerable makes
virtually no guarantees about anything, including order, finiteness, side
effects and speed/efficiency.

This is actually one of the main reasons that the BCL team introduced the
IReadOnlyXXX<> interfaces - over the years, many .NET developers trying to do
the right thing and express intent in their code had taken to using
IEnumerable<> in method signatures to signify that the method would not modify
the list/collection... but an IEnumerable doesn't have to be a
list/collection, it can be infinite! In trying to do the right thing and be
expressive with intent, lots and lots of people were unwittingly losing the
expression of another (very important) assumption.

Any time you are wrangling any kind of enumerable in code, you _have_ to think
about its guarantees and assumptions. LINQ's expressiveness might make it
easier to forget this but it's still the rule - if I hand you a "malicious
IEnumerable", it doesn't matter if you use LINQ or a couple of foreach loops,
it's going to launch the missiles on every call to MoveNext() regardless.

If you are trying to express intent in your code, IEnumerable is almost
_never_ what you want to use.

