profile
viewpoint
If you are wondering where the data of this site comes from, please visit https://api.github.com/users/DeedleFake/events. GitMemory does not store any data, but only uses NGINX to cache data for a period of time. The idea behind GitMemory is simply to give users a better reading experience.
DeedleFake Georgia https://deedlefake.com Computer scientist with interests in economics and linguistics as well. Looking to get into game development, but, really, I just enjoy programming.

DeedleFake/canvas 2

GopherJS Package for Using an HTML5 Canvas

DeedleFake/aa 1

A virtual filesystem and archive abstraction library inspired by PhysicsFS.

DeedleFake/crypto 1

Go implementations of hashes.

DeedleFake/diffpac 1

Modifying pacdiffviewer from yaourt to be a stand alone application

DeedleFake/9ipfs 0

Read-only proof-of-concept IPFS to 9P bridge.

DeedleFake/ac 0

Go package for dealing with ANSI color codes.

DeedleFake/adbkit 0

A pure Node.js client for the Android Debug Bridge.

DeedleFake/adbkit-monkey 0

A Node.js interface to the Android monkey tool.

DeedleFake/aurora 0

An experimental Pacman wrapper inspired by Aura written in Go.

DeedleFake/awesome-go 0

A curated list of awesome Go frameworks, libraries and software

issue commentgolang/go

proposal: spec: allow 'any' for 'interface{}' in non-constraint contexts

@rsc I know. I'm not proposing it. Just mentioning prior art and something generally related.

Personally, I'm not in favor of any, and one of the reasons for that is that unit, the natural counterpart, would be weird. If any hadn't been accepted for use in type constraints, I would have been very against its inclusion as a general-use alias, but because it has been, and only because it has been, it seems to make some sense. That doesn't sit well with me.

Lexkane

comment created time in 17 days

issue commentgolang/go

proposal: spec: allow 'any' for 'interface{}' in non-constraint contexts

I thought it was worth mentioning that interface{} has a natural pairing with struct{}, and both function very similarly to Any and Unit in Kotlin. Any is the equivalent of Java's Object, the automatic top of the class hierarchy, allowing any type to be assigned to a variable of type Any by way of subtype polymorphism, thus acting fairly similarly to interface{} in Go.

Similarly, Unit does the opposite, allowing only the value Unit to be assigned to it and thus carrying no information whatsoever, very similarly to struct{} and other, less commonly used empty types in Go.

Something like unit would have a quirk in Go, of course, as unit could only be a type, not also the value for that type, if it was just an alias for struct{}. The value would instead have to be unit{}, which is kind of odd.

Lexkane

comment created time in 17 days

startedrobpike/expr

started time in 19 days

issue commentgolang/go

proposal: fmt: Sprintf-into-bytes

The Bytes() method literally just returns the underlying slice:

func (b *Buffer) Bytes() []byte { return b.buf[b.off:] }

Does that not work for what you're looking for, @josharian?

seebs

comment created time in 23 days

issue commentgolang/go

proposal: container/list: add Sort() method

I don't have a particular problem with this, but might it make more sense to create a new linked list type (list.ListOf? list.Of?) with generics support and focus development on that one?

gobwas

comment created time in 24 days

issue commentgolang/go

slices: new package to provide generic slice functions

I wanted to comment about this in #47203, but it's been locked, unfortunately. I needed a reverse function for something so I did a manual loop with the intention of replacing it with a call to slices.Reverse() when Go 1.18 comes out, but to my surprise it doesn't seem to have even been proposed. The only equivalent in the standard library that I saw was sort.Reverse(), but that's really inefficient, and a lot more complicated to use, than just a simple reverse.

Any chance that this could get added into the proposal at the last second here?

package slices

func Reverse[T any](s []T) {
  for i := 0; i < len(s) / 2; i++ {
    r := len(s) - i - 1
    s[i], s[r] = s[r], s[i]
  }
}
ianlancetaylor

comment created time in 24 days

issue closedgolang/go

proposal: Go 2: add Reverse function to new slices package

I wanted to comment about this in #47203, but it's been locked, unfortunately. I needed a reverse function for something so I did a manual loop with the intention of replacing it with a call to slices.Reverse() when Go 1.18 comes out, but to my surprise it doesn't seem to have even been proposed. The only equivalent in the standard library that I saw was sort.Reverse(), but that's really inefficient, and a lot more complicated to use, than just a simple reverse.

The proposal's very simple:

package slices

func Reverse[T any](s []T) {
  for i := 0; i < len(s) / 2; i++ {
    r := len(s) - i - 1
    s[i], s[r] = s[r], s[i]
  }
}

closed time in 24 days

DeedleFake

issue commentgolang/go

proposal: Go 2: add Reverse function to new slices package

But #45955 is still open. I'll post this there instead. Sorry about the extra issue.

DeedleFake

comment created time in 24 days

issue openedgolang/go

proposal: Go 2: add Reverse function to new slices package

I wanted to comment this #47203, but it's been locked, unfortunately. I needed a reverse function for something so I did a manual loop with the intention of replacing it with a call to slices.Reverse() when Go 1.18 comes out, but to my surprise it doesn't seem to have even been proposed. The only equivalent in the standard library that I saw was sort.Reverse(), but that's really inefficient, and a lot more complicated to use, than just a simple reverse.

The proposal's very simple:

package slices

func Reverse[T any](s []T) {
  for i := 0; i < len(s) / 2; i++ {
    r := len(s) - i - 1
    s[i], s[r] = s[r], s[i]
  }
}

created time in 24 days

issue commentgolang/go

proposal: Go 2: function values as iterators

@deanveloper

I fixed it. It seems like the problem was that the use of a method value for the finalizer function resulted in an extra reference being kept around, so it never got garbage collected. I changed it to a method expression and it worked.

mknyszek

comment created time in a month

issue commentgolang/go

proposal: Go 2: function values as iterators

For a proper performance improvement, it could also be reimplemented at some point later the way that a bunch of other languages do it, thus getting rid of the channel and background thread, and the API could be left as is.

I'm still not thrilled about the need for yield to return a value to indicate that there's nothing receiving anymore, though. It would be much preferable for the generator function to somehow just return on its own, running deferred functions on the way. Could the yield implementation that gets passed just call runtime.Goexit() instead of returning something?

mknyszek

comment created time in a month

create barnchfixdauto/ent

branch : v0.9.1-workaround

created branch time in a month

issue commentgolang/go

proposal: Go 2: function values as iterators

Relevant code:

// Ranger provides a convenient way to exit a goroutine sending values
// when the receiver stops reading them.
//
// Ranger returns a Sender and a Receiver. The Receiver provides a
// Next method to retrieve values. The Sender provides a Send method
// to send values and a Close method to stop sending values. The Next
// method indicates when the Sender has been closed, and the Send
// method indicates when the Receiver has been freed.
func Ranger[T any]() (*Sender[T], *Receiver[T]) {
	c := make(chan T)
	d := make(chan bool)
	s := &Sender[T]{values: c, done: d}
	r := &Receiver[T]{values: c, done: d}
	// The finalizer on the receiver will tell the sender
	// if the receiver stops listening.
	runtime.SetFinalizer(r, r.finalize)
	return s, r
}

// A Sender is used to send values to a Receiver.
type Sender[T any] struct {
	values chan<- T
	done   <-chan bool
}

// Send sends a value to the receiver. It reports whether any more
// values may be sent; if it returns false the value was not sent.
func (s *Sender[T]) Send(v T) bool {
	select {
	case s.values <- v:
		return true
	case <-s.done:
		// The receiver has stopped listening.
		return false
	}
}

// Close tells the receiver that no more values will arrive.
// After Close is called, the Sender may no longer be used.
func (s *Sender[T]) Close() {
	close(s.values)
}

// A Receiver receives values from a Sender.
type Receiver[T any] struct {
	values <-chan T
	done  chan<- bool
}

// Next returns the next value from the channel. The bool result
// reports whether the value is valid. If the value is not valid, the
// Sender has been closed and no more values will be received.
func (r *Receiver[T]) Next() (T, bool) {
	v, ok := <-r.values
	return v, ok
}

// finalize is a finalizer for the receiver.
// It tells the sender that the receiver has stopped listening.
func (r *Receiver[T]) finalize() {
	close(r.done)
}
mknyszek

comment created time in a month

push eventDeedleFake/dotfiles

DeedleFake

commit sha e8fe6981654da94f4044cfb1e256fb60d7505418

Disable several unused plugins.

view details

push time in a month

issue commentgolang/go

proposal: Go 2: function values as iterators

Python, as a fully interpreted language, doesn't really seem to. It actually just jumps in and out of the stack frame. It's similar to a coroutine, perhaps, but with a very different purpose.

I think without language-level support, there's going to be some pretty bad performance issues that aren't really easily resolvable. It might be possible to optimize the channel for this specific usage and cut out some of the overhead, as I'm guessing that quite a bit of that comes from locking that isn't useful in this particular situation.

mknyszek

comment created time in a month

issue commentgolang/go

proposal: Go 2: function values as iterators

While I'm not sure if runtime.Deadlocked() is exactly the right approach, I do think that it's a good idea. Cooperative cancellation, as with context.Context, feels a lot more Go-like. Maybe, at least to start, it might make sense to make it runtime.deadlocked() instead and then only create a iter.Generator() wrapper around it with an unsafe hook into the unexported runtime API. If you export it, it's going to encourage people to rely on other people checking for that deadlock and you're right back to the same situation as the ignored boolean, but now for potentially every single channel usage that crosses an API boundary.

In whichever case, though, I also worry a little about potential performance issues stemming from having to multi-thread this. I'm not entirely sure that just directly using a channel is the correct approach for a generic iterator system, either. I think that this should just be one possible way to create an iterator, be it iter.Iter[T] or whatever else. Otherwise middleware functionality like map and filter is going to be kind of weird.

@deanveloper

go2go link seems to time out sometimes, but it works other times

The go2go playground's been having that problem a lot recently. I had a ton of trouble with it the other day.

Also, several of the examples above forgot the bool return for yield in the function signature.

mknyszek

comment created time in a month

issue commentgolang/go

proposal: Go 2: function values as iterators

@wsc0

What I always found confusing about yield in Python was that the usage of yield somewhere in the function automatically caused the function itself to behave completely differently from any other function, but there was no difference of any kind in the function signature. I think that a lot of that confusion can be avoided if it's more obvious that a yielding function isn't a normal function, assuming language-level support for it. If the support for it isn't language-level than I think that that'll solve itself. Good documentation helps, too.

mknyszek

comment created time in a month

issue commentgolang/go

proposal: sync, sync/atomic: add PoolOf, MapOf, ValueOf

I've been wondering recently if maybe now that modules are a well-accepted thing, everything that isn't key to the functioning of the language should be moved into golang.org/x and properly versioned. That would also allow updates to the standard library to be completely decoupled from updates to the language, especially thanks to the go directive in go.mod. Then just deprecate most of the standard library, and maybe remove it for a full Go 2 release. You could soft remove it, too, by only allowing access to it via low enough go version specifications.

ianlancetaylor

comment created time in a month

issue commentgolang/go

proposal: Go 2: alternate function call syntax to improve ergonomics of chainable top-level functions

I know Go wanted to go the route of "we should remove all variable shadowing", and obviously this is a step in the opposite direction.

I think that the shadowing problem actually stems more from the oddity of := combined with multiple returns, not that it exists at all. I think that Go needs to move towards variable declaration being per-variable on the left-hand side of the assignment, not an all-or-nothing like := is.

DeedleFake

comment created time in a month

issue openedgolang/go

proposal: Go 2: alternate function call syntax to improve ergonomics of chainable top-level functions

This is a random idea that I came up with. I'm not entirely sure that I like it, but I thought that I'd put it out there and see what people think.

Problem

One of the features purposefully left out of the generics design is adding new type parameters in method declarations. In other words, func (t *SomeType) SomeMethod[T any](v T) is illegal. As the design draft pointed out, the only real functionality difference between methods and top-level functions in Go is in interface satisfaction, and how methods that can add new type parameters would affect satisfaction has a lot of subtle implications. One solution that has been proposed is that those methods simply shouldn't count at all towards interface satisfaction, but then the question is why bother making them methods at all.

Unfortunately, top-level functions are not always ideal. While it's true that there's no functionality difference outside of interface satisfaction, certain common systems, such as iterators, lend themselves towards APIs that are very awkward as top-level functions. Under the current generics proposal, iterator transformation functions, such as map and filter, would have to be implemented as top-level functions, but top-level functions for iterator chaining can be very messy.

One option is to call those functions one after another with large numbers of intermediary variables:

// It's a bit of a contrived example, I know.
it := iter.OfSlice(s)
trunc := iter.Map(it, func(v float64) int { return int(v) })
trunc = iter.Filter(it, func(v int) bool { return v > 0 })
strings := iter.Map(it, func(v int) string { return fmt.Sprintf("%x", v) })
return iter.Slice(it)

This is very messy, as well as error prone. Some variable have to be new because they have new types, but some can be the same, and naming all of them something useful is a whole extra thing to worry about pointlessly. An alternative is to nest the calls, but that's actually worse:

// The reads like a C function pointer type declaration: Inside-out.
return iter.Slice(
  iter.Map(
    iter.Filter(
      iter.Map(
        iter.OfSlice(s),
        func(v float64) int { return int(v) },
      ),
      func(v int) bool { return v > 0 },
    ),
    func(v int) string { return fmt.Sprintf("%x", v) },
  ),
)

Proposal

The idea is simple: Add a syntax, probably in the form of a new operator, that allows top-level functions to be chained like methods. It would be nothing but syntax sugar.

An example syntax for this might look like a() -> b(). This would be equivalent to b(a()). With this syntax, the result of the expression on the left is passed as the first argument of the function call on the right. All other arguments are handled normally. In other words, b(a(1, 2, 3), 8, 9) could also be written as a(1, 2, 3) -> b(8, 9). This usage would make the syntax compatible with method expressions, as well as the majority of functions that already exist due to standard argument order conventions, and allow functions written with this syntax in mind to follow a standard argument ordering as well.

Using this syntax, the above admittedly-contrived iterator example could be rewritten as follows:

return iter.OfSlice(s) ->
  iter.Map(func(v float64) int { return int(v) }) ->
  iter.Filter(func(v int) bool { return v > 0 }) ->
  iter.Map(func(v int) string { return fmt.Sprintf("%x", v) }) ->
  iter.Slice()

It should be noted that this would only be legal if the expression on the left side has at most one return. A multi-return version could be implemented, but this proposal is only for a single-return-only variant.

Conclusion

Like I said above, I'm not entirely sure about this idea myself. One particular problem that I have with it is the namespacing required when chaining to an imported function, but I thought that I'd at least propose it as the lack of additional type parameters on methods is my biggest issue with generics as currently proposed, and this could solve that by simply sidestepping the issue completely.

Another potential issue that I have with this is that if it is decided later to try to allow methods with new type parameters that do satisfy interfaces, this will probably feel fairly redundant, but it could still be useful as pseudo extension functions.

Feel free to leave a thumbs-down if you think that it's too weird.

Language Change Template

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

Experienced.

What other languages do you have experience with?

C, Ruby, Python, Kotlin, Java, Rust, JavaScript, and a few others.

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

Slightly harder due to there being an extra syntactic detail to learn, I suppose, but the idea's pretty straightforwards.

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

I don't think so.

Who does this proposal help, and why?

Anyone trying to write a complicated API that lends itself to chained function calls but that has to be written as top-level functions, It also allows for what are essentially extension methods by way of making top-level functions behave like methods, allowing, for example, for a third-party package to implement some new middleware iterator function and for it to integrate well into existing systems.

What is the proposed change?

Add a new syntax sugar that allows the first argument to any regular, top-level function to be specified before the name of the function. One possibility is that of an -> operator that does just that, making b(a(1, 2, 3), 8, 9) completely equivalent to a(1, 2, 3) -> b(8, 9).

Is this change backward compatible?

Yes.

Show example code before and after the change.

See above.

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?
    • A few would definitely, especially the formatters.
  • What is the compile time cost?
    • There would be one extra syntactical structure that needs to be parsed, so there would be one, but it would probably be pretty minor.
  • What is the run time cost?
    • Non-existent.

Can you describe a possible implementation?

Nope.

Do you have a prototype? (This is not required.)

Nope.

How would the language spec change?

It would need a new section under function call syntax that would describe this syntactical feature.

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

It complements function call syntax by allowing for certain patterns that are currently unfeasible due to incredibly awkward ergonomics.

Is the goal of this change a performance improvement?

No.

Does this affect error handling?

As currently proposed, no, not really, but a variant could allow for chaining functions with multiple returns and then it could be useful.

Is this about generics?

It was inspired by an issue that came up in the generics design, but it doesn't have anything to do with generics directly itself.

created time in a month

issue commentgolang/go

proposal: sync, sync/atomic: add PoolOf, MapOf, ValueOf

Honestly, the more I think about it the more that I realize that what I find strange about the existing API isn't the behavior when p.New is nil, but rather that p.New exists at all. It feels like sync.Pool just has an extra minor convenience feature attached to it that has no particular impact on the actual purpose of the type.

As long as new implementations are being built anyways, could New be removed from PoolOf? Pool could still be reimplemented via PoolOf by just making it

type Pool struct {
  p PoolOf[interface{}]
  New func() interface{}
}

func (p *Pool) Get() interface{} {
  v, ok := p.p.Get()
  if !ok && (p.New != nil) {
    return p.New()
  }
  return v
}

// And Put(), too.
ianlancetaylor

comment created time in a month

issue commentgolang/go

proposal: sync, sync/atomic: add PoolOf, MapOf, ValueOf

No it isn't. The current implementation returns nil, assuming that p.New doesn't itself return nil, if and only if it wants to generate a new value but p.New == nil.

It can't possibly be the same functionality as is proposed here because that would mean that it was both returning nil to indicate that it had generated a new value and was, simultaneously, returning non-nil because it's also returning the generated value. It can't do both at the same time with a single return value.

ianlancetaylor

comment created time in a month

issue commentgolang/go

proposal: sync, sync/atomic: add PoolOf, MapOf, ValueOf

So, just to clarify, what you're saying is that the incompatibility isn't non-obvious nil-equivalents, but rather that the new version isn't just a genercized implementation, but also adds functionality in the form of the ability to tell if a value was in the pool already or was generated on the fly? I'm asking because you had originally said

The current version of sync.Pool.Get returns a single result relies on the caller checking for nil. That doesn't work for sync.PoolOf.Get, because Go has no universal does-not-exist value, so sync.PoolOf.Get has to return two results.

but the current implementation's return of nil isn't particularly useful most of the time. <sup>In fact, I was kind of surprised that it doesn't panic in those circumstances.</sup> I think that that's where my confusion came from. The current implementation returning nil is, as far as I can tell, completely different and unrelated circumstances from those which determine the value of the second return in the new implementation.

ianlancetaylor

comment created time in a month

issue commentgolang/go

proposal: sync, sync/atomic: add PoolOf, MapOf, ValueOf

The bool second return seems like it's adding functionality. If I'm reading the docs correctly, the current sync.Pool.Get() never returns nil unless p.New() returns nil, in which case that's the user deciding that that's a valid value, not the pool's implementation using it as a marker value.

The second return in the genetic implementation doesn't seem to map to any existing behavior.

ianlancetaylor

comment created time in a month

issue commentgolang/go

proposal: sync, sync/atomic: add PoolOf, MapOf, ValueOf

Would it be possible to remove the double implementation that works result from this using type aliases? For example,

type Pool = PoolOf[interface{}]

I'm not familiar enough with the nuances of type aliases to be sure is this is fully backwards compatible or if it would have weird edge cases, such as in embedding. (I'm not actually entirely sure that it's legal to alias to a generic instantiation.)

ianlancetaylor

comment created time in a month

starteddolthub/dolt

started time in a month

push eventDeedleFake/ent

DeedleFake

commit sha 5135c7e949542a13a6a67929c4aaea9efa81b07a

entc: partial implementation of errors for combining `DoNothing()` and `ID()` with PostgreSQL

view details

push time in a month

issue commentent/ent

DoNothing() + Upsert.ID() returns low-level SQL error in Postgres

Agree. Would you like to contribute this change? Thanks 🙏

Certainly. What error should it return?

DeedleFake

comment created time in a month

push eventDeedleFake/ent

DeedleFake

commit sha bff360852301a723bb6679a5521d68310a5c6630

entc: document incompatibility between `DoNothing()` and `ID()` in PostgreSQL

view details

push time in a month