4 ms·
> - a lot of knowledge is implicit (try checking if you can dynamically add children to a Supervisor) What? This is very clear: <https://www.erlang.org/doc/app
by simoncion 2y ago
> - a lot of knowledge is implicit (try checking if you can dynamically add children to a Supervisor)
What? This is very clear: <https://www.erlang.org/doc/apps/stdlib/supervisor.html#start_child/2 https://www.erlang.org/doc/apps/stdlib/supervisor.html#start...>, as is this: <https://hexdocs.pm/elixir/1.18.3/Supervisor.html#start_child/2 https://hexdocs.pm/elixir/1.18.3/Supervisor.html#start_child...>. What am I missing?
> - this order of compilation influences outcome and can lead to buggy code
Do you have an example of this? It's my understanding that the big thing about both Erlang and Elixir are that they're functional languages, it doesn't matter what's compiled when. Is this some nightmare compile-time code manipulation thing?
> ...searching [the docs] shows random versions and there isn’t even a link to „open newest”
Is scrolling to the top of the list contained in the version selector near the top left of hexdocs.pm not good enough? If not, why not?
- dqv 2y agoThey are probably talking about the child spec needing a unique ID if it's the same module being started. The docs problem is more of a Google problem. For some reason Google still only shows the 1.12 docs for a lot of searches. The sidebar issue was fixed more recently, I think in the last year. But basically the sidebar wouldn't get loaded until Mermaid finished loading, so it was updated to defer loading of Mermaid. The latest version of ExDoc shouldn't have this problem.
- simoncion 2y ago> They are probably talking about the child spec needing a unique ID if it's the same module being started. No, my experience says that's not true. I have this code in one of my projects and it works just fine: -behavior(gen_server). start(Mod, Args) -> supervisor:start_child(secret_project_worker_sup:getName(), [{Mod, Args}]). I can spawn as many of those guys as I like and they all become children of the named supervisor. The named supervisor is a 'simple_one_for_one' supervisor with a 'temporary' restart policy. I guess the thing that might trip folks up with how the docs are worded is not noticing this further up in the document A supervisor can have one of the following restart strategies specified with the strategy key in the above map: ... * simple_one_for_one - A simplified one_for_one supervisor, where all child processes are dynamically added instances of the same process type, that is, running the same code. and that 'start_child/2' accepts EITHER a 'child_spec()' OR a list of terms -spec start_child(SupRef, ChildSpec) -> startchild_ret() when SupRef :: sup_ref(), ChildSpec :: child_spec(); (SupRef, ExtraArgs) -> startchild_ret() when SupRef :: sup_ref(), ExtraArgs :: [term()]. and that only the 'child_spec()' type can have an identifier, so the first bullet point in the list of three in the function documentation does not apply. Also, I find the way the docs USED to print out function types a bit easier to understand than the new style: <https://web.archive.org/web/20170509120825/http://erlang.org/doc/man/supervisor.html#start_child-2 https://web.archive.org/web/20170509120825/http://erlang.org...>. (You will need to either close the Archive.org nav banner or scroll up a line to see the first line of the function type information, which is pretty informative.)
- dqv 2y agoI'm talking about the behavior of the one_for_one supervisor: defmodule Testing.Application do use Application @impl Application def start(_type, _args) do children = [] opts = [strategy: :one_for_one, name: Testing.Supervisor] Supervisor.start_link(children, opts) end end defmodule Testing.Server do use GenServer def start_link(_), do: GenServer.start_link(__MODULE__, []) @impl GenServer def init(_), do: {:ok, nil} end When you try to start more than one child, it fails: Erlang/OTP 25 [erts-13.2.2.11] [source] [64-bit] [smp:14:14] [ds:14:14:10] [async-threads:1] [jit:ns] Interactive Elixir (1.17.3) - press Ctrl+C to exit (type h() ENTER for help) iex(1)> Supervisor.start_child(Testing.Supervisor, {Testing.Server, []}) {:ok, #PID<0.135.0>} iex(2)> Supervisor.start_child(Testing.Supervisor, {Testing.Server, [:x]}) {:error, {:already_started, #PID<0.135.0>}} But defining a child spec that sets the id: defmodule Testing.Server do use GenServer def start_link(_), do: GenServer.start_link(__MODULE__, []) def child_spec(arg) do id = Keyword.get(arg, :id) %{id: id, start: {__MODULE__, :start_link, [[]]}} end @impl GenServer def init(_), do: {:ok, nil} end solves the problem: Erlang/OTP 25 [erts-13.2.2.11] [source] [64-bit] [smp:14:14] [ds:14:14:10] [async-threads:1] [jit:ns] Interactive Elixir (1.17.3) - press Ctrl+C to exit (type h() ENTER for help) iex(1)> Supervisor.start_child(Testing.Supervisor, {Testing.Server, id: 1}) {:ok, #PID<0.135.0>} iex(2)> Supervisor.start_child(Testing.Supervisor, {Testing.Server, id: 1}) {:error, {:already_started, #PID<0.135.0>}} iex(3)> Supervisor.start_child(Testing.Supervisor, {Testing.Server, id: 2}) {:ok, #PID<0.136.0>}
- simoncion 2y ago> I'm talking about the behavior of the one_for_one supervisor: Oh, sure, you can vary the ID in non-'simple_one_for_one' supervisors there to make that work. Apologies for inducing you to write out all that transcript and code. But, OP's claim was: > - a lot of knowledge is implicit (try checking if you can dynamically add children to a Supervisor) which is just not fucking true no matter how you slice it. It's true that the relevant documentation doesn't literally say "Calling 'start_child/2' is valid for any kind of 'supervisor'. That's why it's here... to dynamically add children to a 'supervisor'.", but if one bothers to read the docs on supervisors and the function in question it's clear that that's the entire point of 'start_child/2'.
- xlii 2y agoYou’re coming from position of knowledge. I don’t memorize documentation because it changes often and I use 3-5 various languages over the month. For fun and profit ;) So I go into docs, Elixir because that’s the primary source and when I search for „dynamic” and „supervisor” everything points to (no fanfares) DynamicSupervisor. And yet I look at the diff where 12 months earlier my colleague changed DynamicSupervisor to Supervisor because connection adapter tended to crash and not start back up and that day I debug zombie connections. Erlang has it clearly explained, and ultimately, over couple hours of research I found solution and fixed it, but there was no warning that between two lines of shutdown and delete BEAM could restart a child leading to a shadowing (and - in that case - unmanaged as adapter manager lives in other app that has a slot for a single process only) zombie connection handler. This is the stuff people rarely look at because many systems don’t have high idempotency requirements but (only a parabole, that’s not my industry) would you like your system to administer double dosage of potentially lethal drugs? None is preferable but it’s still far from happy system land. As for Hexdocs.pm - this goes once again about operating cost. Yes, I can do this, but search is not great and I more often have a broad queries and search for patterns or guidelines. I rely on „map mode” (how I can find knowledge) and not on „collect mode” (i.e. I keep knowledge), due to some mostly intrinsic traits. And thanks to wonders of modern human tracking^W^Wtechnology I can show anecdotal data of the impact. When working with Elixir I spent (one random, recent day) 40% of my time on browsing Hexdocs and 60% in editor+console. One random recent day on Go I spent 95% time in E+C and 5% in documentation. My first line of code written in Go was less than 6 months ago, my first line of Elixir was written years ago, I would’ve to check my resume when exactly, but somewhere like a 8 years and I toyed with it when it wasn’t yet deemed production ready.
- simoncion 2y ago> ...there was no warning that between two lines of shutdown and delete BEAM could restart a child... If you're talking about calling 'terminate_child/2' followed by 'delete_child/2', there is a very explicit warning. From <https://hexdocs.pm/elixir/1.18.3/Supervisor.html#terminate_child/2 https://hexdocs.pm/elixir/1.18.3/Supervisor.html#terminate_c...> > A non-temporary child process may later be restarted by the supervisor. and from <https://www.erlang.org/doc/apps/stdlib/supervisor.html#terminate_child/2 https://www.erlang.org/doc/apps/stdlib/supervisor.html#termi...> > The process, if any, is terminated and, unless it is a temporary child, the child specification is kept by the supervisor. The child process can later be restarted by the supervisor. In the English-language docs, the warning is very clear: children that a supervisor will restart on termination may be restarted before you get around to calling 'delete_child'. Children with a restart type of 'permanent' will always cause a race between 't_c' and 'd_c'. Children with a restart type of 'transient' will cause a race if they terminate abnormally... which is a term defined by the same document that the warning comes from. You keep insisting that this stuff isn't documented. Are you perhaps reading a poor translation of the docs? > You’re coming from position of knowledge. No, I'm not. I've forgotten most of the details I ever knew about how the system works and only remember broad strokes. My experience with Erlang/OTP was scattered throughout my spare time over an eight to twelve month period ten years ago. Unlike you, I've never been paid to work with it, and you've worked with it far more recently than I. The reason I was able to direct you to the right part of the docs was because I said to myself "Wow, it would be fuckin stupid if you couldn't dynamically add children to a supervisor. I remember the Erlang docs being really, really good, so let's see if they failed to describe if and/or how this works.", and then spent like five minutes reading the docs and another couple cross-checking with the Elixir docs. > I don’t memorize documentation because it changes often... Do the rules for "+", "-", and (if present) "%" change often in most major languages when they are used with built-in types? [0] It's always well worth your time to learn the rules for commonly-used, bedrock parts of a language, major libraries, and runtime systems that you intend to use. Bedrock parts don't substantially change, because if they did, they would invalidate every program ever written against those parts. OTP provides a collection of bedrock parts, and supervisors are one such part. Memorizing docs is really stupid, but having a solid understanding of how the major things you use work is always worth the time. Seriously, how would you function as a programmer if you didn't know how addition or string concatenation worked? If you're using OTP's supervisors, having a good understanding of how they function is just as fundamental. > One random recent day on Go I spent 95% time in E+C and 5% in documentation. Sure, that makes some sense. OTP is far more complex and robust than anything Go offers, so it's quite a bit quicker to come up to speed with what's documented in the Go official docs than what's in the OTP docs. Also, as someone who has written Go professionally for the last five, ten years, I warn you that you're going to get turbofucked by the things that -if they are documented at all- are documented only in blog posts or random tutorials. Go is an absolute grab bag of poorly-documented sharp edges and surprising behavior. > I rely on „map mode” (how I can find knowledge) and not on „collect mode” (i.e. I keep knowledge)... [and] I can show anecdotal data of the impact. The impact of you failing to familiarize yourself with the necessarily-complex tools you chose [1] to use seems pretty clear to me. You got tripped up by documented behaviour that you didn't bother to understand, which caused you to spend hours looking for solutions that would have been clear after a ten minute trip to the documentation for the 'supervisor' module. Given what you've said elsewhere in this subthread about how your project is an "an enormous Jenga tower that's risky to breath around", I suspect that a significant number of your coworkers also refused to familiarize themselves with the tools they use. [0] No, they do not. [1] (or were obligated)