#115

[WIP] [DRAFT] Use *Map(... for T in Iter[...]) instead of *[...]

Draftmsullivanwants to merge intofrom

This lets us turn maps over Iter[Any] into Any, which I think we really might want to do.

Activity

8
vercel[bot]7mo ago

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentActionsUpdated (UTC)
python-typemap ReadyPreview, CommentApr 17, 2026 4:45am
jonathanslenders5mo ago

Question: why exactly is this better? Does Map() allow for better runtime evalution?

Related, I think it would be nice if we could write ... for ... in T when T is a variadic type parameter instead of ... for ... in Iter[tuple[*T]]

As an example, I had the following decorator:

def computed[*T, V](
    *reactives: *[signal[t] for t in Iter[tuple[*T]]],
    name: str | None = None,
) -> Callable[[Callable[[*T], V]], signal[V]]: ...
msullivan5mo ago

Question: why exactly is this better? Does Map() allow for better runtime evalution?

Yes, the idea here is that we would like to be able to turn something like tuple[*[T | None for T in Iter[Any]]] into Any. This isn't doable with our current evaluation system because the list comprehension gets evaluated eagerly and the Iter needs to resolve to something.

By using Map and a generator comprehension, the computation is delayed and we can defer its execution to a place where we can catch an exception raised by it, allowing us to detect that case.

That said, I don't think we are going to go with this approach. I think the real plan is going to be to require being able to extract the AST/string of annotations and support an AST based evaluation. My plan there is to write another PEP for 3.16 for that. Backporting/prototyping gets annoying though; using from __future__ import annotations will be able to work, and I also have a zany scheme for doing "abstract interpretation" of the bytecode of __annotate__ functions to extract ASTs. (A mega-slop draft of that idea here: https://github.com/vercel/python-typemap/tree/bytecode-nonsense)

Related, I think it would be nice if we could write ... for ... in T when T is a variadic type parameter instead of ... for ... in Iter[tuple[*T]]

As an example, I had the following decorator:

def computed[*T, V](
    *reactives: *[signal[t] for t in Iter[tuple[*T]]],
    name: str | None = None,
) -> Callable[[Callable[[*T], V]], signal[V]]: ...

I will ponder this; it might be doable. Did that *reactives type work?

jonathanslenders5mo ago

Thank you!

AST evaluation sounds nice.

The *reactives does not work. Mypy is crashing. You can try the following code if you'd like to reproduce:

from collections.abc import Callable
from dataclasses import dataclass

from typemap_extensions import Iter


@dataclass
class signal[T]:
    value: T | None


def computed[*T, V](
    *reactives: *[signal[t] for t in Iter[tuple[*T]]],
) -> Callable[[Callable[[*T], V]], signal[V]]:
    result = signal[V](None)

    def decorator(func: Callable[[*T], V]) -> signal[V]:
        # Not relevant right now. In here, we'd automatically update the result
        # signal, based on the input signals.
        return result

    return decorator


r1 = signal[int](1)
r2 = signal[int](2)


@computed(r1, r2)
def f1(value1: int, value2: int) -> int:
    # produce a new signal that's the sum of the given signals.
    return value1 + value2


@computed(r1, r2)
def f2(value1: str, value2: str) -> str:
    # Mypy should fail here! Signals are of type int, not str.
    return value1 + value2

This pull request is a draft

Merging is unavailable until it is marked ready for review.