You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository has been archived by the owner on Jan 10, 2023. It is now read-only.
I think the model of channels (and how they're used) has to change before progress can be made on what I think is a major feature - visually observing runtime behaviour.
The current model of creating every channel and giving it a name makes sense if you understand the code coming out the other end, but I can't think of another visual system that does it this way. Referring to the inspiration for this project, SHENZHEN I/O, it has circuit traces (channels) which are anonymous, and connect parts which identify communication via the pin it is communicating on.
I originally thought this low-level approach leads to confusion (pin x0 on one part goes to x3 on another ...) so pressed on with letting the user give each channel a name and having it magically detect channel usage (by parsing the user's Go, go/parser, go/types). It's clever, but not clever enough. SZ-GO would have to get into the business of statically analysing and rewriting other people's code much more precisely in order to progress.
To explain: This is important for what I'm calling "smart channels" - visualising what is passing through a channel at runtime. To do that the channel has to be swapped at build time for some kind of weightier structure that intercepts channel communication, e.g.:
type smartChannel struct {
in, out chan interface{} // Could generate these smart channel types with a template, to handle specific value types.
// Other fields for tracking statistics.
}
// Run in a separate goroutine:
func (c *smartChannel) Track() {
for x := range c.in {
// Accumulate information to display here.
c.out <- x
}
close(c.out)
}
but for this to work, analysis is required for knowing whether to swap each usage of a channel identifier with smartChannel.in or smartChannel.out. It's simple if it is all one of <-, close, or range - the current code works great for those cases. But it doesn't handle channels passed through function arguments or fields. There's also this potential case:
// Third-party package:
func SomeoneElsesCode(info chan interface{}) {
x := <-info
// do something
info <- y
}
// An SZ-GO program:
var info = make(chan interface{}, 0)
// This channel gets exchanged at build-time for:
var info = &smartChannel{ ... }
// in order to visualise information flowing through "info".
go func () {
// The user wrote in some goroutine:
...
SomeoneElsesCode(info)
...
}()
It can't substitute SomeoneElsesCode(info) for both SomeoneElsesCode(info.in) and SomeoneElsesCode(info.out) simultaneously - that's impossible. It could handle it by reparsing and rewriting SomeoneElsesCode but that seems to be too unreasonable - to go that far probably needs compiler changes (or something on the order of compiler changes). And if the compiler is being changed, why not just change the standard channel implementation to implement smart channels? Either way feels like dangerous territory for a spare-time project :-)
It is comparatively much easier to simply lock down whatever channels are being used, and how they are used:
Declaring the "real" channels hidden inside the main/Run function rather than as package variables.
Every goroutine, which today is pasted into an anonymous goroutine function in main/Run, becomes a standalone function with read- or write-channel arguments, e.g.
func myExampleGoroutine(in <-chan int, out chan<- string) { ... }
Goroutine invocation in main/Run passes in the channels and calls the function.
The upside to this is most of the existing channel extraction and renaming business just goes away. Various UI bits could be easier to implement too.
The downside with this proposal is that the user has to declare channel usage at both ends. If everything is a Code part, that's as many as 2 channel declarations (as arguments) per channel (value), i.e. twice the work for the user compared to the current scheme.
The text was updated successfully, but these errors were encountered:
I think i see what your on about in this rant :)
It boils down to interface versus implementation.
go-kit and go-micro provide a Inversion of Control using good old interfaces. So cant you follow the same principle ?
🚨 Self-directed rant. 🚨
I think the model of channels (and how they're used) has to change before progress can be made on what I think is a major feature - visually observing runtime behaviour.
The current model of creating every channel and giving it a name makes sense if you understand the code coming out the other end, but I can't think of another visual system that does it this way. Referring to the inspiration for this project, SHENZHEN I/O, it has circuit traces (channels) which are anonymous, and connect parts which identify communication via the pin it is communicating on.
I originally thought this low-level approach leads to confusion (pin x0 on one part goes to x3 on another ...) so pressed on with letting the user give each channel a name and having it magically detect channel usage (by parsing the user's Go, go/parser, go/types). It's clever, but not clever enough. SZ-GO would have to get into the business of statically analysing and rewriting other people's code much more precisely in order to progress.
To explain: This is important for what I'm calling "smart channels" - visualising what is passing through a channel at runtime. To do that the channel has to be swapped at build time for some kind of weightier structure that intercepts channel communication, e.g.:
but for this to work, analysis is required for knowing whether to swap each usage of a channel identifier with smartChannel.in or smartChannel.out. It's simple if it is all one of <-, close, or range - the current code works great for those cases. But it doesn't handle channels passed through function arguments or fields. There's also this potential case:
It can't substitute
SomeoneElsesCode(info)
for bothSomeoneElsesCode(info.in)
andSomeoneElsesCode(info.out)
simultaneously - that's impossible. It could handle it by reparsing and rewritingSomeoneElsesCode
but that seems to be too unreasonable - to go that far probably needs compiler changes (or something on the order of compiler changes). And if the compiler is being changed, why not just change the standard channel implementation to implement smart channels? Either way feels like dangerous territory for a spare-time project :-)It is comparatively much easier to simply lock down whatever channels are being used, and how they are used:
The upside to this is most of the existing channel extraction and renaming business just goes away. Various UI bits could be easier to implement too.
The downside with this proposal is that the user has to declare channel usage at both ends. If everything is a Code part, that's as many as 2 channel declarations (as arguments) per channel (value), i.e. twice the work for the user compared to the current scheme.
The text was updated successfully, but these errors were encountered: