Skip to content

Commit 2286700

Browse files
committed
Closes #180
1 parent e9b856d commit 2286700

File tree

3 files changed

+72
-4
lines changed

3 files changed

+72
-4
lines changed

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,11 @@ class IntField(Field):
7474

7575
It literally has a lot of problems:
7676

77-
- It is hard to type this code. How can I be sure that my `json` will be parsed by the given schema?
78-
- It contains a lot of boilerplate
79-
- It has complex API: there are usually several methods to override, some fields to adjust. Moreover, we use a class, not a callable
77+
- It is hard to type this code. How can I be sure that my `json` is parseable by the given schema?
78+
- It produces a lot of boilerplate
79+
- It has complex API: there are usually several methods to override, some fields to adjust. Moreover, we use a class, not a simple function
8080
- It is hard to extend the default library for new custom types you will have in your own project
81+
- It is hard to override
8182

8283
There should be a better way of solving this problem!
8384
And typeclasses are a better way!
@@ -107,7 +108,6 @@ How would new API look like with this concept?
107108
... ', '.join(to_json(list_item) for list_item in instance),
108109
... )
109110

110-
111111
```
112112

113113
See how easy it is to works with types and implementation?

docs/pages/concept.rst

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,54 @@ There's even a pattern to allow all objects in:
162162
>>> assert example('a') == 'obj'
163163
164164
165+
Overriding and extending existing instances
166+
-------------------------------------------
167+
168+
Sometimes we really need to override how things work.
169+
With objects and classes this can be problematic,
170+
because we would need to definie a new subclass
171+
and chances are that it won't be used in some situations.
172+
173+
With ``@typeclass`` overriding something is as easy.
174+
Let's define a typeclass with an instance to be overriden later:
175+
176+
.. code:: python
177+
178+
>>> from classes import typeclass
179+
180+
>>> @typeclass
181+
... def example(instance) -> str:
182+
... ...
183+
184+
>>> @example.instance(str)
185+
... def _example_str(instance: str) -> str:
186+
... return instance.lower()
187+
188+
>>> assert example('Hello') == 'hello'
189+
190+
Now, let's change how ``example`` behaves for ``str``.
191+
The only thing we need to do is to define ``.instance(str)`` once again:
192+
193+
.. code:: python
194+
195+
>>> @example.instance(str)
196+
... def _example_str_new(instance: str) -> str:
197+
... return instance.upper()
198+
199+
>>> assert example('Hello') == 'HELLO'
200+
201+
Note, that we can reuse the original implementation
202+
by calling the instance case directly:
203+
204+
.. code:: python
205+
206+
>>> @example.instance(str)
207+
... def _example_str_new(instance: str) -> str:
208+
... return _example_str(instance) + '!'
209+
210+
>>> assert example('Hello') == 'hello!'
211+
212+
165213
supports typeguard
166214
------------------
167215

typesafety/test_typeclass/test_instance/test_instance_method.yml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,3 +247,23 @@
247247
...
248248
249249
a(None)
250+
251+
252+
- case: typeclass_instance_override
253+
disable_cache: false
254+
main: |
255+
from classes import typeclass
256+
257+
@typeclass
258+
def example(instance) -> str:
259+
...
260+
261+
@example.instance(str)
262+
def _example_str(instance: str) -> str:
263+
return instance.lower()
264+
265+
@example.instance(str)
266+
def _example_str_new(instance: str) -> str:
267+
return _example_str(instance) + '!'
268+
269+
reveal_type(example('a')) # N: Revealed type is "builtins.str"

0 commit comments

Comments
 (0)