Skip to content

[Suggestion] Default __result__ sourceHandle #91

Description

@GeigerJ2

Actually, the main point to consider this for is if one wants to pass the entire return dictionary of a function as the input to another function. In that case, each individual key-value pair is resolved to an individual port, but also the entire dictionary contents are wrapped using __result__.

In the case that a function doesn't return a dictionary, should the return value of a function always map to a special sourcePort, e.g., __result__?
-> To pass it as an input to the next task requires a name. To make it beginner-friendly, we do this automatically.

What if the function does return a dictionary, we automatically resolve the keys to individual sourceHandles (as suggested by the PWD JSON snippets we have). Then, should we also return the full dictionary wrapped in __result__, such that this:

def test(x, y):
    return {"prod": x * y, "div": x / y}

yields the sourceHandles: prod, div, and __result__. Or, as we don't really have types, what if we don't know that the return of the function is a dictionary, we still wrap it in __result__? What if the user then defines a function that also contains the key __result__:

def test(x, y):
    return {"prod": x * y, "div": x / y, "__result__": True}

This will except at runtime, as reserved keyword being used. Function might be written by somebody else and we don't have control. Thus, use more convoluted dunder-result. In the workflow definition, one could have an additional key global_workflow_output, such that it can be automatically renamed.

For comparison, when decorating functions with WorkGraph decorators, the mapping of function outputs to ports is handled in the following way:

  1. Function doesn't return a dictionary, but some other data type → return value is wrapped in a dictionary with the default key "result".
  2. Function does return a dictionary, but output names are not explicitly given via the decorator → The whole dictionary is wrapped in another dictionary with the default key "result". In both cases, the function is only assigned a single output port.
  3. Function does return a dictionary, and the outputs are explicitly provided in the decorator, e.g., @task(outputs=["prod", "div"]) → one output port is generated for each explicitly provided output, with the value returned contained in the dictionary at the respective key being the data object that is passed via the port, where the port name is the key of the dictionary (as defined also explicitly in the decorator).

Activity

  1. changed the title [-]Default `__result__` `sourcePort`[/-] [+]Default `__result__` `sourceHandle`[/+] on May 5, 2025
  2. changed the title [-]Default `__result__` `sourceHandle`[/-] [+][Suggestion] Default `__result__` `sourceHandle`[/+] on May 24, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions