Skip to content
This repository has been archived by the owner on Sep 20, 2022. It is now read-only.

invalid operation: operator + not defined for ... (variable of type T) #21

Closed
thewizardplusplus opened this issue Jun 21, 2018 · 2 comments

Comments

@thewizardplusplus
Copy link

Why doesn't this code work?

https://play.folang.org/p/BAoAfXkEfwH

package main

import "fmt"

func Sum[T](slice []T) T {
	var sum T
	for _, item := range slice {
		sum += item
	}

	return sum
}

func main() {
	numbers := []int{1, 2, 3, 4, 5}
	sum := Sum[int](numbers)
	fmt.Println(sum)
}

It outputs: main.go:8:3: invalid operation: operator + not defined for sum (variable of type T).

@albrow
Copy link
Owner

albrow commented Jun 22, 2018

The compiler is behaving as intended (although the error message in the Playground should arguably read "main.fo" instead of "main.go").

When you write a generic function, it means that any type can be substituted in place of the type parameters. In your case, Sum is a function which accepts a slice of any type T. The += operator does not work for every type, so this is an error in the function definition.

What you probably want to do is constrain the type parameter in Sum so that it only accepts types which work with the += operator. This is not possible in Fo right now, but you can see #11 for a discussion of how this might work in the future.

There are two main routes we could take. One is that Fo will come with a predefined sum type called numeric which consists of all built-in numeric types (int, uint, float64, etc). In this case, you could rewrite the function with a type constraint on T:

func Sum[T numeric](slice []T) T {
	var sum T
	for _, item := range slice {
		// Since T must be a member of the numeric type, we know the += operator will work.
		sum += item
	}

	return sum
}

The other route is that we don't define a numeric type (and possibly don't allow sum types to be used as constraints, only interfaces). In this case, you would need to use wrapper types such as Int, Uint, Float32, etc. which have an Add method defined. You would then need to define an Adder interface which consists of a single method Add (or import an existing definition). Constraining the parameter T so that it must satisfy the Adder interface would look like this:

func Sum[T Adder](slice []T) T {
	var sum T
	for _, item := range slice {
		// Since T must be of type Adder, we know that it has an Add method.
		sum = sum.Add(item)
	}

	return sum
}

@albrow
Copy link
Owner

albrow commented Jun 22, 2018

@thewizardplusplus I'm going to close this. If you want to contribute to the discussion about type constraints in general, please do so on #11. If you have any other questions about your specific example, feel free to ask here on this issue.

@albrow albrow closed this as completed Jun 22, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants