Skip to content

Commit

Permalink
deploy: e162c09
Browse files Browse the repository at this point in the history
  • Loading branch information
wesselb committed Aug 18, 2024
1 parent fb4349f commit b86e371
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 45 deletions.
84 changes: 62 additions & 22 deletions _sources/keyword_arguments.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,28 +95,68 @@ NotFoundLookupError: `g(1, 'b')` could not be resolved...
(why)=
## Why Doesn't Dispatch Fully Support Keyword Arguments?

In multiple dispatch, a function can have many implementations, called methods.
For all methods of a function, what is meant by the first argument is unambiguous and
clear.
However, what is meant by an argument named `x` depends on where a method
positioned `x`:
for some methods, `x` might be the first argument, whereas for other method `x`
might be the second argument.
In general, for a function with many methods, argument `x` does not have a unique
position.
In other words, for functions with many methods,
there is usually no correspondence between argument names and positions.

We therefore see that
supporting both positional and named arguments hence results in a specification that
mixes two non-corresponding systems.
Whereas this would be possible, and admittedly it would be convenient to support named
arguments, it would add substantial complexity to the dispatch process.
In addition, for named arguments to be usable,
it would require all methods of a function
to name their arguments in a consistent manner.
This can be particularly problematic if the methods of a function are spread across
It would technically be possible to dispatch of keyword arguments.
Whereas Plum should or not is an ongoing discussion.

The main argument against is that dispatching on keyword arguments
would make the dispatch process sensitive to argument names.
For this to work well, the arguments of all methods of a function would
have to be named consistently.
This can be problematic if the methods of a function are spread across
multiple packages with different authors and code conventions.
In contrast, dispatching only on positional arguments means that
dispatch does not depend on argument names.

In general, Plum closely mimics how multiple dispatch works in the
In general, Plum attempts to mimics how multiple dispatch works in the
[Julia programming language](https://docs.julialang.org/en/).

## I Really Want Keyword Arguments!

You can use the following pattern as a work-around,
which converts all arguments to positional arguments using a wrapper function:

```python
from plum import dispatch


def f(x=None, y=None):
return _f(x, y)


@dispatch
def _f(x: int, y: None):
print("Only `x` is provided! It is an integer.")


@dispatch
def _f(x: float, y: None):
print("Only `x` is provided! It is a float.")


@dispatch
def _f(x: None, y: float):
print("Only `y` is provided! It is a float.")


@dispatch
def _f(x: int, y: float):
print("Both are provided!")
```

```python
>>> f(x=1)
Only `x` is provided! It is an integer.

>>> f(x=1.0)
Only `x` is provided! It is a float.

>>> try: f(y=1)
... except Exception as e: print(f"{type(e).__name__}: {e}")
NotFoundLookupError: `_f(None, 1)` could not be resolved...

>>> f(y=1.0)
Only `y` is provided! It is a float.

>>> f(x=1, y=1.0)
Both are provided!
```
84 changes: 62 additions & 22 deletions keyword_arguments.html
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,7 @@ <h2> Contents </h2>
<ul class="visible nav section-nav flex-column">
<li class="toc-h2 nav-item toc-entry"><a class="reference internal nav-link" href="#default-arguments">Default Arguments</a></li>
<li class="toc-h2 nav-item toc-entry"><a class="reference internal nav-link" href="#why-doesn-t-dispatch-fully-support-keyword-arguments">Why Doesn’t Dispatch Fully Support Keyword Arguments?</a></li>
<li class="toc-h2 nav-item toc-entry"><a class="reference internal nav-link" href="#i-really-want-keyword-arguments">I Really Want Keyword Arguments!</a></li>
</ul>
</nav>
</div>
Expand Down Expand Up @@ -483,30 +484,68 @@ <h2>Default Arguments<a class="headerlink" href="#default-arguments" title="Perm
</section>
<section id="why-doesn-t-dispatch-fully-support-keyword-arguments">
<span id="why"></span><h2>Why Doesn’t Dispatch Fully Support Keyword Arguments?<a class="headerlink" href="#why-doesn-t-dispatch-fully-support-keyword-arguments" title="Permalink to this heading">#</a></h2>
<p>In multiple dispatch, a function can have many implementations, called methods.
For all methods of a function, what is meant by the first argument is unambiguous and
clear.
However, what is meant by an argument named <code class="docutils literal notranslate"><span class="pre">x</span></code> depends on where a method
positioned <code class="docutils literal notranslate"><span class="pre">x</span></code>:
for some methods, <code class="docutils literal notranslate"><span class="pre">x</span></code> might be the first argument, whereas for other method <code class="docutils literal notranslate"><span class="pre">x</span></code>
might be the second argument.
In general, for a function with many methods, argument <code class="docutils literal notranslate"><span class="pre">x</span></code> does not have a unique
position.
In other words, for functions with many methods,
there is usually no correspondence between argument names and positions.</p>
<p>We therefore see that
supporting both positional and named arguments hence results in a specification that
mixes two non-corresponding systems.
Whereas this would be possible, and admittedly it would be convenient to support named
arguments, it would add substantial complexity to the dispatch process.
In addition, for named arguments to be usable,
it would require all methods of a function
to name their arguments in a consistent manner.
This can be particularly problematic if the methods of a function are spread across
multiple packages with different authors and code conventions.</p>
<p>In general, Plum closely mimics how multiple dispatch works in the
<p>It would technically be possible to dispatch of keyword arguments.
Whereas Plum should or not is an ongoing discussion.</p>
<p>The main argument against is that dispatching on keyword arguments
would make the dispatch process sensitive to argument names.
For this to work well, the arguments of all methods of a function would
have to be named consistently.
This can be problematic if the methods of a function are spread across
multiple packages with different authors and code conventions.
In contrast, dispatching only on positional arguments means that
dispatch does not depend on argument names.</p>
<p>In general, Plum attempts to mimics how multiple dispatch works in the
<a class="reference external" href="https://docs.julialang.org/en/">Julia programming language</a>.</p>
</section>
<section id="i-really-want-keyword-arguments">
<h2>I Really Want Keyword Arguments!<a class="headerlink" href="#i-really-want-keyword-arguments" title="Permalink to this heading">#</a></h2>
<p>You can use the following pattern as a work-around,
which converts all arguments to positional arguments using a wrapper function:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">plum</span> <span class="kn">import</span> <span class="n">dispatch</span>


<span class="k">def</span> <span class="nf">f</span><span class="p">(</span><span class="n">x</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">y</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<span class="k">return</span> <span class="n">_f</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">)</span>


<span class="nd">@dispatch</span>
<span class="k">def</span> <span class="nf">_f</span><span class="p">(</span><span class="n">x</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="n">y</span><span class="p">:</span> <span class="kc">None</span><span class="p">):</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Only `x` is provided! It is an integer.&quot;</span><span class="p">)</span>


<span class="nd">@dispatch</span>
<span class="k">def</span> <span class="nf">_f</span><span class="p">(</span><span class="n">x</span><span class="p">:</span> <span class="nb">float</span><span class="p">,</span> <span class="n">y</span><span class="p">:</span> <span class="kc">None</span><span class="p">):</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Only `x` is provided! It is a float.&quot;</span><span class="p">)</span>


<span class="nd">@dispatch</span>
<span class="k">def</span> <span class="nf">_f</span><span class="p">(</span><span class="n">x</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span> <span class="n">y</span><span class="p">:</span> <span class="nb">float</span><span class="p">):</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Only `y` is provided! It is a float.&quot;</span><span class="p">)</span>


<span class="nd">@dispatch</span>
<span class="k">def</span> <span class="nf">_f</span><span class="p">(</span><span class="n">x</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="n">y</span><span class="p">:</span> <span class="nb">float</span><span class="p">):</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Both are provided!&quot;</span><span class="p">)</span>
</pre></div>
</div>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">f</span><span class="p">(</span><span class="n">x</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
<span class="go">Only `x` is provided! It is an integer.</span>

<span class="gp">&gt;&gt;&gt; </span><span class="n">f</span><span class="p">(</span><span class="n">x</span><span class="o">=</span><span class="mf">1.0</span><span class="p">)</span>
<span class="go">Only `x` is provided! It is a float.</span>

<span class="gp">&gt;&gt;&gt; </span><span class="k">try</span><span class="p">:</span> <span class="n">f</span><span class="p">(</span><span class="n">y</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
<span class="gp">... </span><span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="nb">type</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="o">.</span><span class="vm">__name__</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="go">NotFoundLookupError: `_f(None, 1)` could not be resolved...</span>

<span class="gp">&gt;&gt;&gt; </span><span class="n">f</span><span class="p">(</span><span class="n">y</span><span class="o">=</span><span class="mf">1.0</span><span class="p">)</span>
<span class="go">Only `y` is provided! It is a float.</span>

<span class="gp">&gt;&gt;&gt; </span><span class="n">f</span><span class="p">(</span><span class="n">x</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">y</span><span class="o">=</span><span class="mf">1.0</span><span class="p">)</span>
<span class="go">Both are provided!</span>
</pre></div>
</div>
</section>
</section>

<script type="text/x-thebe-config">
Expand Down Expand Up @@ -574,6 +613,7 @@ <h2>Default Arguments<a class="headerlink" href="#default-arguments" title="Perm
<ul class="visible nav section-nav flex-column">
<li class="toc-h2 nav-item toc-entry"><a class="reference internal nav-link" href="#default-arguments">Default Arguments</a></li>
<li class="toc-h2 nav-item toc-entry"><a class="reference internal nav-link" href="#why-doesn-t-dispatch-fully-support-keyword-arguments">Why Doesn’t Dispatch Fully Support Keyword Arguments?</a></li>
<li class="toc-h2 nav-item toc-entry"><a class="reference internal nav-link" href="#i-really-want-keyword-arguments">I Really Want Keyword Arguments!</a></li>
</ul>
</nav></div>

Expand Down
Loading

0 comments on commit b86e371

Please sign in to comment.