Eiji
January 8, 2020, 1:39am
23
@josevalim
Would there be an is_struct/2
version?
defmodule Example do
defstruct […]
def sample(struct) when is_struct(struct, __MODULE__), do: {:ok, struct}
def sample(_), do: :error
end
if not is there any naming convention for it (like we have @type t
spec)?
defmodule Example do
defstruct […]
@type t :: %__MODULE__{…}
defguard is_t(struct) when is_struct(struct) and :erlang.map_get(:__struct__, struct) === __MODULE__
def sample(struct) when is_t(struct), do: {:ok, struct}
def sample(_), do: :error
end
Would be added also other features discussed in this topic?
Hi everyone,
Erlang/OTP 21 comes with two new guards contributed by @michalmuskala : map_get/2 and is_map_key/2. Now we need to discuss how we would integrate those in Elixir. This proposal will be broken in three parts, each with their own discussion. Feel free to comment on any conclusion individually or as a group, but please let us know why.
NOTE: this is a focused thread, so we appreciate if everybody stayed on topic. Feel free to comment anything in regards to maps and guards but avoid of…
Looks like Bob actually sleeps more than a typical human.
For sure generally I don’t mind, but if I remember correctly Bob
had exactly same problem with at least one previous release as well, so it does not a single standalone edge-case.
Also there are some extra warnings when building elixir
at tests step:
opened 02:00AM - 08 Jan 20 UTC
closed 03:00PM - 12 Jan 20 UTC
Kind:Bug
App:Elixir (compiler)
### Environment
* Elixir & Erlang/OTP versions (elixir --version):
At test … compilation stage of git tag reference: `v1.10.0-rc.0` with latest `Erlang` (22.2.1)
```elixir
$ erl
Erlang/OTP 22 [erts-10.6.1] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [hipe]
Eshell V10.6.1
```
* Operating system:
```elixir
$ lsb_release --all
LSB Version: n/a
Distributor ID: openSUSE
Description: openSUSE Tumbleweed
Release: 20191231
Codename: n/a
$ cat /proc/version
Linux version 5.3.12-2-default (geeko@buildhost) (gcc version 9.2.1 20190903 [gcc-9-branch revision 275330] (SUSE Linux)) #1 SMP Thu Nov 21 07:21:43 UTC 2019 (a6f6081)
$ uname -a
Linux install 5.3.12-2-default #1 SMP Thu Nov 21 07:21:43 UTC 2019 (a6f6081) x86_64 x86_64 x86_64 GNU/Linux
```
### Current behavior
This is a current log with warnings.
```elixir
$ asdf install elixir ref:v1.10.0-rc.0
==> Checking whether specified Elixir release/reference exists...
==> Downloading v1.10.0-rc.0 to /tmp/elixir_build_4zBhzP/elixir-ref-v1.10.0-rc.0-src.tar.gz
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 132 0 132 0 0 530 0 --:--:-- --:--:-- --:--:-- 530
100 2268k 0 2268k 0 0 675k 0 --:--:-- 0:00:03 --:--:-- 858k
==> Making the release
rm -rf ebin
rm -rf lib/*/ebin
rm -rf lib/elixir/src/elixir_parser.erl
make[1]: Wejście do katalogu '/home/USERNAME/.asdf/installs/elixir/ref-v1.10.0-rc.0'
rm -rf lib/*/_build/
rm -rf lib/*/tmp/
rm -rf lib/elixir/test/ebin/
rm -rf lib/mix/test/fixtures/deps_on_git_repo/
rm -rf lib/mix/test/fixtures/git_rebar/
rm -rf lib/mix/test/fixtures/git_repo/
rm -rf lib/mix/test/fixtures/git_sparse_repo/
rm -f erl_crash.dump
make[2]: Wejście do katalogu '/home/USERNAME/.asdf/installs/elixir/ref-v1.10.0-rc.0'
rm -f man/elixir.1
rm -f man/elixir.1.bak
rm -f man/iex.1
rm -f man/iex.1.bak
make[2]: Opuszczenie katalogu '/home/USERNAME/.asdf/installs/elixir/ref-v1.10.0-rc.0'
make[1]: Opuszczenie katalogu '/home/USERNAME/.asdf/installs/elixir/ref-v1.10.0-rc.0'
Recompile: src/elixir_utils
Recompile: src/elixir_tokenizer
Recompile: src/elixir_sup
Recompile: src/elixir_rewrite
Recompile: src/elixir_quote
Recompile: src/elixir_parser
Recompile: src/elixir_overridable
Recompile: src/elixir_module
Recompile: src/elixir_map
Recompile: src/elixir_locals
Recompile: src/elixir_lexical
Recompile: src/elixir_interpolation
Recompile: src/elixir_import
Recompile: src/elixir_fn
Recompile: src/elixir_expand
Recompile: src/elixir_errors
Recompile: src/elixir_erl_var
Recompile: src/elixir_erl_try
Recompile: src/elixir_erl_pass
Recompile: src/elixir_erl_for
Recompile: src/elixir_erl_compiler
Recompile: src/elixir_erl_clauses
Recompile: src/elixir_erl
Recompile: src/elixir_env
Recompile: src/elixir_dispatch
Recompile: src/elixir_def
Recompile: src/elixir_config
Recompile: src/elixir_compiler
Recompile: src/elixir_code_server
Recompile: src/elixir_clauses
Recompile: src/elixir_bootstrap
Recompile: src/elixir_bitstring
Recompile: src/elixir_aliases
Recompile: src/elixir
Generated elixir app
==> bootstrap (compile)
Compiled lib/elixir/lib/kernel.ex
Compiled lib/elixir/lib/macro/env.ex
Compiled lib/elixir/lib/keyword.ex
Compiled lib/elixir/lib/module.ex
Compiled lib/elixir/lib/list.ex
Compiled lib/elixir/lib/macro.ex
Compiled lib/elixir/lib/kernel/typespec.ex
Compiled lib/elixir/lib/code.ex
Compiled lib/elixir/lib/code/identifier.ex
Compiled lib/elixir/lib/module/checker.ex
Compiled lib/elixir/lib/module/locals_tracker.ex
Compiled lib/elixir/lib/module/parallel_checker.ex
Compiled lib/elixir/lib/module/types/helpers.ex
Compiled lib/elixir/lib/module/types/infer.ex
Compiled lib/elixir/lib/module/types/expr.ex
Compiled lib/elixir/lib/module/types/pattern.ex
Compiled lib/elixir/lib/module/types.ex
Compiled lib/elixir/lib/kernel/utils.ex
Compiled lib/elixir/lib/exception.ex
Compiled lib/elixir/lib/protocol.ex
Compiled lib/elixir/lib/stream/reducers.ex
Compiled lib/elixir/lib/enum.ex
Compiled lib/elixir/lib/map.ex
Compiled lib/elixir/lib/inspect/algebra.ex
Compiled lib/elixir/lib/inspect.ex
Compiled lib/elixir/lib/access.ex
Compiled lib/elixir/lib/range.ex
Compiled lib/elixir/lib/regex.ex
Compiled lib/elixir/lib/string.ex
Compiled lib/elixir/lib/string/chars.ex
Compiled lib/elixir/lib/io.ex
Compiled lib/elixir/lib/path.ex
Compiled lib/elixir/lib/file.ex
Compiled lib/elixir/lib/system.ex
Compiled lib/elixir/lib/kernel/cli.ex
Compiled lib/elixir/lib/kernel/error_handler.ex
Compiled lib/elixir/lib/kernel/parallel_compiler.ex
Compiled lib/elixir/lib/kernel/lexical_tracker.ex
make[1]: Wejście do katalogu '/home/USERNAME/.asdf/installs/elixir/ref-v1.10.0-rc.0'
==> unicode (compile)
Compiling /home/USERNAME/.asdf/installs/elixir/ref-v1.10.0-rc.0/lib/elixir/unicode/unicode.ex (it's taking more than 15s)
make[1]: Opuszczenie katalogu '/home/USERNAME/.asdf/installs/elixir/ref-v1.10.0-rc.0'
==> elixir (compile)
Compiling /home/USERNAME/.asdf/installs/elixir/ref-v1.10.0-rc.0/lib/elixir/lib/base.ex (it's taking more than 15s)
make[1]: Wejście do katalogu '/home/USERNAME/.asdf/installs/elixir/ref-v1.10.0-rc.0'
Generated elixir app
make[1]: Opuszczenie katalogu '/home/USERNAME/.asdf/installs/elixir/ref-v1.10.0-rc.0'
==> eex (compile)
==> mix (compile)
Generated mix app
==> ex_unit (compile)
Generated ex_unit app
==> logger (compile)
Generated logger app
Generated eex app
==> iex (compile)
Generated iex app
==> elixir (eunit)
All 190 tests passed.
==> elixir (ex_unit)
warning: function clause will never match, found incompatibility:
atom() !~ integer()
in expression:
is_atom(atom) and not(is_integer(atom) and Bitwise.band(atom, 1) == 1)
where "atom" was given the type integer() in:
# test/elixir/integer_test.exs:11
Bitwise.band(atom, 1)
where "atom" was given the type atom() in:
# test/elixir/integer_test.exs:11
is_atom(atom)
Conflict found at
test/elixir/integer_test.exs:11: IntegerTest.test_is_odd_in_guards/1
warning: function clause will never match, found incompatibility:
atom() !~ integer()
in expression:
is_atom(atom) and not(is_integer(atom) and Bitwise.band(atom, 1) == 0)
where "atom" was given the type integer() in:
# test/elixir/integer_test.exs:15
Bitwise.band(atom, 1)
where "atom" was given the type atom() in:
# test/elixir/integer_test.exs:15
is_atom(atom)
Conflict found at
test/elixir/integer_test.exs:15: IntegerTest.test_is_even_in_guards/1
Excluding tags: [windows: true]
......................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................
Finished in 65.3 seconds (34.7s on load, 30.5s on tests)
1572 doctests, 3386 tests, 0 failures, 8 excluded
Randomized with seed 926785
==> ex_unit (ex_unit)
...............................................................................................................................................................................................................................................................................................................................................................
Finished in 8.4 seconds (4.2s on load, 4.2s on tests)
42 doctests, 309 tests, 0 failures
Randomized with seed 732539
==> logger (ex_unit)
............................................................................................................................
Finished in 4.1 seconds (3.5s on load, 0.6s on tests)
3 doctests, 121 tests, 0 failures
Randomized with seed 525517
==> mix (ex_unit)
Excluding tags: [windows: true]
................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................
Finished in 244.6 seconds (9.7s on load, 234.9s on tests)
9 doctests, 615 tests, 0 failures
Randomized with seed 941701
==> eex (ex_unit)
.............................................................................................
Finished in 1.1 seconds (1.1s on load, 0.09s on tests)
5 doctests, 88 tests, 0 failures
Randomized with seed 967235
==> iex (ex_unit)
.......................................................................................................................................................................................................................................
Finished in 16.0 seconds (3.1s on load, 12.8s on tests)
231 tests, 0 failures
Randomized with seed 265094
```
### Expected behavior
There should be no compilation warnings.
2 Likes
Pelemay 0.0.5 works well on Elixir v1.10.0-rc.0.
Try them!
9 Likes
Unfortunately no. There were some complexities in implementing it. Those interested can dig the discussion on GitHub and link it back here please.
Haha, we are looking into it. Bob is like conference wifi, when it works, nobody notices. When it fails, everyone does!
Thanks, we had already noticed it and we are on it. The warnings are correct in being emitted, but their content is partially wrong.
4 Likes
josevalim:
Haha, we are looking into it. Bob is like conference wifi, when it works, nobody notices. When it fails, everyone does!
Maybe make checking https://bobs-list.kobrakai.de/ part of the rc release todo list
2 Likes
Bob is good now and the archives and docs for 1.10.0-rc.0 are available.
6 Likes
hauleth
January 8, 2020, 10:40am
28
elixir-lang:master
← hauleth:feat/is_struct
We need to check what happens when you don't pass an atom as second argument. Id… eally we would want to raise badarg, but that means we would need to make the guard fail instead of returning false and that is not easy to emulate.
Any ideas on how we could emulate it? If we can't, then we will need to postpone is_struct/2 for now. :/
cc @Eiji
However there was a proposed solution on Erlang issue tracker and I need to check if this will pass the Dialyzer and will emit no warnings.
EDIT: It will not work, at least not without deep changes to the Modules.Types.Infer
as currently adding or :fail
to the guard generates hell lot of warnings.
3 Likes
I’m not sure if this is intended as a breaking change, but I guess at least it should be added to the changelog: URI error on getting gravatar elixir v1.10.0-rc.0
1 Like
tme_317
January 8, 2020, 11:22am
30
Eiji:
Would there be an is_struct/2
version?
defmodule Example do
defstruct […]
def sample(struct) when is_struct(struct, __MODULE__), do: {:ok, struct}
def sample(_), do: :error
end
Pattern matching works great here without needing is_struct/2
.
def sample(%__MODULE__{} = struct), do: {:ok, struct}
Actually not sure in what situations I should use the new guard since is_struct/1
could also be written as:
def sample(%_{} = struct), do: {:ok, struct}
The guard reads intent more explicitly to me but AFAIK the pattern matching works as well.
1 Like
alco
January 8, 2020, 11:23am
31
That doesn’t work. I get this error when trying to pass a function to mix xref callers
:
** (Mix) xref callers MODULE expects a MODULE, got: XXX.Import.Jobs.process_job
Eiji
January 8, 2020, 11:55am
32
sure, it’s more useful in defguard
and defguardp
Imagine you want to write is_t
guard like:
defmodule Example do
defstruct […]
@type t :: %__MODULE__{…}
defguard is_t(struct) when is_struct(struct, __MODULE__) …
end
2 Likes
Oh, neat. Please open up a new issue so we can discuss how to address this!
Wlll do, thanks.
1 Like
jswny
January 8, 2020, 4:01pm
34
I’m also wondering what the use case for is_struct/1
is because pattern matching can already do The same thing with an underscore like you said.
I guess that using it inside of defining a new guard is the only new thing really?
In my case it would be readability. %_{}
isn’t exactly something that immediately catches your eye while is_struct
is readily noticeable.
All subjective tastes of course. But to me is_struct
has a very valid place.
is_struct/1 allows things that are not possible with pattern matches, e.g.: when is_struct(term) or is_integer(term)
and when not is_struct(term)
.
10 Likes
Even better! Thanks for the clarification.
bjorng
January 8, 2020, 4:42pm
38
hauleth:
However there was a proposed solution on Erlang issue tracker and I need to check if this will pass the Dialyzer and will emit no warnings.
EDIT: It will not work, at least not without deep changes to the Modules.Types.Infer
as currently adding or :fail
to the guard generates hell lot of warnings.
Not sure if this is useful, but here is how erl_expand_records
forces an exception in a guard:
NL = no_compiler_warning(L),
T1 = {op,NL,'orelse',
{call,NL,
{remote,NL,{atom,NL,erlang},{atom,NL,is_record}},
[R,{atom,NL,Name},{integer,NL,Sz}]},
{atom,NL,fail}},
Here is how warnings are suppressed (for both the Erlang compiler and Dialyzer):
9 Likes
AstonJ
Split this topic
January 9, 2020, 4:18am
39
It does not work correctly any more. https://github.com/elixir-lsp/elixir_sense , the library behind https://github.com/elixir-lsp/elixir-ls uses Mix.Tasks.Xref.calls/0
and it does not properly register some function calls. I know that it is now deprecated but it should not be broken.
This was never public interface of Mix, so there were no guarantees that this will work. This function was never safe to call.
1 Like