Live data from Hacker News

Context should go away for Go 2 (2017)

faiface.github.io

41–50 of 176 posts

Re: Context should go away for Go 2 (2017)

#41

Earlier quoted context omitted.

> React has "Context", SwiftUI has "@Environment", Emacs LISP has dynamic scope (so I heard). C# has AsyncLocal, Node.JS AsyncLocalStorage. Emacs Lisp retains dynamic scope, but it's no longer a default for some time now, in line in other Lisps that remain in use. Dynamic scope is one of the greatest features in Lisp language family, and it's sad to see it's missing almost everywhere else - where, as you noted, it's…

> Emacs Lisp retains dynamic scope, but it's no longer a default for some time now https://www.gnu.org/software/emacs/manual/html_node/elisp/Va... > By default, the local bindings that Emacs creates are dynamic bindings. Such a binding has dynamic scope, meaning that any part of the program can potentially access the variable binding. It also has dynamic extent, meaning that the binding lasts only while the binding c…

Sorry, you're right. It's not a cultural default anymore. I.e. Emacs Lisp got proper lexical scope some time ago, and since then, you're supposed to start every new .elisp file with:

  ;; -*- mode: emacs-lisp; lexical-binding: t; -*-
i.e. explicitly switching the interpreter/compiler to work in lexical binding mode.

Re: Context should go away for Go 2 (2017)

#42

> If you use ctx.Value in my (non-existent) company, you’re fired This is such a bad take. ctx.Value is incredibly useful for passing around context of api calls. We use it a lot, especially for logging such context values as locales, ids, client info, etc. We then use these context values when calling other services as headers so they gain the context around the original call too. Loggers in all services pluck out v…

The author gave a pretty good reasoning why is it a bad idea, in the same section. However, for the demonstration purposes I think the they should have included their vision on how the request scoped data should be passed.

As I understand they propose to pass the data explicitly, like a struct with fields for all possible request-scoped data.

I personally don't like context for value passing either, as it is easy to abuse in a way that it becomes part of the API: the callee is expecting something from the caller but there is no static check that makes sure it happens. Something like passing an argument in a dictionary instead of using parameters.

However, for "optional" data whose presence is not required for the behavior of the call, it should be fine. That sort of discipline has to be enforced on the human level, unfortunately.

Re: Context should go away for Go 2 (2017)

#43
post #26
post #20

Earlier quoted context omitted.

To not repeat other's (Python) mistakes ;-)

The the introduction of Python 3 wasn't a mistake. The mistake was discontinuing Python 2. Just look at how rust does it. Rust 1.0 code still works in the latest version of rustc, you just need to set the project to the Rust 2015 edition. You can even mix-and-match editions, as each crate can have a different edition. Newer versions of rustc will always support all previous editions, and breaking changes are only eve…

It seems you are both saying the same thing. Had Python not introduced a line in the sand and instead continued to support Python 2 amid future updates there would have been no reason for Python 3. The Python 2 line could have kept improving instead.

Just as you say, Python could have introduced what is found in Python 3 without breaking Python 2 support. Which is the direction Go has settled on; hence why Go 2 is off the table. Go 1.0 and Go 1.23 are very different languages, but backwards version support is retained, so no need for a new major version.

Re: Context should go away for Go 2 (2017)

#44

> If you use ctx.Value in my (non-existent) company, you’re fired This is such a bad take. ctx.Value is incredibly useful for passing around context of api calls. We use it a lot, especially for logging such context values as locales, ids, client info, etc. We then use these context values when calling other services as headers so they gain the context around the original call too. Loggers in all services pluck out v…

Let me try to take the other side:

`ctx.Value` is an `any -> any` kv store that does not come with any documentation, type checking for which key and value should be available. It's quick and dirty, but in a large code base, it can be quite tricky to check if you are passing too many values down the chain, or too little, and handle the failure cases.

What if you just use a custom struct with all the fields you may need to be defined inside? Then at least all the field types are properly defined and documented. You can also use multiple custom "context" structs in different call paths, or even compose them if there are overlapping fields.

Re: Context should go away for Go 2 (2017)

#45

Contexts in Go are generally used for convenience in request cancellation, but they're not required , and they're not the only way to do it. Under the hood, a context is just a channel that's closed on cancellation. The way it was done before contexts was pretty much the same: func CancellableOp(done chan error /* , args... */) { for { // ... // cancellable code: select { case Some compare context "virus" to async vi…

This works, but goes against convention in that (from the context package docs) you shouldn’t “store Contexts inside a struct type; instead, pass a Context explicitly to each function that needs it.”

Re: Context should go away for Go 2 (2017)

#47

> If you use ctx.Value in my (non-existent) company, you’re fired This is such a bad take. ctx.Value is incredibly useful for passing around context of api calls. We use it a lot, especially for logging such context values as locales, ids, client info, etc. We then use these context values when calling other services as headers so they gain the context around the original call too. Loggers in all services pluck out v…

The author gave a pretty good reasoning why is it a bad idea, in the same section. However, for the demonstration purposes I think the they should have included their vision on how the request scoped data should be passed. As I understand they propose to pass the data explicitly, like a struct with fields for all possible request-scoped data. I personally don't like context for value passing either, as it is easy to…

> As I understand they propose to pass the data explicitly, like a struct with fields for all possible request-scoped data.

So basically context.Context, except it can't propagate through third party libraries?

Re: Context should go away for Go 2 (2017)

#48
post #38

Earlier quoted context omitted.

An alternative is to add all dependencies explicitly into function argument list or object fields, instead of using them implicitly from the context, without documentation and static typing. Including logger.

I already talked about it above. Main problems with passing dependencies in function argument lists: 1) it pollutes the code and makes refactoring harder (a small change in one place must be propagated to all call sites in the dependency tree which recursively accept user ID/tenant ID and similar info) 2) it violates various architectural principles, for example, from the point of view of our business logic, there's…

I believe this problem isn't solvable under our current paradigm of programming, which I call "working directly on plaintext, single-source-of-truth codebase".

Tenant ID, cancellations, loggers, error handling are all examples of cross-cutting concerns. Depending on what any given function does, and what you (the programmer) are interested in at a given moment, any of them could be critical information or pure noise. Ideally, you should not be seeing the things you don't care about, but our current paradigm forces us to spell out all of them, at all times, hurting readability and increasing complexity.

On the readability/"clean code", our most advanced languages are operating on a Pareto frontier. We have whole math fields being employed in service of packaging up common cross-cutting concerns, as to minimize the noise they generate. This is where all the magic monads come from, this is why you have to pay attention to infectious colors of your functions, etc. Different languages make slightly different trade-offs here, to make some concerns more readable, but since it's a Pareto frontier, it always makes some other aspects of code less comprehensible.

In my not so humble opinion, we won't progress beyond this point until we give up on the paradigm itself. We need to accept that, at any given moment, a programmer may need a different perspective on the code, and we need to build tools to allow writing code from those perspectives. What we now call source code should be relegated to the role of intermediary/object code - a single source of truth for the bowels of the compiler, but otherwise something we never touch directly.

Ultimately, the problem of "context" is a problem of perspective, and should be solved by tooling. That is, when reading or modifying code, I should be able to ignore any and all context I don't care about. One moment, I might care about the happy path, so I should be able to view and edit code with all error propagation removed; at another moment, I might care about how all the data travels through the module, in which case I want to see the same code with every single goddamn thing spelled out explicitly, in the fashion GP is arguing to be the default. Etc.

Plaintext is fine. Single source of truth is fine. A single all-encompassing view of everything in a source file is fine. But they're not fine all together, all the time.

Re: Context should go away for Go 2 (2017)

#49
post #38

Earlier quoted context omitted.

An alternative is to add all dependencies explicitly into function argument list or object fields, instead of using them implicitly from the context, without documentation and static typing. Including logger.

I already talked about it above. Main problems with passing dependencies in function argument lists: 1) it pollutes the code and makes refactoring harder (a small change in one place must be propagated to all call sites in the dependency tree which recursively accept user ID/tenant ID and similar info) 2) it violates various architectural principles, for example, from the point of view of our business logic, there's…

> it violates various architectural principles, for example, from the point of view of our business logic, there's no such thing as "tenant ID"

I'm not sure I understand how hiding this changes anything. Could you just not pass "tenant ID" to doBusinessLogic function and pass it to saveToDatabase function?

Re: Context should go away for Go 2 (2017)

#50

> If you use ctx.Value in my (non-existent) company, you’re fired This is such a bad take. ctx.Value is incredibly useful for passing around context of api calls. We use it a lot, especially for logging such context values as locales, ids, client info, etc. We then use these context values when calling other services as headers so they gain the context around the original call too. Loggers in all services pluck out v…

Let me try to take the other side: `ctx.Value` is an `any -> any` kv store that does not come with any documentation, type checking for which key and value should be available. It's quick and dirty, but in a large code base, it can be quite tricky to check if you are passing too many values down the chain, or too little, and handle the failure cases. What if you just use a custom struct with all the fields you may ne…

> `ctx.Value` is an `any -> any` kv store that does not come with any documentation, type checking for which key and value should be available.

On a similar note, this is also why I highly dislike struct tags. They're string magic that should be used sparingly, yet we've integrated them into data parsing, validation, type definitions and who knows what else just to avoid a bit of verbosity.

Post reply on HN