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

Functional will contain functional programming patterns made possible by Go generics. #55

Closed
wants to merge 6 commits into from

Conversation

sgmiller
Copy link

@sgmiller sgmiller commented Mar 17, 2023

This PR adds the lazy pattern, which allows Producers (func() V), Functions (func(A) V), BiFunctions (func(A,B),V) and a version of each which also returns an error to be wrapped in logic which evaluates the underlying function such that when initially called the function calculates the result. All subsequent calls return the results of the first again.

This can be used to lazily compute a value or reach out to an expensive resource once, yet have the function be called throughout code without worrying about double-calculation or difficult coordinary across function boundaries.

@sgmiller sgmiller changed the title Functional will contain functional programming patterns made possible by Go generics. This PR adds the lazy pattern, which allows producers (func() V), Functions (func(A) V), BiFunctions (func(A,B),V) and a version of each which also returns an error to be wrapped in logic which evaluates the underlying function such that when initially called the function calculates the result. All subsequent calls return the results of the first again. Functional will contain functional programming patterns made possible by Go generics. Mar 17, 2023
Copy link
Collaborator

@johanbrandhorst johanbrandhorst left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think personally this is really neat, from a technical point of view, but I worry about the wider use of it. This trades clarity for code size. It can make sense in some contexts where these patterns are widely established among users, but I think it's going to make the code harder to read to the generic reader. Including it in the secure-stdlib is an implicit approval of the pattern. To me, clarity is paramount and I'd prefer this was kept private to repositories where it is widely employed and understood, if at all. These sort of patterns are not widely used within Go, as far as I know. Even a year on from generics being released these patterns have not emerged as a common way to do things.

swenson
swenson previously approved these changes Mar 17, 2023
Copy link
Contributor

@swenson swenson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, one question

package functional

type Producer[V any] func() V
type ErrorableProducer[V any] func() (V, error)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it standard practice to say Errorable as a prefix? I think in general I like ProducerWithError, for example, just for discoverability.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I didn't love that but didn't know if there was precedent for something better.

@swenson swenson self-requested a review March 17, 2023 18:14
@swenson
Copy link
Contributor

swenson commented Mar 17, 2023

In light of @johanbrandhorst's comment, I retract my review for now :)

@swenson swenson dismissed their stale review March 17, 2023 18:18

other comments

// Package lazy implements generic Lazy functions. Lazy functions are evaluated when first called, while
// all subsequent calls return the results of the initial call. Call lazy functions in your code
// as many times as you like knowing that the computation or side effects will only occur once.
package lazy
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm going to object to using lazy and suggest memoized as that's more likely to land with Go programmers who likely aren't coming from non-applicative languages. But, feel free to sustain my objection.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went with memoized initially, but memoization takes into consideration the values of the arguments, which isn't the case here. A memoized function would re-evaluate if the values of the arguments were distinct.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That said, that may be the more useful generalization, though not as simple an implementation and with some interesting memory usage considerations.

@jimlambrt
Copy link
Collaborator

clarity is paramount and I'd prefer this was kept private to repositories where it is widely employed and understood, if at all. These sort of patterns are not widely used within Go, as far as I know. Even a year on from generics being released these patterns have not emerged as a common way to do things.

Just here to give a strong :+1 to @johanbrandhorst comment

@sgmiller
Copy link
Author

Will pull into the using repo for now.

@sgmiller sgmiller closed this Mar 20, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants