Skip to content
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

Handle arbitrarily high integer values in Process.sleep/1 #13649

Merged
merged 2 commits into from
Jun 9, 2024

Conversation

vegris
Copy link
Contributor

@vegris vegris commented Jun 9, 2024

A while ago OTP timer module was changed to support sleeping with arbitrarily high integer timeout values. Given that Process.sleep/1 is almost the same as :timer.sleep/1 it seems that Elixir could support this too.

There are a number of ways to implement it, each with it's own tradeoffs regarding backward compatibility when supplying wrong types.

In this PR I just translated Erlang's implementation to Elixir. This allows it to keep FunctionClauseError on bad input, but error text now mentions timeout > 4_294_967_295 guard which can be confusing to the end user.

❯ bin/elixir -e "Process.sleep(:atom)"
** (FunctionClauseError) no function clause matching in Process.sleep/1    
    
    The following arguments were given to Process.sleep/1:
    
        # 1
        :atom
    
    Attempted function clauses (showing 2 out of 2):
    
        def sleep(timeout) when is_integer(timeout) and timeout > 4_294_967_295
        def sleep(timeout) when is_integer(timeout) and timeout >= 0 when timeout == :infinity
    
    (elixir 1.18.0-dev) lib/process.ex:313: Process.sleep/1
    nofile:1: (file)
    (stdlib 5.2.3) erl_eval.erl:750: :erl_eval.do_apply/7
    (elixir 1.18.0-dev) lib/code.ex:567: Code.validated_eval_string/3

There is also an option of just delegating sleep to :timer, though in this case we would be getting ErlangError instead of FunctionClauseError:

❯ bin/elixir -e "Process.sleep(:atom)"
** (ErlangError) Erlang error: :timeout_value
    (stdlib 5.2.3) timer.erl:235: :timer.sleep/1
    nofile:1: (file)
    (stdlib 5.2.3) erl_eval.erl:750: :erl_eval.do_apply/7
    (elixir 1.18.0-dev) lib/code.ex:567: Code.validated_eval_string/3

The third option is to keep the guards as is and "delegate" to :timer.sleep by hand in the function body.
This change allows to keep the error message exactly as it was, but introduces a function call with an additional (redundant) argument check.

I'm not sure what is Elixir's stability commitment in regards to exception values, so I'm ready to supply the code for any one of these cases 😃

@josevalim josevalim merged commit f484960 into elixir-lang:main Jun 9, 2024
9 checks passed
@josevalim
Copy link
Member

💚 💙 💜 💛 ❤️

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

2 participants