Skip to content

Commit 21ed59c

Browse files
committed
Add more docs and examples around function_exported?/3 and macro_exported?/3
1 parent 2013e93 commit 21ed59c

File tree

2 files changed

+23
-14
lines changed

2 files changed

+23
-14
lines changed

lib/elixir/lib/kernel.ex

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4515,26 +4515,32 @@ defmodule Kernel do
45154515
Returns `true` if `module` is loaded and contains a
45164516
public `function` with the given `arity`, otherwise `false`.
45174517
4518-
> ### Unloaded modules {: .warning }
4518+
> ### Unloaded modules {: .warning}
45194519
>
45204520
> This function does *not* load the module in case it is not loaded
45214521
> and Elixir lazily loads modules by default (except on releases).
4522-
> This may yield unexpected results in testing when module
4523-
> usage order is random.
4522+
>
4523+
> This may lead to unexpected behaviour as the result of this function
4524+
> may depend if another code has happened to load the given module
4525+
> as argument beforehand. For example, this could manifest in `mix test`
4526+
> by having tests that fail when running in isolation or depending on the
4527+
> test seed. For those reasons, it is recommended to always check for
4528+
> `Code.ensure_loaded?/1` before `function_exported?/3`, unless you are
4529+
> certain the module has been loaded before.
45244530
>
45254531
> See `Code.ensure_loaded/1` for more information.
45264532
45274533
Inlined by the compiler.
45284534
45294535
## Examples
45304536
4531-
iex> function_exported?(Enum, :map, 2)
4537+
iex> Code.ensure_loaded?(Enum) and function_exported?(Enum, :map, 2)
45324538
true
45334539
4534-
iex> function_exported?(Enum, :map, 10)
4540+
iex> Code.ensure_loaded?(Enum) and function_exported?(Enum, :map, 10)
45354541
false
45364542
4537-
iex> function_exported?(List, :to_string, 1)
4543+
iex> Code.ensure_loaded?(List) and function_exported?(List, :to_string, 1)
45384544
true
45394545
"""
45404546
@spec function_exported?(module, atom, arity) :: boolean
@@ -4547,18 +4553,18 @@ defmodule Kernel do
45474553
public `macro` with the given `arity`, otherwise `false`.
45484554
45494555
Note that this function does not load the module in case
4550-
it is not loaded. Check `Code.ensure_loaded/1` for more
4551-
information.
4556+
it is not loaded. See the notes under `function_exported?/3`
4557+
for more information.
45524558
45534559
If `module` is an Erlang module (as opposed to an Elixir module), this
45544560
function always returns `false`.
45554561
45564562
## Examples
45574563
4558-
iex> macro_exported?(Kernel, :use, 2)
4564+
iex> Code.ensure_loaded?(Kernel) and macro_exported?(Kernel, :use, 2)
45594565
true
45604566
4561-
iex> macro_exported?(:erlang, :abs, 1)
4567+
iex> Code.ensure_loaded?(:erlang) and macro_exported?(:erlang, :abs, 1)
45624568
false
45634569
45644570
"""

lib/elixir/pages/references/typespecs.md

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,13 @@ The notation to represent the union of types is the pipe `|`. For example, the t
6262
> #### Differences with set-theoretic types {: .warning}
6363
>
6464
> While they do share some similarities, the types below do not map one-to-one
65-
> to the new types from the set theoretic type system.
65+
> to the new types from the set-theoretic type system.
66+
>
6667
> For example, there is no plan to support subsets of the `integer()` type such
6768
> as positive, ranges or literals.
69+
>
70+
> Furthermore, set-theoretic types support the full range of set operations,
71+
> including intersections and negations.
6872
6973
### Basic types
7074

@@ -388,10 +392,9 @@ Note you don't need to define a behaviour in order to dynamically dispatch on a
388392

389393
Optional callbacks are callbacks that callback modules may implement if they want to, but are not required to. Usually, behaviour modules know if they should call those callbacks based on configuration, or they check if the callbacks are defined with `function_exported?/3` or `macro_exported?/3`.
390394

391-
> Testing Optional Callbacks {: .warning }
395+
> ### Unloaded modules {: .warning}
392396
>
393-
> `mix test` may exhibit unexpected behaviour when testing a conditional call to an optional callback gated
394-
> on `function_exported?/3`, see the documentation on this function for details.
397+
> `function_exported?/3` (and `macro_exported?/3`) do *not* load the module in case it is not loaded and Elixir lazily loads modules by default (except on releases). So in practice you will want to invoke `Code.ensure_loaded?/1` before checking if the function/macro is exported. See the documentation for `function_exported?/3` for examples.
395398
396399
Optional callbacks can be defined through the `@optional_callbacks` module attribute, which has to be a keyword list with function or macro name as key and arity as value. For example:
397400

0 commit comments

Comments
 (0)