Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using an interface to support []float64 and []int #7

Closed
montanaflynn opened this issue Oct 16, 2015 · 9 comments
Closed

Using an interface to support []float64 and []int #7

montanaflynn opened this issue Oct 16, 2015 · 9 comments

Comments

@montanaflynn
Copy link
Owner

I have a feeling it might be possible to use an interface to support both []float64 and []int data. However I've not designed Public interfaces or worked around the lack of generics myself so I'll either have to do some research and hacking or have the excellent community of Gophers help in this area or tell me my attempts will be futile. Either way, any feedback is appreciated!

@montanaflynn
Copy link
Owner Author

This will effect #6 if it proves to be a valid strategy.

@Comdex
Copy link

Comdex commented Oct 18, 2015

I think it will be a good idea to support other types, we can transfer a interface param to other type when a method accpet a interface{}

@Kunde21
Copy link
Contributor

Kunde21 commented Oct 20, 2015

Wrapping everything in an interface would require wrapping basic math operations (+,-,/,*) in function calls. Performance would definitely take a hit with this approach. I think it would be more beneficial to implement the interface version separately from the machine types. That way the machine types like float and int can take advantage of the efficient machine instructions for math operations.

Also, a quick suggestion on the interface design: If it's modeled after the math.big package, those arbitrary-precision types are already implemented and that package will likely grow in future releases.

@justinruggles
Copy link

Given the current API, I think it would be quite reasonable to use interface{} for the global package functions and use introspection to check that the passed object is a supported type, which you can define as one of Float64Data, IntData, UInt64Data, BigIntData, or whatever you decide to implement. If the type is not supported, you can return an error. Using a full-on custom interface type with defined math functions as suggested by @Kunde21 is also a possibility, but it seems less useful than supporting slices of different native types.

@montanaflynn
Copy link
Owner Author

Lot's of good ideas and discussion here, I've played around with the idea of introducing interface{} as an argument / return type but never got it right. Ideally, we can do something where we don't have to lower performance to achieve the same benefits, even if that means some code duplication. For instance another idea of I've toyed with is having two packages, one for float64 and another for int.

Here's some code (playground) that demonstrates how to use an interface for both float64 and int data.

There's a few problems with this approach though, for one the interface loses all the benefits of stuff like len(), append(), range, and indexing(data[i]), then when you add them as methods you lose the ability to use regular []float64 or []int because they don't satisfy the interface.

Anyone know around these issues?

type Data interface {
    Get(int) float64
    Len() int
}

type FloatData []float64

func (f FloatData) Get(i int) float64 { return f[i] }
func (f FloatData) Len() int          { return len(f) }

type IntData []int64

func (f IntData) Get(i int) float64 { return float64(f[i]) }
func (f IntData) Len() int          { return len(f) }

func Mean(data Data) (mean float64) {
    for i := 0; i < data.Len(); i++ {
        mean += (data.Get(i) - mean) / float64(i+1)
    }
    return
}

func main() {
    fdata := FloatData{1, 2, 3, 4.20, 5}
    idata := IntData{1, 2, 3, 4, 5}
    fmt.Println(Mean(fdata))
    fmt.Println(Mean(idata))
}

@justinruggles
Copy link

You can just use native type slices and use introspection to see which type was passed in. For the return value it probably makes sense to use float64 for the generic functions and whatever type suits the function for the per-type functions.

@sarathsp06
Copy link

is it active ?

@montanaflynn
Copy link
Owner Author

@sarathsp06 yes, stats supports types through first converting them into float64 with LoadRawData:

https://github.com/montanaflynn/stats/blob/master/examples/main.go#L11

With Go 2 planning to support generics hopefully we can revisit this at that time to truly support native types without the performance hit of reflection or changing them to float64.

@montanaflynn
Copy link
Owner Author

Generics are probably coming this year, so I'll close this issue.

https://blog.golang.org/generics-proposal

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants