LINQ for Go

1,700 views
Skip to first unread message

Ahmet Alp Balkan

unread,
Jan 4, 2014, 12:31:50 AM1/4/14
to golan...@googlegroups.com
Hi folks,

After reading number of historical threads in this group about how unsuitable Go is for something like LINQ (language integrated query) since there are no generics and lambdas, I funnily decided to do this anyway –and it is finally here. This is my first project in Go. Please check it out:


The library provides methods to query and manipulate objects in in-memory slices, inspired by Microsoft's LINQ library. There are similar projects for Go like fn and gen where one is functional tools and other provides LINQ-like functionality with code generation for type safety, respectively. Here are highlights about what I have built:

* DRY: If your code has a significant SQL-like operations for in-memory objects, this library might help you to do not repeat yourself.
* Accepts slices of any type: There's a reflection hack makes this possible.
* No type safety: You have to make assertions to the type you expect in all predicate/selector functions. Type assertion makes it just a bit slower. Also, need to have 100% code coverage for LINQ code you are writing.
* Parallelization: I implemented PLINQ (parallel linq) using goroutines. So this actually might have a real use in Go projects. There's an example in the wiki about this.
* Strict error handling: Since queries may involve IO operations or calls to other packages, you will see a lot of error parameters here and there. It makes things a lot uglier but Go-ish. I am looking for ways to reduce it without restricting users any further on strict error handling.
* Hard to debug: Since you will end up a query method chain like From().Where().Select().Count(), any error occurred during the query will be returned at the very end propagating through all the methods in the rest of the chain. But it's the same case in .NET anyways, I kept this approach as-is.

I call it v0.9 at this point and I believe you guys might kindly provide some feedback to improve it. It also seems to me like such project has no place in Go ecosystem but a day might come where we can have generics (or even lambdas) and then there will be people who can make use of this library. However, current state of Go is not making things any easier for such type of programs, I suppose there is no harm in doing this project and my motivation was to be just make something useful out of my time.

There are already a few kind tweets about it:

So, I appreciate your feedback, contributions and stars.

Regards,
Alp.

p.s. you might say it's not really 'language integrated' but Microsoft uses the term LINQ for method syntax as well. 

Andrew Gallant

unread,
Jan 4, 2014, 2:14:25 AM1/4/14
to golan...@googlegroups.com
You may be able to improve error messages (for type errors) with https://github.com/BurntSushi/ty (I am the author).

- Andrew

Ibrahim M. Ghazal

unread,
Jan 4, 2014, 3:41:51 AM1/4/14
to Ahmet Alp Balkan, golang-nuts
Minor nitpick: putting the dot on a new line doesn't work because of
Go's semicolon-insertion.

So in <http://ahmetalpbalkan.github.io/go-linq/> :

results, err := From(students)
.Where(func (s T) (bool, error){

Should really be:

results, err := From(students).
Where(func (s T) (bool, error){

Ahmet Alp Balkan

unread,
Jan 4, 2014, 3:49:17 AM1/4/14
to Ibrahim M. Ghazal, golang-nuts
Oops, entirely my bad, I just written the whole thing in HTML without ever gofmting. Fixed now. Thanks.

– Alp.

Donovan Hide

unread,
Jan 4, 2014, 8:01:55 AM1/4/14
to Ahmet Alp Balkan, Ibrahim M. Ghazal, golang-nuts
Who needs generics :-)

I will be using this! Well done!


--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Ahmet Alp Balkan

unread,
Jan 4, 2014, 1:06:55 PM1/4/14
to Andrew Gallant, golang-nuts
Thanks Andrew, I will definitely check this out.

Best,
– Ahmet Alp.

--
You received this message because you are subscribed to a topic in the Google Groups "golang-nuts" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/golang-nuts/nLwWkoS7Bh8/unsubscribe.
To unsubscribe from this group and all its topics, send an email to golang-nuts...@googlegroups.com.

jimmy frasche

unread,
Jan 4, 2014, 2:19:11 PM1/4/14
to Ahmet Alp Balkan, Andrew Gallant, golang-nuts
Instead of taking funcs whose parameters are interface{} you could
take an interface{} and use reflection to dynamically type check that
it's a func of the correct signature or even allow some variations of
the func allowed, like making error optional.

If you use reflection throughout your quickstart example could be

var students []*Student
var over18names []string
//set students
err := linq.From(students).
Where(func(s *Student) bool { //we know this has to be *Student
from the type of students
return s.age >= 18
}).
Select(func(s *Student) string {
return s.name
}).
Results(&over18names) //we know this has to be []string from the
return value of the func in Select

Having to go through reflect will make the function call overhead
greater but you can skip copying everything into a []interface{}, but
if you cared about speed you'd just write:

var over18names []string
for _, s := range students {
if s.age >= 18 {
over18names = append(over18names, s.name)
}
}

Ahmet Alp Balkan

unread,
Jan 4, 2014, 2:29:27 PM1/4/14
to jimmy frasche, Andrew Gallant, golang-nuts
Thanks Jimmy, great suggestions indeed. I started prototyping Query.Results(*slice) approach myself a few days ago but still having a few problems with it I am hoping to solve.

Converting function signatures to interface{} could make things really messy for users since there are 3 types of functions taken as parameters (takes object returns bool, takes object returns another, takes 2 objects return bool by comparing) throughout the library. Also the package documentation would be pretty much unreadable without examples and usage will be more prone to errors.

Yes it'll bring features like optional error handling. Once I start creating several benchmarks for the package, I will start another branch for this and see how it slows down things since calls to the input functions will be through reflection for every single element of slice, which will be as you said, costly.

Thanks,
-Alp

jimmy frasche

unread,
Jan 4, 2014, 2:38:04 PM1/4/14
to Ahmet Alp Balkan, Andrew Gallant, golang-nuts
On Sat, Jan 4, 2014 at 11:29 AM, Ahmet Alp Balkan
<ahmetal...@gmail.com> wrote:
> Thanks Jimmy, great suggestions indeed. I started prototyping
> Query.Results(*slice) approach myself a few days ago but still having a few
> problems with it I am hoping to solve.

What problems were you having?
Message has been deleted

nafiy...@gmail.com

unread,
Jan 29, 2014, 1:43:10 AM1/29/14
to golan...@googlegroups.com

4 Ocak 2014 Cumartesi 07:31:50 UTC+2 tarihinde Ahmet Alp Balkan yazdı:
Reply all
Reply to author
Forward
0 new messages