-
Notifications
You must be signed in to change notification settings - Fork 17.8k
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: Go 2: semi-constant conditionals #56256
Comments
Please note that you should fill https://github.com/golang/proposal/blob/master/go2-language-changes.md when proposing a language change. |
CC @golang/runtime |
What's wrong with
(or use a The branch is very predictable, so it isn't that much more expensive than a raw jump. |
It's exactly the problem I'm trying to address here. :-) Even if we look at global flags in particular, they are already out of hand: stuff like And it's not going to get any better. Some 20 years ago Linux Kernel moved to per-location switches for printks and function tracing. Those were exceptionally successful, but depend a lot on fancy macros. Go has no macros and has no runtime code transforms akin to JVM. Thus, to implement something sane in this department we need compiler help (aka language feature). |
It seems to me that you are replacing one mechanism that is difficult to work with by another mechanism that is difficult to work with. Why don't we try to standardize on one of our existing approaches, such as |
It's time for code snippets. :-) Let's say we want to be able to look at inputs and outputs of typical handler functions and do so without browsing through a lot of noise. In present day Go, the best approach looks as following:
Whereupon, the
This is more or less the best approach right now to have many optional code blocks. It is verbose, typo prone and may need to be repeated many times if there are complex nested handlers. In a typical C library, this stuff can be packaged as macro, with the actual guard flags having "static" linkage (Go has neither macros nor static vars). Moreover, if we feel like being fancy, C libraries can rather easily utilize a distinct linker section to avoid that None of this is possible in Go. But, it will really make a lot of things easier if it was. |
|
This is actually an inferior solution. Not refactor friendly, not copy-paste resilient, not scalable in the long run (have ample user stories to substantiate). And still a lot of typing for a common pattern. :-) Basically, I keep claiming the following:
Indeed:
And only in Go we are forced to keep breaking fingers or keep writing custom code preprocessors (I have several of those :-). |
If you are including things like C macros, then in Go we have build tags that let us select the default value of some constant at build time. |
Of course it has. Have I ever claimed the contrary? When talking about macros in this context, I'm talking about stuff like this (it's a fairly common technique in C logging these days, and it is also applicable to wide range of other scenarios): The activation metadata: The end user construct which can be toggled in runtime via side channel: In Rust, the same technique applies as is. However, at this point, I would actually like to close this thread and write another, much better worded proposal. Assuming my argument holds at least some water. :-) |
I suppose that my feeling right now is that there are already multiple ways to do the kind of thing you are discussing. I don't see the need to add another one. Of course I'm only speaking for myself. (Also the specific suggestion of using reflect seems impossible to implement, but I expect that we could make some vaguely similar approach work.) |
Yes, reflect was not the best idea. It's more a debug into thing. Go being a Turing complete language means that indeed, anything can be implemented. The key question is, of course, one of end user utility. For example:
Does But, it suffers from one major flaw: the "disabled" case is way too expensive for most uses. The closure is always allocated, And something like this will never work outright:
Because Go evaluates function arguments eagerly. However, if |
Based on the discussion above, and the negative emoji voting, this is a likely decline. Leaving open for four weeks for final comments. |
Not widely recognized patterns are doomed to linger. :-) |
No change on consensus. |
There exist a very potent diagnostic technique, long and very successfully used in bigger C language projects (most prominently in Linux Kernel). Unfortunately, managed memory languages seldom implement it even though managed memory makes it rather fail safe, as compared to something like C (it is doable in JVM, of course, but then, almost anything is doable in JVM :-).
In Go, it may look the following:
Here we have an
if
statement without a condition block. By default, it's simply a jump to the (possibly implicit) "else" code block. However, we may add some sort of API (based onreflect
for example) which can be used to "steer" thatif
:This will make the
if
statement atmyLabel
to enter the "then" code block. Setting the controller back to "false" will restore the initial state ("then" code block will be skipped). The label can also be made implicit, auto generated out of code location, thus saving some programmers effort.The feature is pretty straightforward to implement in the compiler. Indeed, 2 methods can be readily employed:
reflect
directly into the "myLabel" location (invoking the necessary mprotect and icache magic as necessary, steering performance being of not much concern).reflect
(possibly in dedicated linker section).It shall be noted, that Linux kernel employs both methods for its various features (the "safe" bool flag method uses a macro and a dedicated linker section).
Why is this useful and what are the alternatives?
When working with highly loaded or otherwise long running network servers we often want to extract some data for diagnostics. Unfortunately, side channel data extraction always carries a rather high performance cost. Even a single extra call to a logging system can have a substantial cost if its parameters are chosen in unfortunate way.
Thus, server developers and operators can really benefit from some mechanism to selectively enable diagnostic code blocks on one by one basis in runtime; the benefit will be even greater if the mechanism for doing so is consistent across the wider Go ecosystem, that is, happens to be part of the language.
Right now, Go doesn't offer any sort of viable alternative to address the problem of selective diagnostics in runtime.
Instead, we are left at the mercy of coarse grained, library level, non standardized global debug switches, which invariably emit either too little or too much data and never play nice with the application code (examples being Go runtime itself, libraries like GRPC and many other). The switches themselves require too much boilerplate and programmer's discipline to use on the library level, may only affect things on start-up and can be rather troublesome in general, both for the implementer and for the library user.
Providing an efficient runtime code steering facility in the core language will substantially improve observability and maintainability of a large number of Go programs.
The text was updated successfully, but these errors were encountered: