Coder Social home page Coder Social logo

Comments (14)

ahmetb avatar ahmetb commented on August 24, 2024 5

Generics proposal is now accepted.
This will be interesting. 😇

from go-linq.

ahmetb avatar ahmetb commented on August 24, 2024 4

If getting rid of type-agnostic From() and leaving the FromXxx, that’s worth pursuing.

from go-linq.

szmcdull avatar szmcdull commented on August 24, 2024 4

Hi, i made myself an early and naive one here https://github.com/szmcdull/glinq. Would you have a try?

from go-linq.

StevenACoffman avatar StevenACoffman commented on August 24, 2024 4

@ahmetb Have you considered using Facilitators to mitigate the limitation of having no generic parameterized methods? See https://rakyll.org/generics-facilititators/

from go-linq.

ahmetb avatar ahmetb commented on August 24, 2024 3

So I tried to imitate what From..Where..Select.. sort of thing would work.
Each Where/Select/... would have different type parameters:

type Array[K any] []K

func (a Array[K]) Print[V any](v V) {
	for _, i := range a {
		fmt.Printf("%v-%v\n",i,v)
	}
}

However this is not supported by design. https://go.googlesource.com/proposal/+/refs/heads/master/design/go2draft-type-parameters.md#methods-may-not-take-additional-type-arguments

from go-linq.

ahmetb avatar ahmetb commented on August 24, 2024 3

Based on my last experimentation, Go generics unfortunately isn't advanced enough to support this by design.

But I also encourage others to try Select().Order() where each method takes a generic type and returns another generic type processed further down the chain.

from go-linq.

ahmetb avatar ahmetb commented on August 24, 2024 2

@StevenACoffman sadly the main problem with Go generics is the chaining won't work the way we currently have in this library. If you look at @szmcdull's glinq library, the chaining goes Any(Where(FromSlice(... (versus what we have today is FromSlice().Where().Any(). As method chaining becomes sophisticated, nested method approach is hard to read and reason about.

I am yet to see a feasible way to achieve the chaining approach we currently have with Go generics.

In the meanwhile, other libraries like lo that aren't fully linq (but offers small helpers) has emerged in the ecosystem. But the reason I insist not going the Go generics route is that I want to preserve the existing way of chaining LINQ methods as this library strives to be close to .NET LINQ in terms of look and feel.

from go-linq.

cleitonmarx avatar cleitonmarx commented on August 24, 2024 1

Here is another try, more complex and playing around with the From function for slices, maps, channels and strings. We need to have a constructor for each type: https://gotipplay.golang.org/p/wUTln-sObFy

from go-linq.

cleitonmarx avatar cleitonmarx commented on August 24, 2024

Here is my first try and keeping the go-linq original design: https://go2goplay.golang.org/p/gH50GCy32S7
Thoughts?

package main

import (
    "fmt"
)

type Query(type T) struct {
    Iterate func() func() (T, bool)
}

func From(type T)(source []T) Query(T) {
    len := len(source)

    return Query(T){
        Iterate: func() func() (T, bool) {
            index := 0
            return func() (item T, ok bool) {
                ok = index < len
                if ok {
                    item = source[index]
                    index++
                }
                return
            }
        },
    }
}

func (q Query(T)) Where(predicate func(T) bool) Query(T) {
    return Query(T){
        Iterate: func() func() (T, bool) {
            next := q.Iterate()
            return func() (item T, ok bool) {
                for item, ok = next(); ok; item, ok = next() {
                    if predicate(item) {
                        return
                    }
                }
                return
            }
        },
    }
}

func (q Query(T)) ToSlice() (r []T) {
    next := q.Iterate()

    for item, ok := next(); ok; item, ok = next() {
        r = append(r, item)
    }
    return
}

func main() {
    sliceInt := []int{1, 2, 3, 4, 5}
    sliceInt = From(sliceInt).
        Where(func(i int) bool {
            return i < 4
        }).ToSlice()

    fmt.Println("Int:", sliceInt)

    sliceStr := []string{"a", "b", "c", "d", "e"}
    sliceStr = From(sliceStr).
        Where(func(i string) bool {
            return i < "d"
        }).ToSlice()

    fmt.Println("Str:", sliceStr)
}

from go-linq.

ahmetb avatar ahmetb commented on August 24, 2024

That’s a good start. I didn’t think a whole lot about this. But in this example basically seems the whole chain works only on the initial type provided. What if we say From(ints) but the result of the chain returns []string?

If there was a way to instruct certain methods such as ForEach<int,string>(ints) that could return []string that would be nice. I suspect that doesn’t exist. So that makes me wonder if we need to integrate with generics at all.

from go-linq.

cleitonmarx avatar cleitonmarx commented on August 24, 2024

What if we say From(ints) but the result of the chain returns []string?

The proposed way will probably be a breaking change in the library. All projection methods that convert a type to another should be declared as a constructor function passing the source query as a parameter. In .NET, the extension methods make the syntax easier.

https://go2goplay.golang.org/p/CFQH-AKIfCU

package main

import (
	"fmt"
	"strconv"
)

type Query(type T) struct {
	Iterate func() func() (T, bool)
}

func From(type TSource)(source []TSource) Query(TSource) {
	len := len(source)
	return Query(TSource){
		Iterate: func() func() (TSource, bool) {
			index := 0
			return func() (item TSource, ok bool) {
				ok = index < len
				if ok {
					item = source[index]
					index++
				}
				return
			}
		},
	}
}

func Select(type TSource, TResult)(q Query(TSource), selector func(TSource) TResult) Query(TResult) {
	return Query(TResult){
		Iterate: func() func() (TResult, bool) {
			next := q.Iterate()
			return func() (item TResult, ok bool) {
				var it TSource
				it, ok = next()
				if ok {
					item = selector(it)
				}
				return
			}
		},
	}
}

func (q Query(T)) Where(predicate func(T) bool) Query(T) {
	return Query(T){
		Iterate: func() func() (T, bool) {
			next := q.Iterate()
			return func() (item T, ok bool) {
				for item, ok = next(); ok; item, ok = next() {
					if predicate(item) {
						return
					}
				}
				return
			}
		},
	}
}

func (q Query(T)) ToSlice() (r []T) {
	next := q.Iterate()

	for item, ok := next(); ok; item, ok = next() {
		r = append(r, item)
	}
	return
}

func main() {
	sliceStr := []int{1, 2, 3, 4, 5}
	sliceInt := Select(
		From(sliceStr).Where(func(i int) bool { return i < 4 }),
		strconv.Itoa,
	).ToSlice()

	fmt.Println("Select:", sliceInt)
}

from go-linq.

ahmetb avatar ahmetb commented on August 24, 2024

That's excellent. So we can do that after all I guess. Which part of the code you're referring to by "constructor"?

from go-linq.

cleitonmarx avatar cleitonmarx commented on August 24, 2024

What I meant was, this kind of implementation would not be possible:

func From(source interface{}) Query {
	src := reflect.ValueOf(source)

	switch src.Kind() {
	case reflect.Slice, reflect.Array:
		return FromSlice(...)
	case reflect.Map:
		return FromMap(...)
	case reflect.String:
		return FromString(...)
	case reflect.Chan:
		return FromChannel(...)
	default:
		return FromIterable(...)
	}
}

We would need to use the specific "Query constructor" function in each particular type.

from go-linq.

metalrex100 avatar metalrex100 commented on August 24, 2024

@ahmetb are there any plans to still try to implement this lib with generics since go 1.18 beta has been released?

from go-linq.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.