Skip to content

Commit ce79d78

Browse files
committed
update for 0.14.3
1 parent 49e793d commit ce79d78

File tree

1 file changed

+89
-14
lines changed

1 file changed

+89
-14
lines changed

doc/features.md

Lines changed: 89 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,10 @@ The exception are the features marked **[M]**, which are primarily intended as a
5252
[**Other**](#other)
5353
- [``def`` as a code block: ``@call``](#def-as-a-code-block-call): run a block of code immediately, in a new lexical scope.
5454
- [``@callwith``: freeze arguments, choose function later](#callwith-freeze-arguments-choose-function-later)
55-
- [``raisef``: ``raise`` as a function](#raisef-raise-as-a-function), useful inside a lambda.
55+
- [``raisef``, ``tryf``: ``raise`` and ``try`` as functions](#raisef-tryf-raise-and-try-as-functions), useful inside a lambda.
56+
- [``equip_with_traceback``](#equip-with-traceback), equip a manually created exception instance with a traceback.
57+
- [``callsite_filename``](#callsite-filename)
58+
- [``safeissubclass``](#safeissubclass), convenience function.
5659
- [``pack``: multi-arg constructor for tuple](#pack-multi-arg-constructor-for-tuple)
5760
- [``namelambda``: rename a function](#namelambda-rename-a-function)
5861
- [``timer``: a context manager for performance testing](#timer-a-context-manager-for-performance-testing)
@@ -427,7 +430,7 @@ Finally, ``frozendict`` obeys the empty-immutable-container singleton invariant:
427430
assert frozendict() is frozendict()
428431
```
429432

430-
*Changed in 0.14.2.* [A bug in `frozendict` pickling](https://github.com/Technologicat/unpythonic/issues/55) has been fixed. Now also the empty `frozendict` pickles and unpickles correctly.
433+
**Changed in 0.14.2**. *[A bug in `frozendict` pickling](https://github.com/Technologicat/unpythonic/issues/55) has been fixed. Now also the empty `frozendict` pickles and unpickles correctly.*
431434

432435

433436
### `cons` and friends: pythonic lispy linked lists
@@ -512,13 +515,13 @@ We provide a ``JackOfAllTradesIterator`` as a compromise that understands both t
512515

513516
### ``box``: a mutable single-item container
514517

515-
*Changed in v0.14.2.* *The `box` container API is now `b.set(newvalue)` to rebind, returning the new value as a convenience. The equivalent syntactic sugar is `b << newvalue`. The item inside the box can be extracted with `b.get()`. The equivalent syntactic sugar is `unbox(b)`.*
518+
**Changed in v0.14.2**. *The `box` container API is now `b.set(newvalue)` to rebind, returning the new value as a convenience. The equivalent syntactic sugar is `b << newvalue`. The item inside the box can be extracted with `b.get()`. The equivalent syntactic sugar is `unbox(b)`.*
516519

517-
*Added in v0.14.2.* *`ThreadLocalBox`: like `box`, but with thread-local contents. It also holds a default object, which is used when a particular thread has not placed any object into the box.*
520+
**Added in v0.14.2**. *`ThreadLocalBox`: like `box`, but with thread-local contents. It also holds a default object, which is used when a particular thread has not placed any object into the box.*
518521

519-
*Added in v0.14.2.* *`Some`: like `box`, but immutable. Useful to mark an optional attribute. `Some(None)` indicates a value that is set to `None`, in contrast to a bare `None`, which can then be used indicate the absence of a value.*
522+
**Added in v0.14.2**. *`Some`: like `box`, but immutable. Useful to mark an optional attribute. `Some(None)` indicates a value that is set to `None`, in contrast to a bare `None`, which can then be used indicate the absence of a value.*
520523

521-
*Changed in v0.14.2.* *Accessing the `.x` attribute of a `box` directly is now deprecated. It will continue to work with `box` at least until 0.15, but it does not and cannot work with `ThreadLocalBox`, which must handle things differently due to implementation reasons. Use the API mentioned above; it supports both kinds of boxes with the same syntax.*
524+
**Changed in v0.14.2**. *Accessing the `.x` attribute of a `box` directly is now deprecated. It will continue to work with `box` at least until 0.15, but it does not and cannot work with `ThreadLocalBox`, which must handle things differently due to implementation reasons. Use the API mentioned above; it supports both kinds of boxes with the same syntax.*
522525

523526
No doubt anyone programming in an imperative language has run into the situation caricatured by this highly artificial example:
524527

@@ -667,7 +670,7 @@ We also provide an **immutable** box, `Some`. This can be useful for optional da
667670

668671
### ``Shim``: redirect attribute accesses
669672

670-
*Added in v0.14.2.*
673+
**Added in v0.14.2**.
671674

672675
A `Shim` is an attribute access proxy. The shim holds a `box` (or a `ThreadLocalBox`), and redirects attribute accesses on the shim to whatever object happens to currently be in the box. The point is that the object in the box can be replaced with a different one later (by sending another object into the box), and the code accessing the proxied object through the shim doesn't need to be aware that anything has changed.
673676

@@ -906,7 +909,7 @@ We also provide ``pipec``, which curries the functions before applying them. Use
906909

907910
Optional **shell-like syntax**, with purely functional updates.
908911

909-
*Changed in v0.14.2*. Both `getvalue` and `runpipe` are now known by the single unified name `exitpipe`. This is just a rename, with no functionality changes. The old names are now deprecated, and will be removed in 0.15.0.
912+
**Changed in v0.14.2**. *Both `getvalue` and `runpipe` are now known by the single unified name `exitpipe`. This is just a rename, with no functionality changes. The old names are now deprecated, and will be removed in 0.15.0.*
910913

911914
```python
912915
from unpythonic import piped, exitpipe
@@ -1536,7 +1539,7 @@ assert tuple(curry(clip, 5, 10, range(20)) == tuple(range(5, 15))
15361539
15371540
### Batteries for network programming
15381541
1539-
*Added in v0.14.2.*
1542+
**Added in v0.14.2**.
15401543
15411544
While all other pure-Python features of `unpythonic` live in the main `unpythonic` package, the network-related features are placed in the subpackage `unpythonic.net`. This subpackage also contains the [REPL server and client](repl.md) for hot-patching live processes.
15421545
@@ -1869,6 +1872,8 @@ There is the read-only cousin ``roview``, which behaves the same except it has n
18691872
18701873
### ``mogrify``: update a mutable container in-place
18711874
1875+
**Changed in v0.14.3.** *`mogrify` now skips `nil`, actually making it useful for processing `ll` linked lists.*
1876+
18721877
Recurse on given container, apply a function to each atom. If the container is mutable, then update in-place; if not, then construct a new copy like ``map`` does.
18731878
18741879
If the container is a mapping, the function is applied to the values; keys are left untouched.
@@ -2012,7 +2017,7 @@ Inspired by Haskell.
20122017
20132018
### ``sym``, ``gensym``, ``Singleton``: symbols and singletons
20142019
2015-
*Added in v0.14.2.*
2020+
**Added in v0.14.2**.
20162021
20172022
We provide **lispy symbols**, an **uninterned symbol generator**, and a **pythonic singleton abstraction**. These are all pickle-aware, and instantiation is thread-safe.
20182023
@@ -2830,6 +2835,12 @@ The implementation is based on the List monad, and a bastardized variant of do-n
28302835
28312836
**Added in v0.14.2**.
28322837
2838+
**Changed in v0.14.3**. *Conditions can now inherit from `BaseException`, not only from `Exception.` `with handlers` catches also derived types, e.g. a handler for `Exception` now catches a signaled `ValueError`.*
2839+
2840+
*When an unhandled `error` or `cerror` occurs, the original unhandled error is now available in the `__cause__` attribute of the `ControlError` exception that is raised in this situation.*
2841+
2842+
*Signaling a class, as in `signal(SomeExceptionClass)`, now implicitly creates an instance with no arguments, just like the `raise` statement does. On Python 3.7+, `signal` now automatically equips the condition instance with a traceback, just like the `raise` statement does for an exception.*
2843+
28332844
One of the killer features of Common Lisp are *conditions*, which are essentially **resumable exceptions**.
28342845
28352846
Following Peter Seibel ([Practical Common Lisp, chapter 19](http://www.gigamonkeys.com/book/beyond-exception-handling-conditions-and-restarts.html)), we define *errors* as the consequences of [Murphy's Law](https://en.wikipedia.org/wiki/Murphy%27s_law), i.e. situations where circumstances cause interaction between the program and the outside world to fail. An error is no bug, but failing to handle an error certainly is.
@@ -2966,6 +2977,8 @@ The core idea can be expressed in fewer than 100 lines of Python; ours is (as of
29662977
29672978
**Changed in v0.14.3**. *The multiple-dispatch decorator `@generic` no longer takes a master definition. Methods are registered directly with `@generic`; the first method definition implicitly creates the generic function.*
29682979
2980+
**Changed in v0.14.3** *The `@generic` and `@typed` decorators can now decorate also instance methods, class methods and static methods (beside regular functions, as previously in 0.14.2).*
2981+
29692982
The ``generic`` decorator allows creating multiple-dispatch generic functions with type annotation syntax.
29702983
29712984
We also provide some friendly utilities: ``typed`` creates a single-method generic with the same syntax (i.e. provides a compact notation for writing dynamic type checking code), and ``isoftype`` (which powers the first two) is the big sister of ``isinstance``, with support for many (but unfortunately not all) features of the ``typing`` standard library module.
@@ -3038,6 +3051,22 @@ See [the unit tests](../unpythonic/test/test_dispatch.py) for more. For which fe
30383051
30393052
Inspired by the [multi-methods of CLOS](http://www.gigamonkeys.com/book/object-reorientation-generic-functions.html) (the Common Lisp Object System), and the [generic functions of Julia](https://docs.julialang.org/en/v1/manual/methods/).
30403053
3054+
##### ``@generic`` and OOP
3055+
3056+
As of version 0.14.3, `@generic` and `@typed` can decorate instance methods, class methods and static methods (beside regular functions as in 0.14.2).
3057+
3058+
When using both `@generic` or `@typed` and OOP:
3059+
3060+
- **`self` and `cls` parameters**.
3061+
- The `self` and `cls` parameters do not participate in dispatching, and need no type annotation.
3062+
- Beside appearing as the first positional-or-keyword parameter, the self-like parameter **must be named** one of `self`, `this`, `cls`, or `klass` to be detected by the ignore mechanism. This limitation is due to implementation reasons; while a class body is being evaluated, the context needed to distinguish a method (OOP sense) from a regular function is not yet present.
3063+
3064+
- **OOP inheritance**.
3065+
- When `@generic` is installed on an OOP method (instance method, or `@classmethod`), then at call time, classes are tried in [MRO](https://en.wikipedia.org/wiki/C3_linearization) order. All generic-function methods of the OOP method defined in the class currently being looked up are tested for matches first, before moving on to the next class in the MRO. (This has subtle consequences, related to in which class in the hierarchy the various generic-function methods for a particular OOP method are defined.)
3066+
- To work with OOP inheritance, `@generic` must be the outermost decorator (except `@classmethod` or `@staticmethod`, which are essentially compiler annotations).
3067+
- However, when installed on a `@staticmethod`, the `@generic` decorator does not support MRO lookup, because that would make no sense. See discussions on interaction between `@staticmethod` and `super` in Python: [[1]](https://bugs.python.org/issue31118) [[2]](https://stackoverflow.com/questions/26788214/super-and-staticmethod-interaction/26807879).
3068+
3069+
30413070
##### Notes
30423071
30433072
*Terminology*: in both CLOS and in Julia, *function* is the generic entity, while *method* refers to its specialization to a particular combination of argument types. Note that *no object instance or class is needed*. Contrast with the classical OOP sense of *method*, i.e. a function that is associated with an object instance or class, with single dispatch based on the class (or in exotic cases, such as monkey-patched instances, on the instance).
@@ -3342,9 +3371,11 @@ assert tuple(m) == (6, 9, 3**(1/2))
33423371
Inspired by *Function application with $* in [LYAH: Higher Order Functions](http://learnyouahaskell.com/higher-order-functions).
33433372
33443373
3345-
### ``raisef``: ``raise`` as a function
3374+
### ``raisef``, ``tryf``: ``raise`` and ``try`` as functions
3375+
3376+
**Changed in v0.14.3**. *Now we have also `tryf`.*
33463377
3347-
*Changed in v0.14.2.* The parameters of `raisef` now more closely match what would be passed to `raise`. See examples below. Old-style parameters are now deprecated, and support for them will be dropped in v0.15.0.
3378+
**Changed in v0.14.2**. *The parameters of `raisef` now more closely match what would be passed to `raise`. See examples below. Old-style parameters are now deprecated, and support for them will be dropped in v0.15.0.*
33483379
33493380
Raise an exception from an expression position:
33503381
@@ -3359,6 +3390,50 @@ exc = TypeError("oof")
33593390
g = lambda x: raisef(RuntimeError("I'm in ur lambda raising exceptions"), cause=exc)
33603391
```
33613392
3393+
Catch an exception in an expression position:
3394+
3395+
```python
3396+
from unpythonic import raisef, tryf
3397+
3398+
raise_instance = lambda: raisef(ValueError("all ok"))
3399+
test[tryf(lambda: raise_instance(),
3400+
(ValueError, lambda err: "got a ValueError: '{}'".format(err.args[0]))) == "got a ValueError: 'all ok'"]
3401+
```
3402+
3403+
The exception handler is a function. It may optionally accept one argument, the exception instance.
3404+
3405+
Functions can also be specified for the `else` and `finally` behavior; see the docstring of `unpythonic.misc.tryf` for details.
3406+
3407+
3408+
### ``equip_with_traceback``
3409+
3410+
**Added in v0.14.3**.
3411+
3412+
Equip a manually created exception instance with a traceback. This is useful mainly in special cases, where `raise` cannot be used for some reason. (The `signal` function in the conditions-and-restarts system uses this.)
3413+
3414+
```python
3415+
e = SomeException(...)
3416+
e = equip_with_traceback(e)
3417+
```
3418+
3419+
The traceback is automatically extracted from the call stack of the calling thread.
3420+
3421+
Optionally, you can cull a number of the topmost frames by passing the optional argument `stacklevel=...`. Typically, for direct use of this function `stacklevel` should be the default `1` (so it excludes `equip_with_traceback` itself, but shows all stack levels from your code), and for use in a utility function that itself is called from your code, it should be `2` (so it excludes the utility function, too).
3422+
3423+
3424+
### ``callsite_filename``
3425+
3426+
**Added in v0.14.3**.
3427+
3428+
Return the filename from which this function is being called. Useful as a building block for debug utilities and similar.
3429+
3430+
3431+
### ``safeissubclass``
3432+
3433+
**Added in v0.14.3**.
3434+
3435+
Convenience function. Like `issubclass(cls)`, but if `cls` is not a class, swallow the `TypeError` and return `False`.
3436+
33623437
33633438
### ``pack``: multi-arg constructor for tuple
33643439
@@ -3449,7 +3524,7 @@ assert getattrrec(w, "x") == 23
34493524
34503525
### ``arities``, ``kwargs``, ``resolve_bindings``: Function signature inspection utilities
34513526
3452-
*Added in v0.14.2*: `resolve_bindings`. Get the parameter bindings a given callable would establish if it was called with the given args and kwargs. This is mainly of interest for implementing memoizers, since this allows them to see (e.g.) `f(1)` and `f(a=1)` as the same thing for `def f(a): pass`.
3527+
**Added in v0.14.2**: `resolve_bindings`. *Get the parameter bindings a given callable would establish if it was called with the given args and kwargs. This is mainly of interest for implementing memoizers, since this allows them to see (e.g.) `f(1)` and `f(a=1)` as the same thing for `def f(a): pass`.*
34533528
34543529
Convenience functions providing an easy-to-use API for inspecting a function's signature. The heavy lifting is done by ``inspect``.
34553530
@@ -3620,7 +3695,7 @@ For more reading, see [David Goldberg (1991): What every computer scientist shou
36203695
36213696
### ``async_raise``: inject an exception to another thread
36223697
3623-
*Added in v0.14.2.*
3698+
**Added in v0.14.2**.
36243699
36253700
*Currently CPython only, because as of this writing (March 2020) PyPy3 does not expose the required functionality to the Python level, nor there seem to be any plans to do so.*
36263701

0 commit comments

Comments
 (0)