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

proposal: spec: add structfield type and syntax to directly access a structs structfield #70564

Open
codeliger opened this issue Nov 25, 2024 · 4 comments
Labels
LanguageChange Suggested changes to the Go language LanguageChangeReview Discussed by language change review committee Proposal
Milestone

Comments

@codeliger
Copy link

codeliger commented Nov 25, 2024

Proposal Details

Problem:

I want to write generic functions without manually rewriting functions for each struct field i am comparing.

Would you consider yourself a novice, intermediate, or experienced Go programmer?

  • Intermediate

What other languages do you have experience with?

  • Python, C#, Java, PHP, Lua, Javascript

Would this change make Go easier or harder to learn, and why?

  • It should have no effect for beginners

Has this idea, or one like it, been proposed before?

  • I couldn't find anything similar

Who does this proposal help, and why?

  • Anyone who wants to write less code to do more

What is the proposed change?

  • Add a structfield type
  • Add some sort of syntax (ex: "..") to statically access the structfield of a struct
  • May need to add a struct type for the structfield[S struct] syntax. I don't think any would work in the definition.

Is this change backward compatible?

  • Most likely because it only adds functionality

Show example code before and after the change.

Current state of Go:

type User struct {
	FirstName string
	LastName  string
	Email     string
}

func UserByFirstName(users []User, firstName string) User {
	index := slices.IndexFunc(users, func(user User) bool {
		return user.FirstName == firstName
	})
	if index == -1 {
		return User{}
	}
	return users[index]
}

func UserByLastName(users []User, lastName string) User {
	index := slices.IndexFunc(users, func(user User) bool {
		return user.LastName == lastName
	})
	if index == -1 {
		return User{}
	}
	return users[index]
}

func UserByEmail(users []User, email string) User {
	index := slices.IndexFunc(users, func(user User) bool {
		return user.Email == email
	})
	if index == -1 {
		return User{}
	}
	return users[index]
}

Proposed go code:

type User struct {
	FirstName string
	LastName  string
	Email     string
}

func UserBy[V any](users []User, field structfield[User], value V) User {
	index := slices.IndexFunc(users, func(u User) bool {
		return user.(field) == value
	})
	if index == -1 {
		return User{}
	}
	return users[index]
}

func By[S any, V any](items []S, field, structfield[S], value V) S {
	index := slices.IndexFunc(items, func(item S) bool {
		return item.(field) == value
	})
	if index == -1 {
		return S{}
	}
	return items[index]
}

func main() {
	users := []User{} // imagine long list of users

	user1 := UserBy(users, ..User.FirstName, "Bob")
	user2 := UserBy(users, ..User.Email, "[email protected]")

	user3 := By(users, ..User.Email, "[email protected]")

        // zero valued struct checking omitted
}

What is the cost of this proposal? (Every language change has a cost).
How many tools (such as vet, gopls, gofmt, goimports, etc.) would be affected?

  • All of the tools that involve syntax parsing and highlighting

What is the compile time cost?

  • Relatively small, and prevents the need to use reflect at runtime, or AST and //go:generate meta programming

What is the run time cost?

  • Less runtime cost than static compile cost

Can you describe a possible implementation?

  • I have not worked with C or contributing to the go language itself.

How would the language spec change?

  • The compiler would need to understand that ..User.FirstName refers to the FirstName field of the User struct.
  • Extend the concept of methods to include operations on structfield types. For example, allowing == to work with structfield to compare field values.
  • Ensure that accessing non-existent fields results in compile-time errors or runtime panics, similar to how Go handles other errors.

Orthogonality: how does this change interact or overlap with existing features?

  • The syntax might be a bad idea and hard to read ... or .. in certain cases.

Is the goal of this change a performance improvement?

  • No just a usability improvement.

Does this affect error handling?

  • No

Is this about generics?

  • Not really but it should work well with generics.
@gabyhelp
Copy link

Related Issues

(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.)

@gopherbot gopherbot added this to the Proposal milestone Nov 25, 2024
@ianlancetaylor ianlancetaylor added LanguageChange Suggested changes to the Go language LanguageChangeReview Discussed by language change review committee labels Nov 25, 2024
@ianlancetaylor
Copy link
Contributor

You can, of course, use the reflect package for this kind of thing.

@seankhliao
Copy link
Member

Please fill out https://github.com/golang/proposal/blob/master/go2-language-changes.md when proposing language changes

@seankhliao seankhliao changed the title proposal: add structfield type and syntax to directly access a structs structfield proposal: spec: add structfield type and syntax to directly access a structs structfield Nov 26, 2024
@seankhliao
Copy link
Member

Python does this with a key func, https://docs.python.org/3/howto/sorting.html#key-functions
You could apply the same here:

func UserBy[V comparable](users []User, v V, key func(User) V) User {
	index := slices.IndexFunc(users, func(u User) bool {
		return key(u) == v
	})
	if index == -1 {
		return User{}
	}
	return users[index]
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
LanguageChange Suggested changes to the Go language LanguageChangeReview Discussed by language change review committee Proposal
Projects
None yet
Development

No branches or pull requests

5 participants