diff --git a/CHANGELOG.md b/CHANGELOG.md index 425b5ff92a..68ea047e98 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ * [Kernel] `is_alive/0` is deprecated in favor of `Node.alive?` * [Kernel] `Kernel.inspect/2` with `Inspect.Opts[]` is deprecated in favor of `Inspect.Algebra.to_doc/2` * [Kernel] `Kernel.inspect/2` with `:raw` option is deprecated, use `:records` option instead + * [Kernel] Deprecate `<-/2` in favor of `send/2` * Backwards incompatible changes * [String] Change `String.next_grapheme/1` and `String.next_codepoint/1` to return `nil` on string end diff --git a/lib/elixir/lib/kernel.ex b/lib/elixir/lib/kernel.ex index 19e2536491..f8822b237c 100644 --- a/lib/elixir/lib/kernel.ex +++ b/lib/elixir/lib/kernel.ex @@ -866,6 +866,24 @@ defmodule Kernel do :erlang.round(number) end + @doc """ + Sends a message to the given `dest` and returns the message. + + `dest` may be a remote or local pid, a (local) port, a locally + registered name, or a tuple `{registed_name, node}` for a registered + name at another node. + + ## Examples + + iex> send self(), :hello + :hello + + """ + @spec send(dest :: pid | port | atom | { atom, node }, msg) :: msg when msg: any + def send(dest, msg) do + :erlang.send(dest, msg) + end + @doc """ Returns the pid (process identifier) of the calling process. Allowed in guard clauses. @@ -893,7 +911,7 @@ defmodule Kernel do ## Examples current = Kernel.self - child = spawn(fn -> current <- { Kernel.self, 1 + 2 } end) + child = spawn(fn -> send current, { Kernel.self, 1 + 2 } end) receive do { ^child, 3 } -> IO.puts "Received 3 back" @@ -931,7 +949,7 @@ defmodule Kernel do ## Examples current = Kernel.self - child = spawn_link(fn -> current <- { Kernel.self, 1 + 2 } end) + child = spawn_link(fn -> send current, { Kernel.self, 1 + 2 } end) receive do { ^child, 3 } -> IO.puts "Received 3 back" @@ -1118,19 +1136,10 @@ defmodule Kernel do quote do: __op__(:/, unquote(left), unquote(right)) end - @doc """ - Sends a message to the process identified on the left. - A process can be identified by its PID or, if it is registered, - by an atom. - - ## Examples - - process = Kernel.self - process <- { :ok, "Sending myself a message" } - - """ - defmacro pid <- msg do - quote do: :erlang.!(unquote(pid), unquote(msg)) + @doc false + def pid <- msg do + IO.write "<-/2 is deprecated, please use send/2 instead\n#{Exception.format_stacktrace}" + :erlang.!(pid, msg) end @doc """ @@ -1773,7 +1782,7 @@ defmodule Kernel do end def inspect(arg, opts) when is_list(opts) do - case opts[:raw] do + case Keyword.get(opts, :raw) do nil -> :ok raw -> diff --git a/lib/elixir/lib/kernel/error_handler.ex b/lib/elixir/lib/kernel/error_handler.ex index ec63bab55a..bb58555986 100644 --- a/lib/elixir/lib/kernel/error_handler.ex +++ b/lib/elixir/lib/kernel/error_handler.ex @@ -19,7 +19,7 @@ defmodule Kernel.ErrorHandler do { :error, _ } -> parent = :erlang.get(:elixir_compiler_pid) ref = :erlang.make_ref - parent <- { :waiting, self(), ref, module } + send parent, { :waiting, self(), ref, module } :erlang.garbage_collect(self) receive do { ^ref, :ready } -> diff --git a/lib/elixir/lib/kernel/parallel_compiler.ex b/lib/elixir/lib/kernel/parallel_compiler.ex index 4944784ad0..d51582a51c 100644 --- a/lib/elixir/lib/kernel/parallel_compiler.ex +++ b/lib/elixir/lib/kernel/parallel_compiler.ex @@ -65,7 +65,7 @@ defmodule Kernel.ParallelCompiler do # Release waiting processes defp spawn_compilers([h|t], original, output, callbacks, waiting, queued, schedulers, result) when is_pid(h) do { ^h, ref, _ } = List.keyfind(waiting, h, 0) - h <- { ref, :ready } + send h, { ref, :ready } waiting = List.keydelete(waiting, h, 0) spawn_compilers(t, original, output, callbacks, waiting, queued, schedulers, result) end @@ -107,7 +107,7 @@ defmodule Kernel.ParallelCompiler do defp spawn_compilers([], original, output, callbacks, waiting, queued, schedulers, result) when length(waiting) == length(queued) do Enum.each queued, fn { child, _, _ } -> { ^child, ref, _ } = List.keyfind(waiting, child, 0) - child <- { ref, :release } + send child, { ref, :release } end wait_for_messages([], original, output, callbacks, waiting, queued, schedulers, result) end @@ -126,7 +126,7 @@ defmodule Kernel.ParallelCompiler do end # Release the module loader which is waiting for an ack - child <- { ref, :ack } + send child, { ref, :ack } available = lc { pid, _, waiting_module } inlist waiting, waiting_module == module, @@ -138,7 +138,7 @@ defmodule Kernel.ParallelCompiler do { :waiting, child, ref, on } -> # Oops, we already got this module. Do not put it on waiting. if :lists.member(on, result) do - child <- { :release, ref } + send child, { :release, ref } else waiting = [{ child, ref, on }|waiting] end diff --git a/lib/elixir/lib/process.ex b/lib/elixir/lib/process.ex index 8699f0d444..cefbd7572a 100644 --- a/lib/elixir/lib/process.ex +++ b/lib/elixir/lib/process.ex @@ -264,8 +264,8 @@ defmodule Process do @doc """ Associates the name with a pid or a port identifier. name, which must - be an atom, can be used instead of the pid / port identifier in the - send operator (name <- message). + be an atom, can be used instead of the pid / port identifier with the + `Kernel.send/2` function. See http://www.erlang.org/doc/man/erlang.html#register-2 for more info. """ diff --git a/lib/elixir/lib/stream.ex b/lib/elixir/lib/stream.ex index 96916e1441..442dd19675 100644 --- a/lib/elixir/lib/stream.ex +++ b/lib/elixir/lib/stream.ex @@ -340,7 +340,7 @@ defmodule Stream do ## Examples - iex> stream = Stream.each([1, 2, 3], fn(x) -> self <- x end) + iex> stream = Stream.each([1, 2, 3], fn(x) -> send self, x end) iex> Enum.to_list(stream) iex> receive do: (x when is_integer(x) -> x) 1 diff --git a/lib/elixir/src/elixir_dispatch.erl b/lib/elixir/src/elixir_dispatch.erl index e14e74deaf..f5c2c75254 100644 --- a/lib/elixir/src/elixir_dispatch.erl +++ b/lib/elixir/src/elixir_dispatch.erl @@ -375,6 +375,7 @@ in_erlang_functions() -> % { now, 0 }, { round, 1 }, { self, 0 }, + { send, 2 }, { size, 1 }, { spawn, 1 }, { spawn, 3 }, diff --git a/lib/elixir/test/elixir/stream_test.exs b/lib/elixir/test/elixir/stream_test.exs index 806f7d8baa..e9b70ca674 100644 --- a/lib/elixir/test/elixir/stream_test.exs +++ b/lib/elixir/test/elixir/stream_test.exs @@ -169,18 +169,18 @@ defmodule StreamTest do par = self pid = spawn_link fn -> Enum.each Stream.drop(&inbox_stream/2, -3), - fn x -> par <- { :stream, x } end + fn x -> send par, { :stream, x } end end - pid <- { :stream, 1 } - pid <- { :stream, 2 } - pid <- { :stream, 3 } + send pid, { :stream, 1 } + send pid, { :stream, 2 } + send pid, { :stream, 3 } refute_receive { :stream, 1 } - pid <- { :stream, 4 } + send pid, { :stream, 4 } assert_receive { :stream, 1 } - pid <- { :stream, 5 } + send pid, { :stream, 5 } assert_receive { :stream, 2 } refute_receive { :stream, 3 } end diff --git a/lib/elixir/test/erlang/control_test.erl b/lib/elixir/test/erlang/control_test.erl index 5d4e44c0eb..8931a022e4 100644 --- a/lib/elixir/test/erlang/control_test.erl +++ b/lib/elixir/test/erlang/control_test.erl @@ -60,13 +60,13 @@ try_else_test() -> % Receive receive_test() -> - {10, _} = eval("self() <- :foo\nreceive do\n:foo -> 10\nend"), - {20, _} = eval("self() <- :bar\nreceive do\n:foo -> 10\n_ -> 20\nend"), + {10, _} = eval("send self(), :foo\nreceive do\n:foo -> 10\nend"), + {20, _} = eval("send self(), :bar\nreceive do\n:foo -> 10\n_ -> 20\nend"), {30, _} = eval("receive do\nafter 1 -> 30\nend"). vars_receive_test() -> - {10, _} = eval("self() <- :foo\nreceive do\n:foo ->\na = 10\n:bar -> nil\nend\na"), - {nil, _} = eval("self() <- :bar\nreceive do\n:foo ->\nb = 10\n_ -> 20\nend\nb"), + {10, _} = eval("send self(), :foo\nreceive do\n:foo ->\na = 10\n:bar -> nil\nend\na"), + {nil, _} = eval("send self(), :bar\nreceive do\n:foo ->\nb = 10\n_ -> 20\nend\nb"), {30, _} = eval("receive do\n:foo -> nil\nafter\n1 -> c = 30\nend\nc"), {30, _} = eval("x = 1\nreceive do\n:foo -> nil\nafter\nx -> c = 30\nend\nc"). diff --git a/lib/ex_unit/lib/ex_unit/assertions.ex b/lib/ex_unit/lib/ex_unit/assertions.ex index 57d8cdba96..08865eb81a 100644 --- a/lib/ex_unit/lib/ex_unit/assertions.ex +++ b/lib/ex_unit/lib/ex_unit/assertions.ex @@ -292,12 +292,12 @@ defmodule ExUnit.Assertions do ## Examples - self <- :hello + send self, :hello assert_received :hello You can also match against specific patterns: - self <- { :hello, "world" } + send self, { :hello, "world" } assert_received { :hello, _ } """ @@ -478,7 +478,7 @@ defmodule ExUnit.Assertions do ## Examples - self <- :hello + send self, :hello refute_received :bye """ diff --git a/lib/ex_unit/lib/ex_unit/capture_io.ex b/lib/ex_unit/lib/ex_unit/capture_io.ex index c2164c6679..f1ff328436 100644 --- a/lib/ex_unit/lib/ex_unit/capture_io.ex +++ b/lib/ex_unit/lib/ex_unit/capture_io.ex @@ -93,7 +93,7 @@ defmodule ExUnit.CaptureIO do fun.() after :erlang.group_leader(original_gl, self) - capture_gl <- :stop + send capture_gl, :stop end receive do @@ -117,7 +117,7 @@ defmodule ExUnit.CaptureIO do after Process.unregister(device) Process.register(original_io, device) - capture_io <- :stop + send capture_io, :stop end receive do @@ -178,7 +178,7 @@ defmodule ExUnit.CaptureIO do group_leader_loop(runner, 0, buf) after wait -> :erlang.process_flag(:priority, :normal) - runner <- { self, buffer_to_result(buf) } + send runner, { self, buffer_to_result(buf) } end end @@ -189,7 +189,7 @@ defmodule ExUnit.CaptureIO do end defp io_reply(from, reply_as, reply) do - from <- { :io_reply, reply_as, reply } + send from, { :io_reply, reply_as, reply } end defp io_request({ :put_chars, chars }, buf) do diff --git a/lib/ex_unit/lib/ex_unit/runner.ex b/lib/ex_unit/lib/ex_unit/runner.ex index eeb682df01..18e1387dcb 100644 --- a/lib/ex_unit/lib/ex_unit/runner.ex +++ b/lib/ex_unit/lib/ex_unit/runner.ex @@ -101,7 +101,7 @@ defmodule ExUnit.Runner do # entities involved. Enum.each failed, &run_test(config, &1, []) config.formatter.case_finished(config.formatter_id, test_case) - pid <- { self, :case_finished, test_case } + send pid, { self, :case_finished, test_case } end defp prepare_tests(config, tests) do @@ -132,7 +132,7 @@ defmodule ExUnit.Runner do end test_case = exec_case_teardown(test_case, context) - self_pid <- { self, :case_finished, test_case, tests } + send self_pid, { self, :case_finished, test_case, tests } end receive do @@ -181,7 +181,7 @@ defmodule ExUnit.Runner do exec_test_teardown(test, context) end) - self_pid <- { self, :test_finished, test.time(us) } + send self_pid, { self, :test_finished, test.time(us) } end) receive do diff --git a/lib/ex_unit/test/ex_unit/assertions_test.exs b/lib/ex_unit/test/ex_unit/assertions_test.exs index 28a4ebbdf2..cdfa052549 100644 --- a/lib/ex_unit/test/ex_unit/assertions_test.exs +++ b/lib/ex_unit/test/ex_unit/assertions_test.exs @@ -88,12 +88,12 @@ defmodule ExUnit.AssertionsTest do test "assert receive waits" do parent = self - spawn fn -> parent <- :hello end + spawn fn -> send parent, :hello end :hello = assert_receive :hello end test "assert received does not wait" do - self <- :hello + send self, :hello :hello = assert_received :hello end @@ -115,7 +115,7 @@ defmodule ExUnit.AssertionsTest do end test "refute received when equal" do - self <- :hello + send self, :hello try do "This should never be tested" = refute_received :hello rescue diff --git a/lib/ex_unit/test/ex_unit/capture_io_test.exs b/lib/ex_unit/test/ex_unit/capture_io_test.exs index a91f9e4d79..77316af962 100644 --- a/lib/ex_unit/test/ex_unit/capture_io_test.exs +++ b/lib/ex_unit/test/ex_unit/capture_io_test.exs @@ -21,7 +21,7 @@ defmodule ExUnit.CaptureIOTest.GetUntil do end def get_line(device // Process.group_leader) do - device <- { :io_request, self, device, { :get_until, :unicode, "", __MODULE__, :until_new_line, [?\n] } } + send device, { :io_request, self, device, { :get_until, :unicode, "", __MODULE__, :until_new_line, [?\n] } } receive do { :io_reply, _, data } -> data end @@ -289,7 +289,7 @@ defmodule ExUnit.CaptureIOTest do end defp send_and_receive_io(req) do - :erlang.group_leader <- { :io_request, self, self, req } + send :erlang.group_leader, { :io_request, self, self, req } s = self receive do { :io_reply, ^s, res} -> res diff --git a/lib/iex/lib/iex/cli.ex b/lib/iex/lib/iex/cli.ex index d099fa10cf..45148d1f15 100644 --- a/lib/iex/lib/iex/cli.ex +++ b/lib/iex/lib/iex/cli.ex @@ -107,13 +107,13 @@ defmodule IEx.CLI do receive do { :begin, ^ref, other } -> :elixir.start_cli - other <- { :done, ref } + send other, { :done, ref } end end fn -> IEx.start(config, fn -> - parent <- { :begin, ref, self } + send parent, { :begin, ref, self } receive do: ({ :done, ^ref } -> :ok) end) end diff --git a/lib/iex/lib/iex/evaluator.ex b/lib/iex/lib/iex/evaluator.ex index 269d31640f..f45505a57b 100644 --- a/lib/iex/lib/iex/evaluator.ex +++ b/lib/iex/lib/iex/evaluator.ex @@ -30,7 +30,7 @@ defmodule IEx.Evaluator do defp loop(server) do receive do { :eval, ^server, code, config } -> - server <- { :evaled, self, eval(code, config) } + send server, { :evaled, self, eval(code, config) } loop(server) { :done, ^server } -> IEx.History.reset diff --git a/lib/iex/lib/iex/helpers.ex b/lib/iex/lib/iex/helpers.ex index a2881b27a6..659cad40d0 100644 --- a/lib/iex/lib/iex/helpers.ex +++ b/lib/iex/lib/iex/helpers.ex @@ -452,7 +452,7 @@ defmodule IEx.Helpers do """ def respawn do if whereis = IEx.Server.whereis do - whereis <- { :respawn, self } + send whereis, { :respawn, self } true else false diff --git a/lib/iex/lib/iex/server.ex b/lib/iex/lib/iex/server.ex index 1969d14777..51a26b2a76 100644 --- a/lib/iex/lib/iex/server.ex +++ b/lib/iex/lib/iex/server.ex @@ -41,12 +41,12 @@ defmodule IEx.Server do { :error, :no_iex } true -> ref = make_ref() - server <- { :take?, self, ref } + send server, { :take?, self, ref } receive do ^ref -> opts = Keyword.put(opts, :evaluator, self) - server <- { :take, self, identifier, ref, opts } + send server, { :take, self, identifier, ref, opts } receive do { ^ref, nil } -> @@ -84,15 +84,15 @@ defmodule IEx.Server do defp start_loop(opts, pid, ref) do receive do { :take?, other, ref } -> - other <- ref + send other, ref start_loop(opts, pid, ref) { :take, other, identifier, ref, opts } -> if allow_take?(identifier) do - other <- { ref, Process.group_leader } + send other, { ref, Process.group_leader } run(opts) else - other <- { ref, nil } + send other, { ref, nil } start_loop(opts, pid, ref) end @@ -126,7 +126,7 @@ defmodule IEx.Server do Process.delete(:evaluator) Process.demonitor(evaluator_ref) if done? do - evaluator <- { :done, self } + send evaluator, { :done, self } end :ok end @@ -145,7 +145,7 @@ defmodule IEx.Server do # Input handling. # Message either go back to the main loop or exit. { :input, ^input, code } when is_binary(code) -> - evaluator <- { :eval, self, code, config } + send evaluator, { :eval, self, code, config } wait_eval(evaluator, evaluator_ref) { :input, ^input, { :error, :interrupted } } -> io_error "** (EXIT) interrupted" @@ -161,16 +161,16 @@ defmodule IEx.Server do # needs to take hold of the IO, so it kills the input, # re-runs the server OR goes back to the main loop. { :take?, other, ref } -> - other <- ref + send other, ref wait_input(config, evaluator, evaluator_ref, input) { :take, other, identifier, ref, opts } -> kill_input(input) if allow_take?(identifier) do - other <- { ref, Process.group_leader } + send other, { ref, Process.group_leader } reset_loop(opts, evaluator, evaluator_ref) else - other <- { ref, nil } + send other, { ref, nil } loop(config, evaluator, evaluator_ref) end @@ -192,14 +192,14 @@ defmodule IEx.Server do { :evaled, ^evaluator, config } -> loop(config, evaluator, evaluator_ref) { :take?, other, ref } -> - other <- ref + send other, ref wait_eval(evaluator, evaluator_ref) { :take, other, identifier, ref, opts } -> if allow_take?(identifier) do - other <- { ref, Process.group_leader } + send other, { ref, Process.group_leader } reset_loop(opts, evaluator, evaluator_ref) else - other <- { ref, nil } + send other, { ref, nil } wait_eval(evaluator, evaluator_ref) end end @@ -248,7 +248,7 @@ defmodule IEx.Server do "#{prefix || "iex"}(#{counter})> " end - pid <- { :input, self, IO.gets(:stdio, prompt) } + send pid, { :input, self, IO.gets(:stdio, prompt) } end defp io_error(result) do diff --git a/lib/iex/test/iex/helpers_test.exs b/lib/iex/test/iex/helpers_test.exs index 26892ebc51..a06841f498 100644 --- a/lib/iex/test/iex/helpers_test.exs +++ b/lib/iex/test/iex/helpers_test.exs @@ -130,7 +130,7 @@ defmodule IEx.HelpersTest do end test "flush helper" do - assert capture_io(fn -> self() <- :hello; flush end) == ":hello\n" + assert capture_io(fn -> send self(), :hello; flush end) == ":hello\n" end test "pwd helper" do diff --git a/lib/mix/lib/mix/shell/process.ex b/lib/mix/lib/mix/shell/process.ex index 65246156d0..5761dfc4c9 100644 --- a/lib/mix/lib/mix/shell/process.ex +++ b/lib/mix/lib/mix/shell/process.ex @@ -46,7 +46,7 @@ defmodule Mix.Shell.Process do def cmd(command) do put_app Mix.Shell.cmd(command, fn(data) -> - self <- { :mix_shell, :run, [data] } + send self, { :mix_shell, :run, [data] } end) end @@ -55,7 +55,7 @@ defmodule Mix.Shell.Process do """ def info(message) do put_app - self <- { :mix_shell, :info, [IO.ANSI.escape(message, false)] } + send self, { :mix_shell, :info, [IO.ANSI.escape(message, false)] } end @doc """ @@ -63,7 +63,7 @@ defmodule Mix.Shell.Process do """ def error(message) do put_app - self <- { :mix_shell, :error, [IO.ANSI.escape(message, false)] } + send self, { :mix_shell, :error, [IO.ANSI.escape(message, false)] } end @doc """ @@ -77,7 +77,7 @@ defmodule Mix.Shell.Process do """ def yes?(message) do put_app - self <- { :mix_shell, :yes?, [IO.ANSI.escape(message, false)] } + send self, { :mix_shell, :yes?, [IO.ANSI.escape(message, false)] } receive do { :mix_shell_input, :yes?, response } -> response @@ -88,7 +88,7 @@ defmodule Mix.Shell.Process do defp put_app do if Mix.Shell.output_app? do - self <- { :mix_shell, :info, ["==> #{Mix.project[:app]}"] } + send self, { :mix_shell, :info, ["==> #{Mix.project[:app]}"] } end end end diff --git a/lib/mix/test/mix/generator_test.exs b/lib/mix/test/mix/generator_test.exs index 3b816aea8e..db73c2f27c 100644 --- a/lib/mix/test/mix/generator_test.exs +++ b/lib/mix/test/mix/generator_test.exs @@ -32,7 +32,7 @@ defmodule Mix.GeneratorTest do test :create_with_conflict_returning_true do in_tmp "create_file", fn -> File.write! "foo", "HELLO" - self <- { :mix_shell_input, :yes?, true } + send self, { :mix_shell_input, :yes?, true } create_file "foo", "WORLD" assert File.read!("foo") == "WORLD" @@ -44,7 +44,7 @@ defmodule Mix.GeneratorTest do test :create_with_conflict_returning_false do in_tmp "create_file", fn -> File.write! "foo", "HELLO" - self <- { :mix_shell_input, :yes?, false } + send self, { :mix_shell_input, :yes?, false } create_file "foo", "WORLD" assert File.read!("foo") == "HELLO" diff --git a/lib/mix/test/mix/shell_test.exs b/lib/mix/test/mix/shell_test.exs index 43675c8837..9664fe0096 100644 --- a/lib/mix/test/mix/shell_test.exs +++ b/lib/mix/test/mix/shell_test.exs @@ -17,7 +17,7 @@ defmodule Mix.ShellTest do assert_received { :mix_shell, :info, ["abc"] } assert_received { :mix_shell, :error, ["def"] } - self <- { :mix_shell_input, :yes?, true } + send self, { :mix_shell_input, :yes?, true } assert Mix.shell.yes?("hello?") assert_received { :mix_shell, :yes?, ["hello?"] } diff --git a/lib/mix/test/mix/tasks/local_test.exs b/lib/mix/test/mix/tasks/local_test.exs index 5c2d398d76..5e9c63931d 100644 --- a/lib/mix/test/mix/tasks/local_test.exs +++ b/lib/mix/test/mix/tasks/local_test.exs @@ -25,7 +25,7 @@ defmodule Mix.Tasks.LocalTest do Mix.Tasks.Archive.run [] assert File.regular? "archive-0.1.0.ez" - self <- { :mix_shell_input, :yes?, true } + send self, { :mix_shell_input, :yes?, true } Mix.Tasks.Local.Install.run [] assert File.regular? tmp_path("userhome/.mix/archives/archive-0.1.0.ez") @@ -43,14 +43,14 @@ defmodule Mix.Tasks.LocalTest do Mix.Tasks.Archive.run ["--no_compile"] assert File.regular? "archive-0.2.0.ez" - self <- { :mix_shell_input, :yes?, true } + send self, { :mix_shell_input, :yes?, true } Mix.Tasks.Local.Install.run [] assert File.regular? tmp_path("userhome/.mix/archives/archive-0.2.0.ez") refute File.regular? tmp_path("userhome/.mix/archives/archive-0.1.0.ez") Mix.Local.append_archives # Remove it! - self <- { :mix_shell_input, :yes?, true } + send self, { :mix_shell_input, :yes?, true } Mix.Tasks.Local.Uninstall.run ["archive"] refute File.regular? tmp_path("userhome/.mix/archives/archive-0.2.0.ez") Mix.Project.pop