4 ms·
This has a lot of interesting accidental rebuttals to some "features" of go. > If you’re not in an entry-point function and you need to call a function that ta
by kevincox 3y ago
This has a lot of interesting accidental rebuttals to some "features" of go.
> If you’re not in an entry-point function and you need to call a function that takes a context, your function should accept a context and pass that along.
This is in contrast to the fact that Go's cheap threading means that you don't need to colour your functions with async or not async. But this quote that you sort of have to do this with context or no context.
It isn't quite as bad as you can "skip steps" such as passing a context to a callback directly rather than needing the function that calls the callback to support contexts. But still in general your functions do have colour if you want to use contexts properly.
> most seasoned Go devs would leap out of their seats to tell you it’s an anti-pattern for libraries to start their own goroutines.
If goroutines are so cheap then why not let the library spawn them. As long as the interface doesn't reveal if they are being used or not it shouldn't matter.
- icholy 3y ago> This is in contrast to the fact that Go's cheap threading means that you don't need to colour your functions with async or not async. But this quote that you sort of have to do this with context or no context. This doesn't have the usual problems associated with colored functions though (ie, calling async functions from non-async functions or vice-versa). If you don't need cancellation, pass a `context.Background()` and you're done. > If goroutines are so cheap then why not let the library spawn them. As long as the interface doesn't reveal if they are being used or not it shouldn't matter. Agreed. providing a synchronous API is what's important.
- mariusor 3y ago> you don't need to colour your functions with async or not async. Context is useful for synchronous functions also, it has nothing to do with async.
- jerf 3y agoYou can't extend the concept of "coloring" a function to all possible environment and parameters a function needs to execute. That's not because that's a useless concept; I actually find it a very important concept to be thinking about and I often explicitly think in terms of trying to minimize the size of such things in my code. But you can't extend the "coloring" concept that far because you've stretched it all out of shape at that point, into an entirely different concept. All code in all languages everywhere is going to have state that flows through some combination of function parameters through the program and have certain requirements for that state without which the functions (methods/whatever) will not run. Coloration is a very particular very strong instance of such things that is so strong it causes its own special effects and imposes very special constraints on the code. Generally if you need to call something that wants a context but you don't have one, you just pass in the trivially-obtained "context.Background()" and move on. Nowhere near the level of blockage as a color issue. "If goroutines are so cheap then why not let the library spawn them." It's not about cost, it's about software engineering, and it's a particular antipattern you may not know about if you're not in the community. As I said in another post, many libraries "helpfully" spawn goroutines to do a thing and offer a promise-like interface to the results. This is the core antipattern being referred to, which I've seen quite a lot. The resulting API is complexified relative to simply having a function that takes parameters and returns results. If you write such a complex API, an end-user of that API can't uncomplexify it. However, if you write the simple, normal function, an end-user of your API who does want that additional functionality can trivially add it, and moreover, they can add it in whatever other combination of things they may want, e.g., perhaps your library is part of a three-step pipeline you choose to run in its own goroutine, or some other complex threading setup you need. It is better for a library to provide the simple "synchronous" API than to try to guess and possibly even as a result forstall the real setup you need. It isn't a hard-and-fast rule that libraries must never spawn goroutines, it's a particular set of antipatterns being referred to.
- the_gipsy 3y ago> You can't extend the concept of "coloring" a function to all possible environment and parameters a function needs to execute. It's not the particular abstraction, it's the concept of two different colors: functions that take or don't take context.Context. Ultimately we do have two colors. Seasoned go devs will have refactored some to the other by drilling through `ctx` or removing it and know exactly what "color" is. > many libraries "helpfully" spawn goroutines to do a thing and offer a promise-like interface to the results. This is the core antipattern being referred to, which I've seen quite a lot. The resulting API is complexified relative to simply having a function that takes parameters and returns results. If you write such a complex API, an end-user of that API can't uncomplexify it. However, if you write the simple, normal function, an end-user of your API who does want that additional functionality can trivially add it, and moreover, they can add it in whatever other combination of things they may want Do you not read that as "two colors"?
- jerf 3y ago"Ultimately we do have two colors." If you consider this a color, we don't have two colors. We have millions. As I said, it is not that such a concept would be useless; I use it all the time. But it's not "color" any more. "Do you not read that as "two colors"?" That is in response to a completely different question about the cheapness of goroutines, not coloration. Coloration is much stronger than you seem to be understanding. It is not "oh, this function requires that parameter and that one does not, so they must be different colors". It is that you can't correctly run an async function from within a synchronous one and vice versa in the languages in which these are considered completely different things (which does not include Go). While conversion is ultimately possible, it is expensive and high-consquence. If you have a hard time seeing that because, say, a sync function can "simply" bring up an async execution engine for its async calls and an async function can "simply" spawn an entire OS thread to run sync code and collect the results through a promise, consider nesting such an approach arbitrarily deeply as a deep call stack alternates between async and sync calls, which is 100% realistic. It becomes more clear how high-consequence this is if you remember that such programming language constructs must be able to compose essentially arbitrarily deeply. Context parameters can be satisfied by no-context functions simply by passing "context.Background()", and the result is low-consequence. The code does not come apart at the seams, the code using contexts simply ends up not having any data come from the background (empty) context and the background context will never generate a cancellation event, which is apparently what the caller wants since they are asking for that more-or-less explicitly. If that is not what the caller wants, "ctx, cancelF := context.WithTimout(context.Background(), time.Second)" is also trivially available, correct, and low-consequence. If you define coloration down to this level, you completely lose the entire point of the original essay, which is the high-effort, high-consequence effects of bridging sync and async code. Defining colors down to "This function takes a file pointer, thus it is 'file pointer colored'" is profoundly missing the entire point. The idea of function color is useful precisely because it is limited to only certain high-cost conversions, not spread so thin as to cover literally every function parameter. Contexts aren't very special; it is literally easier come up with one if you don't have one ("context.Background()") than it is to come up with an integer, in which you must actually pick one. It isn't anywhere near special enough to justify being called a "color" any more than a file pointer, or a database connection, or any of hundreds of other resource types, most of which impose more constraints on the code than contexts.
- Thaxll 3y agoGo routine are cheap this is not the point, the point is should libraries expose blocking or not blocking API. Who should create goroutine etc...